🏡 index : ~doyle/titanirc.git

author Jordan Doyle <jordan@doyle.la> 2024-01-30 20:27:34.0 +00:00:00
committer Jordan Doyle <jordan@doyle.la> 2024-01-30 20:27:34.0 +00:00:00
commit
85756a6a8fd501482cde14bc263d338a05b16dd1 [patch]
tree
772f8387158f93caaec65da2274ba6d7a4a83a6c
parent
192341583d34dec0ba3c9999eea22a93947ce052
download
85756a6a8fd501482cde14bc263d338a05b16dd1.tar.gz

Implement SAQUIT



Diff

 src/client.rs          | 42 +++++++++++++++++++++++++++++++++++-------
 src/messages.rs        |  8 ++++++++
 src/server.rs          | 20 +++++++++++++++++---
 src/server/response.rs | 18 ++++++++++++++++++
 4 files changed, 78 insertions(+), 10 deletions(-)

diff --git a/src/client.rs b/src/client.rs
index 9de2125..7afc711 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -24,9 +24,9 @@ use crate::{
        Broadcast, ChannelFetchTopic, ChannelFetchWhoList, ChannelInvite, ChannelJoin,
        ChannelKickUser, ChannelList, ChannelMemberList, ChannelMessage, ChannelPart,
        ChannelSetMode, ChannelUpdateTopic, ClientAway, ConnectedChannels, FetchClientDetails,
        FetchUserPermission, FetchWhoList, FetchWhois, KillUser, MessageKind, PrivateMessage,
        ServerAdminInfo, ServerDisconnect, ServerFetchMotd, ServerListUsers, UserKickedFromChannel,
        UserNickChange, UserNickChangeInternal, Wallops,
        FetchUserPermission, FetchWhoList, FetchWhois, ForceDisconnect, KillUser, MessageKind,
        PrivateMessage, ServerAdminInfo, ServerDisconnect, ServerFetchMotd, ServerListUsers,
        UserKickedFromChannel, UserNickChange, UserNickChangeInternal, Wallops,
    },
    persistence::{
        events::{
@@ -35,7 +35,10 @@ use crate::{
        },
        Persistence,
    },
    server::{response::WhoList, Server},
    server::{
        response::{NoSuchNick, WhoList},
        Server,
    },
    SERVER_NAME,
};

@@ -296,6 +299,15 @@ impl Handler<ConnectedChannels> for Client {
    }
}

impl Handler<ForceDisconnect> for Client {
    type Result = MessageResult<ForceDisconnect>;

    fn handle(&mut self, _msg: ForceDisconnect, ctx: &mut Self::Context) -> Self::Result {
        ctx.stop();
        MessageResult(true)
    }
}

