🏡 index : ~doyle/titanirc.git

author Jordan Doyle <jordan@doyle.la> 2023-01-08 0:00:11.0 +00:00:00
committer Jordan Doyle <jordan@doyle.la> 2023-01-08 0:08:32.0 +00:00:00
commit
bdd2421072bf3334f1bc05c03f1c5ec1ceac46f6 [patch]
tree
1c8e3054c9b8e1c40ee2255afddc834799044057
parent
62b2142b866d4501827c00ddedd8015f6c237896
download
bdd2421072bf3334f1bc05c03f1c5ec1ceac46f6.tar.gz

Implement SANICK command



Diff

 src/client.rs   | 58 +++++++++++++++++++++++++++++++++++++++-------------------
 src/messages.rs |  9 +++++++++-
 src/server.rs   | 20 +++++++++++++++++++-
 3 files changed, 67 insertions(+), 20 deletions(-)

diff --git a/src/client.rs b/src/client.rs
index 7fc1927..722718b 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -17,6 +17,7 @@ use crate::{
        Broadcast, ChannelFetchTopic, ChannelInvite, ChannelJoin, ChannelKickUser, ChannelList,
        ChannelMemberList, ChannelMessage, ChannelPart, ChannelUpdateTopic, FetchClientDetails,
        ServerDisconnect, ServerFetchMotd, UserKickedFromChannel, UserNickChange,
        UserNickChangeInternal,
    },
    server::Server,
    SERVER_NAME,
@@ -221,6 +222,34 @@ impl Handler<ListChannelMemberRequest> for Client {
    }
}

impl Handler<UserNickChangeInternal> for Client {
    type Result = ();

    #[instrument(parent = &msg.span, skip_all)]
    fn handle(&mut self, msg: UserNickChangeInternal, ctx: &mut Self::Context) -> Self::Result {
        // alert the server to the nick change (we'll receive this event back so the user
        // gets the notification too)
        self.server.do_send(UserNickChange {
            client: ctx.address(),
            connection: self.connection.clone(),
            new_nick: msg.new_nick.clone(),
            span: Span::current(),
        });

        for channel in self.channels.values() {
            channel.do_send(UserNickChange {
                client: ctx.address(),
                connection: self.connection.clone(),
                new_nick: msg.new_nick.clone(),
                span: Span::current(),
            });
        }

        // updates our nick locally
        self.connection.nick = msg.new_nick;
    }
}

/// A message received from the root server to indicate that another known user has changed their
/// nick
impl Handler<UserNickChange> for Client {
@@ -280,26 +309,11 @@ impl StreamHandler<Result<irc_proto::Message, ProtocolError>> for Client {
                // these were already handled by `negotiate_client_connection`
            }
            Command::NICK(new_nick) => {
                // alert the server to the nick change (we'll receive this event back so the user
                // gets the notification too)
                self.server.do_send(UserNickChange {
                    client: ctx.address(),
                    connection: self.connection.clone(),
                    new_nick: new_nick.clone(),
                ctx.notify(UserNickChangeInternal {
                    old_nick: self.connection.nick.to_string(),
                    new_nick,
                    span: Span::current(),
                });

                for channel in self.channels.values() {
                    channel.do_send(UserNickChange {
                        client: ctx.address(),
                        connection: self.connection.clone(),
                        new_nick: new_nick.clone(),
                        span: Span::current(),
                    });
                }

                // updates our nick locally
                self.connection.nick = new_nick;
            }
            Command::OPER(_, _) => {}
            Command::UserMODE(_, _) => {}
@@ -499,7 +513,13 @@ impl StreamHandler<Result<irc_proto::Message, ProtocolError>> for Client {
            Command::ISON(_) => {}
            Command::SAJOIN(_, _) => {}
            Command::SAMODE(_, _, _) => {}
            Command::SANICK(_, _) => {}
            Command::SANICK(old_nick, new_nick) => {
                self.server.do_send(UserNickChangeInternal {
                    old_nick,
                    new_nick,
                    span: Span::current(),
                });
            }
            Command::SAPART(_, _) => {}
            Command::SAQUIT(_, _) => {}
            Command::NICKSERV(_) => {}
diff --git a/src/messages.rs b/src/messages.rs
index 94344cc..4b54dba 100644
--- a/src/messages.rs
+++ b/src/messages.rs
@@ -23,6 +23,15 @@ pub struct ServerDisconnect {
    pub span: Span,
}

/// Internal event to update a user's nick.
#[derive(Message, Clone)]
#[rtype(result = "()")]
pub struct UserNickChangeInternal {
    pub old_nick: String,
    pub new_nick: String,
    pub span: Span,
}

/// Sent when the user changes their nick.
#[derive(Message, Clone)]
#[rtype(result = "()")]
diff --git a/src/server.rs b/src/server.rs
index 8346421..5fa8adc 100644
--- a/src/server.rs
+++ b/src/server.rs
@@ -6,7 +6,7 @@ use actix::{Actor, Addr, AsyncContext, Context, Handler, MessageResult, Response
use futures::{stream::FuturesOrdered, TryFutureExt};
use irc_proto::{Command, Message, Prefix, Response};
use tokio_stream::StreamExt;
use tracing::{instrument, Span};
use tracing::{debug, instrument, warn, Span};

use crate::{
    channel::Channel,
@@ -16,6 +16,7 @@ use crate::{
    messages::{
        Broadcast, ChannelFetchTopic, ChannelJoin, ChannelList, ChannelMemberList,
        FetchClientByNick, ServerDisconnect, ServerFetchMotd, UserConnected, UserNickChange,
        UserNickChangeInternal,
    },
    server::response::Motd,
    SERVER_NAME,
@@ -28,6 +29,23 @@ pub struct Server {
    pub config: Config,
}

/// Received when an admin SANICKs another user.
impl Handler<UserNickChangeInternal> for Server {
    type Result = ();

    fn handle(&mut self, msg: UserNickChangeInternal, _ctx: &mut Self::Context) -> Self::Result {
        let client = self.clients.iter().find(|(_k, v)| v.nick == msg.old_nick);
        let Some((client, _)) = client else {
            warn!(%msg.old_nick, %msg.new_nick, "User attempted to update nick for unknown user");
            return;
        };

        debug!(%msg.old_nick, %msg.new_nick, "User is updating nick for another user");

        client.do_send(msg);
    }
}

/// Received when a user connects to the server, and sends them the server preamble
impl Handler<UserConnected> for Server {
    type Result = ();