From 1d69387dc8f2dad7c35da8003efee8b7aa00d427 Mon Sep 17 00:00:00 2001 From: Avii Date: Thu, 6 Mar 2025 14:24:01 +0100 Subject: [PATCH] ping no worky --- src/main.rs | 110 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 101 insertions(+), 9 deletions(-) diff --git a/src/main.rs b/src/main.rs index 6f0cb04..66167ce 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::{io::Cursor, net::SocketAddr, str::FromStr, sync::Arc, time::Duration}; use irc_rust::Message; @@ -12,29 +12,37 @@ use tokio::{ }; use tokio_rustls::{TlsAcceptor, server::TlsStream}; -type Result = std::result::Result>; +type Result = std::result::Result>; #[derive(Debug)] struct Client { - peer_addr: SocketAddr, rx: Receiver, tx: Sender, + nick: Option, + username: Option, + realname: Option, + + modes: HashSet, // [byte per mode](https://www.unrealircd.org/docs/User_modes) c2s_tx: Option>, s2c_rx: Option>, } impl Client { - pub fn new(peer_addr: SocketAddr) -> Self { + pub fn new() -> Self { let (c2s_tx, c2s_rx) = mpsc::channel(32); let (s2c_tx, s2c_rx) = mpsc::channel(32); Self { - peer_addr, tx: s2c_tx, rx: c2s_rx, + nick: None, + username: None, + realname: None, + + modes: HashSet::new(), c2s_tx: Some(c2s_tx), s2c_rx: Some(s2c_rx), @@ -56,7 +64,7 @@ struct AppState { impl AppState { pub async fn add_client(&self, peer_addr: SocketAddr) -> (Sender, Receiver) { - let mut client = Client::new(peer_addr); + let mut client = Client::new(); let Ok((c2s_tx, s2c_rx)) = client.take_channels() else { eprintln!("Unable to take channels for {}", peer_addr); unreachable!(); @@ -72,6 +80,33 @@ impl AppState { } } + pub async fn user( + &self, + peer_addr: SocketAddr, + username: &str, + mode: u16, + realname: Option<&str>, + ) { + if let Some(client) = self.clients.write().await.get_mut(&peer_addr) { + client.username = Some(username.to_string()); + client.realname = realname.map(str::to_string) + } + } + + async fn pass(&self, peer_addr: SocketAddr, _password: &str) -> bool { + if let Some(_client) = self.clients.write().await.get_mut(&peer_addr) { + return true; // client exists, there is no database rn, just return true for now + } + + false + } + + async fn quit(&self, peer_addr: SocketAddr, reason: Option<&str>) { + // broadcast user leaving unless invisible flag was set + + self.clients.write().await.remove(&peer_addr); + } + // clients still needs mod/op status stuff // join channel @@ -106,6 +141,16 @@ impl AppState { client.tx.send(msg).await?; Ok(()) } + + pub async fn broadcast(&self, msg: Message) -> Result<()> { + let clients = self.clients.read().await; + let addresses = clients.keys().cloned(); + for peer_addr in addresses { + self.send(peer_addr, msg.clone()).await?; + } + + Ok(()) + } } #[tokio::main] @@ -171,6 +216,33 @@ async fn main() -> Result<()> { } }); + // Ping loop + let state: Arc = app_state.clone(); + tokio::spawn(async move { + loop { + let clients = state.clients.read().await; + for (peer_addr, client) in clients.iter() { + println!("PING :{}", client.username.clone().unwrap_or_default()); + state + .send( + *peer_addr, + Message::from_str(&format!( + ":localhost PING :{}", + client.username.clone().unwrap_or_default() + ))?, + ) + .await?; + } + + drop(clients); + + tokio::time::sleep(Duration::from_secs(30)).await; + } + + #[allow(unreachable_code)] + Ok::<(), Box>(()) + }); + tokio::signal::ctrl_c().await?; Ok(()) @@ -186,9 +258,29 @@ async fn handle( state.send(peer_addr, Message::from_str("NONE")?).await?; } "NICK" => { - state - .set_nick(peer_addr, msg.params()?.next().unwrap()) - .await; + let nick = msg.params()?.next().unwrap_or_default(); + state.set_nick(peer_addr, nick).await; + } + "USER" => { + let mut params = msg.params()?; + let username = params.next().unwrap_or_default(); // aviinl + let mode = params.next().unwrap_or_default().parse::()?; // mode + params.next().unwrap_or_default(); // unused + + let realname = msg.trailing()?; // realname + + dbg!(username, realname); + + state.user(peer_addr, username, mode, realname).await; + } + "PASS" => { + let mut params = msg.params()?; + let password = params.next().unwrap_or_default(); // aviinl + state.pass(peer_addr, password).await; + } + "QUIT" => { + let reason = msg.trailing()?; // realname + state.quit(peer_addr, reason).await; } _ => { return Err(format!("Unknown Command: {:?}", msg.command()?).into());