improvement: do not save typing edus in db
Signed-off-by: strawberry <strawberry@puppygock.gay>
This commit is contained in:
parent
a47923820c
commit
019a82850d
5 changed files with 77 additions and 30 deletions
|
@ -861,10 +861,10 @@ async fn load_joined_room(
|
||||||
.map(|(_, _, v)| v)
|
.map(|(_, _, v)| v)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
if services().rooms.edus.typing.last_typing_update(room_id)? > since {
|
if services().rooms.edus.typing.last_typing_update(room_id).await? > since {
|
||||||
edus.push(
|
edus.push(
|
||||||
serde_json::from_str(
|
serde_json::from_str(
|
||||||
&serde_json::to_string(&services().rooms.edus.typing.typings_all(room_id)?)
|
&serde_json::to_string(&services().rooms.edus.typing.typings_all(room_id).await?)
|
||||||
.expect("event is valid, we just created it"),
|
.expect("event is valid, we just created it"),
|
||||||
)
|
)
|
||||||
.expect("event is valid, we just created it"),
|
.expect("event is valid, we just created it"),
|
||||||
|
|
|
@ -17,13 +17,18 @@ pub async fn create_typing_event_route(
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Typing::Yes(duration) = body.state {
|
if let Typing::Yes(duration) = body.state {
|
||||||
services().rooms.edus.typing.typing_add(
|
services()
|
||||||
sender_user,
|
.rooms
|
||||||
&body.room_id,
|
.edus
|
||||||
duration.as_millis() as u64 + utils::millis_since_unix_epoch(),
|
.typing
|
||||||
)?;
|
.typing_add(
|
||||||
|
sender_user,
|
||||||
|
&body.room_id,
|
||||||
|
duration.as_millis() as u64 + utils::millis_since_unix_epoch(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
} else {
|
} else {
|
||||||
services().rooms.edus.typing.typing_remove(sender_user, &body.room_id)?;
|
services().rooms.edus.typing.typing_remove(sender_user, &body.room_id).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(create_typing_event::v3::Response {})
|
Ok(create_typing_event::v3::Response {})
|
||||||
|
|
|
@ -854,13 +854,14 @@ pub async fn send_transaction_message_route(
|
||||||
Edu::Typing(typing) => {
|
Edu::Typing(typing) => {
|
||||||
if services().rooms.state_cache.is_joined(&typing.user_id, &typing.room_id)? {
|
if services().rooms.state_cache.is_joined(&typing.user_id, &typing.room_id)? {
|
||||||
if typing.typing {
|
if typing.typing {
|
||||||
services().rooms.edus.typing.typing_add(
|
services()
|
||||||
&typing.user_id,
|
.rooms
|
||||||
&typing.room_id,
|
.edus
|
||||||
3000 + utils::millis_since_unix_epoch(),
|
.typing
|
||||||
)?;
|
.typing_add(&typing.user_id, &typing.room_id, 3000 + utils::millis_since_unix_epoch())
|
||||||
|
.await?;
|
||||||
} else {
|
} else {
|
||||||
services().rooms.edus.typing.typing_remove(&typing.user_id, &typing.room_id)?;
|
services().rooms.edus.typing.typing_remove(&typing.user_id, &typing.room_id).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -80,6 +80,8 @@ impl Services<'_> {
|
||||||
},
|
},
|
||||||
typing: rooms::edus::typing::Service {
|
typing: rooms::edus::typing::Service {
|
||||||
db,
|
db,
|
||||||
|
typing: RwLock::new(BTreeMap::new()),
|
||||||
|
last_typing_update: RwLock::new(BTreeMap::new()),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
event_handler: rooms::event_handler::Service,
|
event_handler: rooms::event_handler::Service,
|
||||||
|
|
|
@ -1,45 +1,84 @@
|
||||||
mod data;
|
mod data;
|
||||||
|
|
||||||
pub use data::Data;
|
use std::collections::BTreeMap;
|
||||||
use ruma::{events::SyncEphemeralRoomEvent, RoomId, UserId};
|
|
||||||
|
|
||||||
use crate::Result;
|
pub use data::Data;
|
||||||
|
use ruma::{events::SyncEphemeralRoomEvent, OwnedRoomId, OwnedUserId, RoomId, UserId};
|
||||||
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
|
use crate::{services, utils, Result};
|
||||||
|
|
||||||
pub struct Service {
|
pub struct Service {
|
||||||
pub db: &'static dyn Data,
|
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 */
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Service {
|
impl Service {
|
||||||
/// Sets a user as typing until the timeout timestamp is reached or
|
/// Sets a user as typing until the timeout timestamp is reached or
|
||||||
/// roomtyping_remove is called.
|
/// roomtyping_remove is called.
|
||||||
pub fn typing_add(&self, user_id: &UserId, room_id: &RoomId, timeout: u64) -> Result<()> {
|
pub async fn typing_add(&self, user_id: &UserId, room_id: &RoomId, timeout: u64) -> Result<()> {
|
||||||
self.db.typing_add(user_id, room_id, timeout)
|
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()?);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes a user from typing before the timeout is reached.
|
/// Removes a user from typing before the timeout is reached.
|
||||||
pub fn typing_remove(&self, user_id: &UserId, room_id: &RoomId) -> Result<()> {
|
pub async fn typing_remove(&self, user_id: &UserId, room_id: &RoomId) -> Result<()> {
|
||||||
self.db.typing_remove(user_id, room_id)
|
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()?);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes sure that typing events with old timestamps get removed.
|
/// Makes sure that typing events with old timestamps get removed.
|
||||||
fn typings_maintain(&self, room_id: &RoomId) -> Result<()> { self.db.typings_maintain(room_id) }
|
async fn typings_maintain(&self, room_id: &RoomId) -> Result<()> {
|
||||||
|
let current_timestamp = utils::millis_since_unix_epoch();
|
||||||
|
let mut removable = Vec::new();
|
||||||
|
{
|
||||||
|
let typing = self.typing.read().await;
|
||||||
|
let Some(room) = typing.get(room_id) else {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
for (user, timeout) in room {
|
||||||
|
if *timeout < current_timestamp {
|
||||||
|
removable.push(user.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
drop(typing)
|
||||||
|
};
|
||||||
|
|
||||||
|
if !removable.is_empty() {
|
||||||
|
let typing = &mut self.typing.write().await;
|
||||||
|
let room = typing.entry(room_id.to_owned()).or_default();
|
||||||
|
for user in removable {
|
||||||
|
room.remove(&user);
|
||||||
|
}
|
||||||
|
self.last_typing_update.write().await.insert(room_id.to_owned(), services().globals.next_count()?);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the count of the last typing update in this room.
|
/// Returns the count of the last typing update in this room.
|
||||||
pub fn last_typing_update(&self, room_id: &RoomId) -> Result<u64> {
|
pub async fn last_typing_update(&self, room_id: &RoomId) -> Result<u64> {
|
||||||
self.typings_maintain(room_id)?;
|
self.typings_maintain(room_id).await?;
|
||||||
|
Ok(self.last_typing_update.read().await.get(room_id).copied().unwrap_or(0))
|
||||||
self.db.last_typing_update(room_id)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a new typing EDU.
|
/// Returns a new typing EDU.
|
||||||
pub fn typings_all(
|
pub async fn typings_all(
|
||||||
&self, room_id: &RoomId,
|
&self, room_id: &RoomId,
|
||||||
) -> Result<SyncEphemeralRoomEvent<ruma::events::typing::TypingEventContent>> {
|
) -> Result<SyncEphemeralRoomEvent<ruma::events::typing::TypingEventContent>> {
|
||||||
let user_ids = self.db.typings_all(room_id)?;
|
|
||||||
|
|
||||||
Ok(SyncEphemeralRoomEvent {
|
Ok(SyncEphemeralRoomEvent {
|
||||||
content: ruma::events::typing::TypingEventContent {
|
content: ruma::events::typing::TypingEventContent {
|
||||||
user_ids: user_ids.into_iter().collect(),
|
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