use std::
{
io::Write,
path::Path,
fs::{ self, File },
sync::
{
Arc,
Mutex,
mpsc::Sender,
},
};
use sha2::{ Sha256, Digest };
use crate::
{
config,
options,
crypto as chat_crypto,
network::
{
self,
EncryptionMode,
file::{ self, FilePacket },
client::{ self, ClientEvent },
},
};
pub fn upload(token: [u8; 32], uid: u64, file_hash: [u8; 32], tx: Sender<ClientEvent>)
{
let mut stream = client::connect(options::get_server_address()).expect("File connection failed");
stream.write_all(&token).unwrap();
let path = client::ACTIVE_UPLOADS.lock().unwrap().remove(&file_hash).unwrap(); let filename = path.clone().file_name().and_then(|n| n.to_str()
.map(|s| s.to_string())).unwrap_or_else(|| String::from("Unknown"));
let size = path.metadata().unwrap().len();
tx.send(ClientEvent::Upload(filename.clone())).unwrap();
tx.send(ClientEvent::Prompt).unwrap();
let mut seq = 0usize;
let mut rex_stream = chat_crypto::init_rex_stream(options::get_keys().as_ref().unwrap(), &token).unwrap();
network::send_tcp(&mut stream, FilePacket
{
uid,
size: Some(size),
filename: Some(filename),
hash: Some(file_hash),
..Default::default()
}, EncryptionMode::Stream(&mut rex_stream), Some(&mut seq));
file::send_file(path, stream, uid, &mut rex_stream, Some(&mut seq));
}
pub fn download(token: [u8; 32], tx: Sender<ClientEvent>)
{
let mut stream = client::connect(options::get_server_address()).expect("File connection failed");
stream.write_all(&token).unwrap();
let write_stream = Arc::new(Mutex::new(stream.try_clone().expect("Failed cloning stream")));
let mut streams = (&mut stream, write_stream);
let mut seq = 0usize;
let mut rex_stream = chat_crypto::init_rex_stream(options::get_keys().as_ref().unwrap(), &token).unwrap();
let metadata_packet = match file::receive_file(&mut streams, &mut rex_stream, &mut seq)
{
Some(p) => p,
None => return,
};
let size = metadata_packet.size.unwrap();
let hash = metadata_packet.hash.unwrap();
let download_dir = config::read_config::<String>("download_directory")
.replace("{HOME}", dirs::home_dir().expect("Could not determine home directory")
.to_str().expect("Invalid home directory"));
let filename = Path::new(&metadata_packet.filename.unwrap())
.file_name()
.and_then(|f| f.to_str())
.unwrap_or("unnamed_file")
.to_string();
fs::create_dir_all(&download_dir).expect("Creating download directory failed");
tx.send(ClientEvent::Download(filename.clone())).unwrap();
tx.send(ClientEvent::Prompt).unwrap();
let mut current_size = 0u64;
let mut file = File::create(Path::new(&download_dir).join(&filename)).expect("Creating download file failed");
let mut hasher = Sha256::new();
loop
{
let read = match file::receive_file(&mut streams, &mut rex_stream, &mut seq)
{
Some(r) => r,
None => return
};
let chunk_data = read.data.unwrap();
if file.write_all(&chunk_data).is_ok()
{
current_size += chunk_data.len() as u64;
hasher.update(&chunk_data);
if current_size == size
{
let final_hash: [u8; 32] = hasher.clone().finalize().into();
tx.send(if hash == final_hash
{
ClientEvent::Downloaded(filename)
} else
{
ClientEvent::DownloadFailed(filename)
}).unwrap();
tx.send(ClientEvent::Prompt).unwrap();
return;
}
}
}
}