/// Retrieves the entire WHO list for the user.
impl Handler<FetchWhoList> for Client {
    type Result = ResponseFuture<<FetchWhoList as actix::Message>::Result>;
@@ -380,7 +392,7 @@ impl Handler<SetAway> for Client {
impl Handler<KillUser> for Client {
    type Result = ();

    #[instrument(parent = & msg.span, skip_all)]
    #[instrument(parent = &msg.span, skip_all)]
    fn handle(&mut self, msg: KillUser, ctx: &mut Self::Context) -> Self::Result {
        self.server_leave_reason = Some(format!("Killed ({} ({}))", msg.killer, msg.comment));
        ctx.stop();
@@ -900,7 +912,6 @@ impl StreamHandler<Result<irc_proto::Message, ProtocolError>> for Client {
            Command::REHASH => {}
            Command::DIE => {}
            Command::RESTART => {}
            Command::USERS(_) => {}
            Command::WALLOPS(message) if self.connection.mode.contains(UserMode::OPER) => {
                self.server.do_send(Wallops {
                    span: Span::current(),
@@ -919,7 +930,24 @@ impl StreamHandler<Result<irc_proto::Message, ProtocolError>> for Client {
                });
            }
            Command::SAPART(_, _) => {}
            Command::SAQUIT(_, _) => {}
            Command::SAQUIT(user, comment) if self.connection.mode.contains(UserMode::OPER) => {
                let span = Span::current();
                self.server_send_map_write(
                    ctx,
                    ForceDisconnect {
                        span,
                        user: user.to_string(),
                        comment,
                    },
                    move |res, this| {
                        if res {
                            vec![]
                        } else {
                            NoSuchNick { nick: user }.into_messages(&this.connection.nick)
                        }
                    },
                );
            }
            Command::AUTHENTICATE(_) => {
                self.writer.write(
                    SaslAlreadyAuthenticated(self.connection.nick.to_string()).into_message(),
diff --git a/src/messages.rs b/src/messages.rs
index 8265e2e..ab1aec6 100644
--- a/src/messages.rs
+++ b/src/messages.rs
@@ -37,6 +37,14 @@ pub struct KillUser {
    pub killed: String,
}

#[derive(Message, Clone)]
#[rtype(result = "bool")]
pub struct ForceDisconnect {
    pub span: Span,
    pub user: String,
    pub comment: String,
}

/// Internal event to update a user's nick.
#[derive(Message, Clone)]
#[rtype(result = "()")]
diff --git a/src/server.rs b/src/server.rs
index 7b78b19..c3c386d 100644
--- a/src/server.rs
+++ b/src/server.rs
@@ -26,9 +26,9 @@ use crate::{
    messages::{
        Broadcast, ChannelFetchTopic, ChannelFetchWhoList, ChannelJoin, ChannelList,
        ChannelMemberList, ClientAway, ConnectedChannels, FetchClientByNick, FetchWhoList,
        FetchWhois, KillUser, MessageKind, PrivateMessage, ServerAdminInfo, ServerDisconnect,
        ServerFetchMotd, ServerListUsers, UserConnected, UserNickChange, UserNickChangeInternal,
        Wallops,
        FetchWhois, ForceDisconnect, KillUser, MessageKind, PrivateMessage, ServerAdminInfo,
        ServerDisconnect, ServerFetchMotd, ServerListUsers, UserConnected, UserNickChange,
        UserNickChangeInternal, Wallops,
    },
    persistence::Persistence,
    server::response::{AdminInfo, ListUsers, Motd, WhoList, Whois},
@@ -306,6 +306,20 @@ impl Handler<FetchWhois> for Server {
    }
}

impl Handler<ForceDisconnect> for Server {
    type Result = MessageResult<ForceDisconnect>;

    #[instrument(parent = &msg.span, skip_all)]
    fn handle(&mut self, msg: ForceDisconnect, _ctx: &mut Self::Context) -> Self::Result {
        if let Some((handle, _)) = self.clients.iter().find(|(_, v)| v.nick == msg.user) {
            handle.do_send(msg);
            MessageResult(true)
        } else {
            MessageResult(false)
        }
    }
}

impl Handler<FetchWhoList> for Server {
    type Result = ResponseFuture<<FetchWhoList as actix::Message>::Result>;

diff --git a/src/server/response.rs b/src/server/response.rs
index 94c5fec..3f75c04 100644
--- a/src/server/response.rs
+++ b/src/server/response.rs
@@ -84,6 +84,24 @@ impl Whois {
    }
}

pub struct NoSuchNick {
    pub nick: String,
}

impl NoSuchNick {
    #[must_use]
    pub fn into_messages(self, for_user: &str) -> Vec<Message> {
        vec![Message {
            tags: None,
            prefix: Some(Prefix::ServerName(SERVER_NAME.to_string())),
            command: Command::Response(
                Response::ERR_NOSUCHNICK,
                vec![for_user.to_string(), self.nick, "No such nick".to_string()],
            ),
        }]
    }
}

#[derive(Default)]
pub struct WhoList {
    pub list: Vec<crate::channel::response::ChannelWhoList>,