feat: add logging support
This commit is contained in:
+115
-13
@@ -1,7 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
peer::{DefaultPeer, Peer},
|
peer::{ConnectionType, DefaultPeer, Peer},
|
||||||
server::{PeerAddress, Server},
|
server::{PeerAddress, Server, ServerOperation},
|
||||||
types::FileSearchResult,
|
types::{FileSearchResult, Transfer},
|
||||||
utils::{md5, thread_pool::ThreadPool},
|
utils::{md5, thread_pool::ThreadPool},
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
@@ -22,11 +22,15 @@ pub enum ClientOperation {
|
|||||||
ConnectToPeer(Peer),
|
ConnectToPeer(Peer),
|
||||||
SearchResult(FileSearchResult),
|
SearchResult(FileSearchResult),
|
||||||
PeerDisconnected(String),
|
PeerDisconnected(String),
|
||||||
|
TransferRequest(Transfer),
|
||||||
|
PierceFireWall(Peer),
|
||||||
}
|
}
|
||||||
struct ClientContext {
|
struct ClientContext {
|
||||||
peers: HashMap<String, DefaultPeer>,
|
peers: HashMap<String, DefaultPeer>,
|
||||||
sender: Option<Sender<ClientOperation>>,
|
sender: Option<Sender<ClientOperation>>,
|
||||||
|
server_sender: Option<Sender<crate::server::ServerOperation>>,
|
||||||
search_results: Vec<FileSearchResult>,
|
search_results: Vec<FileSearchResult>,
|
||||||
|
downloads: HashMap<u32, Transfer>,
|
||||||
thread_pool: ThreadPool,
|
thread_pool: ThreadPool,
|
||||||
}
|
}
|
||||||
impl ClientContext {
|
impl ClientContext {
|
||||||
@@ -34,7 +38,9 @@ impl ClientContext {
|
|||||||
Self {
|
Self {
|
||||||
peers: HashMap::new(),
|
peers: HashMap::new(),
|
||||||
sender: None,
|
sender: None,
|
||||||
|
server_sender: None,
|
||||||
search_results: Vec::new(),
|
search_results: Vec::new(),
|
||||||
|
downloads: HashMap::new(),
|
||||||
thread_pool: ThreadPool::new(MAX_THREADS),
|
thread_pool: ThreadPool::new(MAX_THREADS),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -49,6 +55,7 @@ pub struct Client {
|
|||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
pub fn new(address: PeerAddress, username: String, password: String) -> Self {
|
pub fn new(address: PeerAddress, username: String, password: String) -> Self {
|
||||||
|
crate::utils::logger::init();
|
||||||
Self {
|
Self {
|
||||||
address,
|
address,
|
||||||
username,
|
username,
|
||||||
@@ -67,17 +74,20 @@ impl Client {
|
|||||||
// self.read_form_channel(message_reader);
|
// self.read_form_channel(message_reader);
|
||||||
self.server = match Server::new(self.address.clone(), sender) {
|
self.server = match Server::new(self.address.clone(), sender) {
|
||||||
Ok(server) => {
|
Ok(server) => {
|
||||||
println!(
|
info!(
|
||||||
"Connected to server at {}:{}",
|
"Connected to server at {}:{}",
|
||||||
server.get_address().get_host(),
|
server.get_address().get_host(),
|
||||||
server.get_address().get_port()
|
server.get_address().get_port()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Store the server sender in the client context
|
||||||
|
self.context.lock().unwrap().server_sender = Some(server.get_sender().clone());
|
||||||
|
|
||||||
Self::listen_to_client_operations(message_reader, self.context.clone());
|
Self::listen_to_client_operations(message_reader, self.context.clone());
|
||||||
Some(server)
|
Some(server)
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Error connecting to server: {}", e);
|
error!("Error connecting to server: {}", e);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -85,7 +95,7 @@ impl Client {
|
|||||||
|
|
||||||
pub fn login(&self) -> Result<bool, std::io::Error> {
|
pub fn login(&self) -> Result<bool, std::io::Error> {
|
||||||
// Attempt to login
|
// Attempt to login
|
||||||
println!("Logging in as {}", self.username);
|
info!("Logging in as {}", self.username);
|
||||||
if let Some(server) = &self.server {
|
if let Some(server) = &self.server {
|
||||||
let result = server.login(&self.username, &self.password);
|
let result = server.login(&self.username, &self.password);
|
||||||
if result.unwrap() {
|
if result.unwrap() {
|
||||||
@@ -108,18 +118,18 @@ impl Client {
|
|||||||
pub fn remove_peer(&self, username: &str) {
|
pub fn remove_peer(&self, username: &str) {
|
||||||
let mut context = self.context.lock().unwrap();
|
let mut context = self.context.lock().unwrap();
|
||||||
if let Some(peer) = context.peers.remove(username) {
|
if let Some(peer) = context.peers.remove(username) {
|
||||||
drop(peer); // Explicitly drop to trigger cleanup
|
drop(peer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn search(&self, query: &str, timeout: Duration) -> Vec<FileSearchResult> {
|
pub fn search(&self, query: &str, timeout: Duration) -> Vec<FileSearchResult> {
|
||||||
println!("Searching for {}", query);
|
info!("Searching for {}", query);
|
||||||
if let Some(server) = &self.server {
|
if let Some(server) = &self.server {
|
||||||
let hash = md5::md5(query);
|
let hash = md5::md5(query);
|
||||||
let token = i32::from_str_radix(&hash[0..5], 16).unwrap();
|
let token = u32::from_str_radix(&hash[0..5], 16).unwrap();
|
||||||
server.file_search(token, query);
|
server.file_search(token, query);
|
||||||
} else {
|
} else {
|
||||||
eprintln!("Not connected to server");
|
warn!("Not connected to server");
|
||||||
}
|
}
|
||||||
|
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
@@ -131,6 +141,52 @@ impl Client {
|
|||||||
return self.context.lock().unwrap().search_results.clone();
|
return self.context.lock().unwrap().search_results.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn download(&self, filename: String, username: String) -> crate::types::DownloadResult {
|
||||||
|
use crate::types::{DownloadResult, DownloadStatus};
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
|
println!("Downloading {} from {}", filename, username);
|
||||||
|
let start_time = Instant::now();
|
||||||
|
|
||||||
|
// Start the download request
|
||||||
|
let context = self.context.lock().unwrap();
|
||||||
|
let download_initiated = context
|
||||||
|
.peers
|
||||||
|
.get(&username)
|
||||||
|
.map(|p| p.transfer_request(filename.clone()))
|
||||||
|
.is_some();
|
||||||
|
|
||||||
|
drop(context);
|
||||||
|
|
||||||
|
let timeout = Duration::from_secs(50);
|
||||||
|
let check_interval = Duration::from_millis(100);
|
||||||
|
|
||||||
|
if !download_initiated {
|
||||||
|
return DownloadResult {
|
||||||
|
filename,
|
||||||
|
username,
|
||||||
|
status: DownloadStatus::Failed,
|
||||||
|
elapsed_time: start_time.elapsed(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Non-blocking wait loop
|
||||||
|
while start_time.elapsed() < timeout {
|
||||||
|
// Check download status (for now just wait, actual download logic will be implemented later)
|
||||||
|
std::thread::sleep(check_interval);
|
||||||
|
|
||||||
|
// TODO: Check actual download progress here
|
||||||
|
// For now, we'll just wait for the timeout
|
||||||
|
}
|
||||||
|
|
||||||
|
DownloadResult {
|
||||||
|
filename,
|
||||||
|
username,
|
||||||
|
status: DownloadStatus::TimedOut,
|
||||||
|
elapsed_time: start_time.elapsed(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn listen_to_client_operations(
|
fn listen_to_client_operations(
|
||||||
reader: Receiver<ClientOperation>,
|
reader: Receiver<ClientOperation>,
|
||||||
client_context: Arc<Mutex<ClientContext>>,
|
client_context: Arc<Mutex<ClientContext>>,
|
||||||
@@ -139,6 +195,14 @@ impl Client {
|
|||||||
if let Ok(operation) = reader.recv() {
|
if let Ok(operation) = reader.recv() {
|
||||||
match operation {
|
match operation {
|
||||||
ClientOperation::ConnectToPeer(peer) => {
|
ClientOperation::ConnectToPeer(peer) => {
|
||||||
|
match peer.connection_type {
|
||||||
|
ConnectionType::P => (),
|
||||||
|
ConnectionType::F => {
|
||||||
|
debug!("Peer with F {:?}", peer)
|
||||||
|
}
|
||||||
|
ConnectionType::D => (),
|
||||||
|
};
|
||||||
|
|
||||||
Self::connect_to_peer(peer, client_context.clone())
|
Self::connect_to_peer(peer, client_context.clone())
|
||||||
}
|
}
|
||||||
ClientOperation::SearchResult(file_search) => {
|
ClientOperation::SearchResult(file_search) => {
|
||||||
@@ -154,6 +218,16 @@ impl Client {
|
|||||||
drop(peer); // Explicitly drop to trigger cleanup
|
drop(peer); // Explicitly drop to trigger cleanup
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ClientOperation::TransferRequest(transfer) => {
|
||||||
|
client_context
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.downloads
|
||||||
|
.insert(transfer.token, transfer);
|
||||||
|
}
|
||||||
|
ClientOperation::PierceFireWall(peer) => {
|
||||||
|
Self::pierce_firewall(peer, client_context.clone());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -174,14 +248,42 @@ impl Client {
|
|||||||
let mut context = client_context.lock().unwrap();
|
let mut context = client_context.lock().unwrap();
|
||||||
context.peers.insert(peer.username, p);
|
context.peers.insert(peer.username, p);
|
||||||
}
|
}
|
||||||
Err(_e) => {
|
Err(e) => {
|
||||||
// eprintln!("Error connecting to peer: {:?}", e)
|
trace!(
|
||||||
|
"Can't connect to {} {}:{} {:?} - {}",
|
||||||
|
peer.username,
|
||||||
|
peer.host,
|
||||||
|
peer.port,
|
||||||
|
peer.connection_type,
|
||||||
|
e
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
eprintln!("No sender found");
|
error!("No sender found");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn pierce_firewall(peer: Peer, client_context: Arc<Mutex<ClientContext>>) {
|
||||||
|
debug!("Piercing firewall for peer: {:?}", peer);
|
||||||
|
|
||||||
|
let context = client_context.lock().unwrap();
|
||||||
|
if let Some(server_sender) = &context.server_sender {
|
||||||
|
if let Some(token) = peer.token {
|
||||||
|
match server_sender.send(ServerOperation::PierceFirewall(token)) {
|
||||||
|
Ok(_) => debug!("Sent PierceFirewall message with token: {}", token),
|
||||||
|
Err(e) => error!("Failed to send PierceFirewall message: {}", e),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error!("No token available for PierceFirewall");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error!("No server sender available for PierceFirewall");
|
||||||
|
}
|
||||||
|
|
||||||
|
drop(context);
|
||||||
|
// Also try to connect to the peer directly
|
||||||
|
Self::connect_to_peer(peer, client_context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -19,7 +19,7 @@ impl<Op> MessageDispatcher<Op> {
|
|||||||
message.set_pointer(8);
|
message.set_pointer(8);
|
||||||
handler.handle(message, self.sender.clone());
|
handler.handle(message, self.sender.clone());
|
||||||
} else {
|
} else {
|
||||||
println!(
|
warn!(
|
||||||
"No handler found for message code: {:?}",
|
"No handler found for message code: {:?}",
|
||||||
message.get_message_code()
|
message.get_message_code()
|
||||||
);
|
);
|
||||||
|
|||||||
+10
-4
@@ -1,14 +1,15 @@
|
|||||||
|
#[macro_use]
|
||||||
|
mod utils;
|
||||||
mod client;
|
mod client;
|
||||||
mod dispatcher;
|
mod dispatcher;
|
||||||
mod message;
|
mod message;
|
||||||
mod peer;
|
mod peer;
|
||||||
mod server;
|
mod server;
|
||||||
mod types;
|
mod types;
|
||||||
mod utils;
|
|
||||||
|
|
||||||
use client::Client;
|
use client::Client;
|
||||||
use server::PeerAddress;
|
use server::PeerAddress;
|
||||||
use std::time::Duration;
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
// PeerAddress::new(String::from("server.slsknet.org"), 2416),
|
// PeerAddress::new(String::from("server.slsknet.org"), 2416),
|
||||||
fn main() {
|
fn main() {
|
||||||
@@ -25,10 +26,15 @@ fn main() {
|
|||||||
match client.login() {
|
match client.login() {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
let results = client.search("Fantazia", Duration::from_secs(10));
|
let results = client.search("Fantazia", Duration::from_secs(10));
|
||||||
println!("Search results: {:?}", results);
|
println!("Search results: {} - {:?} ", results.len(), results);
|
||||||
|
if !results.is_empty() && !results[0].files.is_empty() {
|
||||||
|
let file = results[0].files[0].clone();
|
||||||
|
let download_result = client.download(file.name, file.username);
|
||||||
|
println!("Download result: {:?}", download_result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("Failed to login: {}", e);
|
error!("Failed to login: {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+101
-22
@@ -8,6 +8,25 @@ pub use message_reader::*;
|
|||||||
|
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum MessageType {
|
||||||
|
Server,
|
||||||
|
Peer,
|
||||||
|
PeerInit,
|
||||||
|
Distributed,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Error(String);
|
||||||
|
|
||||||
|
impl std::fmt::Display for Error {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for Error {}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct Message {
|
pub struct Message {
|
||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
@@ -62,7 +81,7 @@ impl Message {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
println!();
|
trace!("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
@@ -122,9 +141,9 @@ impl Message {
|
|||||||
pub fn new_with_data(data: Vec<u8>) -> Self {
|
pub fn new_with_data(data: Vec<u8>) -> Self {
|
||||||
Self { data, pointer: 0 }
|
Self { data, pointer: 0 }
|
||||||
}
|
}
|
||||||
// pub fn reset_pointer(&mut self) {
|
pub fn reset_pointer(&mut self) {
|
||||||
// self.pointer = 0;
|
self.pointer = 0;
|
||||||
// }
|
}
|
||||||
pub fn set_pointer(&mut self, pointer: usize) {
|
pub fn set_pointer(&mut self, pointer: usize) {
|
||||||
self.pointer = pointer;
|
self.pointer = pointer;
|
||||||
}
|
}
|
||||||
@@ -169,27 +188,16 @@ impl Message {
|
|||||||
|
|
||||||
String::from_utf8(data.to_vec()).expect("Failed to read string")
|
String::from_utf8(data.to_vec()).expect("Failed to read string")
|
||||||
}
|
}
|
||||||
pub fn read_raw_hex_str(&mut self, size: usize) -> String {
|
|
||||||
let hex_str = self.data[self.pointer..self.pointer + size]
|
|
||||||
.iter()
|
|
||||||
.fold(String::new(), |mut acc, byte| {
|
|
||||||
use std::fmt::Write;
|
|
||||||
write!(acc, "{:02x}", byte).expect("Failed to write to string");
|
|
||||||
acc
|
|
||||||
});
|
|
||||||
self.pointer += size;
|
|
||||||
hex_str
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read_int8(&mut self) -> i8 {
|
pub fn read_int8(&mut self) -> u8 {
|
||||||
let val = self.data[self.pointer] as i8;
|
let val = self.data[self.pointer];
|
||||||
self.pointer += 1;
|
self.pointer += 1;
|
||||||
val
|
val
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn read_int64(&mut self) -> i64 {
|
pub fn read_int64(&mut self) -> u64 {
|
||||||
let val = i64::from_le_bytes([
|
let val = u64::from_le_bytes([
|
||||||
self.data[self.pointer],
|
self.data[self.pointer],
|
||||||
self.data[self.pointer + 1],
|
self.data[self.pointer + 1],
|
||||||
self.data[self.pointer + 2],
|
self.data[self.pointer + 2],
|
||||||
@@ -203,12 +211,12 @@ impl Message {
|
|||||||
val
|
val
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_int32(&mut self) -> i32 {
|
pub fn read_int32(&mut self) -> u32 {
|
||||||
if self.pointer + 4 > self.data.len() {
|
if self.pointer + 4 > self.data.len() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let val = i32::from_le_bytes([
|
let val = u32::from_le_bytes([
|
||||||
self.data[self.pointer],
|
self.data[self.pointer],
|
||||||
self.data[self.pointer + 1],
|
self.data[self.pointer + 1],
|
||||||
self.data[self.pointer + 2],
|
self.data[self.pointer + 2],
|
||||||
@@ -231,7 +239,12 @@ impl Message {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_int32(&mut self, value: i32) -> &mut Self {
|
pub fn write_int32(&mut self, value: u32) -> &mut Self {
|
||||||
|
self.data.extend_from_slice(&value.to_le_bytes());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_int64(&mut self, value: u64) -> &mut Self {
|
||||||
self.data.extend_from_slice(&value.to_le_bytes());
|
self.data.extend_from_slice(&value.to_le_bytes());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@@ -240,6 +253,11 @@ impl Message {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn write_bool(&mut self, value: bool) -> &mut Self {
|
||||||
|
self.data.push(if value { 1 } else { 0 });
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn write_raw_hex_string(&mut self, val: &str) -> &mut Self {
|
pub fn write_raw_hex_string(&mut self, val: &str) -> &mut Self {
|
||||||
let mut b = Vec::new();
|
let mut b = Vec::new();
|
||||||
for i in (0..val.len()).step_by(2) {
|
for i in (0..val.len()).step_by(2) {
|
||||||
@@ -251,6 +269,67 @@ impl Message {
|
|||||||
self.pointer += b.len();
|
self.pointer += b.len();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_message_name(&self, msg_type: MessageType, code: u32) -> Result<&str, Error> {
|
||||||
|
match msg_type {
|
||||||
|
MessageType::Server => match code {
|
||||||
|
1 => Ok("Login"),
|
||||||
|
2 => Ok("SetWaitPort"),
|
||||||
|
3 => Ok("GetPeerAddress"),
|
||||||
|
5 => Ok("WatchUser"),
|
||||||
|
6 => Ok("UnwatchUser"),
|
||||||
|
7 => Ok("GetUserStatus"),
|
||||||
|
13 => Ok("SayChatroom"),
|
||||||
|
14 => Ok("JoinRoom"),
|
||||||
|
15 => Ok("LeaveRoom"),
|
||||||
|
18 => Ok("ConnectToPeer"),
|
||||||
|
22 => Ok("MessageUser"),
|
||||||
|
23 => Ok("MessageAcked"),
|
||||||
|
26 => Ok("FileSearch"),
|
||||||
|
28 => Ok("SetStatus"),
|
||||||
|
32 => Ok("ServerPing"),
|
||||||
|
35 => Ok("SharedFoldersFiles"),
|
||||||
|
36 => Ok("GetUserStats"),
|
||||||
|
41 => Ok("Relogged"),
|
||||||
|
42 => Ok("UserSearch"),
|
||||||
|
64 => Ok("RoomList"),
|
||||||
|
92 => Ok("CheckPrivileges"),
|
||||||
|
100 => Ok("AcceptChildren"),
|
||||||
|
102 => Ok("PossibleParents"),
|
||||||
|
1001 => Ok("CantConnectToPeer"),
|
||||||
|
_ => Err(Error(format!("Unknown server message code: {}", code))),
|
||||||
|
},
|
||||||
|
MessageType::PeerInit => match code {
|
||||||
|
0 => Ok("PierceFireWall"),
|
||||||
|
1 => Ok("PeerInit"),
|
||||||
|
_ => Err(Error(format!("Unknown peer init message code: {}", code))),
|
||||||
|
},
|
||||||
|
MessageType::Peer => match code {
|
||||||
|
4 => Ok("GetShareFileList"),
|
||||||
|
5 => Ok("SharedFileListResponse"),
|
||||||
|
9 => Ok("FileSearchResponse"),
|
||||||
|
15 => Ok("UserInfoRequest"),
|
||||||
|
16 => Ok("UserInfoResponse"),
|
||||||
|
36 => Ok("FolderContentsRequest"),
|
||||||
|
37 => Ok("FolderContentsResponse"),
|
||||||
|
40 => Ok("TransferRequest"),
|
||||||
|
41 => Ok("TransferResponse"),
|
||||||
|
43 => Ok("QueueUpload"),
|
||||||
|
44 => Ok("PlaceInQueueResponse"),
|
||||||
|
46 => Ok("UploadFailed"),
|
||||||
|
50 => Ok("UploadDenied"),
|
||||||
|
51 => Ok("PlaceInQueueRequest"),
|
||||||
|
_ => Err(Error(format!("Unknown peer message code: {}", code))),
|
||||||
|
},
|
||||||
|
MessageType::Distributed => match code {
|
||||||
|
3 => Ok("SearchRequest"),
|
||||||
|
4 => Ok("BranchLevel"),
|
||||||
|
5 => Ok("BranchRoot"),
|
||||||
|
93 => Ok("EmbeddedMessage"),
|
||||||
|
_ => Err(Error(format!("Unknown distributed message code: {}", code))),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
// pub fn decode(&self) {
|
// pub fn decode(&self) {
|
||||||
// println!("{:?}", self.data);
|
// println!("{:?}", self.data);
|
||||||
// }
|
// }
|
||||||
|
|||||||
@@ -1,55 +1,8 @@
|
|||||||
use crate::message::{Message, MessageHandler};
|
use crate::message::{Message, MessageHandler};
|
||||||
use crate::peer::PeerOperation;
|
use crate::peer::PeerOperation;
|
||||||
use crate::types::{File, FileSearchResult};
|
use crate::types::FileSearchResult;
|
||||||
use crate::utils::zlib::deflate;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::sync::mpsc::Sender;
|
use std::sync::mpsc::Sender;
|
||||||
|
|
||||||
fn decompress_buffer(buffer: &[u8]) -> Result<Vec<u8>, String> {
|
|
||||||
deflate(buffer)
|
|
||||||
}
|
|
||||||
impl FileSearchResult {
|
|
||||||
pub fn new_from_message(message: &mut Message) -> Self {
|
|
||||||
let pointer = message.get_pointer();
|
|
||||||
let size = message.get_size();
|
|
||||||
let data: Vec<u8> = message.get_slice(pointer, size);
|
|
||||||
let deflated = decompress_buffer(&data).unwrap();
|
|
||||||
let mut message = Message::new_with_data(deflated);
|
|
||||||
|
|
||||||
let username = message.read_string();
|
|
||||||
let token = message.read_raw_hex_str(4);
|
|
||||||
let n_files = message.read_int32();
|
|
||||||
let mut files: Vec<File> = Vec::new();
|
|
||||||
for _ in 0..n_files {
|
|
||||||
message.read_int8();
|
|
||||||
let name = message.read_string();
|
|
||||||
let size = message.read_int32();
|
|
||||||
message.read_int32();
|
|
||||||
message.read_string();
|
|
||||||
let n_attribs = message.read_int32();
|
|
||||||
let mut attribs: HashMap<i32, i32> = HashMap::new();
|
|
||||||
|
|
||||||
for _ in 0..n_attribs {
|
|
||||||
attribs.insert(message.read_int32(), message.read_int32());
|
|
||||||
}
|
|
||||||
files.push(File {
|
|
||||||
username: username.clone(),
|
|
||||||
name,
|
|
||||||
size,
|
|
||||||
attribs,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
let slots = message.read_int8();
|
|
||||||
let speed = message.read_int32();
|
|
||||||
|
|
||||||
Self {
|
|
||||||
token,
|
|
||||||
files,
|
|
||||||
slots,
|
|
||||||
speed,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub struct FileSearchResponse;
|
pub struct FileSearchResponse;
|
||||||
impl MessageHandler<PeerOperation> for FileSearchResponse {
|
impl MessageHandler<PeerOperation> for FileSearchResponse {
|
||||||
fn get_code(&self) -> u8 {
|
fn get_code(&self) -> u8 {
|
||||||
@@ -85,7 +38,7 @@ fn test_new_from_message() {
|
|||||||
message.set_pointer(8);
|
message.set_pointer(8);
|
||||||
|
|
||||||
let file_search = FileSearchResult::new_from_message(&mut message);
|
let file_search = FileSearchResult::new_from_message(&mut message);
|
||||||
assert_eq!(file_search.token, "6d2b9434");
|
assert_eq!(file_search.token, 23);
|
||||||
assert_eq!(file_search.files.len(), 2);
|
assert_eq!(file_search.files.len(), 2);
|
||||||
let file = &file_search.files[0];
|
let file = &file_search.files[0];
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
use crate::{
|
||||||
|
message::{server::MessageFactory, Message, MessageHandler},
|
||||||
|
peer::PeerOperation,
|
||||||
|
};
|
||||||
|
use std::sync::mpsc::Sender;
|
||||||
|
|
||||||
|
pub struct GetShareFileList;
|
||||||
|
impl MessageHandler<PeerOperation> for GetShareFileList {
|
||||||
|
fn get_code(&self) -> u8 {
|
||||||
|
4
|
||||||
|
}
|
||||||
|
fn handle(&self, _message: &mut Message, sender: Sender<PeerOperation>) {
|
||||||
|
let message = MessageFactory::build_shared_folders_message(100, 800);
|
||||||
|
|
||||||
|
sender.send(PeerOperation::SendMessage(message)).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
pub mod file_search_response;
|
pub mod file_search_response;
|
||||||
|
pub mod get_share_file_list;
|
||||||
|
pub mod transfer_request;
|
||||||
|
pub mod upload_failed;
|
||||||
|
|
||||||
pub use self::file_search_response::*;
|
pub use self::file_search_response::*;
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
use crate::{
|
||||||
|
message::{Message, MessageHandler},
|
||||||
|
peer::PeerOperation,
|
||||||
|
types::Transfer,
|
||||||
|
};
|
||||||
|
use std::sync::mpsc::Sender;
|
||||||
|
|
||||||
|
pub struct TransferRequest;
|
||||||
|
impl MessageHandler<PeerOperation> for TransferRequest {
|
||||||
|
fn get_code(&self) -> u8 {
|
||||||
|
40
|
||||||
|
}
|
||||||
|
fn handle(&self, message: &mut Message, sender: Sender<PeerOperation>) {
|
||||||
|
let transfer = Transfer::new_from_message(message);
|
||||||
|
|
||||||
|
sender
|
||||||
|
.send(PeerOperation::TransferRequest(transfer))
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
use crate::{
|
||||||
|
message::{Message, MessageHandler},
|
||||||
|
peer::PeerOperation,
|
||||||
|
types::UploadFailed,
|
||||||
|
};
|
||||||
|
use std::sync::mpsc::Sender;
|
||||||
|
|
||||||
|
pub struct UploadFailedHandler;
|
||||||
|
impl MessageHandler<PeerOperation> for UploadFailedHandler {
|
||||||
|
fn get_code(&self) -> u8 {
|
||||||
|
46
|
||||||
|
}
|
||||||
|
fn handle(&self, message: &mut Message, sender: Sender<PeerOperation>) {
|
||||||
|
let upload_failed = UploadFailed::new_from_message(message);
|
||||||
|
info!("Upload failed for ${}", upload_failed.filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::message::{Message, MessageHandler};
|
use crate::message::{Message, MessageHandler};
|
||||||
use crate::peer::Peer;
|
use crate::peer::{ConnectionType, Peer};
|
||||||
use crate::server::ServerOperation;
|
use crate::server::ServerOperation;
|
||||||
use std::sync::mpsc::Sender;
|
use std::sync::mpsc::Sender;
|
||||||
pub struct ConnectToPeerHandler;
|
pub struct ConnectToPeerHandler;
|
||||||
@@ -9,6 +9,12 @@ impl MessageHandler<ServerOperation> for ConnectToPeerHandler {
|
|||||||
}
|
}
|
||||||
fn handle(&self, message: &mut Message, sender: Sender<ServerOperation>) {
|
fn handle(&self, message: &mut Message, sender: Sender<ServerOperation>) {
|
||||||
let peer = Peer::new_from_message(message);
|
let peer = Peer::new_from_message(message);
|
||||||
|
match peer.connection_type {
|
||||||
|
ConnectionType::P => (),
|
||||||
|
ConnectionType::F => trace!("[server] ConnectToPeer {:?}", peer),
|
||||||
|
ConnectionType::D => (),
|
||||||
|
}
|
||||||
|
|
||||||
sender.send(ServerOperation::ConnectToPeer(peer)).unwrap();
|
sender.send(ServerOperation::ConnectToPeer(peer)).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,6 @@ impl MessageHandler<ServerOperation> for ExcludedSearchPhrasesHandler {
|
|||||||
let phrase = message.read_string();
|
let phrase = message.read_string();
|
||||||
exluded_phrases.push(phrase);
|
exluded_phrases.push(phrase);
|
||||||
}
|
}
|
||||||
println!("Excluded search phrases: {:?}", exluded_phrases);
|
debug!("Excluded search phrases: {:?}", exluded_phrases);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,11 +12,11 @@ impl MessageHandler<ServerOperation> for FileSearchHandler {
|
|||||||
26
|
26
|
||||||
}
|
}
|
||||||
fn handle(&self, message: &mut Message, _sender: Sender<ServerOperation>) {
|
fn handle(&self, message: &mut Message, _sender: Sender<ServerOperation>) {
|
||||||
println!("Handling file search message");
|
debug!("Handling file search message");
|
||||||
let username = message.read_string();
|
let username = message.read_string();
|
||||||
let token = message.read_int32();
|
let token = message.read_int32();
|
||||||
let query = message.read_string();
|
let query = message.read_string();
|
||||||
println!(
|
info!(
|
||||||
"Message search username:{}, token: {}, query: {}",
|
"Message search username:{}, token: {}, query: {}",
|
||||||
username, token, query
|
username, token, query
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ impl MessageHandler<ServerOperation> for LoginHandler {
|
|||||||
return sender.send(ServerOperation::LoginStatus(false)).unwrap();
|
return sender.send(ServerOperation::LoginStatus(false)).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("Login successful");
|
info!("Login successful");
|
||||||
let greeting = message.read_string();
|
let greeting = message.read_string();
|
||||||
println!("Server greeting: {:?}", greeting);
|
debug!("Server greeting: {:?}", greeting);
|
||||||
|
|
||||||
sender.send(ServerOperation::LoginStatus(true)).unwrap();
|
sender.send(ServerOperation::LoginStatus(true)).unwrap();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::{message::Message, utils::md5};
|
use crate::{message::Message, types::Transfer, utils::md5};
|
||||||
|
|
||||||
pub struct MessageFactory;
|
pub struct MessageFactory;
|
||||||
impl MessageFactory {
|
impl MessageFactory {
|
||||||
@@ -18,7 +18,7 @@ impl MessageFactory {
|
|||||||
// ]
|
// ]
|
||||||
// .to_vec(),
|
// .to_vec(),
|
||||||
// )
|
// )
|
||||||
// .clone()
|
// .clone()fac
|
||||||
let hash = md5([username, password].join("").as_str());
|
let hash = md5([username, password].join("").as_str());
|
||||||
|
|
||||||
let mut message = Message::new();
|
let mut message = Message::new();
|
||||||
@@ -34,14 +34,14 @@ impl MessageFactory {
|
|||||||
message
|
message
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_shared_folders_message(folder_count: i32, file_count: i32) -> Message {
|
pub fn build_shared_folders_message(folder_count: u32, file_count: u32) -> Message {
|
||||||
Message::new()
|
Message::new()
|
||||||
.write_int32(35)
|
.write_int32(35)
|
||||||
.write_int32(folder_count)
|
.write_int32(folder_count)
|
||||||
.write_int32(file_count)
|
.write_int32(file_count)
|
||||||
.clone()
|
.clone()
|
||||||
}
|
}
|
||||||
pub fn build_file_search_message(token: i32, query: &str) -> Message {
|
pub fn build_file_search_message(token: u32, query: &str) -> Message {
|
||||||
// Message::new_with_data(
|
// Message::new_with_data(
|
||||||
// [
|
// [
|
||||||
// 26, 0, 0, 0, 219, 178, 47, 28, 11, 0, 0, 0, 116, 104, 101, 32, 119, 101, 101, 107, 101,
|
// 26, 0, 0, 0, 219, 178, 47, 28, 11, 0, 0, 0, 116, 104, 101, 32, 119, 101, 101, 107, 101,
|
||||||
@@ -56,7 +56,7 @@ impl MessageFactory {
|
|||||||
.write_string(query)
|
.write_string(query)
|
||||||
.clone()
|
.clone()
|
||||||
}
|
}
|
||||||
pub fn build_set_status_message(status_code: i32) -> Message {
|
pub fn build_set_status_message(status_code: u32) -> Message {
|
||||||
Message::new()
|
Message::new()
|
||||||
.write_int32(28)
|
.write_int32(28)
|
||||||
.write_int32(status_code)
|
.write_int32(status_code)
|
||||||
@@ -68,17 +68,38 @@ impl MessageFactory {
|
|||||||
pub fn build_set_wait_port_message() -> Message {
|
pub fn build_set_wait_port_message() -> Message {
|
||||||
Message::new().write_int32(2).write_int32(2234).clone()
|
Message::new().write_int32(2).write_int32(2234).clone()
|
||||||
}
|
}
|
||||||
pub fn build_watch_user(token: &str) -> Message {
|
pub fn build_watch_user(token: u32) -> Message {
|
||||||
Message::new()
|
Message::new()
|
||||||
.write_raw_bytes([5, 0, 0, 0, 0].to_vec())
|
.write_raw_bytes([5, 0, 0, 0, 0].to_vec())
|
||||||
.write_raw_hex_string(token)
|
.write_int32(token)
|
||||||
|
.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_queue_upload_message(filename: &str) -> Message {
|
||||||
|
Message::new()
|
||||||
|
.write_int32(43)
|
||||||
|
.write_string(filename)
|
||||||
|
.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_transfer_response_message(transfer: Transfer) -> Message {
|
||||||
|
Message::new()
|
||||||
|
.write_int32(41)
|
||||||
|
.write_int32(transfer.token)
|
||||||
|
.write_bool(true)
|
||||||
|
.clone()
|
||||||
|
}
|
||||||
|
pub fn build_pierce_firewall_message(token: u32) -> Message {
|
||||||
|
Message::new()
|
||||||
|
.write_int32(0) // PierceFirewall message code
|
||||||
|
.write_int32(token)
|
||||||
.clone()
|
.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_build_watch_user() {
|
fn test_build_watch_user() {
|
||||||
let token = "5b581500";
|
let token: u32 = 223;
|
||||||
let message = MessageFactory::build_watch_user(token);
|
let message = MessageFactory::build_watch_user(token);
|
||||||
let expect: Vec<u8> = [5, 0, 0, 0, 0, 91, 88, 21, 0].to_vec();
|
let expect: Vec<u8> = [5, 0, 0, 0, 0, 91, 88, 21, 0].to_vec();
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ impl MessageHandler<ServerOperation> for MessageUser {
|
|||||||
new_message,
|
new_message,
|
||||||
);
|
);
|
||||||
|
|
||||||
println!("User message received:",);
|
info!("User message received:");
|
||||||
user_message.print()
|
user_message.print()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,6 @@ impl MessageHandler<ServerOperation> for ParentMinSpeedHandler {
|
|||||||
fn handle(&self, message: &mut Message, sender: Sender<ServerOperation>) {
|
fn handle(&self, message: &mut Message, sender: Sender<ServerOperation>) {
|
||||||
let _ = sender;
|
let _ = sender;
|
||||||
let number = message.read_int32();
|
let number = message.read_int32();
|
||||||
println!("Parent min speed: {}", number);
|
debug!("Parent min speed: {}", number);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,6 @@ impl MessageHandler<ServerOperation> for ParentSpeedRatioHandler {
|
|||||||
|
|
||||||
fn handle(&self, message: &mut Message, _sender: Sender<ServerOperation>) {
|
fn handle(&self, message: &mut Message, _sender: Sender<ServerOperation>) {
|
||||||
let number = message.read_int32();
|
let number = message.read_int32();
|
||||||
println!("Parent min speed: {}", number);
|
debug!("Parent speed ratio: {}", number);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,6 @@ impl MessageHandler<ServerOperation> for PrivilegedUsersHandler {
|
|||||||
|
|
||||||
fn handle(&self, message: &mut Message, _sender: Sender<ServerOperation>) {
|
fn handle(&self, message: &mut Message, _sender: Sender<ServerOperation>) {
|
||||||
let number = message.read_int32();
|
let number = message.read_int32();
|
||||||
println!("Number of privilaged users: {}", number);
|
debug!("Number of privileged users: {}", number);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,6 @@ impl MessageHandler<ServerOperation> for WishListIntervalHandler {
|
|||||||
|
|
||||||
fn handle(&self, message: &mut Message, _sender: Sender<ServerOperation>) {
|
fn handle(&self, message: &mut Message, _sender: Sender<ServerOperation>) {
|
||||||
let number = message.read_int32();
|
let number = message.read_int32();
|
||||||
println!("Wishlist search interval: {} in seconds", number);
|
debug!("Wishlist search interval: {} in seconds", number);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+96
-37
@@ -1,8 +1,11 @@
|
|||||||
use crate::dispatcher::MessageDispatcher;
|
use crate::dispatcher::MessageDispatcher;
|
||||||
|
use crate::message::peer::get_share_file_list::GetShareFileList;
|
||||||
|
use crate::message::peer::transfer_request::TransferRequest;
|
||||||
|
use crate::message::peer::upload_failed::UploadFailedHandler;
|
||||||
use crate::message::peer::FileSearchResponse;
|
use crate::message::peer::FileSearchResponse;
|
||||||
use crate::message::server::MessageFactory;
|
use crate::message::server::MessageFactory;
|
||||||
use crate::message::{Handlers, Message, MessageReader};
|
use crate::message::{Handlers, Message, MessageReader, MessageType};
|
||||||
use crate::types::FileSearchResult;
|
use crate::types::{FileSearchResult, Transfer};
|
||||||
|
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
use std::sync::mpsc::{Receiver, Sender};
|
use std::sync::mpsc::{Receiver, Sender};
|
||||||
@@ -20,7 +23,6 @@ pub struct DefaultPeer {
|
|||||||
peer: Peer,
|
peer: Peer,
|
||||||
peer_channel: Option<Sender<PeerOperation>>,
|
peer_channel: Option<Sender<PeerOperation>>,
|
||||||
client_channel: Sender<ClientOperation>,
|
client_channel: Sender<ClientOperation>,
|
||||||
// Store thread handles for proper lifecycle management
|
|
||||||
read_thread: Option<JoinHandle<()>>,
|
read_thread: Option<JoinHandle<()>>,
|
||||||
write_thread: Option<JoinHandle<()>>,
|
write_thread: Option<JoinHandle<()>>,
|
||||||
}
|
}
|
||||||
@@ -29,6 +31,7 @@ pub struct DefaultPeer {
|
|||||||
pub enum PeerOperation {
|
pub enum PeerOperation {
|
||||||
SendMessage(Message),
|
SendMessage(Message),
|
||||||
FileSearchResult(FileSearchResult),
|
FileSearchResult(FileSearchResult),
|
||||||
|
TransferRequest(Transfer),
|
||||||
}
|
}
|
||||||
impl DefaultPeer {
|
impl DefaultPeer {
|
||||||
pub fn new(peer: Peer, client_channel: Sender<ClientOperation>) -> Self {
|
pub fn new(peer: Peer, client_channel: Sender<ClientOperation>) -> Self {
|
||||||
@@ -46,13 +49,14 @@ impl DefaultPeer {
|
|||||||
.next()
|
.next()
|
||||||
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Invalid address"))?;
|
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Invalid address"))?;
|
||||||
|
|
||||||
let mut stream = TcpStream::connect_timeout(&socket_address, Duration::from_secs(10))?;
|
let mut stream = TcpStream::connect_timeout(&socket_address, Duration::from_secs(20))?;
|
||||||
|
|
||||||
stream.set_read_timeout(Some(Duration::from_secs(5)))?;
|
stream.set_read_timeout(Some(Duration::from_secs(5)))?;
|
||||||
stream.set_write_timeout(Some(Duration::from_secs(5)))?;
|
stream.set_write_timeout(Some(Duration::from_secs(5)))?;
|
||||||
if let Some(token) = self.peer.token.clone() {
|
|
||||||
|
if let Some(token) = self.peer.token {
|
||||||
stream
|
stream
|
||||||
.write_all(&MessageFactory::build_watch_user(token.as_str()).get_data())
|
.write_all(&MessageFactory::build_watch_user(token).get_data())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
self.start_read_write_loops(stream)?;
|
self.start_read_write_loops(stream)?;
|
||||||
@@ -64,6 +68,9 @@ impl DefaultPeer {
|
|||||||
let (peer_sender, peer_reader): (Sender<PeerOperation>, Receiver<PeerOperation>) =
|
let (peer_sender, peer_reader): (Sender<PeerOperation>, Receiver<PeerOperation>) =
|
||||||
mpsc::channel();
|
mpsc::channel();
|
||||||
|
|
||||||
|
// Set the peer_channel so transfer_request can send messages
|
||||||
|
self.peer_channel = Some(peer_sender.clone());
|
||||||
|
|
||||||
let mut read_stream = stream.try_clone()?;
|
let mut read_stream = stream.try_clone()?;
|
||||||
let mut write_stream = stream; // Use the original stream for writing
|
let mut write_stream = stream; // Use the original stream for writing
|
||||||
|
|
||||||
@@ -74,6 +81,9 @@ impl DefaultPeer {
|
|||||||
self.read_thread = Some(thread::spawn(move || {
|
self.read_thread = Some(thread::spawn(move || {
|
||||||
let mut handlers = Handlers::new();
|
let mut handlers = Handlers::new();
|
||||||
handlers.register_handler(FileSearchResponse);
|
handlers.register_handler(FileSearchResponse);
|
||||||
|
handlers.register_handler(TransferRequest);
|
||||||
|
handlers.register_handler(GetShareFileList);
|
||||||
|
handlers.register_handler(UploadFailedHandler);
|
||||||
|
|
||||||
let dispatcher = MessageDispatcher::new(peer_sender, handlers);
|
let dispatcher = MessageDispatcher::new(peer_sender, handlers);
|
||||||
|
|
||||||
@@ -83,27 +93,41 @@ impl DefaultPeer {
|
|||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => continue,
|
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => continue,
|
||||||
Err(ref e) if e.kind() == io::ErrorKind::TimedOut => {
|
Err(ref e) if e.kind() == io::ErrorKind::TimedOut => {
|
||||||
println!(
|
debug!(
|
||||||
"Read operation timed out in default peer {:}:{:}",
|
"Read operation timed out in default peer {:}:{:}",
|
||||||
peer.host, peer.port
|
peer.host, peer.port
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Error reading from peer: {}. Terminating read loop.", e);
|
error!("Error reading from peer: {}. Terminating read loop.", e);
|
||||||
let _ = client_channel_for_read.send(ClientOperation::PeerDisconnected(peer.username.clone()));
|
let _ = client_channel_for_read
|
||||||
|
.send(ClientOperation::PeerDisconnected(peer.username.clone()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match buffered_reader.extract_message() {
|
match buffered_reader.extract_message() {
|
||||||
Ok(Some(mut message)) => dispatcher.dispatch(&mut message),
|
Ok(Some(mut message)) => {
|
||||||
|
trace!(
|
||||||
|
"[default_peer:{:?}] ← {:?}",
|
||||||
|
peer.username,
|
||||||
|
message
|
||||||
|
.get_message_name(
|
||||||
|
MessageType::Peer,
|
||||||
|
message.get_message_code() as u32
|
||||||
|
)
|
||||||
|
.map_err(|e| e.to_string())
|
||||||
|
);
|
||||||
|
dispatcher.dispatch(&mut message)
|
||||||
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!(
|
warn!(
|
||||||
"Error extracting message in default peer: {}. Terminating read loop.",
|
"Error extracting message in default peer: {}. Terminating read loop.",
|
||||||
e
|
e
|
||||||
);
|
);
|
||||||
let _ = client_channel_for_read.send(ClientOperation::PeerDisconnected(peer.username.clone()));
|
let _ = client_channel_for_read
|
||||||
|
.send(ClientOperation::PeerDisconnected(peer.username.clone()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Ok(None) => continue,
|
Ok(None) => continue,
|
||||||
@@ -112,29 +136,62 @@ impl DefaultPeer {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
let client_channel = self.client_channel.clone();
|
let client_channel = self.client_channel.clone();
|
||||||
|
let peer_channel = self.peer_channel.clone();
|
||||||
let peer_username = self.peer.username.clone();
|
let peer_username = self.peer.username.clone();
|
||||||
|
|
||||||
self.write_thread = Some(thread::spawn(move || {
|
self.write_thread = Some(thread::spawn(move || {
|
||||||
loop {
|
loop {
|
||||||
match peer_reader.recv() {
|
match peer_reader.recv() {
|
||||||
Ok(operation) => {
|
Ok(operation) => match operation {
|
||||||
match operation {
|
PeerOperation::SendMessage(message) => {
|
||||||
PeerOperation::SendMessage(message) => {
|
trace!(
|
||||||
if let Err(e) = write_stream.write_all(&message.get_buffer()) {
|
"[default_peer:{:?}] ➡ {:?} - {:?}",
|
||||||
eprintln!("Error writing message to stream: {}. Terminating write loop.", e);
|
peer_username,
|
||||||
let _ = client_channel.send(ClientOperation::PeerDisconnected(peer_username.clone()));
|
message
|
||||||
break;
|
.get_message_name(
|
||||||
}
|
MessageType::Peer,
|
||||||
|
u32::from_le_bytes(
|
||||||
|
message.get_slice(0, 4).try_into().unwrap()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.map_err(|e| e.to_string()),
|
||||||
|
message
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Err(e) = write_stream.write_all(&message.get_buffer()) {
|
||||||
|
error!("Error writing message to stream: {} - {}. Terminating write loop.", peer_username, e);
|
||||||
|
let _ = client_channel
|
||||||
|
.send(ClientOperation::PeerDisconnected(peer_username.clone()));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
PeerOperation::FileSearchResult(file_search) => {
|
}
|
||||||
client_channel
|
PeerOperation::FileSearchResult(file_search) => {
|
||||||
.send(ClientOperation::SearchResult(file_search))
|
client_channel
|
||||||
|
.send(ClientOperation::SearchResult(file_search))
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
PeerOperation::TransferRequest(transfer) => {
|
||||||
|
debug!(
|
||||||
|
"[default_peer:{}] transfer request: {:?}",
|
||||||
|
peer_username, transfer
|
||||||
|
);
|
||||||
|
client_channel
|
||||||
|
.send(ClientOperation::TransferRequest(transfer.clone()))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let transfer_response =
|
||||||
|
MessageFactory::build_transfer_response_message(transfer.clone());
|
||||||
|
|
||||||
|
if let Some(sender) = peer_channel.clone() {
|
||||||
|
sender
|
||||||
|
.send(PeerOperation::SendMessage(transfer_response))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
// The sender has been dropped, the peer is shutting down.
|
// The sender has been dropped, the peer is shutting down.
|
||||||
println!("Peer channel closed. Terminating write loop.");
|
debug!("Peer channel closed. Terminating write loop.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -143,31 +200,33 @@ impl DefaultPeer {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn transfer_request(&self, filename: String) -> Result<(), io::Error> {
|
||||||
|
let message = MessageFactory::build_queue_upload_message(&filename);
|
||||||
|
if let Some(sender) = &self.peer_channel {
|
||||||
|
sender.send(PeerOperation::SendMessage(message)).unwrap();
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for DefaultPeer {
|
impl Drop for DefaultPeer {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// Signal threads to shut down (e.g., by dropping the sender half of the channel)
|
|
||||||
// For now, we'll just drop the peer_channel, which will cause the writer thread
|
|
||||||
// to exit its loop. A more robust solution might involve a shared AtomicBool
|
|
||||||
// or a dedicated shutdown channel.
|
|
||||||
self.peer_channel = None;
|
self.peer_channel = None;
|
||||||
|
|
||||||
// Join the read thread
|
|
||||||
if let Some(handle) = self.read_thread.take() {
|
if let Some(handle) = self.read_thread.take() {
|
||||||
println!("Joining read thread...");
|
debug!("Joining read thread...");
|
||||||
match handle.join() {
|
match handle.join() {
|
||||||
Ok(_) => println!("Read thread joined successfully."),
|
Ok(_) => debug!("Read thread joined successfully."),
|
||||||
Err(e) => eprintln!("Read thread panicked: {:?}", e),
|
Err(e) => error!("Read thread panicked: {:?}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Join the write thread
|
|
||||||
if let Some(handle) = self.write_thread.take() {
|
if let Some(handle) = self.write_thread.take() {
|
||||||
println!("Joining write thread...");
|
debug!("Joining write thread...");
|
||||||
match handle.join() {
|
match handle.join() {
|
||||||
Ok(_) => println!("Write thread joined successfully."),
|
Ok(_) => debug!("Write thread joined successfully."),
|
||||||
Err(e) => eprintln!("Write thread panicked: {:?}", e),
|
Err(e) => error!("Write thread panicked: {:?}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-9
@@ -8,7 +8,7 @@ pub struct Listen {}
|
|||||||
|
|
||||||
impl Listen {
|
impl Listen {
|
||||||
pub fn start(port: u32, _server_channel: Sender<ServerOperation>) {
|
pub fn start(port: u32, _server_channel: Sender<ServerOperation>) {
|
||||||
println!("starting listener on port {port}");
|
info!("starting listener on port {port}");
|
||||||
let listener = TcpListener::bind(format!("0.0.0.0:{port}")).unwrap();
|
let listener = TcpListener::bind(format!("0.0.0.0:{port}")).unwrap();
|
||||||
for stream in listener.incoming() {
|
for stream in listener.incoming() {
|
||||||
let mut read_stream = stream.unwrap();
|
let mut read_stream = stream.unwrap();
|
||||||
@@ -20,19 +20,19 @@ impl Listen {
|
|||||||
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => continue,
|
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => continue,
|
||||||
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => continue,
|
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => continue,
|
||||||
Err(ref e) if e.kind() == io::ErrorKind::TimedOut => {
|
Err(ref e) if e.kind() == io::ErrorKind::TimedOut => {
|
||||||
println!("Read operation timed out");
|
debug!("Read operation timed out");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Error reading from server: {}", e);
|
error!("Error reading from server: {}", e);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match buffered_reader.extract_message() {
|
match buffered_reader.extract_message() {
|
||||||
Ok(Some(mut message)) => {
|
Ok(Some(mut message)) => {
|
||||||
println!("Received message: {:?}", message.get_message_code());
|
debug!("Received message: {:?}", message.get_message_code());
|
||||||
println!("{:?}", message.get_data());
|
trace!("{:?}", message.get_data());
|
||||||
message.print_hex();
|
message.print_hex();
|
||||||
|
|
||||||
if message.get_message_code() == 1 {
|
if message.get_message_code() == 1 {
|
||||||
@@ -45,8 +45,8 @@ impl Listen {
|
|||||||
// // message.read_string().parse().unwrap();
|
// // message.read_string().parse().unwrap();
|
||||||
// // let token = message.read_int32();
|
// // let token = message.read_int32();
|
||||||
//
|
//
|
||||||
println!("type: {:?}", typex);
|
debug!("type: {:?}", typex);
|
||||||
println!("user: {:?}", size);
|
debug!("user: {:?}", size);
|
||||||
|
|
||||||
// server_channel
|
// server_channel
|
||||||
// .send(ServerOperation::ConnectToPeer(peer))
|
// .send(ServerOperation::ConnectToPeer(peer))
|
||||||
@@ -54,13 +54,13 @@ impl Listen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("Error extracting message: {}", e)
|
warn!("Error extracting message: {}", e)
|
||||||
}
|
}
|
||||||
Ok(None) => continue,
|
Ok(None) => continue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("Connection established!");
|
info!("Connection established!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-13
@@ -46,11 +46,11 @@ pub struct Peer {
|
|||||||
pub username: String,
|
pub username: String,
|
||||||
pub connection_type: ConnectionType,
|
pub connection_type: ConnectionType,
|
||||||
pub host: String,
|
pub host: String,
|
||||||
pub port: i32,
|
pub port: u32,
|
||||||
pub token: Option<String>,
|
pub token: Option<u32>,
|
||||||
pub privileged: i8,
|
pub privileged: u8,
|
||||||
pub unknown: i8,
|
pub unknown: u8,
|
||||||
pub obfuscated_port: i8,
|
pub obfuscated_port: u8,
|
||||||
}
|
}
|
||||||
impl Peer {
|
impl Peer {
|
||||||
#[allow(clippy::too_many_arguments, dead_code)]
|
#[allow(clippy::too_many_arguments, dead_code)]
|
||||||
@@ -58,11 +58,11 @@ impl Peer {
|
|||||||
username: String,
|
username: String,
|
||||||
connection_type: ConnectionType,
|
connection_type: ConnectionType,
|
||||||
host: String,
|
host: String,
|
||||||
port: i32,
|
port: u32,
|
||||||
token: String,
|
token: u32,
|
||||||
privileged: i8,
|
privileged: u8,
|
||||||
unknown: i8,
|
unknown: u8,
|
||||||
obfuscated_port: i8,
|
obfuscated_port: u8,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
username,
|
username,
|
||||||
@@ -78,7 +78,7 @@ impl Peer {
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn new_from_message(message: &mut Message) -> Self {
|
pub fn new_from_message(message: &mut Message) -> Self {
|
||||||
let username = message.read_string();
|
let username = message.read_string();
|
||||||
let connection_type: ConnectionType = message.read_string().parse().unwrap();
|
let connection_type = message.read_string().parse().unwrap();
|
||||||
|
|
||||||
let mut ip: Vec<i32> = vec![];
|
let mut ip: Vec<i32> = vec![];
|
||||||
for _ in 0..4 {
|
for _ in 0..4 {
|
||||||
@@ -94,7 +94,7 @@ impl Peer {
|
|||||||
|
|
||||||
let (port, token, privileged, unknown, obfuscated_port) = (
|
let (port, token, privileged, unknown, obfuscated_port) = (
|
||||||
message.read_int32(),
|
message.read_int32(),
|
||||||
message.read_raw_hex_str(4),
|
message.read_int32(),
|
||||||
message.read_int8(),
|
message.read_int8(),
|
||||||
message.read_int8(),
|
message.read_int8(),
|
||||||
message.read_int8(),
|
message.read_int8(),
|
||||||
@@ -155,4 +155,3 @@ fn test_new_from_message2() {
|
|||||||
assert_eq!(peer.unknown, 1);
|
assert_eq!(peer.unknown, 1);
|
||||||
assert_eq!(peer.obfuscated_port, 0);
|
assert_eq!(peer.obfuscated_port, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+82
-30
@@ -15,6 +15,7 @@ use crate::message::Handlers;
|
|||||||
use crate::message::Message;
|
use crate::message::Message;
|
||||||
use crate::message::MessageReader;
|
use crate::message::MessageReader;
|
||||||
use crate::peer::listen::Listen;
|
use crate::peer::listen::Listen;
|
||||||
|
use crate::peer::ConnectionType;
|
||||||
use crate::peer::Peer;
|
use crate::peer::Peer;
|
||||||
|
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
@@ -71,16 +72,16 @@ impl Context {
|
|||||||
}
|
}
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct UserMessage {
|
pub struct UserMessage {
|
||||||
id: i32,
|
id: u32,
|
||||||
timestamp: i32,
|
timestamp: u32,
|
||||||
username: String,
|
username: String,
|
||||||
message: String,
|
message: String,
|
||||||
new_message: bool,
|
new_message: bool,
|
||||||
}
|
}
|
||||||
impl UserMessage {
|
impl UserMessage {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
id: i32,
|
id: u32,
|
||||||
timestamp: i32,
|
timestamp: u32,
|
||||||
username: String,
|
username: String,
|
||||||
message: String,
|
message: String,
|
||||||
new_message: bool,
|
new_message: bool,
|
||||||
@@ -94,7 +95,7 @@ impl UserMessage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn print(&self) {
|
pub fn print(&self) {
|
||||||
println!(
|
debug!(
|
||||||
"Timestamp: {}. User: {}, Id: #{}, New message: {} Message: {}",
|
"Timestamp: {}. User: {}, Id: #{}, New message: {} Message: {}",
|
||||||
self.timestamp, self.username, self.id, self.new_message, self.message
|
self.timestamp, self.username, self.id, self.new_message, self.message
|
||||||
);
|
);
|
||||||
@@ -121,19 +122,19 @@ impl Rooms {
|
|||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn print(&self) {
|
pub fn print(&self) {
|
||||||
println!("Public rooms ({}):", self.public_rooms.len());
|
info!("Public rooms ({}):", self.public_rooms.len());
|
||||||
for room in &self.public_rooms {
|
for room in &self.public_rooms {
|
||||||
room.print();
|
room.print();
|
||||||
}
|
}
|
||||||
println!("Owned private rooms ({}):", self.owned_private_rooms.len());
|
info!("Owned private rooms ({}):", self.owned_private_rooms.len());
|
||||||
for room in &self.owned_private_rooms {
|
for room in &self.owned_private_rooms {
|
||||||
room.print();
|
room.print();
|
||||||
}
|
}
|
||||||
println!("Private rooms ({}):", self.private_rooms.len());
|
info!("Private rooms ({}):", self.private_rooms.len());
|
||||||
for room in &self.private_rooms {
|
for room in &self.private_rooms {
|
||||||
room.print();
|
room.print();
|
||||||
}
|
}
|
||||||
println!(
|
info!(
|
||||||
"Operated private rooms ({}):",
|
"Operated private rooms ({}):",
|
||||||
self.operated_private_rooms.len()
|
self.operated_private_rooms.len()
|
||||||
);
|
);
|
||||||
@@ -160,7 +161,7 @@ impl Room {
|
|||||||
self.number_of_users = number_of_users;
|
self.number_of_users = number_of_users;
|
||||||
}
|
}
|
||||||
pub fn print(&self) {
|
pub fn print(&self) {
|
||||||
println!(
|
debug!(
|
||||||
"Room: {}, Number of users: {}",
|
"Room: {}, Number of users: {}",
|
||||||
self.name, self.number_of_users
|
self.name, self.number_of_users
|
||||||
);
|
);
|
||||||
@@ -172,6 +173,7 @@ pub enum ServerOperation {
|
|||||||
SendMessage(Message),
|
SendMessage(Message),
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
ConnectToPeer(Peer),
|
ConnectToPeer(Peer),
|
||||||
|
PierceFirewall(u32),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -205,6 +207,10 @@ impl Server {
|
|||||||
&self.address
|
&self.address
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_sender(&self) -> &Sender<ServerOperation> {
|
||||||
|
&self.sender
|
||||||
|
}
|
||||||
|
|
||||||
/// Start reading and writing loops in separate threads
|
/// Start reading and writing loops in separate threads
|
||||||
fn start_read_write_loops(
|
fn start_read_write_loops(
|
||||||
&mut self,
|
&mut self,
|
||||||
@@ -216,7 +222,7 @@ impl Server {
|
|||||||
.next()
|
.next()
|
||||||
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Invalid address"))?;
|
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Invalid address"))?;
|
||||||
|
|
||||||
println!(
|
info!(
|
||||||
"Connecting to server at {}:{}",
|
"Connecting to server at {}:{}",
|
||||||
self.address.host, self.address.port
|
self.address.host, self.address.port
|
||||||
);
|
);
|
||||||
@@ -261,24 +267,31 @@ impl Server {
|
|||||||
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => continue,
|
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => continue,
|
||||||
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => continue,
|
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => continue,
|
||||||
Err(ref e) if e.kind() == io::ErrorKind::TimedOut => {
|
Err(ref e) if e.kind() == io::ErrorKind::TimedOut => {
|
||||||
println!("Read operation timed out");
|
debug!("Read operation timed out");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Error reading from server: {}", e);
|
error!("Error reading from server: {}", e);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match buffered_reader.extract_message() {
|
match buffered_reader.extract_message() {
|
||||||
Ok(Some(mut message)) => {
|
Ok(Some(mut message)) => {
|
||||||
// println!("Received message: {:?}", message.get_message_code_u32());
|
// trace!(
|
||||||
// message.print_hex();
|
// "[server] ← {:?}",
|
||||||
|
// message
|
||||||
|
// .get_message_name(
|
||||||
|
// MessageType::Server,
|
||||||
|
// message.get_message_code() as u32
|
||||||
|
// )
|
||||||
|
// .map_err(|e| e.to_string())
|
||||||
|
// );
|
||||||
|
|
||||||
dispatcher.dispatch(&mut message)
|
dispatcher.dispatch(&mut message)
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("Error extracting message: {}", e)
|
warn!("Error extracting message: {}", e)
|
||||||
}
|
}
|
||||||
Ok(None) => continue,
|
Ok(None) => continue,
|
||||||
}
|
}
|
||||||
@@ -295,24 +308,56 @@ impl Server {
|
|||||||
loop {
|
loop {
|
||||||
if let Ok(operation) = server_channel.recv() {
|
if let Ok(operation) = server_channel.recv() {
|
||||||
match operation {
|
match operation {
|
||||||
ServerOperation::ConnectToPeer(peer) => {
|
ServerOperation::ConnectToPeer(peer) => match peer.connection_type {
|
||||||
match client_channel.send(ClientOperation::ConnectToPeer(peer)) {
|
ConnectionType::P => {
|
||||||
Ok(_) => {}
|
match client_channel.send(ClientOperation::ConnectToPeer(peer)) {
|
||||||
Err(e) => {
|
Ok(_) => {}
|
||||||
println!("Error sending message: {}", e);
|
Err(_e) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
ConnectionType::F => {
|
||||||
|
match client_channel.send(ClientOperation::PierceFireWall(peer)) {
|
||||||
|
Ok(_) => {
|
||||||
|
debug!("Sent PierceFireWall operation for F-type connection");
|
||||||
|
}
|
||||||
|
Err(_e) => {
|
||||||
|
error!("Failed to send PierceFireWall operation");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ConnectionType::D => {}
|
||||||
|
},
|
||||||
ServerOperation::LoginStatus(message) => {
|
ServerOperation::LoginStatus(message) => {
|
||||||
context.lock().unwrap().logged_in = Some(message);
|
context.lock().unwrap().logged_in = Some(message);
|
||||||
}
|
}
|
||||||
|
ServerOperation::PierceFirewall(token) => {
|
||||||
|
let pierce_message = MessageFactory::build_pierce_firewall_message(token);
|
||||||
|
match write_stream.write_all(&pierce_message.get_buffer()) {
|
||||||
|
Ok(_) => {
|
||||||
|
debug!("Sent PierceFirewall message with token: {}", token);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("Error writing PierceFirewall message: {}", e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
ServerOperation::SendMessage(message) => {
|
ServerOperation::SendMessage(message) => {
|
||||||
// message.decode();
|
// trace!(
|
||||||
// message.print_hex2();
|
// "[server] ➡ {:?}",
|
||||||
|
// message
|
||||||
|
// .get_message_name(
|
||||||
|
// MessageType::Server,
|
||||||
|
// u32::from_le_bytes(
|
||||||
|
// message.get_slice(0, 4).try_into().unwrap()
|
||||||
|
// )
|
||||||
|
// )
|
||||||
|
// .map_err(|e| e.to_string()),
|
||||||
|
// );
|
||||||
match write_stream.write_all(&message.get_buffer()) {
|
match write_stream.write_all(&message.get_buffer()) {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Error writing message to stream : {}", e);
|
error!("Error writing message to stream : {}", e);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -328,7 +373,7 @@ impl Server {
|
|||||||
fn queue_message(&self, message: Message) {
|
fn queue_message(&self, message: Message) {
|
||||||
match self.sender.send(ServerOperation::SendMessage(message)) {
|
match self.sender.send(ServerOperation::SendMessage(message)) {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(e) => println!("Failed to send: {}", e),
|
Err(e) => error!("Failed to send: {}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn start_listener(&self, server_channel: Sender<ServerOperation>) {
|
fn start_listener(&self, server_channel: Sender<ServerOperation>) {
|
||||||
@@ -347,7 +392,7 @@ impl Server {
|
|||||||
// wait till server says your logged in or not
|
// wait till server says your logged in or not
|
||||||
loop {
|
loop {
|
||||||
if start.elapsed() > timeout {
|
if start.elapsed() > timeout {
|
||||||
println!("Timeout waiting for login response");
|
warn!("Timeout waiting for login response");
|
||||||
return Err(std::io::Error::new(
|
return Err(std::io::Error::new(
|
||||||
std::io::ErrorKind::TimedOut,
|
std::io::ErrorKind::TimedOut,
|
||||||
"Timeout waiting for login response",
|
"Timeout waiting for login response",
|
||||||
@@ -364,9 +409,9 @@ impl Server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if logged_in.unwrap() {
|
if logged_in.unwrap() {
|
||||||
println!("Logged in as {}", username);
|
info!("Logged in as {}", username);
|
||||||
self.queue_message(MessageFactory::build_set_wait_port_message());
|
self.queue_message(MessageFactory::build_set_wait_port_message());
|
||||||
self.queue_message(MessageFactory::build_shared_folders_message(1, 1));
|
self.queue_message(MessageFactory::build_shared_folders_message(1, 499));
|
||||||
self.queue_message(MessageFactory::build_no_parent_message());
|
self.queue_message(MessageFactory::build_no_parent_message());
|
||||||
self.queue_message(MessageFactory::build_set_status_message(2));
|
self.queue_message(MessageFactory::build_set_status_message(2));
|
||||||
}
|
}
|
||||||
@@ -374,7 +419,14 @@ impl Server {
|
|||||||
Ok(logged_in.unwrap())
|
Ok(logged_in.unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn file_search(&self, token: i32, query: &str) {
|
pub fn file_search(&self, token: u32, query: &str) {
|
||||||
self.queue_message(MessageFactory::build_file_search_message(token, query));
|
self.queue_message(MessageFactory::build_file_search_message(token, query));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn pierce_firewall(&self, token: u32) {
|
||||||
|
match self.sender.send(ServerOperation::PierceFirewall(token)) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(e) => error!("Failed to send PierceFirewall: {}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+98
-5
@@ -1,20 +1,113 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use crate::{message::Message, utils::zlib::deflate};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub struct File {
|
pub struct File {
|
||||||
pub username: String,
|
pub username: String,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub size: i32,
|
pub size: u32,
|
||||||
pub attribs: HashMap<i32, i32>,
|
pub attribs: HashMap<u32, u32>,
|
||||||
}
|
}
|
||||||
|
pub struct UploadFailed {
|
||||||
|
pub filename: String,
|
||||||
|
}
|
||||||
|
impl UploadFailed {
|
||||||
|
pub fn new_from_message(message: &mut Message) -> Self {
|
||||||
|
let filename = message.read_string();
|
||||||
|
|
||||||
|
Self { filename }
|
||||||
|
}
|
||||||
|
}
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub struct FileSearchResult {
|
pub struct FileSearchResult {
|
||||||
pub token: String,
|
pub token: u32,
|
||||||
pub files: Vec<File>,
|
pub files: Vec<File>,
|
||||||
pub slots: i8,
|
pub slots: u8,
|
||||||
pub speed: i32,
|
pub speed: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FileSearchResult {
|
||||||
|
pub fn new_from_message(message: &mut Message) -> Self {
|
||||||
|
let pointer = message.get_pointer();
|
||||||
|
let size = message.get_size();
|
||||||
|
let data: Vec<u8> = message.get_slice(pointer, size);
|
||||||
|
let deflated = deflate(&data).unwrap();
|
||||||
|
let mut message = Message::new_with_data(deflated);
|
||||||
|
|
||||||
|
let username = message.read_string();
|
||||||
|
let token = message.read_int32();
|
||||||
|
let n_files = message.read_int32();
|
||||||
|
let mut files: Vec<File> = Vec::new();
|
||||||
|
for _ in 0..n_files {
|
||||||
|
message.read_int8();
|
||||||
|
let name = message.read_string();
|
||||||
|
let size = message.read_int32();
|
||||||
|
message.read_int32();
|
||||||
|
message.read_string();
|
||||||
|
let n_attribs = message.read_int32();
|
||||||
|
let mut attribs: HashMap<u32, u32> = HashMap::new();
|
||||||
|
|
||||||
|
for _ in 0..n_attribs {
|
||||||
|
attribs.insert(message.read_int32(), message.read_int32());
|
||||||
|
}
|
||||||
|
files.push(File {
|
||||||
|
username: username.clone(),
|
||||||
|
name,
|
||||||
|
size,
|
||||||
|
attribs,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let slots = message.read_int8();
|
||||||
|
let speed = message.read_int32();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
token,
|
||||||
|
files,
|
||||||
|
slots,
|
||||||
|
speed,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Transfer {
|
||||||
|
pub direction: u32,
|
||||||
|
pub token: u32,
|
||||||
|
pub filename: String,
|
||||||
|
pub size: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct DownloadResult {
|
||||||
|
pub filename: String,
|
||||||
|
pub username: String,
|
||||||
|
pub status: DownloadStatus,
|
||||||
|
pub elapsed_time: std::time::Duration,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum DownloadStatus {
|
||||||
|
Pending,
|
||||||
|
InProgress,
|
||||||
|
Completed,
|
||||||
|
Failed,
|
||||||
|
TimedOut,
|
||||||
|
}
|
||||||
|
impl Transfer {
|
||||||
|
pub fn new_from_message(message: &mut Message) -> Self {
|
||||||
|
let direction = message.read_int32();
|
||||||
|
let token = message.read_int32();
|
||||||
|
let filename = message.read_string();
|
||||||
|
let size = message.read_int64();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
direction,
|
||||||
|
token,
|
||||||
|
filename,
|
||||||
|
size,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,133 @@
|
|||||||
|
use std::env;
|
||||||
|
use std::sync::Once;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub enum LogLevel {
|
||||||
|
Error = 0,
|
||||||
|
Warn = 1,
|
||||||
|
Info = 2,
|
||||||
|
Debug = 3,
|
||||||
|
Trace = 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
static INIT: Once = Once::new();
|
||||||
|
static mut LOG_LEVEL: LogLevel = LogLevel::Debug; // Default to VERBOSE (mapped to DEBUG)
|
||||||
|
|
||||||
|
pub fn init() {
|
||||||
|
INIT.call_once(|| {
|
||||||
|
let level = env::var("LOG_LEVEL")
|
||||||
|
.or_else(|_| env::var("RUST_LOG"))
|
||||||
|
.unwrap_or_else(|_| "VERBOSE".to_string())
|
||||||
|
.to_uppercase();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
LOG_LEVEL = match level.as_str() {
|
||||||
|
"ERROR" => LogLevel::Error,
|
||||||
|
"WARN" => LogLevel::Warn,
|
||||||
|
"INFO" => LogLevel::Info,
|
||||||
|
"DEBUG" => LogLevel::Debug,
|
||||||
|
"TRACE" => LogLevel::Trace,
|
||||||
|
"VERBOSE" => LogLevel::Debug, // Map VERBOSE to DEBUG
|
||||||
|
_ => LogLevel::Debug, // Default to VERBOSE
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn log(level: LogLevel, message: &str) {
|
||||||
|
unsafe {
|
||||||
|
if level <= LOG_LEVEL {
|
||||||
|
let level_str = match level {
|
||||||
|
LogLevel::Error => "\x1b[31mERROR\x1b[0m", // Red
|
||||||
|
LogLevel::Warn => "\x1b[33mWARN\x1b[0m", // Yellow
|
||||||
|
LogLevel::Info => "\x1b[32mINFO\x1b[0m", // Green
|
||||||
|
LogLevel::Debug => "\x1b[34mDEBUG\x1b[0m", // Blue
|
||||||
|
LogLevel::Trace => "\x1b[35mTRACE\x1b[0m", // Magenta
|
||||||
|
};
|
||||||
|
|
||||||
|
let now = std::time::SystemTime::now();
|
||||||
|
let datetime = now.duration_since(std::time::UNIX_EPOCH).unwrap();
|
||||||
|
let secs = datetime.as_secs();
|
||||||
|
let subsec_millis = datetime.subsec_millis();
|
||||||
|
|
||||||
|
// Format as YYYY-MM-DD HH:MM:SS.mmm
|
||||||
|
let days_since_epoch = secs / 86400;
|
||||||
|
let days_since_1970 = days_since_epoch as i32;
|
||||||
|
|
||||||
|
// Calculate year (approximately)
|
||||||
|
let mut year = 1970;
|
||||||
|
let mut remaining_days = days_since_1970;
|
||||||
|
|
||||||
|
while remaining_days >= 365 {
|
||||||
|
let is_leap = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
|
||||||
|
let days_in_year = if is_leap { 366 } else { 365 };
|
||||||
|
if remaining_days >= days_in_year {
|
||||||
|
remaining_days -= days_in_year;
|
||||||
|
year += 1;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate month and day (simplified)
|
||||||
|
let month_days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
||||||
|
let is_leap = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
|
||||||
|
let mut month = 1;
|
||||||
|
let mut day = remaining_days + 1;
|
||||||
|
|
||||||
|
for &days_in_month in &month_days {
|
||||||
|
let actual_days = if month == 2 && is_leap { 29 } else { days_in_month };
|
||||||
|
if day > actual_days {
|
||||||
|
day -= actual_days;
|
||||||
|
month += 1;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate time of day
|
||||||
|
let seconds_in_day = secs % 86400;
|
||||||
|
let hours = seconds_in_day / 3600;
|
||||||
|
let minutes = (seconds_in_day % 3600) / 60;
|
||||||
|
let seconds = seconds_in_day % 60;
|
||||||
|
|
||||||
|
eprintln!("[{:04}-{:02}-{:02} {:02}:{:02}:{:02}.{:03}] [{}] {}",
|
||||||
|
year, month, day, hours, minutes, seconds, subsec_millis, level_str, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! error {
|
||||||
|
($($arg:tt)*) => {
|
||||||
|
$crate::utils::logger::log($crate::utils::logger::LogLevel::Error, &format!($($arg)*))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! warn {
|
||||||
|
($($arg:tt)*) => {
|
||||||
|
$crate::utils::logger::log($crate::utils::logger::LogLevel::Warn, &format!($($arg)*))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! info {
|
||||||
|
($($arg:tt)*) => {
|
||||||
|
$crate::utils::logger::log($crate::utils::logger::LogLevel::Info, &format!($($arg)*))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! debug {
|
||||||
|
($($arg:tt)*) => {
|
||||||
|
$crate::utils::logger::log($crate::utils::logger::LogLevel::Debug, &format!($($arg)*))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! trace {
|
||||||
|
($($arg:tt)*) => {
|
||||||
|
$crate::utils::logger::log($crate::utils::logger::LogLevel::Trace, &format!($($arg)*))
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#[macro_use]
|
||||||
|
pub mod logger;
|
||||||
pub mod md5;
|
pub mod md5;
|
||||||
pub mod thread_pool;
|
pub mod thread_pool;
|
||||||
pub mod zlib;
|
pub mod zlib;
|
||||||
|
|||||||
Reference in New Issue
Block a user