mod addr;
mod utils;
use indicatif::{ProgressBar, ProgressState, ProgressStyle};
pub use addr::{get_receiver_addr, get_sender_addr};
use std::fmt::Write as FWrite;
use std::fs;
use std::io::{BufWriter, Cursor};
use std::path::PathBuf;
use std::str::FromStr;
use std::{
fs::File,
io::{self, BufReader, Read, Write},
net::TcpStream,
path::Path,
};
pub use utils::sha256;
pub trait ShareFs {
fn send_eof(&mut self) -> io::Result<()>;
fn receive<W: io::Write>(&mut self, stdout: &mut W) -> io::Result<bool>;
fn send_msg<T: AsRef<str>>(&mut self, value: T) -> io::Result<()>;
fn send_info<T: AsRef<str>>(&mut self, name: T) -> io::Result<()>;
fn send_file<P: AsRef<Path>, W: io::Write>(
&mut self,
file: P,
stdout: &mut W,
) -> io::Result<()>;
}
impl ShareFs for TcpStream {
fn send_eof(&mut self) -> io::Result<()> {
write!(self, ":00:")
}
fn send_msg<T: AsRef<str>>(&mut self, value: T) -> io::Result<()> {
let msg = value.as_ref();
write!(self, "msg:{}:", msg.as_bytes().len())?;
let mut cursor = Cursor::new(msg);
transfer_with_progress(&mut cursor, self, msg.len())?;
let mut v = Vec::with_capacity(4);
transfer_without_progress(self, &mut v, 4)?;
let prefix = std::str::from_utf8(&v).unwrap_or_default();
match prefix {
":ss:" => {}
_ => {
eprintln!(".....Falid to Send.....");
std::process::exit(1);
}
}
Ok(())
}
fn send_info<T: AsRef<str>>(&mut self, _name: T) -> io::Result<()> {
todo!()
}
fn send_file<P: AsRef<Path>, W: io::Write>(
&mut self,
file: P,
stdout: &mut W,
) -> io::Result<()> {
let f_name = file
.as_ref()
.display()
.to_string()
.replace("\"", "")
.replace("'", "");
let f = File::open(file)?;
let file_len = f.metadata()?.len();
writeln!(
stdout,
"Sending file: {}, size: {} bytes",
&f_name, file_len
)?;
write!(
self,
"fff:{}:{}:{}",
f_name.as_bytes().len(),
file_len,
f_name
)?;
let mut reader = BufReader::new(f);
transfer_with_progress(&mut reader, self, file_len as usize)?;
let mut buffer: Vec<u8> = vec![0; 4];
self.read_exact(&mut buffer[0..4])?;
let prefix = std::str::from_utf8(&buffer[0..4]).unwrap_or_default();
match prefix {
":ss:" => {}
_ => {
writeln!(stdout, ".....Falid to Send.....")?;
std::process::exit(1);
}
}
Ok(())
}
fn receive<W: io::Write>(&mut self, stdout: &mut W) -> io::Result<bool> {
let mut v: Vec<u8> = Vec::with_capacity(4);
transfer_without_progress(self, &mut v, 4)?;
let prefix = std::str::from_utf8(&v).unwrap_or_default();
match prefix {
":00:" => Ok(false),
"msg:" => {
let len = read_num(self)?;
transfer_with_progress(self, stdout, len)?;
stdout.write_all(b"\n")?;
self.write_all(b":ss:")?;
Ok(true)
}
"fff:" => {
let name_length = read_num(self)?;
let file_length = read_num(self)?;
let mut name: Vec<u8> = Vec::with_capacity(name_length);
transfer_without_progress(self, &mut name, name_length)?;
let name = std::str::from_utf8(&name).unwrap_or_default();
let f_n = PathBuf::from_str(name).unwrap();
let f = fs::File::create_new(f_n.file_name().unwrap())?;
let mut file_writer = BufWriter::new(f);
writeln!(
stdout,
"File Receiving: {}, Size: {} bytes",
name, file_length
)?;
transfer_with_progress(self, &mut file_writer, file_length)?;
file_writer.flush()?;
self.write_all(b":ss:")?;
Ok(true)
}
_ => unreachable!(),
}
}
}
fn transfer_without_progress<R: io::Read, W: io::Write>(
r: &mut R,
w: &mut W,
n: usize,
) -> io::Result<()> {
let mut remain = n;
let mut buffer = vec![0; std::cmp::min(n, 1024 * 32)];
while remain > 0 {
let to_read = std::cmp::min(buffer.len(), remain);
let read_count = r.read(&mut buffer[..to_read])?;
if read_count == 0 {
break;
}
w.write_all(&buffer[..read_count])?;
remain -= read_count;
}
Ok(())
}
fn transfer_with_progress<R: io::Read, W: io::Write>(
r: &mut R,
w: &mut W,
n: usize,
) -> io::Result<()> {
let mut remain = n;
let mut buffer = vec![0; std::cmp::min(n, 1024 * 32)];
let mut i = 0;
let pb = ProgressBar::new(n as u64);
pb.set_style(ProgressStyle::with_template("{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({eta})")
.unwrap()
.with_key("eta", |state: &ProgressState, w: &mut dyn FWrite| write!(w, "{:.1}s", state.eta().as_secs_f64()).unwrap())
.progress_chars("#>-"));
while remain > 0 {
let to_read = std::cmp::min(buffer.len(), remain);
let read_count = r.read(&mut buffer[..to_read])?;
if read_count == 0 {
break;
}
w.write_all(&buffer[..read_count])?;
remain -= read_count;
i += read_count as u64;
pb.set_position(i);
}
pb.finish();
Ok(())
}
fn read_num<R: io::Read>(r: &mut R) -> io::Result<usize> {
let mut buffer = [0; 1];
let mut num = 0;
loop {
let c = r.read(&mut buffer)?;
if c == 0 || !buffer[0].is_ascii_digit() {
break;
}
if num > usize::MAX / 10 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"Number too large",
));
}
num = num * 10 + (buffer[0] - b'0') as usize;
}
Ok(num)
}
#[cfg(test)]
mod tests {
use std::io::{self, sink, Cursor, Read};
use crate::{read_num, transfer_with_progress};
#[test]
fn test_read_num_valid() {
let data = b"123045:abc";
let mut cursor = Cursor::new(data);
let result = read_num(&mut cursor).unwrap();
assert_eq!(result, 123045);
}
#[test]
fn test_read_num_empty() {
let data = b"";
let mut cursor = Cursor::new(data);
let result = read_num(&mut cursor).unwrap();
assert_eq!(result, 0);
}
#[test]
fn test_read_num_with_leading_zeros() {
let data = b"000000000000000000000000000000123";
let mut cursor = Cursor::new(data);
let result = read_num(&mut cursor).unwrap();
assert_eq!(result, 123);
}
#[test]
fn test_read_num_very_large_number() {
let data = format!("00000000{}::::::", usize::MAX);
let mut cursor = Cursor::new(data);
let result = read_num(&mut cursor).unwrap();
assert_eq!(result, usize::MAX);
}
#[test]
fn test_read_num_too_large_number() {
let data = b"9999999999999999999999999999999999";
let mut cursor = Cursor::new(data);
let result = read_num(&mut cursor);
assert!(result.is_err());
assert_eq!(result.unwrap_err().kind(), io::ErrorKind::InvalidData);
}
#[test]
fn test_read_num() {
let data = b"0000100xyz43210?1*";
let mut cursor = Cursor::new(data);
let result = read_num(&mut cursor).unwrap(); assert_eq!(result, 100);
let result = read_num(&mut cursor).unwrap(); assert_eq!(result, 0);
let result = read_num(&mut cursor).unwrap(); assert_eq!(result, 0);
let result = read_num(&mut cursor).unwrap(); assert_eq!(result, 43210);
let result = read_num(&mut cursor).unwrap(); assert_eq!(result, 1);
}
#[test]
fn test_read_n_bytes_exact() {
let data = b"1234567890";
let mut reader = Cursor::new(data);
let mut writer = Vec::new();
transfer_with_progress(&mut reader, &mut writer, 10).unwrap();
assert_eq!(writer, data);
}
#[test]
fn test_read_n_bytes_partial() {
let data = b"1234567890";
let mut reader = Cursor::new(data);
let mut writer = Vec::new();
transfer_with_progress(&mut reader, &mut writer, 5).unwrap();
assert_eq!(writer, b"12345");
}
#[test]
fn test_read_n_bytes_large_n() {
let data = b"1234567890";
let mut reader = Cursor::new(data);
let mut writer = Vec::new();
transfer_with_progress(&mut reader, &mut writer, 20).unwrap();
assert_eq!(writer, data); }
#[test]
fn test_read_n_bytes_empty_input() {
let data = b"";
let mut reader = Cursor::new(data);
let mut writer = Vec::new();
transfer_with_progress(&mut reader, &mut writer, 10).unwrap();
assert!(writer.is_empty()); }
#[test]
fn test_read_n_bytes_zero_bytes() {
let data = b"1234567890";
let mut reader = Cursor::new(data);
let mut writer = Vec::new();
transfer_with_progress(&mut reader, &mut writer, 0).unwrap();
assert!(writer.is_empty());
}
#[test]
fn test_read_n_bytes_sink() {
let data = b"1234567890";
let mut reader = Cursor::new(data);
let mut writer = sink(); transfer_with_progress(&mut reader, &mut writer, 5).unwrap();
}
#[test]
fn test_read_n_bytes_sink_large_data() {
use std::io::repeat;
let data = repeat(b'x'); let mut reader = data.take(5 * 1024 * 1024 * 1024); let mut writer = sink(); transfer_with_progress(&mut reader, &mut writer, 3 * 1024 * 1024 * 1024 / 2).unwrap();
}
#[test]
fn test_read_n_bytes() {
let data = String::from_iter((0..20).into_iter().map(|_| {
format!(
"{}{}{}",
String::from_iter('a'..='z'),
String::from_iter('A'..='Z'),
String::from_iter('0'..='9')
)
}));
let mut reader = Cursor::new(data); let mut writer = Vec::new();
transfer_with_progress(&mut reader, &mut writer, 1).unwrap();
assert_eq!(writer, b"a");
let mut writer = Vec::new();
transfer_with_progress(&mut reader, &mut writer, 15).unwrap();
assert_eq!(writer, b"bcdefghijklmnop");
transfer_with_progress(&mut reader, &mut writer, 5).unwrap();
let mut writer = Vec::new();
transfer_with_progress(&mut reader, &mut writer, 15).unwrap();
assert_eq!(writer, b"vwxyzABCDEFGHIJ");
transfer_with_progress(&mut reader, &mut writer, (1240 - 36) - 20).unwrap();
let mut writer = Vec::new();
transfer_with_progress(&mut reader, &mut writer, 20).unwrap();
assert_eq!(writer, b"QRSTUVWXYZ0123456789");
}
}