forked from lavina/lavina
irc: move CHATHISTORY message handling into a separate module
This commit is contained in:
parent
a22cde0ea8
commit
25fe041698
|
@ -3,15 +3,15 @@ use std::future::Future;
|
|||
use anyhow::Result;
|
||||
use tokio::io::AsyncWrite;
|
||||
|
||||
use crate::RegisteredUser;
|
||||
use lavina_core::player::PlayerConnection;
|
||||
use lavina_core::prelude::Str;
|
||||
|
||||
pub struct IrcConnection<'a, T: AsyncWrite + Unpin> {
|
||||
pub server_name: Str,
|
||||
/// client is nick of requester
|
||||
pub client: Str,
|
||||
pub writer: &'a mut T,
|
||||
pub player_connection: &'a mut PlayerConnection,
|
||||
pub user: &'a RegisteredUser,
|
||||
}
|
||||
|
||||
/// Represents a client-to-server IRC message that can be handled by the server.
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
use anyhow::Result;
|
||||
use chrono::SecondsFormat;
|
||||
use tokio::io::{AsyncWrite, AsyncWriteExt};
|
||||
|
||||
use crate::cap::Capabilities;
|
||||
use crate::handler::{IrcCommand, IrcConnection};
|
||||
use lavina_core::player::RoomHistoryResult;
|
||||
use lavina_core::room::RoomId;
|
||||
use proto_irc::client::ChatHistory;
|
||||
use proto_irc::server::{ServerMessage, ServerMessageBody};
|
||||
use proto_irc::{Chan, Recipient, Tag};
|
||||
|
||||
impl IrcCommand for ChatHistory {
|
||||
async fn handle_with(&self, conn: &mut IrcConnection<'_, impl AsyncWrite + Unpin>) -> Result<()> {
|
||||
if !conn.user.enabled_capabilities.contains(Capabilities::ChatHistory) {
|
||||
tracing::debug!(
|
||||
"Requested chat history for user {:?} even though the capability was not negotiated",
|
||||
conn.user.nickname
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
let channel_name = match self.chan.clone() {
|
||||
Chan::Global(chan) => chan,
|
||||
// TODO Respond with an error when a local channel is requested
|
||||
Chan::Local(chan) => chan,
|
||||
};
|
||||
let room_id = &RoomId::try_from(channel_name.clone())?;
|
||||
let res = conn.player_connection.get_room_message_history(room_id, self.limit).await?;
|
||||
match res {
|
||||
RoomHistoryResult::Success(messages) => {
|
||||
for message in messages {
|
||||
let mut tags = vec![];
|
||||
if conn.user.enabled_capabilities.contains(Capabilities::ServerTime) {
|
||||
let tag = Tag {
|
||||
key: "time".into(),
|
||||
value: Some(message.created_at.to_rfc3339_opts(SecondsFormat::Millis, true).into()),
|
||||
};
|
||||
tags.push(tag);
|
||||
}
|
||||
ServerMessage {
|
||||
tags,
|
||||
sender: Some(message.author_name.into()),
|
||||
body: ServerMessageBody::PrivateMessage {
|
||||
target: Recipient::Chan(self.chan.clone()),
|
||||
body: message.content.into(),
|
||||
},
|
||||
}
|
||||
.write_async(conn.writer)
|
||||
.await?;
|
||||
}
|
||||
conn.writer.flush().await?;
|
||||
}
|
||||
RoomHistoryResult::NoSuchRoom => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -14,6 +14,8 @@ use tokio::net::tcp::{ReadHalf, WriteHalf};
|
|||
use tokio::net::{TcpListener, TcpStream};
|
||||
use tokio::sync::mpsc::channel;
|
||||
|
||||
use crate::cap::Capabilities;
|
||||
use crate::handler::{IrcCommand, IrcConnection};
|
||||
use lavina_core::auth::Verdict;
|
||||
use lavina_core::player::*;
|
||||
use lavina_core::prelude::*;
|
||||
|
@ -29,14 +31,9 @@ use proto_irc::{Chan, Recipient, Tag};
|
|||
use sasl::AuthBody;
|
||||
|
||||
mod cap;
|
||||
|
||||
use handler::{IrcCommand, IrcConnection};
|
||||
|
||||
mod whois;
|
||||
|
||||
use crate::cap::Capabilities;
|
||||
|
||||
mod handler;
|
||||
mod history;
|
||||
mod whois;
|
||||
|
||||
pub const APP_VERSION: &str = concat!("lavina", "_", env!("CARGO_PKG_VERSION"));
|
||||
|
||||
|
@ -829,9 +826,9 @@ async fn handle_incoming_message(
|
|||
ClientMessage::Whois(cmd) => {
|
||||
let mut conn = IrcConnection {
|
||||
server_name: config.server_name.clone(),
|
||||
client: user.nickname.clone(),
|
||||
writer,
|
||||
player_connection: user_handle,
|
||||
user,
|
||||
};
|
||||
cmd.handle_with(&mut conn).await?;
|
||||
writer.flush().await?;
|
||||
|
@ -874,48 +871,15 @@ async fn handle_incoming_message(
|
|||
log::info!("Received QUIT");
|
||||
return Ok(HandleResult::Leave);
|
||||
}
|
||||
ClientMessage::ChatHistory { chan, limit } => {
|
||||
if user.enabled_capabilities.contains(Capabilities::ChatHistory) {
|
||||
let channel_name = match chan.clone() {
|
||||
Chan::Global(chan) => chan,
|
||||
// TODO Respond with an error when a local channel is requested
|
||||
Chan::Local(chan) => chan,
|
||||
};
|
||||
let room_id = &RoomId::try_from(channel_name.clone())?;
|
||||
let res = user_handle.get_room_message_history(room_id, limit).await?;
|
||||
match res {
|
||||
RoomHistoryResult::Success(messages) => {
|
||||
for message in messages {
|
||||
let mut tags = vec![];
|
||||
if user.enabled_capabilities.contains(Capabilities::ServerTime) {
|
||||
let tag = Tag {
|
||||
key: "time".into(),
|
||||
value: Some(
|
||||
message.created_at.to_rfc3339_opts(SecondsFormat::Millis, true).into(),
|
||||
),
|
||||
};
|
||||
tags.push(tag);
|
||||
}
|
||||
ServerMessage {
|
||||
tags,
|
||||
sender: Some(message.author_name.into()),
|
||||
body: ServerMessageBody::PrivateMessage {
|
||||
target: Recipient::Chan(chan.clone()),
|
||||
body: message.content.into(),
|
||||
},
|
||||
}
|
||||
.write_async(writer)
|
||||
.await?;
|
||||
}
|
||||
writer.flush().await?;
|
||||
}
|
||||
RoomHistoryResult::NoSuchRoom => {}
|
||||
}
|
||||
} else {
|
||||
log::warn!(
|
||||
"Requested chat history for user {user:?} even though the capability was not negotiated"
|
||||
);
|
||||
}
|
||||
ClientMessage::ChatHistory(cmd) => {
|
||||
let mut conn = IrcConnection {
|
||||
server_name: config.server_name.clone(),
|
||||
writer,
|
||||
player_connection: user_handle,
|
||||
user,
|
||||
};
|
||||
cmd.handle_with(&mut conn).await?;
|
||||
writer.flush().await?;
|
||||
}
|
||||
cmd => {
|
||||
log::warn!("Not implemented handler for client command: {cmd:?}");
|
||||
|
|
|
@ -35,7 +35,7 @@ async fn handle_nick_target(nick: Str, conn: &mut IrcConnection<'_, impl AsyncWr
|
|||
GetInfoResult::UserDoesntExist => {
|
||||
IrcResponseMessage::empty_tags(
|
||||
Some(conn.server_name.clone()),
|
||||
ErrNoSuchNick401::new(conn.client.clone(), nick.clone()),
|
||||
ErrNoSuchNick401::new(conn.user.nickname.clone(), nick.clone()),
|
||||
)
|
||||
.write_response(conn.writer)
|
||||
.await?
|
||||
|
@ -43,7 +43,7 @@ async fn handle_nick_target(nick: Str, conn: &mut IrcConnection<'_, impl AsyncWr
|
|||
}
|
||||
IrcResponseMessage::empty_tags(
|
||||
Some(conn.server_name.clone()),
|
||||
RplEndOfWhois318::new(conn.client.clone(), nick.clone()),
|
||||
RplEndOfWhois318::new(conn.user.nickname.clone(), nick.clone()),
|
||||
)
|
||||
.write_response(conn.writer)
|
||||
.await?;
|
||||
|
|
|
@ -63,10 +63,7 @@ pub enum ClientMessage {
|
|||
reason: Str,
|
||||
},
|
||||
Authenticate(Str),
|
||||
ChatHistory {
|
||||
chan: Chan,
|
||||
limit: u32,
|
||||
},
|
||||
ChatHistory(ChatHistory),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
|
@ -76,6 +73,12 @@ pub enum Whois {
|
|||
EmptyArgs,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct ChatHistory {
|
||||
pub chan: Chan,
|
||||
pub limit: u32,
|
||||
}
|
||||
|
||||
pub fn client_message(input: &str) -> Result<ClientMessage> {
|
||||
let res = all_consuming(alt((
|
||||
client_message_capability,
|
||||
|
@ -273,7 +276,7 @@ fn client_message_chathistory(input: &str) -> IResult<&str, ClientMessage> {
|
|||
let (input, _) = tag(" * ")(input)?;
|
||||
let (input, limit) = limit(input)?;
|
||||
|
||||
Ok((input, ClientMessage::ChatHistory { chan, limit }))
|
||||
Ok((input, ClientMessage::ChatHistory(ChatHistory { chan, limit })))
|
||||
}
|
||||
|
||||
fn limit(input: &str) -> IResult<&str, u32> {
|
||||
|
@ -514,10 +517,10 @@ mod test {
|
|||
#[test]
|
||||
fn test_client_chat_history_latest() {
|
||||
let input = "CHATHISTORY LATEST #chan * 10";
|
||||
let expected = ClientMessage::ChatHistory {
|
||||
let expected = ClientMessage::ChatHistory(ChatHistory {
|
||||
chan: Chan::Global("chan".into()),
|
||||
limit: 10,
|
||||
};
|
||||
});
|
||||
|
||||
let result = client_message(input);
|
||||
assert_matches!(result, Ok(result) => assert_eq!(expected, result));
|
||||
|
|
Loading…
Reference in New Issue