refactor: remove previous typing implementation and add sync wakeup for new one
This commit is contained in:
parent
6bd7ff4917
commit
d2817679e5
11 changed files with 101 additions and 185 deletions
|
@ -4,7 +4,7 @@ use std::{
|
|||
};
|
||||
|
||||
use lru_cache::LruCache;
|
||||
use tokio::sync::Mutex;
|
||||
use tokio::sync::{broadcast, Mutex};
|
||||
|
||||
use crate::{Config, Result};
|
||||
use tokio::sync::RwLock;
|
||||
|
@ -66,7 +66,11 @@ impl Services {
|
|||
edus: rooms::edus::Service {
|
||||
presence: rooms::edus::presence::Service { db },
|
||||
read_receipt: rooms::edus::read_receipt::Service { db },
|
||||
typing: rooms::edus::typing::Service { db, typing: RwLock::new(BTreeMap::new()), last_typing_update: RwLock::new(BTreeMap::new()) },
|
||||
typing: rooms::edus::typing::Service {
|
||||
typing: RwLock::new(BTreeMap::new()),
|
||||
last_typing_update: RwLock::new(BTreeMap::new()),
|
||||
typing_update_sender: broadcast::channel(100).0,
|
||||
},
|
||||
},
|
||||
event_handler: rooms::event_handler::Service,
|
||||
lazy_loading: rooms::lazy_loading::Service {
|
||||
|
|
|
@ -2,7 +2,7 @@ pub mod presence;
|
|||
pub mod read_receipt;
|
||||
pub mod typing;
|
||||
|
||||
pub trait Data: presence::Data + read_receipt::Data + typing::Data + 'static {}
|
||||
pub trait Data: presence::Data + read_receipt::Data + 'static {}
|
||||
|
||||
pub struct Service {
|
||||
pub presence: presence::Service,
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
use crate::Result;
|
||||
use ruma::{OwnedUserId, RoomId, UserId};
|
||||
use std::collections::HashSet;
|
||||
|
||||
pub trait Data: Send + Sync {
|
||||
/// Sets a user as typing until the timeout timestamp is reached or roomtyping_remove is
|
||||
/// called.
|
||||
fn typing_add(&self, user_id: &UserId, room_id: &RoomId, timeout: u64) -> Result<()>;
|
||||
|
||||
/// Removes a user from typing before the timeout is reached.
|
||||
fn typing_remove(&self, user_id: &UserId, room_id: &RoomId) -> Result<()>;
|
||||
|
||||
/// Makes sure that typing events with old timestamps get removed.
|
||||
fn typings_maintain(&self, room_id: &RoomId) -> Result<()>;
|
||||
|
||||
/// Returns the count of the last typing update in this room.
|
||||
fn last_typing_update(&self, room_id: &RoomId) -> Result<u64>;
|
||||
|
||||
/// Returns all user ids currently typing.
|
||||
fn typings_all(&self, room_id: &RoomId) -> Result<HashSet<OwnedUserId>>;
|
||||
}
|
|
@ -1,31 +1,57 @@
|
|||
mod data;
|
||||
|
||||
pub use data::Data;
|
||||
use ruma::{events::SyncEphemeralRoomEvent, RoomId, UserId, OwnedRoomId, OwnedUserId};
|
||||
use tokio::sync::RwLock;
|
||||
use ruma::{events::SyncEphemeralRoomEvent, OwnedRoomId, OwnedUserId, RoomId, UserId};
|
||||
use std::collections::BTreeMap;
|
||||
use tokio::sync::{broadcast, RwLock};
|
||||
|
||||
use crate::{utils, services, Result};
|
||||
use crate::{services, utils, Result};
|
||||
|
||||
pub struct Service {
|
||||
pub db: &'static dyn Data,
|
||||
pub typing: RwLock<BTreeMap<OwnedRoomId, BTreeMap<OwnedUserId, u64>>>, // u64 is unix timestamp of timeout
|
||||
pub last_typing_update: RwLock<BTreeMap<OwnedRoomId, u64>>, // timestamp of the last change to typing users
|
||||
pub typing_update_sender: broadcast::Sender<OwnedRoomId>,
|
||||
}
|
||||
|
||||
impl Service {
|
||||
/// Sets a user as typing until the timeout timestamp is reached or roomtyping_remove is
|
||||
/// called.
|
||||
pub async fn typing_add(&self, user_id: &UserId, room_id: &RoomId, timeout: u64) -> Result<()> {
|
||||
self.typing.write().await.entry(room_id.to_owned()).or_default().insert(user_id.to_owned(), timeout);
|
||||
self.last_typing_update.write().await.insert(room_id.to_owned(), services().globals.next_count()?);
|
||||
self.typing
|
||||
.write()
|
||||
.await
|
||||
.entry(room_id.to_owned())
|
||||
.or_default()
|
||||
.insert(user_id.to_owned(), timeout);
|
||||
self.last_typing_update
|
||||
.write()
|
||||
.await
|
||||
.insert(room_id.to_owned(), services().globals.next_count()?);
|
||||
let _ = self.typing_update_sender.send(room_id.to_owned());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Removes a user from typing before the timeout is reached.
|
||||
pub async fn typing_remove(&self, user_id: &UserId, room_id: &RoomId) -> Result<()> {
|
||||
self.typing.write().await.entry(room_id.to_owned()).or_default().remove(user_id);
|
||||
self.last_typing_update.write().await.insert(room_id.to_owned(), services().globals.next_count()?);
|
||||
self.typing
|
||||
.write()
|
||||
.await
|
||||
.entry(room_id.to_owned())
|
||||
.or_default()
|
||||
.remove(user_id);
|
||||
self.last_typing_update
|
||||
.write()
|
||||
.await
|
||||
.insert(room_id.to_owned(), services().globals.next_count()?);
|
||||
let _ = self.typing_update_sender.send(room_id.to_owned());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn wait_for_update(&self, room_id: &RoomId) -> Result<()> {
|
||||
let mut receiver = self.typing_update_sender.subscribe();
|
||||
while let Ok(next) = receiver.recv().await {
|
||||
if next == room_id {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -35,7 +61,9 @@ impl Service {
|
|||
let mut removable = Vec::new();
|
||||
{
|
||||
let typing = self.typing.read().await;
|
||||
let Some(room) = typing.get(room_id) else { return Ok(()); };
|
||||
let Some(room) = typing.get(room_id) else {
|
||||
return Ok(());
|
||||
};
|
||||
for (user, timeout) in room {
|
||||
if *timeout < current_timestamp {
|
||||
removable.push(user.clone());
|
||||
|
@ -49,7 +77,11 @@ impl Service {
|
|||
for user in removable {
|
||||
room.remove(&user);
|
||||
}
|
||||
self.last_typing_update.write().await.insert(room_id.to_owned(), services().globals.next_count()?);
|
||||
self.last_typing_update
|
||||
.write()
|
||||
.await
|
||||
.insert(room_id.to_owned(), services().globals.next_count()?);
|
||||
let _ = self.typing_update_sender.send(room_id.to_owned());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -57,7 +89,13 @@ impl Service {
|
|||
/// Returns the count of the last typing update in this room.
|
||||
pub async fn last_typing_update(&self, room_id: &RoomId) -> Result<u64> {
|
||||
self.typings_maintain(room_id).await?;
|
||||
Ok(self.last_typing_update.read().await.get(room_id).copied().unwrap_or(0))
|
||||
Ok(self
|
||||
.last_typing_update
|
||||
.read()
|
||||
.await
|
||||
.get(room_id)
|
||||
.copied()
|
||||
.unwrap_or(0))
|
||||
}
|
||||
|
||||
/// Returns a new typing EDU.
|
||||
|
@ -67,7 +105,13 @@ impl Service {
|
|||
) -> Result<SyncEphemeralRoomEvent<ruma::events::typing::TypingEventContent>> {
|
||||
Ok(SyncEphemeralRoomEvent {
|
||||
content: ruma::events::typing::TypingEventContent {
|
||||
user_ids: self.typing.read().await.get(room_id).map(|m| m.keys().cloned().collect()).unwrap_or_default(),
|
||||
user_ids: self
|
||||
.typing
|
||||
.read()
|
||||
.await
|
||||
.get(room_id)
|
||||
.map(|m| m.keys().cloned().collect())
|
||||
.unwrap_or_default(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue