From 253e47b477e83cc65e9d151602d695368a2d217f Mon Sep 17 00:00:00 2001 From: Jordan Doyle Date: Mon, 29 Jan 2024 03:03:03 +0000 Subject: [PATCH] Implement AWAY --- src/channel.rs | 23 +++++++++++++++++++++-- src/client.rs | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- src/messages.rs | 9 +++++++++ src/server.rs | 16 +++++++++++++--- 4 files changed, 102 insertions(+), 7 deletions(-) diff --git a/src/channel.rs b/src/channel.rs index b7da4cb..377443c 100644 --- a/src/channel.rs +++ b/src/channel.rs @@ -25,8 +25,8 @@ use crate::{ messages::{ Broadcast, ChannelFetchTopic, ChannelFetchWhoList, ChannelInvite, ChannelJoin, ChannelKickUser, ChannelMemberList, ChannelMessage, ChannelPart, ChannelSetMode, - ChannelUpdateTopic, FetchClientByNick, FetchUserPermission, MessageKind, ServerDisconnect, - UserKickedFromChannel, UserNickChange, + ChannelUpdateTopic, ClientAway, FetchClientByNick, FetchUserPermission, MessageKind, + ServerDisconnect, UserKickedFromChannel, UserNickChange, }, persistence::{ events::{FetchAllUserChannelPermissions, SetUserChannelPermissions}, @@ -115,6 +115,25 @@ impl Handler for Channel { } } +impl Handler for Channel { + type Result = (); + + #[instrument(parent = &msg.span, skip_all)] + fn handle(&mut self, msg: ClientAway, ctx: &mut Self::Context) -> Self::Result { + if let Some(c) = self.clients.get_mut(&msg.handle) { + c.away = msg.message; + ctx.notify(Broadcast { + message: Message { + tags: None, + prefix: Some(c.to_nick()), + command: Command::AWAY(c.away.clone()), + }, + span: msg.span, + }); + } + } +} + /// Fetches the user's permission for the current channel. impl Handler for Channel { type Result = MessageResult; diff --git a/src/client.rs b/src/client.rs index 8eaecc0..f6163b6 100644 --- a/src/client.rs +++ b/src/client.rs @@ -23,7 +23,7 @@ use crate::{ messages::{ Broadcast, ChannelFetchTopic, ChannelFetchWhoList, ChannelInvite, ChannelJoin, ChannelKickUser, ChannelList, ChannelMemberList, ChannelMessage, ChannelPart, - ChannelSetMode, ChannelUpdateTopic, ConnectedChannels, FetchClientDetails, + ChannelSetMode, ChannelUpdateTopic, ClientAway, ConnectedChannels, FetchClientDetails, FetchUserPermission, FetchWhoList, FetchWhois, MessageKind, PrivateMessage, ServerAdminInfo, ServerDisconnect, ServerFetchMotd, ServerListUsers, UserKickedFromChannel, UserNickChange, UserNickChangeInternal, @@ -283,6 +283,50 @@ impl Handler for Client { } } +impl Handler for Client { + type Result = (); + + #[instrument(parent = &msg.span, skip_all)] + fn handle(&mut self, msg: SetAway, ctx: &mut Self::Context) -> Self::Result { + self.connection.away = msg.msg.filter(|msg| !msg.is_empty()); + + let broadcast = ClientAway { + span: msg.span, + handle: ctx.address(), + message: self.connection.away.clone(), + }; + + self.server.do_send(broadcast.clone()); + for channel in self.channels.values() { + channel.do_send(broadcast.clone()); + } + + let resp = if self.connection.away.is_some() { + Command::Response( + Response::RPL_NOWAWAY, + vec![ + self.connection.nick.to_string(), + "You have been marked as being away".to_string(), + ], + ) + } else { + Command::Response( + Response::RPL_UNAWAY, + vec![ + self.connection.nick.to_string(), + "You are no longer marked as being away".to_string(), + ], + ) + }; + + self.writer.write(Message { + tags: None, + prefix: None, + command: resp, + }); + } +} + /// A self-message from the Client's [`StreamHandler`] implementation when the user /// sends a join command out. /// @@ -838,7 +882,12 @@ impl StreamHandler> for Client { Command::PONG(_, _) => { self.last_active = Instant::now(); } - Command::AWAY(_) => {} + Command::AWAY(msg) => { + ctx.notify(SetAway { + span: Span::current(), + msg, + }); + } Command::REHASH => {} Command::DIE => {} Command::RESTART => {} @@ -957,3 +1006,11 @@ struct JoinChannelRequest { channels: Vec, span: Span, } + +/// A [`Client`] internal self-notification to set away status +#[derive(actix::Message, Debug)] +#[rtype(result = "()")] +struct SetAway { + msg: Option, + span: Span, +} diff --git a/src/messages.rs b/src/messages.rs index 89b573f..33d7158 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -54,6 +54,15 @@ pub struct ConnectedChannels { pub span: Span, } +/// Marks the client as being away (or not away, if `message` is none) +#[derive(Message, Clone)] +#[rtype(result = "()")] +pub struct ClientAway { + pub span: Span, + pub handle: Addr, + pub message: Option, +} + /// Fetches all the channels visible to the user. #[derive(Message, Clone)] #[rtype(result = "super::server::response::ChannelList")] diff --git a/src/server.rs b/src/server.rs index 3aa2cbb..7eaf60f 100644 --- a/src/server.rs +++ b/src/server.rs @@ -25,9 +25,9 @@ use crate::{ connection::InitiatedConnection, messages::{ Broadcast, ChannelFetchTopic, ChannelFetchWhoList, ChannelJoin, ChannelList, - ChannelMemberList, ConnectedChannels, FetchClientByNick, FetchWhoList, FetchWhois, - MessageKind, PrivateMessage, ServerAdminInfo, ServerDisconnect, ServerFetchMotd, - ServerListUsers, UserConnected, UserNickChange, UserNickChangeInternal, + ChannelMemberList, ClientAway, ConnectedChannels, FetchClientByNick, FetchWhoList, + FetchWhois, MessageKind, PrivateMessage, ServerAdminInfo, ServerDisconnect, + ServerFetchMotd, ServerListUsers, UserConnected, UserNickChange, UserNickChangeInternal, }, persistence::Persistence, server::response::{AdminInfo, ListUsers, Motd, WhoList, Whois}, @@ -215,6 +215,16 @@ impl Handler for Server { } } +impl Handler for Server { + type Result = (); + + fn handle(&mut self, msg: ClientAway, _ctx: &mut Self::Context) -> Self::Result { + if let Some(c) = self.clients.get_mut(&msg.handle) { + c.away = msg.message; + } + } +} + /// Fetches a client's handle by their nick impl Handler for Server { type Result = MessageResult; -- libgit2 1.7.2