Add windowsize option to receive
This commit is contained in:
parent
3ed9834b60
commit
849dd2e041
2 changed files with 117 additions and 29 deletions
126
src/window.rs
126
src/window.rs
|
|
@ -1,4 +1,9 @@
|
|||
use std::{collections::VecDeque, error::Error, fs::File, io::Read};
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
error::Error,
|
||||
fs::File,
|
||||
io::{Read, Write},
|
||||
};
|
||||
|
||||
/// Window `struct` is used to store chunks of data from a file.
|
||||
/// It is used to store the data that is being sent or received for
|
||||
|
|
@ -55,10 +60,21 @@ impl Window {
|
|||
Ok(true)
|
||||
}
|
||||
|
||||
/// Empties the `Window` by writing the data to the file.
|
||||
pub fn empty(&mut self) -> Result<(), Box<dyn Error>> {
|
||||
for data in &self.elements {
|
||||
self.file.write_all(data)?;
|
||||
}
|
||||
|
||||
self.elements.clear();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Removes the first `amount` of elements from the `Window`.
|
||||
pub fn remove(&mut self, amount: u16) -> Result<(), Box<dyn Error>> {
|
||||
pub fn remove(&mut self, amount: u16) -> Result<(), &'static str> {
|
||||
if amount > self.len() {
|
||||
return Err("amount cannot be larger than size".into());
|
||||
return Err("amount cannot be larger than length of window");
|
||||
}
|
||||
|
||||
drop(self.elements.drain(0..amount as usize));
|
||||
|
|
@ -66,6 +82,17 @@ impl Window {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Adds a data `Vec<u8>` to the `Window`.
|
||||
pub fn add(&mut self, data: Vec<u8>) -> Result<(), &'static str> {
|
||||
if self.len() == self.size {
|
||||
return Err("cannot add to a full window");
|
||||
}
|
||||
|
||||
self.elements.push_back(data);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns a reference to the `VecDeque` containing the elements.
|
||||
pub fn get_elements(&self) -> &VecDeque<Vec<u8>> {
|
||||
&self.elements
|
||||
|
|
@ -80,16 +107,32 @@ impl Window {
|
|||
pub fn is_empty(&self) -> bool {
|
||||
self.elements.is_empty()
|
||||
}
|
||||
|
||||
/// Returns `true` if the `Window` is full.
|
||||
pub fn is_full(&self) -> bool {
|
||||
self.elements.len() as u16 == self.size
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::{fs, io::Write};
|
||||
use std::{
|
||||
fs::{self, OpenOptions},
|
||||
io::{Seek, Write},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
const DIR_NAME: &str = "tmp";
|
||||
|
||||
#[test]
|
||||
fn fills_and_removes_from_window() {
|
||||
let file = initialize();
|
||||
const FILE_NAME: &str = "fills_and_removes_from_window.txt";
|
||||
|
||||
let mut file = initialize(FILE_NAME);
|
||||
file.write_all(b"Hello, world!").unwrap();
|
||||
file.flush().unwrap();
|
||||
file.rewind().unwrap();
|
||||
|
||||
let mut window = Window::new(2, 5, file);
|
||||
window.fill().unwrap();
|
||||
|
|
@ -106,30 +149,65 @@ mod tests {
|
|||
assert_eq!(window.elements[0], b", wor"[..]);
|
||||
assert_eq!(window.elements[1], b"ld!"[..]);
|
||||
|
||||
clean();
|
||||
clean(FILE_NAME);
|
||||
}
|
||||
|
||||
fn initialize() -> File {
|
||||
let dir_name = "tmp";
|
||||
let file_name = "tmp/test.txt";
|
||||
#[test]
|
||||
fn adds_to_and_empties_window() {
|
||||
const FILE_NAME: &str = "adds_to_and_empties_window.txt";
|
||||
|
||||
if fs::metadata(dir_name).is_err() {
|
||||
fs::create_dir(dir_name).unwrap();
|
||||
let file = initialize(FILE_NAME);
|
||||
|
||||
let mut window = Window::new(3, 5, file);
|
||||
window.add(b"Hello".to_vec()).unwrap();
|
||||
assert_eq!(window.elements.len(), 1);
|
||||
assert_eq!(window.elements[0], b"Hello"[..]);
|
||||
|
||||
window.add(b", wor".to_vec()).unwrap();
|
||||
assert_eq!(window.elements.len(), 2);
|
||||
assert_eq!(window.elements[0], b"Hello"[..]);
|
||||
assert_eq!(window.elements[1], b", wor"[..]);
|
||||
|
||||
window.add(b"ld!".to_vec()).unwrap();
|
||||
assert_eq!(window.elements.len(), 3);
|
||||
assert_eq!(window.elements[0], b"Hello"[..]);
|
||||
assert_eq!(window.elements[1], b", wor"[..]);
|
||||
assert_eq!(window.elements[2], b"ld!"[..]);
|
||||
|
||||
window.empty().unwrap();
|
||||
assert_eq!(window.elements.len(), 0);
|
||||
|
||||
let mut contents = Default::default();
|
||||
File::read_to_string(
|
||||
&mut File::open(DIR_NAME.to_string() + "/" + FILE_NAME).unwrap(),
|
||||
&mut contents,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(contents, "Hello, world!");
|
||||
|
||||
clean(FILE_NAME);
|
||||
}
|
||||
|
||||
if File::open(file_name).is_ok() {
|
||||
fn initialize(file_name: &str) -> File {
|
||||
let file_name = DIR_NAME.to_string() + "/" + file_name;
|
||||
if !Path::new(DIR_NAME).is_dir() {
|
||||
fs::create_dir(DIR_NAME).unwrap();
|
||||
}
|
||||
|
||||
if File::open(&file_name).is_ok() {
|
||||
fs::remove_file(&file_name).unwrap();
|
||||
}
|
||||
|
||||
OpenOptions::new()
|
||||
.read(true)
|
||||
.append(true)
|
||||
.create(true)
|
||||
.open(&file_name)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn clean(file_name: &str) {
|
||||
let file_name = DIR_NAME.to_string() + "/" + file_name;
|
||||
fs::remove_file(file_name).unwrap();
|
||||
}
|
||||
|
||||
let mut file = File::create(file_name).unwrap();
|
||||
file.write_all(b"Hello, world!").unwrap();
|
||||
file.flush().unwrap();
|
||||
|
||||
File::open(file_name).unwrap()
|
||||
}
|
||||
|
||||
fn clean() {
|
||||
fs::remove_file("tmp/test.txt").unwrap();
|
||||
fs::remove_dir("tmp").unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use std::{
|
||||
error::Error,
|
||||
fs::{self, File},
|
||||
io::Write,
|
||||
net::{SocketAddr, UdpSocket},
|
||||
path::PathBuf,
|
||||
thread,
|
||||
|
|
@ -101,7 +100,7 @@ impl Worker {
|
|||
let worker_options = parse_options(&mut options, &work_type)?;
|
||||
|
||||
accept_request(&socket, &options, &work_type)?;
|
||||
receive_file(&socket, &mut File::create(&file_path)?, &worker_options)?;
|
||||
receive_file(&socket, File::create(&file_path)?, &worker_options)?;
|
||||
|
||||
Ok(())
|
||||
};
|
||||
|
|
@ -135,6 +134,7 @@ fn send_file(
|
|||
) -> Result<(), Box<dyn Error>> {
|
||||
let mut block_number = 1;
|
||||
let mut window = Window::new(worker_options.windowsize, worker_options.blk_size, file);
|
||||
|
||||
loop {
|
||||
let filled = window.fill()?;
|
||||
|
||||
|
|
@ -177,14 +177,16 @@ fn send_file(
|
|||
|
||||
fn receive_file(
|
||||
socket: &UdpSocket,
|
||||
file: &mut File,
|
||||
file: File,
|
||||
worker_options: &WorkerOptions,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let mut block_number: u16 = 0;
|
||||
loop {
|
||||
let size;
|
||||
let mut window = Window::new(worker_options.windowsize, worker_options.blk_size, file);
|
||||
|
||||
loop {
|
||||
let mut size;
|
||||
let mut retry_cnt = 0;
|
||||
|
||||
loop {
|
||||
match Message::recv_packet_with_size(socket, worker_options.blk_size) {
|
||||
Ok(Packet::Data {
|
||||
|
|
@ -193,10 +195,17 @@ fn receive_file(
|
|||
}) => {
|
||||
if received_block_number == block_number.wrapping_add(1) {
|
||||
block_number = received_block_number;
|
||||
file.write_all(&data)?;
|
||||
size = data.len();
|
||||
window.add(data)?;
|
||||
|
||||
if size < worker_options.blk_size {
|
||||
break;
|
||||
}
|
||||
|
||||
if window.is_full() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(Packet::Error { code, msg }) => {
|
||||
return Err(format!("Received error code {code}: {msg}").into());
|
||||
|
|
@ -210,6 +219,7 @@ fn receive_file(
|
|||
}
|
||||
}
|
||||
|
||||
window.empty()?;
|
||||
Message::send_ack(socket, block_number)?;
|
||||
if size < worker_options.blk_size {
|
||||
break;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue