From b7a472e34e89ec2bf0a128e30fba86c2fff16ca4 Mon Sep 17 00:00:00 2001 From: Jordan Doyle Date: Wed, 11 Jan 2023 00:22:31 +0000 Subject: [PATCH] Implement peer-to-peer messaging --- src/channel.rs | 1 + src/client.rs | 12 +++++++++--- src/messages.rs | 10 ++++++++++ src/server.rs | 36 ++++++++++++++++++++++++++++++++++-- 4 files changed, 54 insertions(+), 5 deletions(-) diff --git a/src/channel.rs b/src/channel.rs index 25e08d4..d77662f 100644 --- a/src/channel.rs +++ b/src/channel.rs @@ -116,6 +116,7 @@ impl Handler for Channel { // build the nick prefix for the message we're about to broadcast let nick = sender.to_nick(); + // TODO: implement client msg recv acks self.persistence .do_send(crate::persistence::events::ChannelMessage { channel_id: self.channel_id, diff --git a/src/client.rs b/src/client.rs index f96afd1..5dcb23b 100644 --- a/src/client.rs +++ b/src/client.rs @@ -16,8 +16,8 @@ use crate::{ messages::{ Broadcast, ChannelFetchTopic, ChannelInvite, ChannelJoin, ChannelKickUser, ChannelList, ChannelMemberList, ChannelMessage, ChannelPart, ChannelSetMode, ChannelUpdateTopic, - FetchClientDetails, ServerDisconnect, ServerFetchMotd, UserKickedFromChannel, - UserNickChange, UserNickChangeInternal, + FetchClientDetails, PeerToPeerMessage, ServerDisconnect, ServerFetchMotd, + UserKickedFromChannel, UserNickChange, UserNickChangeInternal, }, persistence::{ events::{FetchUnseenMessages, FetchUserChannels, ReserveNick}, @@ -511,7 +511,12 @@ impl StreamHandler> for Client { Command::PRIVMSG(target, message) => { if !target.is_channel_name() { // private message to another user - error!("Private messages not implemented"); + self.server.do_send(PeerToPeerMessage { + destination: target, + message, + from: ctx.address(), + span: Span::current(), + }); } else if let Some(channel) = self.channels.get(&target) { channel.do_send(ChannelMessage { client: ctx.address(), @@ -586,6 +591,7 @@ impl StreamHandler> for Client { Command::SAJOIN(_, _) => {} Command::SAMODE(_, _, _) => {} Command::SANICK(old_nick, new_nick) => { + // TODO: permission checks self.server.do_send(UserNickChangeInternal { old_nick, new_nick, diff --git a/src/messages.rs b/src/messages.rs index f261b95..68dfbdf 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -168,3 +168,13 @@ pub struct ChannelInvite { pub struct FetchClientByNick { pub nick: String, } + +/// Sends a private message between two users. +#[derive(Message)] +#[rtype(result = "()")] +pub struct PeerToPeerMessage { + pub destination: String, + pub message: String, + pub from: Addr, + pub span: Span, +} diff --git a/src/server.rs b/src/server.rs index ac57ed1..548e56a 100644 --- a/src/server.rs +++ b/src/server.rs @@ -21,8 +21,8 @@ use crate::{ connection::InitiatedConnection, messages::{ Broadcast, ChannelFetchTopic, ChannelJoin, ChannelList, ChannelMemberList, - FetchClientByNick, ServerDisconnect, ServerFetchMotd, UserConnected, UserNickChange, - UserNickChangeInternal, + FetchClientByNick, PeerToPeerMessage, ServerDisconnect, ServerFetchMotd, UserConnected, + UserNickChange, UserNickChangeInternal, }, persistence::Persistence, server::response::Motd, @@ -253,6 +253,38 @@ impl Handler for Server { } } +// TODO: implement offline messaging and replay +impl Handler for Server { + type Result = (); + + #[instrument(parent = &msg.span, skip_all)] + fn handle(&mut self, msg: PeerToPeerMessage, _ctx: &mut Self::Context) -> Self::Result { + let Some(source) = self.clients.get(&msg.from) else { + // user is not yet registered with the server + return; + }; + + // TODO: O(1) lookup of users by nick + let target = self + .clients + .iter() + .find(|(_handle, connection)| connection.nick == msg.destination); + let Some((target, _)) = target else { + // return error to caller that user does not exist + return; + }; + + target.do_send(Broadcast { + message: Message { + tags: None, + prefix: Some(source.to_nick()), + command: Command::PRIVMSG(msg.destination, msg.message), + }, + span: msg.span, + }); + } +} + impl Actor for Server { type Context = Context; } -- libgit2 1.7.2