Files
soulseek-rs-modded/.gp.md
T
2024-09-09 08:32:51 +02:00

6.9 KiB

Additional context is provided below.

I have the following from soulseek_download/src/main.rs:

use std::collections::VecDeque;
use std::io::{self, Write};
use std::net::{TcpStream, ToSocketAddrs};
use std::sync::{Arc, Barrier, Condvar, Mutex};
use std::thread::{self, sleep};
use std::time::Duration;

mod buffered_reader;
mod message;
mod message_factory;

#[derive(Debug, Clone)]
struct ServerAddress {
    host: String,
    port: u16,
}

struct Client {
    address: ServerAddress,
    username: String,
    password: String,
}

struct Server {
    address: ServerAddress,
    stream: Arc<Mutex<TcpStream>>,
    message_queue: Arc<(Mutex<VecDeque<Vec<u8>>>, Condvar)>,
}

impl Server {
    /// Create a new instance of Server, returning a Result
    fn new(address: ServerAddress) -> Result<Self, io::Error> {
        println!("Connecting to server at {}:{}", address.host, address.port);

        // Convert the host and port into a socket address
        let socket_address = format!("{}:{}", address.host, address.port)
            .to_socket_addrs()?
            .next()
            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Invalid address"))?;

        // Establish the connection with a timeout
        let stream = TcpStream::connect_timeout(&socket_address, Duration::from_secs(10))?;

        // Set the stream to non-blocking mode if needed or configure timeouts
        stream.set_read_timeout(Some(Duration::from_secs(5)))?;
        stream.set_write_timeout(Some(Duration::from_secs(5)))?;

        let message_queue = Arc::new((Mutex::new(VecDeque::new()), Condvar::new())); // Initialize the message queue with Condvar

        let server = Self {
            address,
            stream: Arc::new(Mutex::new(stream)),
            message_queue,
        };

        server.start_read_write_loops();

        Ok(server)
    }
    /// Start reading and writing loops in separate threads
    fn start_read_write_loops(&self) {
        // Create a channel to send messages to the write thread
        let read_stream = Arc::clone(&self.stream);
        let write_stream = Arc::clone(&self.stream);

        let barrier = Arc::new(Barrier::new(2));
        let read_barrier = barrier.clone();
        let write_barrier = barrier.clone();
        let message_queue = self.message_queue.clone();

        // Spawn a thread to handle reading from the server
        thread::spawn(move || {
            read_barrier.wait();
            let mut buffered_reader = buffered_reader::BufferedReader::new();

            loop {
                match buffered_reader.read_from_socket(&mut read_stream.lock().unwrap()) {
                    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 => {
                        println!("Read operation timed out");
                        continue;
                    }
                    Err(e) => {
                        eprintln!("Error reading from server: {}", e);
                        break;
                    }
                }

                match buffered_reader.extract_message() {
                    Ok(Some(mut message)) => {
                        println!("Received message: {:?}", message.get_data());
                        self.handle_message(&mut message);
                    }
                    Err(e) => {
                        println!("Error extracting message: {}", e)
                    }
                    Ok(None) => continue,
                }
            }
        });
        thread::spawn(move || {
            write_barrier.wait();

            loop {
                let (lock, cvar) = &*message_queue;
                let mut queue = lock.lock().unwrap();

                // Wait for a message to be added to the queue
                while queue.is_empty() {
                    queue = cvar.wait(queue).unwrap();
                }

                // Pop and send the message
                if let Some(message) = queue.pop_front() {
                    match write_stream.lock().unwrap().write_all(&message) {
                        Ok(_) => println!("Sent buffered message: {:?}", message),
                        Err(e) => {
                            eprintln!("Failed to send buffered message: {}", e);
                            // Handle error appropriately
                            break;
                        }
                    }
                }
            }
        });
    }

    fn queue_message(&self, message: Vec<u8>) {
        let (lock, cvar) = &*self.message_queue;
        let mut queue = lock.lock().unwrap();
        queue.push_back(message);
        cvar.notify_one();
    }

    fn login(&mut self, username: &str, password: &str) -> Result<(), std::io::Error> {
        self.queue_message(message_factory::build_init_message().get_data());
        self.queue_message(message_factory::build_login_message(username, password).get_data());
        Ok(())
    }

    fn handle_message(&mut self, message: &mut message::Message) {
        let code = message.get_code();
        match code {
            1 => {
                println!("Received login response");
                let response = message.read_int8();
                if response == 1 {
                    println!("Login successful");
                } else {
                    println!("Login failed");
                }
            }
            _ => {
                println!("Received unknown message with code {}", code);
            }
        }
    }
}

impl Client {
    fn new(address: ServerAddress, username: String, password: String) -> Self {
        Self {
            address,
            username,
            password,
        }
    }
    fn connect(&self) {
        // Attempt to create a server instance
        match Server::new(self.address.clone()) {
            Ok(mut server) => {
                println!(
                    "Connected to server at {}:{}",
                    server.address.host, server.address.port
                );
                // Attempt to login
                println!("Logging in as {}", self.username);

                if let Err(e) = server.login(&self.username, &self.password) {
                    eprintln!("Error during login: {}", e);
                }
            }
            Err(e) => eprintln!("Error connecting to server: {}", e),
        }
    }
}
// ServerAddress {
//     host: String::from("server.slsknet.org"),
//     port: 2242,
// },

fn main() {
    let client = Client::new(
        ServerAddress {
            // host: String::from("server.slsknet.org"),
            host: String::from("localhost"),
            port: 2242,
        },
        String::from("insane_in_the_brain2"),
        String::from("invalid"),
        // String::from("13375137"),
    );
    client.connect();
    loop {
        thread::park();
    }
}