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 +++ a/src/channel.rs @@ -25,8 +25,8 @@ 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}, @@ -111,6 +111,25 @@ fn handle(&mut self, msg: Broadcast, _ctx: &mut Self::Context) -> Self::Result { for client in self.clients.keys() { client.do_send(msg.clone()); + } + } +} + +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, + }); } } } diff --git a/src/client.rs b/src/client.rs index 8eaecc0..f6163b6 100644 --- a/src/client.rs +++ a/src/client.rs @@ -23,7 +23,7 @@ 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 { + 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. /// @@ -837,8 +881,13 @@ } Command::PONG(_, _) => { self.last_active = Instant::now(); + } + Command::AWAY(msg) => { + ctx.notify(SetAway { + span: Span::current(), + msg, + }); } - Command::AWAY(_) => {} Command::REHASH => {} Command::DIE => {} Command::RESTART => {} @@ -955,5 +1004,13 @@ #[rtype(result = "()")] 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 +++ a/src/messages.rs @@ -54,6 +54,15 @@ 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 +++ a/src/server.rs @@ -25,9 +25,9 @@ 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}, @@ -211,6 +211,16 @@ if let Some(client) = self.clients.get_mut(&msg.client) { *client = msg.connection; client.nick = msg.new_nick; + } + } +} + +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; } } } -- rgit 0.1.5