diff --git a/src/channels.rs b/src/channels.rs index c1a804a..e130379 100644 --- a/src/channels.rs +++ b/src/channels.rs @@ -25,6 +25,7 @@ impl Channel { pub async fn names_list_send( &self, user: User, + channel: &Channel, writer: &mut BufWriter, hostname: &str, ) -> Result<(), SenderError> { @@ -34,6 +35,13 @@ impl Channel { members.push(member.nickname.unwrap()); } + for member in channel.joined_users.clone() { + members.push(member.nickname.unwrap()); + } + + members.sort(); + members.dedup(); + IrcResponseCodes::NameReply .into_irc_response( user.nickname.clone().unwrap(), diff --git a/src/commands/cap.rs b/src/commands/cap.rs index ec23c4f..b13135a 100644 --- a/src/commands/cap.rs +++ b/src/commands/cap.rs @@ -1,9 +1,7 @@ use async_trait::async_trait; -use tokio::sync::broadcast::Sender; use crate::{ commands::{IrcAction, IrcHandler}, - messages::Message, user::User, }; @@ -16,7 +14,6 @@ impl IrcHandler for Cap { _arguments: Vec, _authenticated: bool, _user_state: &mut User, - _sender: Sender, ) -> super::IrcAction { IrcAction::DoNothing } diff --git a/src/commands/join.rs b/src/commands/join.rs index 67c6321..1dc9775 100644 --- a/src/commands/join.rs +++ b/src/commands/join.rs @@ -1,11 +1,9 @@ use async_trait::async_trait; -use tokio::sync::broadcast::Sender; use crate::{ JOINED_CHANNELS, channels::Channel, commands::{IrcAction, IrcHandler}, - messages::{JoinMessage, Message}, user::User, }; @@ -18,7 +16,6 @@ impl IrcHandler for Join { arguments: Vec, authenticated: bool, user_state: &mut User, - sender: Sender, ) -> super::IrcAction { let mut joined_channels = JOINED_CHANNELS.lock().await; let mut channels = Vec::new(); @@ -56,14 +53,6 @@ impl IrcHandler for Join { } } - for channel in channels.clone() { - let join_message = JoinMessage { - sender: user_state.clone().unwrap_all(), - channel: channel.clone(), - }; - sender.send(Message::JoinMessage(join_message)).unwrap(); - } - IrcAction::JoinChannels(channels) } } diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 9caa9f7..c51db82 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -11,7 +11,7 @@ use crate::{ cap::Cap, join::Join, nick::Nick, ping::Ping, privmsg::PrivMsg, user::User as UserHandler, }, error_structs::CommandExecError, - messages::Message, + messages::{JoinMessage, Message}, sender::IrcResponse, user::User, }; @@ -36,6 +36,7 @@ pub struct IrcMessage { pub enum IrcAction { SendText(IrcResponse), + SendMessage(Message), JoinChannels(Vec), ErrorAuthenticateFirst, DoNothing, @@ -50,7 +51,6 @@ pub trait IrcHandler: Send + Sync { command: Vec, authenticated: bool, user_state: &mut User, - sender: Sender, ) -> IrcAction; } @@ -118,10 +118,11 @@ impl IrcCommand { self.arguments.clone(), user_state.is_populated(), user_state, - broadcast_sender, ) .await; - action.execute(writer, hostname, &user_state).await; + action + .execute(writer, hostname, &user_state, broadcast_sender) + .await; Ok(()) } @@ -133,6 +134,7 @@ impl IrcAction { writer: &mut BufWriter, hostname: &str, user_state: &User, + sender: Sender, ) { match self { IrcAction::SendText(msg) => { @@ -141,18 +143,18 @@ impl IrcAction { IrcAction::JoinChannels(channels) => { for channel in channels { - channel - .send_topic(user_state.clone(), writer, hostname) - .await - .unwrap(); - - channel - .names_list_send(user_state.clone(), writer, hostname) - .await - .unwrap(); + let join_message = JoinMessage { + sender: user_state.clone().unwrap_all(), + channel: channel.clone(), + }; + sender.send(Message::JoinMessage(join_message)).unwrap(); } } + IrcAction::SendMessage(msg) => { + sender.send(msg.clone()).unwrap(); + } + _ => {} } } diff --git a/src/commands/nick.rs b/src/commands/nick.rs index abf0774..aea53f2 100644 --- a/src/commands/nick.rs +++ b/src/commands/nick.rs @@ -1,9 +1,7 @@ use async_trait::async_trait; -use tokio::sync::broadcast::Sender; use crate::{ commands::{IrcAction, IrcHandler}, - messages::Message, user::User, }; @@ -16,7 +14,6 @@ impl IrcHandler for Nick { command: Vec, _authenticated: bool, user_state: &mut User, - _sender: Sender, ) -> IrcAction { user_state.nickname = Some(command[0].clone()); diff --git a/src/commands/ping.rs b/src/commands/ping.rs index 2eea4fb..dee180d 100644 --- a/src/commands/ping.rs +++ b/src/commands/ping.rs @@ -1,9 +1,7 @@ use async_trait::async_trait; -use tokio::sync::broadcast::Sender; use crate::{ commands::{IrcAction, IrcHandler}, - messages::Message, sender::IrcResponse, user::User, }; @@ -17,7 +15,6 @@ impl IrcHandler for Ping { command: Vec, authenticated: bool, user_state: &mut User, - _sender: Sender, ) -> IrcAction { if authenticated { IrcAction::SendText(IrcResponse { diff --git a/src/commands/privmsg.rs b/src/commands/privmsg.rs index 88eff31..6088734 100644 --- a/src/commands/privmsg.rs +++ b/src/commands/privmsg.rs @@ -1,5 +1,4 @@ use async_trait::async_trait; -use tokio::sync::broadcast::Sender; use crate::{ CONNECTED_USERS, @@ -17,7 +16,6 @@ impl IrcHandler for PrivMsg { command: Vec, authenticated: bool, user_state: &mut User, - sender: Sender, ) -> IrcAction { if !authenticated { return IrcAction::ErrorAuthenticateFirst; @@ -32,9 +30,7 @@ impl IrcHandler for PrivMsg { receiver: command[0].clone(), text: command[1].clone(), }; - println!("SENDING: {message:#?}"); - sender.send(Message::PrivMessage(message)).unwrap(); - IrcAction::DoNothing + IrcAction::SendMessage(Message::PrivMessage(message)) } } diff --git a/src/commands/user.rs b/src/commands/user.rs index 807e5ba..91b6a45 100644 --- a/src/commands/user.rs +++ b/src/commands/user.rs @@ -1,9 +1,7 @@ use async_trait::async_trait; -use tokio::sync::broadcast::Sender; use crate::{ commands::{IrcAction, IrcHandler}, - messages::Message, user::User as UserState, }; @@ -16,7 +14,6 @@ impl IrcHandler for User { command: Vec, _authenticated: bool, user_state: &mut UserState, - _sender: Sender, ) -> IrcAction { if command.len() < 4 { return IrcAction::DoNothing; // XXX: return an error diff --git a/src/main.rs b/src/main.rs index 4aed1ae..64879df 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ use std::{ collections::HashSet, net::{SocketAddr, TcpListener, TcpStream}, str::FromStr, + time::Duration, }; use anyhow::Error as AnyhowError; @@ -14,6 +15,7 @@ use tokio::{ Mutex, broadcast::{self, Receiver, Sender}, }, + time::sleep, }; use tracing::instrument; @@ -96,6 +98,8 @@ async fn handle_connection( let mut tcp_writer = TokioBufWriter::new(TokioTcpStream::from_std(stream)?); let mut state = User::default(); + let hostname = info.server_hostname.clone(); + loop { tokio::select! { result = tcp_listener(&stream_tcp, state.clone(), &info, &mut tcp_reader) => { @@ -109,7 +113,7 @@ async fn handle_connection( } } }, - result = message_listener(&state, &mut message_receiver, &mut tcp_writer) => { + result = message_listener(&state, &mut message_receiver, &mut tcp_writer, &hostname) => { match result { Ok(_) => {}, Err(err) => { @@ -189,8 +193,11 @@ async fn message_listener( user_wrapped: &User, receiver: &mut Receiver, writer: &mut TokioBufWriter, + hostname: &str, ) -> Result<(), ListenerError> { if !user_wrapped.is_populated() { + sleep(Duration::from_millis(250)).await; // avoid immediately returns b'cuz they result in high + // cpu usage return Err(ListenerError::UserIsUnidentified); } @@ -237,6 +244,8 @@ async fn message_listener( Message::JoinMessage(message) => { if message.channel.joined_users.contains(user_wrapped) || message.sender == user { + let channel = message.channel.clone(); + IrcResponse { sender: Some(message.sender.hostmask().clone()), command: "JOIN".into(), @@ -246,6 +255,16 @@ async fn message_listener( } .send("", writer, true) .await?; + + channel + .send_topic(user_wrapped.clone(), writer, hostname) + .await + .unwrap(); + + channel + .names_list_send(user_wrapped.clone(), &channel, writer, hostname) + .await + .unwrap(); } } }