|
|
|
/*
|
|
|
|
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<u8> {
|
|
|
|
let mut packet_as_bytes: Vec<u8> = Vec::<u8>::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<u8>) -> Option<Error> {
|
|
|
|
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<FileInfoPacket, Error> {
|
|
|
|
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<u8> {
|
|
|
|
let mut packet_as_bytes: Vec<u8> = Vec::<u8>::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<u8>) -> Option<Error> {
|
|
|
|
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<u8> {
|
|
|
|
let mut packet_bytes: Vec<u8> = Vec::<u8>::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<u8>) -> Option<Error> {
|
|
|
|
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<u8> {
|
|
|
|
return vec!(constants::CONNECTION_SHUTDOWN_PACKET_ID.to_be_bytes()[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn from_bytes(&mut self, _packet_bytes: Vec<u8>) -> Option<Error> {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
}
|