/* ddtu - digital data transferring utility Copyright (C) 2022 Kasyanov Nikolay Alexeyevich (Unbewohnte) This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. */ use crate::util::error::Error; use crate::util::buf_read::{read_u128_slice, read_utf8_string_slice}; use crate::protocol::constants; use crate::protocol::specs::*; use crate::fsys::file::ChunkedFile; pub struct TextPacket { pub text: String, } impl TextPacket { pub fn empty() -> TextPacket { return TextPacket{ text: "".to_string(), }; } pub fn new(txt: &str) -> TextPacket { return TextPacket { text: txt.to_string(), } } } impl Packet for TextPacket { fn get_type(&self) -> PacketType { return PacketType::TextData; } fn as_bytes(&self) -> Vec { let mut packet_as_bytes: Vec = Vec::::new(); packet_as_bytes.extend_from_slice(&constants::TEXT_PACKET_ID.to_be_bytes()); let text_length: u128 = self.text.len() as u128; packet_as_bytes.extend_from_slice(&text_length.to_be_bytes()); packet_as_bytes.extend_from_slice(&self.text.as_bytes()); return packet_as_bytes; } fn from_bytes(&mut self, packet_bytes: Vec) -> Option { if packet_bytes.len() < 18 { return Some( Error::new(format!("{} bytes is too small for a text packet to be valid", packet_bytes.len()).as_str() )); } // retrieve and check for packet type byte match packet_bytes[0].to_be() { constants::TEXT_PACKET_ID => {} _ => { return Some(Error::new("packet type is not of a text packet")); } } // get text length let text_length: u128 = read_u128_slice(&packet_bytes[1..17]); if text_length as usize > packet_bytes[17..].len() { return Some( Error::new( format!( "text length ({}) is bigger than provided packet bytes length ({})", text_length, packet_bytes[16..].len() ).as_str() ) ); } // extract text self.text = read_utf8_string_slice(&packet_bytes[17..]); return None; } } pub struct FileInfoPacket { pub file_id: u128, pub filename: String, pub filesize: u128, pub relative_path: String, } impl FileInfoPacket { pub fn empty() -> FileInfoPacket { return FileInfoPacket{ file_id: 0, filename: String::new(), filesize: 0, relative_path: String::new(), }; } pub fn new(file: &ChunkedFile, file_id: u128, rel_path: String) -> Result { let mut new_fileinfo_packet: FileInfoPacket = FileInfoPacket::empty(); // id new_fileinfo_packet.file_id = file_id; //filename match file.path.file_name() { Some(filename) => { match filename.to_owned().into_string() { Ok(filename_string) => { new_fileinfo_packet.filename = filename_string; } Err(filename_os_string) => { return Err( Error::new(format!("could not convert \'{:?}\' (OsString) to String", filename_os_string).as_str()) ); } } } None => { return Err( Error::new(format!("could not get filename from \'{}\'", file.path.display()).as_str()) ); } } // size new_fileinfo_packet.filesize = file.size; // rel path new_fileinfo_packet.relative_path = rel_path; return Ok(new_fileinfo_packet); } } impl Packet for FileInfoPacket { fn get_type(&self) -> PacketType { return PacketType::FileInfo; } fn as_bytes(&self) -> Vec { let mut packet_as_bytes: Vec = Vec::::new(); // file id packet_as_bytes.extend_from_slice(&self.file_id.to_be_bytes()); // filename let filename_bytes_length: u128 = self.filename.len() as u128; packet_as_bytes.extend_from_slice(&filename_bytes_length.to_be_bytes()); packet_as_bytes.extend_from_slice(&self.filename.as_bytes()); // filesize packet_as_bytes.extend_from_slice(&self.filesize.to_be_bytes()); // relative path let relative_path_bytes_length: u128 = self.relative_path.len() as u128; packet_as_bytes.extend_from_slice(&relative_path_bytes_length.to_be_bytes()); packet_as_bytes.extend_from_slice(&self.relative_path.as_bytes()); return packet_as_bytes; } fn from_bytes(&mut self, packet_bytes: Vec) -> Option { if packet_bytes.len() < 16+16+16+16+1+1 { return Some( Error::new(format!("{} bytes is too small for a fileinfo packet to be valid", packet_bytes.len()).as_str() )); } // file id self.file_id = read_u128_slice(&packet_bytes[0..16]); // get filename let filename_length: u128 = read_u128_slice(&packet_bytes[16..32]); self.filename = read_utf8_string_slice(&packet_bytes[32..(filename_length+32) as usize]); // filesize self.filesize = read_u128_slice(&packet_bytes[(filename_length+32) as usize..(filename_length+32+16) as usize]); // relative path let rel_path_length: u128 = read_u128_slice( &packet_bytes[(filename_length+32+16) as usize..(filename_length+32+16+16)as usize] ); self.relative_path = read_utf8_string_slice( &packet_bytes[(filename_length+32+16+16) as usize..(filename_length+32+16+16+rel_path_length) as usize] ); return None; } } pub struct FileDataPacket { pub file_id: u128, pub chunk_no: u128, pub chunk: [u8; constants::CHUNK_SIZE], } impl FileDataPacket { pub fn empty() -> FileDataPacket { return FileDataPacket { file_id: 0, chunk_no: 0, chunk: [0; constants::CHUNK_SIZE], } } } impl Packet for FileDataPacket { fn get_type(&self) -> PacketType { return PacketType::FileData; } fn as_bytes(&self) -> Vec { let mut packet_bytes: Vec = Vec::::new(); // file id packet_bytes.extend_from_slice(&self.file_id.to_be_bytes()); // chunk number packet_bytes.extend_from_slice(&self.chunk_no.to_be_bytes()); // chunk packet_bytes.extend_from_slice(&self.chunk.len().to_be_bytes()); packet_bytes.extend_from_slice(&self.chunk); return packet_bytes; } fn from_bytes(&mut self, packet_bytes: Vec) -> Option { if packet_bytes.len() < 16+16+16+1 { return Some( Error::new(format!("{} bytes is too small for a fileinfo packet to be valid", packet_bytes.len()).as_str() )); } // file id self.file_id = read_u128_slice(&packet_bytes[0..16]); // chunk number self.chunk_no = read_u128_slice(&packet_bytes[16..32]); // chunk bytes let chunk_length = read_u128_slice(&packet_bytes[32..48]); for i in 48..(48+chunk_length) as usize { self.chunk[i-48] = packet_bytes[i]; } return None; } } pub struct ConnectionShutdownPacket {} impl Packet for ConnectionShutdownPacket { fn get_type(&self) -> PacketType { return PacketType::ConnectionShutdown; } fn as_bytes(&self) -> Vec { return vec!(constants::CONNECTION_SHUTDOWN_PACKET_ID.to_be_bytes()[0]); } fn from_bytes(&mut self, _packet_bytes: Vec) -> Option { return None; } }