mirror of
https://forgejo.ellis.link/continuwuation/continuwuity.git
synced 2026-11-14 12:46:49 +00:00
feat: Add support for MSC4388
This commit is contained in:
1 parent
77e8a6b41b
commit
0c266c28f6
10 files changed
+289
-11
No files matched your search
@@ -33,6 +33,7 @@ pub mod oidc;
|
||||
pub mod presence;
|
||||
pub mod pusher;
|
||||
pub mod registration_tokens;
|
||||
pub mod rendezvous;
|
||||
pub mod rooms;
|
||||
pub mod sending;
|
||||
pub mod server_keys;
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
use std::{
|
||||
sync::Arc,
|
||||
time::{Duration, SystemTime},
|
||||
};
|
||||
|
||||
use conduwuit::{Err, Result, SyncMappedMutexGuard, SyncMutex, SyncMutexGuard, at, err, utils};
|
||||
use lru_cache::LruCache;
|
||||
use ruma::{
|
||||
OwnedTransactionId,
|
||||
api::client::rendezvous::{
|
||||
create_rendezvous_session, delete_rendezvous_session, get_rendezvous_session,
|
||||
update_rendezvous_session,
|
||||
},
|
||||
};
|
||||
|
||||
pub struct Service {
|
||||
sessions: SyncMutex<LruCache<String, Session>>,
|
||||
}
|
||||
|
||||
struct Session {
|
||||
data: String,
|
||||
created_at: SystemTime,
|
||||
last_sequence_token: String,
|
||||
transaction_sequences: LruCache<OwnedTransactionId, String>,
|
||||
}
|
||||
|
||||
impl Session {
|
||||
const SAVED_TRANSACTION_SEQUENCES: usize = 256;
|
||||
|
||||
fn new(data: String, sequence_token: String) -> Self {
|
||||
Self {
|
||||
data,
|
||||
created_at: SystemTime::now(),
|
||||
last_sequence_token: sequence_token,
|
||||
transaction_sequences: LruCache::new(Self::SAVED_TRANSACTION_SEQUENCES),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::Service for Service {
|
||||
fn build(_: crate::Args<'_>) -> Result<Arc<Self>> {
|
||||
Ok(Arc::new(Self {
|
||||
sessions: SyncMutex::new(LruCache::new(Self::MAX_SESSIONS)),
|
||||
}))
|
||||
}
|
||||
|
||||
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
|
||||
}
|
||||
|
||||
impl Service {
|
||||
const MAX_DATA_SIZE_BYTES: usize = 4096;
|
||||
const MAX_SESSIONS: usize = 256;
|
||||
const SESSION_MAX_AGE: Duration = Duration::from_secs(300);
|
||||
const TOKEN_LENGTH: usize = 32;
|
||||
|
||||
fn create_token() -> String { utils::random_string(Self::TOKEN_LENGTH) }
|
||||
|
||||
fn lock_session(&self, id: &str) -> Result<SyncMappedMutexGuard<'_, Session>> {
|
||||
SyncMutexGuard::try_map_or_err(self.sessions.lock(), |sessions| {
|
||||
sessions
|
||||
.get_mut(id)
|
||||
.filter(|session| {
|
||||
SystemTime::now()
|
||||
.duration_since(session.created_at)
|
||||
.is_ok_and(|duration| duration < Self::SESSION_MAX_AGE)
|
||||
})
|
||||
.ok_or_else(|| err!(Request(NotFound("Unknown session"))))
|
||||
})
|
||||
.map_err(at!(1))
|
||||
}
|
||||
|
||||
pub fn create_session(
|
||||
&self,
|
||||
data: String,
|
||||
) -> Result<create_rendezvous_session::msc4388::Response> {
|
||||
if data.len() > Self::MAX_DATA_SIZE_BYTES {
|
||||
return Err!(Request(TooLarge("Data too large")));
|
||||
}
|
||||
|
||||
let id = Self::create_token();
|
||||
let sequence_token = Self::create_token();
|
||||
|
||||
self.sessions
|
||||
.lock()
|
||||
.insert(id.clone(), Session::new(data, sequence_token.clone()));
|
||||
|
||||
Ok(create_rendezvous_session::msc4388::Response::new(
|
||||
id,
|
||||
sequence_token,
|
||||
Self::SESSION_MAX_AGE,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn update_session(
|
||||
&self,
|
||||
id: &str,
|
||||
transaction: OwnedTransactionId,
|
||||
sequence_token: String,
|
||||
data: String,
|
||||
) -> Result<update_rendezvous_session::msc4388::Response> {
|
||||
let mut session = self.lock_session(id)?;
|
||||
|
||||
if data.len() > Self::MAX_DATA_SIZE_BYTES {
|
||||
return Err!(Request(TooLarge("Data too large")));
|
||||
}
|
||||
|
||||
let mut session = self.lock_session(id)?;
|
||||
|
||||
if let Some(sequence_token) = session.transaction_sequences.get_mut(&transaction) {
|
||||
return Ok(update_rendezvous_session::msc4388::Response::new(
|
||||
sequence_token.to_owned(),
|
||||
));
|
||||
}
|
||||
|
||||
if session.last_sequence_token != sequence_token {
|
||||
return Err!(Request(ConcurrentWrite("Sequence token mismatch")));
|
||||
}
|
||||
|
||||
let new_sequence_token = Self::create_token();
|
||||
|
||||
session.data = data;
|
||||
session.last_sequence_token.clone_from(&new_sequence_token);
|
||||
session
|
||||
.transaction_sequences
|
||||
.insert(transaction, sequence_token);
|
||||
|
||||
Ok(update_rendezvous_session::msc4388::Response::new(new_sequence_token))
|
||||
}
|
||||
|
||||
pub fn get_session(&self, id: &str) -> Result<get_rendezvous_session::unstable::Response> {
|
||||
let session = self.lock_session(id)?;
|
||||
|
||||
let session_age = SystemTime::now()
|
||||
.duration_since(session.created_at)
|
||||
.unwrap_or(Duration::MAX);
|
||||
|
||||
let session_time_remaining = Self::SESSION_MAX_AGE.saturating_sub(session_age);
|
||||
|
||||
Ok(get_rendezvous_session::msc4388::Response::new(
|
||||
session.last_sequence_token.clone(),
|
||||
session.data.clone(),
|
||||
session_time_remaining,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn delete_session(
|
||||
&self,
|
||||
id: &str,
|
||||
) -> Result<delete_rendezvous_session::msc4388::Response> {
|
||||
let mut sessions = self.sessions.lock();
|
||||
|
||||
if sessions.remove(id).is_some() {
|
||||
Ok(delete_rendezvous_session::msc4388::Response::new())
|
||||
} else {
|
||||
Err!(Request(NotFound("Unknown session")))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,8 @@ use crate::{
|
||||
account_data, admin, announcements, antispam, appservice, client, config, emergency,
|
||||
federation, firstrun, globals, key_backups, mailer,
|
||||
manager::Manager,
|
||||
media, moderation, oauth, oidc, presence, pusher, registration_tokens, rooms, sending,
|
||||
server_keys,
|
||||
media, moderation, oauth, oidc, presence, pusher, registration_tokens, rendezvous, rooms,
|
||||
sending, server_keys,
|
||||
service::{self, Args, Map, Service},
|
||||
sync, threepid, transactions, uiaa, users,
|
||||
};
|
||||
@@ -33,6 +33,7 @@ pub struct Services {
|
||||
pub presence: Arc<presence::Service>,
|
||||
pub pusher: Arc<pusher::Service>,
|
||||
pub registration_tokens: Arc<registration_tokens::Service>,
|
||||
pub rendezvous: Arc<rendezvous::Service>,
|
||||
pub rooms: rooms::Service,
|
||||
pub federation: Arc<federation::Service>,
|
||||
pub firstrun: Arc<firstrun::Service>,
|
||||
@@ -89,6 +90,7 @@ impl Services {
|
||||
presence: build!(presence::Service),
|
||||
pusher: build!(pusher::Service),
|
||||
registration_tokens: build!(registration_tokens::Service),
|
||||
rendezvous: build!(rendezvous::Service),
|
||||
rooms: rooms::Service {
|
||||
alias: build!(rooms::alias::Service),
|
||||
auth_chain: build!(rooms::auth_chain::Service),
|
||||
|
||||
Reference in new issue
Block a user