aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar cel 🌸 <cel@bunny.garden>2025-03-06 10:43:57 +0000
committerLibravatar cel 🌸 <cel@bunny.garden>2025-03-06 10:43:57 +0000
commitb81f7f5bb418fb64211e5ec711cbcbecf8a681aa (patch)
treea4817781c7883417a9da37b68caab45848b773ca
parent9baf682466d191f23dc830a9897948d84068b3cc (diff)
downloadluz-b81f7f5bb418fb64211e5ec711cbcbecf8a681aa.tar.gz
luz-b81f7f5bb418fb64211e5ec711cbcbecf8a681aa.tar.bz2
luz-b81f7f5bb418fb64211e5ec711cbcbecf8a681aa.zip
feat: order chats by most recent message
-rw-r--r--README.md6
-rw-r--r--TODO.md22
-rw-r--r--jabber/Cargo.toml2
-rw-r--r--luz/src/chat.rs5
-rw-r--r--luz/src/db/mod.rs20
-rw-r--r--luz/src/lib.rs4
6 files changed, 36 insertions, 23 deletions
diff --git a/README.md b/README.md
index 06e98a3..0a7375b 100644
--- a/README.md
+++ b/README.md
@@ -4,9 +4,9 @@
## TODO:
-- [ ] how to know if stanza has been sent
+- [x] how to know if stanza has been sent
- [ ] error states for all negotiation parts
-- [ ] better errors
+- [x] better errors
- [x] rename structs
- [x] remove commented code
- [ ] asynchronous connect (with take_mut?)
@@ -16,7 +16,7 @@
### specs:
- [x] rfc 6120: core
-- [ ] rfc 6121: im
+- [x] rfc 6121: im
- [x] rfc 7590: tls
- [x] xep-0368: srv records for xmpp over tls
- [ ] server side downgrade protection for sasl
diff --git a/TODO.md b/TODO.md
index 47c86d9..aaa18a9 100644
--- a/TODO.md
+++ b/TODO.md
@@ -3,18 +3,7 @@
## next
feat(luz): everything in rfc6120 and rfc6121
- feat(luz): handle_online
- feat(luz): handle_offline
- feat(luz): handle_stanza
- feat(luz): database
feat(luz): error handling on stream according to rfc6120
- feat(luz): send message
- feat(luz): receive message
- feat(luz): retreive messages stored in database
- feat(luz): get roster (online and offline)
- feat(luz): set roster
- feat(luz): reconnect supervisorcommand
-feat: thiserror everywhere
feat(luz): proper stanza ids
test: proper tests
ci: doc generation
@@ -35,3 +24,14 @@ feature: sasl
feature: resource binding
feature: jabber client connection
feature: jid
+feat: thiserror everywhere
+feat(luz): handle_online
+feat(luz): handle_offline
+feat(luz): handle_stanza
+feat(luz): database
+feat(luz): send message
+feat(luz): receive message
+feat(luz): retreive messages stored in database
+feat(luz): get roster (online and offline)
+feat(luz): set roster
+feat(luz): reconnect supervisorcommand
diff --git a/jabber/Cargo.toml b/jabber/Cargo.toml
index b6093cf..0a50877 100644
--- a/jabber/Cargo.toml
+++ b/jabber/Cargo.toml
@@ -11,7 +11,7 @@ async-recursion = "1.0.4"
async-trait = "0.1.68"
lazy_static = "1.4.0"
nanoid = "0.4.0"
-# TODO: remove unneeded features
+# TODO: remove unneeded features and dependencies
rsasl = { version = "2.0.1", default_features = false, features = [
"provider_base64",
"plain",
diff --git a/luz/src/chat.rs b/luz/src/chat.rs
index 97518da..c1194ea 100644
--- a/luz/src/chat.rs
+++ b/luz/src/chat.rs
@@ -31,10 +31,15 @@ pub struct Body {
#[derive(sqlx::FromRow, Debug, Clone)]
pub struct Chat {
pub correspondent: JID,
+ // pub unread_messages: i32,
+ // pub latest_message: Message,
+ // when a new message is received, the chat should be updated, and the new message should be delivered too.
// message history is not stored in chat, retreived separately.
// pub message_history: Vec<Message>,
}
+pub enum ChatUpdate {}
+
impl Chat {
pub fn new(correspondent: JID) -> Self {
Self { correspondent }
diff --git a/luz/src/db/mod.rs b/luz/src/db/mod.rs
index 673ba48..d9fb3e3 100644
--- a/luz/src/db/mod.rs
+++ b/luz/src/db/mod.rs
@@ -129,12 +129,11 @@ impl Db {
}
pub(crate) async fn read_contact_opt(&self, contact: &JID) -> Result<Option<Contact>, Error> {
- let contact: Option<Contact> = sqlx::query_as(
- "select * from roster full outer join users on jid = user_jid where jid = ?",
- )
- .bind(contact)
- .fetch_optional(&self.db)
- .await?;
+ let contact: Option<Contact> =
+ sqlx::query_as("select * from roster join users on jid = user_jid where jid = ?")
+ .bind(contact)
+ .fetch_optional(&self.db)
+ .await?;
if let Some(mut contact) = contact {
#[derive(sqlx::FromRow)]
struct Row {
@@ -325,6 +324,15 @@ impl Db {
Ok(chats)
}
+ /// chats ordered by date of last message
+ // greatest-n-per-group
+ pub(crate) async fn read_chats_ordered(&self) -> Result<Vec<Chat>, Error> {
+ let chats = sqlx::query_as("select c.*, m.* from chats c join (select chat_id, max(timestamp) max_timestamp from messages group by chat_id) max_timestamps on c.id = max_timestamps.chat_id join messages m on max_timestamps.chat_id = m.chat_id and max_timestamps.max_timestamp = m.timestamp order by m.timestamp desc")
+ .fetch_all(&self.db)
+ .await?;
+ Ok(chats)
+ }
+
async fn read_chat_id(&self, chat: JID) -> Result<Uuid, Error> {
#[derive(sqlx::FromRow)]
struct Row {
diff --git a/luz/src/lib.rs b/luz/src/lib.rs
index c84d5ff..f7d8a23 100644
--- a/luz/src/lib.rs
+++ b/luz/src/lib.rs
@@ -323,7 +323,7 @@ impl CommandMessage {
}
}
CommandMessage::GetChats(sender) => {
- let chats = db.read_chats().await.map_err(|e| e.into());
+ let chats = db.read_chats_ordered().await.map_err(|e| e.into());
sender.send(chats);
}
CommandMessage::GetChat(jid, sender) => {
@@ -509,7 +509,7 @@ impl CommandMessage {
}
}
CommandMessage::GetChats(sender) => {
- let chats = db.read_chats().await.map_err(|e| e.into());
+ let chats = db.read_chats_ordered().await.map_err(|e| e.into());
sender.send(chats);
}
CommandMessage::GetChat(jid, sender) => {