use std::
{
io::Write,
path::Path,
fs::{ self, File },
sync::
{
Arc,
Mutex,
mpsc::Sender,
},
};
use sha2::{ Sha256, Digest };
use crate::
{
config,
options,
network::
{
self,
client::{ self, ClientEvent },
FilePayload,
MessageCode,
},
};
pub fn upload(payload: FilePayload, tx: Sender<ClientEvent>)
{
let mut stream = client::connect(options::get_server_address()).expect("File connection failed");
stream.write_all(&payload.token.unwrap()).unwrap();
let file_hash = payload.hash.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"));
tx.send(ClientEvent::Upload(filename)).unwrap();
tx.send(ClientEvent::Prompt(options::INPUT_READ.lock().unwrap().iter().collect::<String>())).unwrap();
network::send_file(path, stream, payload.uid, MessageCode::Upload, options::get_keys().as_ref());
}
pub fn download(payload: FilePayload, tx: Sender<ClientEvent>)
{
let mut stream = client::connect(options::get_server_address()).expect("File connection failed");
stream.write_all(&payload.token.unwrap()).unwrap();
let write_stream = Arc::new(Mutex::new(stream.try_clone().expect("Failed cloning stream")));
let mut streams = (&mut stream, write_stream);
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(&payload.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(options::INPUT_READ.lock().unwrap().iter().collect::<String>())).unwrap();
let mut seq = 0usize;
let size = payload.size.unwrap();
let hash = payload.hash.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 network::receive(&mut streams, options::get_keys().as_ref(), Some(&mut seq))
{
Some(r) => r,
None => return
};
let chunk_data = read.file.and_then(|f| f.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(options::INPUT_READ.lock().unwrap().iter().collect::<String>())).unwrap();
return;
}
}
}
}