use std::sync::Arc; use ruma::{RoomId, UserId}; use tuwunel_core::{ Result, implement, trace, utils::stream::{ReadyExt, TryIgnore}, }; use tuwunel_database::{Database, Deserialized, Interfix, Map}; use crate::rooms::short::ShortStateHash; pub struct Service { db: Data, services: Arc, } struct Data { db: Arc, userroomid_notificationcount: Arc, userroomid_highlightcount: Arc, roomuserid_lastnotificationread: Arc, roomsynctoken_shortstatehash: Arc, } impl crate::Service for Service { fn build(args: &crate::Args<'_>) -> Result> { Ok(Arc::new(Self { db: Data { db: args.db.clone(), userroomid_notificationcount: args.db["userroomid_notificationcount"].clone(), userroomid_highlightcount: args.db["userroomid_highlightcount"].clone(), roomuserid_lastnotificationread: args.db["userroomid_highlightcount"].clone(), roomsynctoken_shortstatehash: args.db["roomsynctoken_shortstatehash"].clone(), }, services: args.services.clone(), })) } fn name(&self) -> &str { crate::service::make_name(std::module_path!()) } } #[implement(Service)] pub fn reset_notification_counts(&self, user_id: &UserId, room_id: &RoomId) { let count = self.services.globals.next_count(); let userroom_id = (user_id, room_id); self.db .userroomid_highlightcount .put(userroom_id, 0_u64); self.db .userroomid_notificationcount .put(userroom_id, 0_u64); let roomuser_id = (room_id, user_id); self.db .roomuserid_lastnotificationread .put(roomuser_id, *count); } #[implement(Service)] pub async fn notification_count(&self, user_id: &UserId, room_id: &RoomId) -> u64 { let key = (user_id, room_id); self.db .userroomid_notificationcount .qry(&key) .await .deserialized() .unwrap_or(0) } #[implement(Service)] pub async fn highlight_count(&self, user_id: &UserId, room_id: &RoomId) -> u64 { let key = (user_id, room_id); self.db .userroomid_highlightcount .qry(&key) .await .deserialized() .unwrap_or(0) } #[implement(Service)] pub async fn last_notification_read(&self, user_id: &UserId, room_id: &RoomId) -> u64 { let key = (room_id, user_id); self.db .roomuserid_lastnotificationread .qry(&key) .await .deserialized() .unwrap_or(0) } #[implement(Service)] pub async fn delete_room_notification_read(&self, room_id: &RoomId) -> Result { let key = (room_id, Interfix); self.db .roomuserid_lastnotificationread .keys_prefix_raw(&key) .ignore_err() .ready_for_each(|key| { trace!("Removing key: {key:?}"); self.db .roomuserid_lastnotificationread .remove(key); }) .await; Ok(()) } #[implement(Service)] #[tracing::instrument(level = "trace", skip(self))] pub async fn associate_token_shortstatehash( &self, room_id: &RoomId, token: u64, shortstatehash: ShortStateHash, ) { let shortroomid = self .services .short .get_shortroomid(room_id) .await .expect("room exists"); let _cork = self.db.db.cork(); let key: &[u64] = &[shortroomid, token]; self.db .roomsynctoken_shortstatehash .put(key, shortstatehash); } #[implement(Service)] pub async fn get_token_shortstatehash( &self, room_id: &RoomId, token: u64, ) -> Result { let shortroomid = self .services .short .get_shortroomid(room_id) .await?; let key: &[u64] = &[shortroomid, token]; self.db .roomsynctoken_shortstatehash .qry(key) .await .deserialized() } #[implement(Service)] pub async fn delete_room_synctokens(&self, room_id: &RoomId) -> Result { let shortroomid = self .services .short .get_shortroomid(room_id) .await?; self.db .roomsynctoken_shortstatehash .keys_prefix_raw(&shortroomid) .ignore_err() .ready_for_each(|key| { trace!("Removing key: {key:?}"); self.db.roomsynctoken_shortstatehash.remove(key); }) .await; Ok(()) }