diff --git a/crates/lavina-core/src/repo/room.rs b/crates/lavina-core/src/repo/room.rs index bca612b..19ab90b 100644 --- a/crates/lavina-core/src/repo/room.rs +++ b/crates/lavina-core/src/repo/room.rs @@ -30,7 +30,7 @@ impl Storage { } #[tracing::instrument(skip(self), name = "Storage::retrieve_room_message_history")] - pub async fn get_room_message_history(&self, room_id: u32) -> Result> { + pub async fn get_room_message_history(&self, room_id: u32, limit: u32) -> Result> { let mut executor = self.conn.lock().await; let res = sqlx::query_as( " @@ -47,10 +47,14 @@ impl Storage { where room_id = ? order by - messages.id; + messages.id + -- + limit ?; ", + // todo: implement limit ) .bind(room_id) + .bind(limit) .fetch_all(&mut *executor) .await?; diff --git a/crates/projection-irc/src/lib.rs b/crates/projection-irc/src/lib.rs index 4bceaf5..49c929d 100644 --- a/crates/projection-irc/src/lib.rs +++ b/crates/projection-irc/src/lib.rs @@ -140,7 +140,7 @@ impl RegistrationState { sender: Some(config.server_name.clone().into()), body: ServerMessageBody::Cap { target: self.future_nickname.clone().unwrap_or_else(|| "*".into()), - subcmd: CapSubBody::Ls("sasl=PLAIN server-time".into()), + subcmd: CapSubBody::Ls("sasl=PLAIN server-time draft/chathistory".into()), }, } .write_async(writer) @@ -167,6 +167,13 @@ impl RegistrationState { self.enabled_capabilities |= Capabilities::ServerTime; } acked.push(cap); + } else if &*cap.name == "draft/chathistory" { + if cap.to_disable { + self.enabled_capabilities &= !Capabilities::ChatHistory; + } else { + self.enabled_capabilities |= Capabilities::ChatHistory; + } + acked.push(cap); } else { naked.push(cap); } @@ -853,6 +860,8 @@ async fn handle_incoming_message( log::info!("Received QUIT"); return Ok(HandleResult::Leave); } + // todo: implement chat history logic here. + // ClientMessage:ChatHistory { ... } => {} cmd => { log::warn!("Not implemented handler for client command: {cmd:?}"); } diff --git a/crates/proto-irc/src/client.rs b/crates/proto-irc/src/client.rs index 5a62427..294807d 100644 --- a/crates/proto-irc/src/client.rs +++ b/crates/proto-irc/src/client.rs @@ -65,6 +65,10 @@ pub enum ClientMessage { reason: Str, }, Authenticate(Str), + Chathistory { + chan: Chan, + limit: u32, + }, } pub mod command_args { @@ -95,6 +99,7 @@ pub fn client_message(input: &str) -> Result { client_message_privmsg, client_message_quit, client_message_authenticate, + client_message_chathistory, )))(input); match res { Ok((_, e)) => Ok(e), @@ -134,6 +139,7 @@ fn client_message_nick(input: &str) -> IResult<&str, ClientMessage> { }, )) } + fn client_message_pass(input: &str) -> IResult<&str, ClientMessage> { let (input, _) = tag("PASS ")(input)?; let (input, r) = opt(tag(":"))(input)?; @@ -172,6 +178,7 @@ fn client_message_user(input: &str) -> IResult<&str, ClientMessage> { }, )) } + fn client_message_join(input: &str) -> IResult<&str, ClientMessage> { let (input, _) = tag("JOIN ")(input)?; let (input, chan) = chan(input)?; @@ -280,6 +287,22 @@ fn client_message_authenticate(input: &str) -> IResult<&str, ClientMessage> { Ok((input, ClientMessage::Authenticate(body.into()))) } +fn client_message_chathistory(input: &str) -> IResult<&str, ClientMessage> { + let (input, _) = tag("CHATHISTORY LATEST ")(input)?; + let (input, chan) = chan(input)?; + + let (input, _) = tag(" * ")(input)?; + let (input, limit) = limit(input)?; + + Ok((input, ClientMessage::Chathistory { chan, limit })) +} + +fn limit(input: &str) -> IResult<&str, u32> { + let (input, limit) = receiver(input)?; + let limit = limit.parse().unwrap(); + Ok((input, limit)) +} + #[derive(Clone, Debug, PartialEq, Eq)] pub enum CapabilitySubcommand { /// CAP LS {code} @@ -383,6 +406,7 @@ mod test { let result = client_message(input); assert_matches!(result, Ok(result) => assert_eq!(expected, result)); } + #[test] fn test_client_message_pong() { let input = "PONG 1337"; @@ -391,6 +415,7 @@ mod test { let result = client_message(input); assert_matches!(result, Ok(result) => assert_eq!(expected, result)); } + #[test] fn test_client_message_nick() { let input = "NICK SomeNick"; @@ -401,6 +426,7 @@ mod test { let result = client_message(input); assert_matches!(result, Ok(result) => assert_eq!(expected, result)); } + #[test] fn test_client_message_whois() { let test_user = "WHOIS val"; @@ -461,6 +487,7 @@ mod test { assert_matches!(res_more_than_two_params, Ok(result) => assert_eq!(expected_more_than_two_params, result)); assert_matches!(res_none_none_params, Ok(result) => assert_eq!(expected_none_none_params, result)) } + #[test] fn test_client_message_user() { let input = "USER SomeNick 8 * :Real Name"; @@ -472,6 +499,7 @@ mod test { let result = client_message(input); assert_matches!(result, Ok(result) => assert_eq!(expected, result)); } + #[test] fn test_client_message_part() { let input = "PART #chan :Pokasiki !!!"; @@ -483,6 +511,7 @@ mod test { let result = client_message(input); assert_matches!(result, Ok(result) => assert_eq!(expected, result)); } + #[test] fn test_client_message_part_empty() { let input = "PART #chan"; @@ -494,6 +523,7 @@ mod test { let result = client_message(input); assert_matches!(result, Ok(result) => assert_eq!(expected, result)); } + #[test] fn test_client_cap_req() { let input = "CAP REQ :multi-prefix -sasl"; @@ -513,4 +543,16 @@ mod test { let result = client_message(input); assert_matches!(result, Ok(result) => assert_eq!(expected, result)); } + + #[test] + fn test_client_chat_history_latest() { + let input = "CHATHISTORY LATEST #chan * 10"; + let expected = ClientMessage::Chathistory { + chan: Chan::Global("chan".into()), + limit: 10, + }; + + let result = client_message(input); + assert_matches!(result, Ok(result) => assert_eq!(expected, result)); + } }