#[cfg(feature = "client_base")]
pub mod client;
#[cfg(feature = "server")]
pub mod server;
use std::
{
fs::File,
io::Read,
path::PathBuf,
net::TcpStream,
};
use wincode::{ SchemaRead, SchemaWrite };
use why2::stream::RexStream;
use crate::
{
consts::{ self, Streams },
network::
{
self,
EncryptionMode,
SequencedPacket,
},
};
#[cfg(feature = "server")]
use crate::
{
crypto,
network::server as chat_server,
};
#[derive(SchemaWrite, SchemaRead, Clone, Default)]
pub struct FilePacket {
pub uid: u64, pub data: Option<Vec<u8>>, pub size: Option<u64>, pub filename: Option<String>, pub hash: Option<[u8; 32]>, pub seq: usize, }
impl SequencedPacket for FilePacket
{
fn seq(&self) -> usize { self.seq }
fn set_seq(&mut self, seq: usize) { self.seq = seq; }
}
pub fn send_file (
path: PathBuf,
mut stream: TcpStream,
uid: u64,
rex_stream: &mut RexStream,
mut seq: Option<&mut usize>,
#[cfg(feature = "server")] disk_stream: &mut RexStream,
)
{
let mut file = File::open(path).expect("Cannot open file for upload");
let mut buffer = vec![0; consts::UPLOAD_CHUNK_SIZE];
loop
{
match file.read(&mut buffer)
{
Ok(0) => break, Ok(bytes) =>
{
let plaintext =
{
#[cfg(feature = "server")]
{
let input_i64 = crypto::bytes_to_i64(&buffer[..bytes]);
let mut decrypted_i64 = disk_stream.update(&input_i64).expect("Disk stream decryption failed");
decrypted_i64.extend(disk_stream.finalize().expect("Disk stream finalize failed"));
let mut out = crypto::i64_to_bytes(&decrypted_i64);
out.truncate(bytes);
out
}
#[cfg(feature = "client_base")]
{
buffer[..bytes].to_vec()
}
};
network::send_tcp(&mut stream, FilePacket
{
uid,
data: Some(plaintext),
..Default::default()
}, EncryptionMode::Stream(rex_stream), seq.as_deref_mut());
},
Err(_) => {}, }
}
}
pub fn receive_file
(
streams: &mut Streams,
rex_stream: &mut RexStream,
seq: &mut usize
) -> Option<FilePacket>
{
let read = network::read_tcp
(
streams,
EncryptionMode::Stream(rex_stream),
#[cfg(feature = "server")] true,
)?;
match wincode::deserialize::<FilePacket>(&read.data)
{
Ok(packet) =>
{
if packet.seq > *seq || *seq == 0 {
*seq = packet.seq;
} else { return None; }
Some(packet)
},
Err(_) =>
{
#[cfg(feature = "server")]
chat_server::remove_connection(&read.peer_addr, false, Some("packet"));
None
}
}
}