feat: add logging support
This commit is contained in:
+115
-13
@@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
peer::{DefaultPeer, Peer},
|
||||
server::{PeerAddress, Server},
|
||||
types::FileSearchResult,
|
||||
peer::{ConnectionType, DefaultPeer, Peer},
|
||||
server::{PeerAddress, Server, ServerOperation},
|
||||
types::{FileSearchResult, Transfer},
|
||||
utils::{md5, thread_pool::ThreadPool},
|
||||
};
|
||||
use std::{
|
||||
@@ -22,11 +22,15 @@ pub enum ClientOperation {
|
||||
ConnectToPeer(Peer),
|
||||
SearchResult(FileSearchResult),
|
||||
PeerDisconnected(String),
|
||||
TransferRequest(Transfer),
|
||||
PierceFireWall(Peer),
|
||||
}
|
||||
struct ClientContext {
|
||||
peers: HashMap<String, DefaultPeer>,
|
||||
sender: Option<Sender<ClientOperation>>,
|
||||
server_sender: Option<Sender<crate::server::ServerOperation>>,
|
||||
search_results: Vec<FileSearchResult>,
|
||||
downloads: HashMap<u32, Transfer>,
|
||||
thread_pool: ThreadPool,
|
||||
}
|
||||
impl ClientContext {
|
||||
@@ -34,7 +38,9 @@ impl ClientContext {
|
||||
Self {
|
||||
peers: HashMap::new(),
|
||||
sender: None,
|
||||
server_sender: None,
|
||||
search_results: Vec::new(),
|
||||
downloads: HashMap::new(),
|
||||
thread_pool: ThreadPool::new(MAX_THREADS),
|
||||
}
|
||||
}
|
||||
@@ -49,6 +55,7 @@ pub struct Client {
|
||||
|
||||
impl Client {
|
||||
pub fn new(address: PeerAddress, username: String, password: String) -> Self {
|
||||
crate::utils::logger::init();
|
||||
Self {
|
||||
address,
|
||||
username,
|
||||
@@ -67,17 +74,20 @@ impl Client {
|
||||
// self.read_form_channel(message_reader);
|
||||
self.server = match Server::new(self.address.clone(), sender) {
|
||||
Ok(server) => {
|
||||
println!(
|
||||
info!(
|
||||
"Connected to server at {}:{}",
|
||||
server.get_address().get_host(),
|
||||
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());
|
||||
Some(server)
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Error connecting to server: {}", e);
|
||||
error!("Error connecting to server: {}", e);
|
||||
None
|
||||
}
|
||||
};
|
||||
@@ -85,7 +95,7 @@ impl Client {
|
||||
|
||||
pub fn login(&self) -> Result<bool, std::io::Error> {
|
||||
// Attempt to login
|
||||
println!("Logging in as {}", self.username);
|
||||
info!("Logging in as {}", self.username);
|
||||
if let Some(server) = &self.server {
|
||||
let result = server.login(&self.username, &self.password);
|
||||
if result.unwrap() {
|
||||
@@ -108,18 +118,18 @@ impl Client {
|
||||
pub fn remove_peer(&self, username: &str) {
|
||||
let mut context = self.context.lock().unwrap();
|
||||
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> {
|
||||
println!("Searching for {}", query);
|
||||
info!("Searching for {}", query);
|
||||
if let Some(server) = &self.server {
|
||||
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);
|
||||
} else {
|
||||
eprintln!("Not connected to server");
|
||||
warn!("Not connected to server");
|
||||
}
|
||||
|
||||
let start = Instant::now();
|
||||
@@ -131,6 +141,52 @@ impl Client {
|
||||
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(
|
||||
reader: Receiver<ClientOperation>,
|
||||
client_context: Arc<Mutex<ClientContext>>,
|
||||
@@ -139,6 +195,14 @@ impl Client {
|
||||
if let Ok(operation) = reader.recv() {
|
||||
match operation {
|
||||
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())
|
||||
}
|
||||
ClientOperation::SearchResult(file_search) => {
|
||||
@@ -154,6 +218,16 @@ impl Client {
|
||||
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();
|
||||
context.peers.insert(peer.username, p);
|
||||
}
|
||||
Err(_e) => {
|
||||
// eprintln!("Error connecting to peer: {:?}", e)
|
||||
Err(e) => {
|
||||
trace!(
|
||||
"Can't connect to {} {}:{} {:?} - {}",
|
||||
peer.username,
|
||||
peer.host,
|
||||
peer.port,
|
||||
peer.connection_type,
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} 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);
|
||||
handler.handle(message, self.sender.clone());
|
||||
} else {
|
||||
println!(
|
||||
warn!(
|
||||
"No handler found for message code: {:?}",
|
||||
message.get_message_code()
|
||||
);
|
||||
|
||||
+10
-4
@@ -1,14 +1,15 @@
|
||||
#[macro_use]
|
||||
mod utils;
|
||||
mod client;
|
||||
mod dispatcher;
|
||||
mod message;
|
||||
mod peer;
|
||||
mod server;
|
||||
mod types;
|
||||
mod utils;
|
||||
|
||||
use client::Client;
|
||||
use server::PeerAddress;
|
||||
use std::time::Duration;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
// PeerAddress::new(String::from("server.slsknet.org"), 2416),
|
||||
fn main() {
|
||||
@@ -25,10 +26,15 @@ fn main() {
|
||||
match client.login() {
|
||||
Ok(_) => {
|
||||
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) => {
|
||||
println!("Failed to login: {}", e);
|
||||
error!("Failed to login: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+101
-22
@@ -8,6 +8,25 @@ pub use message_reader::*;
|
||||
|
||||
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)]
|
||||
pub struct Message {
|
||||
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 {
|
||||
Self { data, pointer: 0 }
|
||||
}
|
||||
// pub fn reset_pointer(&mut self) {
|
||||
// self.pointer = 0;
|
||||
// }
|
||||
pub fn reset_pointer(&mut self) {
|
||||
self.pointer = 0;
|
||||
}
|
||||
pub fn set_pointer(&mut self, pointer: usize) {
|
||||
self.pointer = pointer;
|
||||
}
|
||||
@@ -169,27 +188,16 @@ impl Message {
|
||||
|
||||
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 {
|
||||
let val = self.data[self.pointer] as i8;
|
||||
pub fn read_int8(&mut self) -> u8 {
|
||||
let val = self.data[self.pointer];
|
||||
self.pointer += 1;
|
||||
val
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn read_int64(&mut self) -> i64 {
|
||||
let val = i64::from_le_bytes([
|
||||
pub fn read_int64(&mut self) -> u64 {
|
||||
let val = u64::from_le_bytes([
|
||||
self.data[self.pointer],
|
||||
self.data[self.pointer + 1],
|
||||
self.data[self.pointer + 2],
|
||||
@@ -203,12 +211,12 @@ impl Message {
|
||||
val
|
||||
}
|
||||
|
||||
pub fn read_int32(&mut self) -> i32 {
|
||||
pub fn read_int32(&mut self) -> u32 {
|
||||
if self.pointer + 4 > self.data.len() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let val = i32::from_le_bytes([
|
||||
let val = u32::from_le_bytes([
|
||||
self.data[self.pointer],
|
||||
self.data[self.pointer + 1],
|
||||
self.data[self.pointer + 2],
|
||||
@@ -231,7 +239,12 @@ impl Message {
|
||||
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
|
||||
}
|
||||
@@ -240,6 +253,11 @@ impl Message {
|
||||
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 {
|
||||
let mut b = Vec::new();
|
||||
for i in (0..val.len()).step_by(2) {
|
||||
@@ -251,6 +269,67 @@ impl Message {
|
||||
self.pointer += b.len();
|
||||
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) {
|
||||
// println!("{:?}", self.data);
|
||||
// }
|
||||
|
||||
@@ -1,55 +1,8 @@
|
||||
use crate::message::{Message, MessageHandler};
|
||||
use crate::peer::PeerOperation;
|
||||
use crate::types::{File, FileSearchResult};
|
||||
use crate::utils::zlib::deflate;
|
||||
use std::collections::HashMap;
|
||||
use crate::types::FileSearchResult;
|
||||
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;
|
||||
impl MessageHandler<PeerOperation> for FileSearchResponse {
|
||||
fn get_code(&self) -> u8 {
|
||||
@@ -85,7 +38,7 @@ fn test_new_from_message() {
|
||||
message.set_pointer(8);
|
||||
|
||||
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);
|
||||
let file = &file_search.files[0];
|
||||
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 get_share_file_list;
|
||||
pub mod transfer_request;
|
||||
pub mod upload_failed;
|
||||
|
||||
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::peer::Peer;
|
||||
use crate::peer::{ConnectionType, Peer};
|
||||
use crate::server::ServerOperation;
|
||||
use std::sync::mpsc::Sender;
|
||||
pub struct ConnectToPeerHandler;
|
||||
@@ -9,6 +9,12 @@ impl MessageHandler<ServerOperation> for ConnectToPeerHandler {
|
||||
}
|
||||
fn handle(&self, message: &mut Message, sender: Sender<ServerOperation>) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,6 @@ impl MessageHandler<ServerOperation> for ExcludedSearchPhrasesHandler {
|
||||
let phrase = message.read_string();
|
||||
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
|
||||
}
|
||||
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 token = message.read_int32();
|
||||
let query = message.read_string();
|
||||
println!(
|
||||
info!(
|
||||
"Message search username:{}, token: {}, query: {}",
|
||||
username, token, query
|
||||
);
|
||||
|
||||
@@ -20,9 +20,9 @@ impl MessageHandler<ServerOperation> for LoginHandler {
|
||||
return sender.send(ServerOperation::LoginStatus(false)).unwrap();
|
||||
}
|
||||
|
||||
println!("Login successful");
|
||||
info!("Login successful");
|
||||
let greeting = message.read_string();
|
||||
println!("Server greeting: {:?}", greeting);
|
||||
debug!("Server greeting: {:?}", greeting);
|
||||
|
||||
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;
|
||||
impl MessageFactory {
|
||||
@@ -18,7 +18,7 @@ impl MessageFactory {
|
||||
// ]
|
||||
// .to_vec(),
|
||||
// )
|
||||
// .clone()
|
||||
// .clone()fac
|
||||
let hash = md5([username, password].join("").as_str());
|
||||
|
||||
let mut message = Message::new();
|
||||
@@ -34,14 +34,14 @@ impl MessageFactory {
|
||||
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()
|
||||
.write_int32(35)
|
||||
.write_int32(folder_count)
|
||||
.write_int32(file_count)
|
||||
.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(
|
||||
// [
|
||||
// 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)
|
||||
.clone()
|
||||
}
|
||||
pub fn build_set_status_message(status_code: i32) -> Message {
|
||||
pub fn build_set_status_message(status_code: u32) -> Message {
|
||||
Message::new()
|
||||
.write_int32(28)
|
||||
.write_int32(status_code)
|
||||
@@ -68,17 +68,38 @@ impl MessageFactory {
|
||||
pub fn build_set_wait_port_message() -> Message {
|
||||
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()
|
||||
.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()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_build_watch_user() {
|
||||
let token = "5b581500";
|
||||
let token: u32 = 223;
|
||||
let message = MessageFactory::build_watch_user(token);
|
||||
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,
|
||||
);
|
||||
|
||||
println!("User message received:",);
|
||||
info!("User message received:");
|
||||
user_message.print()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,6 @@ impl MessageHandler<ServerOperation> for ParentMinSpeedHandler {
|
||||
fn handle(&self, message: &mut Message, sender: Sender<ServerOperation>) {
|
||||
let _ = sender;
|
||||
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>) {
|
||||
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>) {
|
||||
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>) {
|
||||
let number = message.read_int32();
|
||||
println!("Wishlist search interval: {} in seconds", number);
|
||||
debug!("Wishlist search interval: {} in seconds", number);
|
||||
}
|
||||
}
|
||||
|
||||
+88
-29
@@ -1,8 +1,11 @@
|
||||
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::server::MessageFactory;
|
||||
use crate::message::{Handlers, Message, MessageReader};
|
||||
use crate::types::FileSearchResult;
|
||||
use crate::message::{Handlers, Message, MessageReader, MessageType};
|
||||
use crate::types::{FileSearchResult, Transfer};
|
||||
|
||||
use std::sync::mpsc;
|
||||
use std::sync::mpsc::{Receiver, Sender};
|
||||
@@ -20,7 +23,6 @@ pub struct DefaultPeer {
|
||||
peer: Peer,
|
||||
peer_channel: Option<Sender<PeerOperation>>,
|
||||
client_channel: Sender<ClientOperation>,
|
||||
// Store thread handles for proper lifecycle management
|
||||
read_thread: Option<JoinHandle<()>>,
|
||||
write_thread: Option<JoinHandle<()>>,
|
||||
}
|
||||
@@ -29,6 +31,7 @@ pub struct DefaultPeer {
|
||||
pub enum PeerOperation {
|
||||
SendMessage(Message),
|
||||
FileSearchResult(FileSearchResult),
|
||||
TransferRequest(Transfer),
|
||||
}
|
||||
impl DefaultPeer {
|
||||
pub fn new(peer: Peer, client_channel: Sender<ClientOperation>) -> Self {
|
||||
@@ -46,13 +49,14 @@ impl DefaultPeer {
|
||||
.next()
|
||||
.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_write_timeout(Some(Duration::from_secs(5)))?;
|
||||
if let Some(token) = self.peer.token.clone() {
|
||||
|
||||
if let Some(token) = self.peer.token {
|
||||
stream
|
||||
.write_all(&MessageFactory::build_watch_user(token.as_str()).get_data())
|
||||
.write_all(&MessageFactory::build_watch_user(token).get_data())
|
||||
.unwrap();
|
||||
}
|
||||
self.start_read_write_loops(stream)?;
|
||||
@@ -64,6 +68,9 @@ impl DefaultPeer {
|
||||
let (peer_sender, peer_reader): (Sender<PeerOperation>, Receiver<PeerOperation>) =
|
||||
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 write_stream = stream; // Use the original stream for writing
|
||||
|
||||
@@ -74,6 +81,9 @@ impl DefaultPeer {
|
||||
self.read_thread = Some(thread::spawn(move || {
|
||||
let mut handlers = Handlers::new();
|
||||
handlers.register_handler(FileSearchResponse);
|
||||
handlers.register_handler(TransferRequest);
|
||||
handlers.register_handler(GetShareFileList);
|
||||
handlers.register_handler(UploadFailedHandler);
|
||||
|
||||
let dispatcher = MessageDispatcher::new(peer_sender, handlers);
|
||||
|
||||
@@ -83,27 +93,41 @@ impl DefaultPeer {
|
||||
Ok(_) => {}
|
||||
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => continue,
|
||||
Err(ref e) if e.kind() == io::ErrorKind::TimedOut => {
|
||||
println!(
|
||||
debug!(
|
||||
"Read operation timed out in default peer {:}:{:}",
|
||||
peer.host, peer.port
|
||||
);
|
||||
continue;
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Error reading from peer: {}. Terminating read loop.", e);
|
||||
let _ = client_channel_for_read.send(ClientOperation::PeerDisconnected(peer.username.clone()));
|
||||
error!("Error reading from peer: {}. Terminating read loop.", e);
|
||||
let _ = client_channel_for_read
|
||||
.send(ClientOperation::PeerDisconnected(peer.username.clone()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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) => {
|
||||
println!(
|
||||
warn!(
|
||||
"Error extracting message in default 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;
|
||||
}
|
||||
Ok(None) => continue,
|
||||
@@ -112,16 +136,32 @@ impl DefaultPeer {
|
||||
}));
|
||||
|
||||
let client_channel = self.client_channel.clone();
|
||||
let peer_channel = self.peer_channel.clone();
|
||||
let peer_username = self.peer.username.clone();
|
||||
|
||||
self.write_thread = Some(thread::spawn(move || {
|
||||
loop {
|
||||
match peer_reader.recv() {
|
||||
Ok(operation) => {
|
||||
match operation {
|
||||
Ok(operation) => match operation {
|
||||
PeerOperation::SendMessage(message) => {
|
||||
trace!(
|
||||
"[default_peer:{:?}] ➡ {:?} - {:?}",
|
||||
peer_username,
|
||||
message
|
||||
.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()) {
|
||||
eprintln!("Error writing message to stream: {}. Terminating write loop.", e);
|
||||
let _ = client_channel.send(ClientOperation::PeerDisconnected(peer_username.clone()));
|
||||
error!("Error writing message to stream: {} - {}. Terminating write loop.", peer_username, e);
|
||||
let _ = client_channel
|
||||
.send(ClientOperation::PeerDisconnected(peer_username.clone()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -130,11 +170,28 @@ impl DefaultPeer {
|
||||
.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();
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(_) => {
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
@@ -143,31 +200,33 @@ impl DefaultPeer {
|
||||
|
||||
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 {
|
||||
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;
|
||||
|
||||
// Join the read thread
|
||||
if let Some(handle) = self.read_thread.take() {
|
||||
println!("Joining read thread...");
|
||||
debug!("Joining read thread...");
|
||||
match handle.join() {
|
||||
Ok(_) => println!("Read thread joined successfully."),
|
||||
Err(e) => eprintln!("Read thread panicked: {:?}", e),
|
||||
Ok(_) => debug!("Read thread joined successfully."),
|
||||
Err(e) => error!("Read thread panicked: {:?}", e),
|
||||
}
|
||||
}
|
||||
|
||||
// Join the write thread
|
||||
if let Some(handle) = self.write_thread.take() {
|
||||
println!("Joining write thread...");
|
||||
debug!("Joining write thread...");
|
||||
match handle.join() {
|
||||
Ok(_) => println!("Write thread joined successfully."),
|
||||
Err(e) => eprintln!("Write thread panicked: {:?}", e),
|
||||
Ok(_) => debug!("Write thread joined successfully."),
|
||||
Err(e) => error!("Write thread panicked: {:?}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+9
-9
@@ -8,7 +8,7 @@ pub struct Listen {}
|
||||
|
||||
impl Listen {
|
||||
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();
|
||||
for stream in listener.incoming() {
|
||||
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::TimedOut => {
|
||||
println!("Read operation timed out");
|
||||
debug!("Read operation timed out");
|
||||
continue;
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Error reading from server: {}", e);
|
||||
error!("Error reading from server: {}", e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
match buffered_reader.extract_message() {
|
||||
Ok(Some(mut message)) => {
|
||||
println!("Received message: {:?}", message.get_message_code());
|
||||
println!("{:?}", message.get_data());
|
||||
debug!("Received message: {:?}", message.get_message_code());
|
||||
trace!("{:?}", message.get_data());
|
||||
message.print_hex();
|
||||
|
||||
if message.get_message_code() == 1 {
|
||||
@@ -45,8 +45,8 @@ impl Listen {
|
||||
// // message.read_string().parse().unwrap();
|
||||
// // let token = message.read_int32();
|
||||
//
|
||||
println!("type: {:?}", typex);
|
||||
println!("user: {:?}", size);
|
||||
debug!("type: {:?}", typex);
|
||||
debug!("user: {:?}", size);
|
||||
|
||||
// server_channel
|
||||
// .send(ServerOperation::ConnectToPeer(peer))
|
||||
@@ -54,13 +54,13 @@ impl Listen {
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Error extracting message: {}", e)
|
||||
warn!("Error extracting message: {}", e)
|
||||
}
|
||||
Ok(None) => continue,
|
||||
}
|
||||
}
|
||||
|
||||
println!("Connection established!");
|
||||
info!("Connection established!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
-13
@@ -46,11 +46,11 @@ pub struct Peer {
|
||||
pub username: String,
|
||||
pub connection_type: ConnectionType,
|
||||
pub host: String,
|
||||
pub port: i32,
|
||||
pub token: Option<String>,
|
||||
pub privileged: i8,
|
||||
pub unknown: i8,
|
||||
pub obfuscated_port: i8,
|
||||
pub port: u32,
|
||||
pub token: Option<u32>,
|
||||
pub privileged: u8,
|
||||
pub unknown: u8,
|
||||
pub obfuscated_port: u8,
|
||||
}
|
||||
impl Peer {
|
||||
#[allow(clippy::too_many_arguments, dead_code)]
|
||||
@@ -58,11 +58,11 @@ impl Peer {
|
||||
username: String,
|
||||
connection_type: ConnectionType,
|
||||
host: String,
|
||||
port: i32,
|
||||
token: String,
|
||||
privileged: i8,
|
||||
unknown: i8,
|
||||
obfuscated_port: i8,
|
||||
port: u32,
|
||||
token: u32,
|
||||
privileged: u8,
|
||||
unknown: u8,
|
||||
obfuscated_port: u8,
|
||||
) -> Self {
|
||||
Self {
|
||||
username,
|
||||
@@ -78,7 +78,7 @@ impl Peer {
|
||||
#[allow(dead_code)]
|
||||
pub fn new_from_message(message: &mut Message) -> Self {
|
||||
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![];
|
||||
for _ in 0..4 {
|
||||
@@ -94,7 +94,7 @@ impl Peer {
|
||||
|
||||
let (port, token, privileged, unknown, obfuscated_port) = (
|
||||
message.read_int32(),
|
||||
message.read_raw_hex_str(4),
|
||||
message.read_int32(),
|
||||
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.obfuscated_port, 0);
|
||||
}
|
||||
|
||||
|
||||
+79
-27
@@ -15,6 +15,7 @@ use crate::message::Handlers;
|
||||
use crate::message::Message;
|
||||
use crate::message::MessageReader;
|
||||
use crate::peer::listen::Listen;
|
||||
use crate::peer::ConnectionType;
|
||||
use crate::peer::Peer;
|
||||
|
||||
use std::io::{self, Write};
|
||||
@@ -71,16 +72,16 @@ impl Context {
|
||||
}
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct UserMessage {
|
||||
id: i32,
|
||||
timestamp: i32,
|
||||
id: u32,
|
||||
timestamp: u32,
|
||||
username: String,
|
||||
message: String,
|
||||
new_message: bool,
|
||||
}
|
||||
impl UserMessage {
|
||||
pub fn new(
|
||||
id: i32,
|
||||
timestamp: i32,
|
||||
id: u32,
|
||||
timestamp: u32,
|
||||
username: String,
|
||||
message: String,
|
||||
new_message: bool,
|
||||
@@ -94,7 +95,7 @@ impl UserMessage {
|
||||
}
|
||||
}
|
||||
pub fn print(&self) {
|
||||
println!(
|
||||
debug!(
|
||||
"Timestamp: {}. User: {}, Id: #{}, New message: {} Message: {}",
|
||||
self.timestamp, self.username, self.id, self.new_message, self.message
|
||||
);
|
||||
@@ -121,19 +122,19 @@ impl Rooms {
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn print(&self) {
|
||||
println!("Public rooms ({}):", self.public_rooms.len());
|
||||
info!("Public rooms ({}):", self.public_rooms.len());
|
||||
for room in &self.public_rooms {
|
||||
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 {
|
||||
room.print();
|
||||
}
|
||||
println!("Private rooms ({}):", self.private_rooms.len());
|
||||
info!("Private rooms ({}):", self.private_rooms.len());
|
||||
for room in &self.private_rooms {
|
||||
room.print();
|
||||
}
|
||||
println!(
|
||||
info!(
|
||||
"Operated private rooms ({}):",
|
||||
self.operated_private_rooms.len()
|
||||
);
|
||||
@@ -160,7 +161,7 @@ impl Room {
|
||||
self.number_of_users = number_of_users;
|
||||
}
|
||||
pub fn print(&self) {
|
||||
println!(
|
||||
debug!(
|
||||
"Room: {}, Number of users: {}",
|
||||
self.name, self.number_of_users
|
||||
);
|
||||
@@ -172,6 +173,7 @@ pub enum ServerOperation {
|
||||
SendMessage(Message),
|
||||
#[allow(dead_code)]
|
||||
ConnectToPeer(Peer),
|
||||
PierceFirewall(u32),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -205,6 +207,10 @@ impl Server {
|
||||
&self.address
|
||||
}
|
||||
|
||||
pub fn get_sender(&self) -> &Sender<ServerOperation> {
|
||||
&self.sender
|
||||
}
|
||||
|
||||
/// Start reading and writing loops in separate threads
|
||||
fn start_read_write_loops(
|
||||
&mut self,
|
||||
@@ -216,7 +222,7 @@ impl Server {
|
||||
.next()
|
||||
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Invalid address"))?;
|
||||
|
||||
println!(
|
||||
info!(
|
||||
"Connecting to server at {}:{}",
|
||||
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::TimedOut => {
|
||||
println!("Read operation timed out");
|
||||
debug!("Read operation timed out");
|
||||
continue;
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Error reading from server: {}", e);
|
||||
error!("Error reading from server: {}", e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
match buffered_reader.extract_message() {
|
||||
Ok(Some(mut message)) => {
|
||||
// println!("Received message: {:?}", message.get_message_code_u32());
|
||||
// message.print_hex();
|
||||
// trace!(
|
||||
// "[server] ← {:?}",
|
||||
// message
|
||||
// .get_message_name(
|
||||
// MessageType::Server,
|
||||
// message.get_message_code() as u32
|
||||
// )
|
||||
// .map_err(|e| e.to_string())
|
||||
// );
|
||||
|
||||
dispatcher.dispatch(&mut message)
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Error extracting message: {}", e)
|
||||
warn!("Error extracting message: {}", e)
|
||||
}
|
||||
Ok(None) => continue,
|
||||
}
|
||||
@@ -295,24 +308,56 @@ impl Server {
|
||||
loop {
|
||||
if let Ok(operation) = server_channel.recv() {
|
||||
match operation {
|
||||
ServerOperation::ConnectToPeer(peer) => {
|
||||
ServerOperation::ConnectToPeer(peer) => match peer.connection_type {
|
||||
ConnectionType::P => {
|
||||
match client_channel.send(ClientOperation::ConnectToPeer(peer)) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
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) => {
|
||||
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) => {
|
||||
// message.decode();
|
||||
// message.print_hex2();
|
||||
// trace!(
|
||||
// "[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()) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
eprintln!("Error writing message to stream : {}", e);
|
||||
error!("Error writing message to stream : {}", e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -328,7 +373,7 @@ impl Server {
|
||||
fn queue_message(&self, message: Message) {
|
||||
match self.sender.send(ServerOperation::SendMessage(message)) {
|
||||
Ok(_) => {}
|
||||
Err(e) => println!("Failed to send: {}", e),
|
||||
Err(e) => error!("Failed to send: {}", e),
|
||||
}
|
||||
}
|
||||
fn start_listener(&self, server_channel: Sender<ServerOperation>) {
|
||||
@@ -347,7 +392,7 @@ impl Server {
|
||||
// wait till server says your logged in or not
|
||||
loop {
|
||||
if start.elapsed() > timeout {
|
||||
println!("Timeout waiting for login response");
|
||||
warn!("Timeout waiting for login response");
|
||||
return Err(std::io::Error::new(
|
||||
std::io::ErrorKind::TimedOut,
|
||||
"Timeout waiting for login response",
|
||||
@@ -364,9 +409,9 @@ impl Server {
|
||||
}
|
||||
|
||||
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_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_set_status_message(2));
|
||||
}
|
||||
@@ -374,7 +419,14 @@ impl Server {
|
||||
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));
|
||||
}
|
||||
|
||||
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 crate::{message::Message, utils::zlib::deflate};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[allow(dead_code)]
|
||||
pub struct File {
|
||||
pub username: String,
|
||||
pub name: String,
|
||||
pub size: i32,
|
||||
pub attribs: HashMap<i32, i32>,
|
||||
pub size: u32,
|
||||
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)]
|
||||
#[allow(dead_code)]
|
||||
pub struct FileSearchResult {
|
||||
pub token: String,
|
||||
pub token: u32,
|
||||
pub files: Vec<File>,
|
||||
pub slots: i8,
|
||||
pub speed: i32,
|
||||
pub slots: u8,
|
||||
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 thread_pool;
|
||||
pub mod zlib;
|
||||
|
||||
Reference in New Issue
Block a user