2025-02-02 17:27:39 +00:00
|
|
|
mod room_state;
|
|
|
|
|
mod server_can;
|
|
|
|
|
mod state;
|
|
|
|
|
mod user_can;
|
|
|
|
|
|
2025-04-02 22:38:47 -04:00
|
|
|
use std::sync::Arc;
|
2022-09-06 23:15:09 +02:00
|
|
|
|
2025-03-15 04:07:53 +00:00
|
|
|
use async_trait::async_trait;
|
2023-02-18 13:20:20 +01:00
|
|
|
use ruma::{
|
2025-04-04 01:05:43 +00:00
|
|
|
EventEncryptionAlgorithm, JsOption, OwnedRoomAliasId, RoomId, UserId,
|
2023-02-18 13:20:20 +01:00
|
|
|
events::{
|
2025-02-23 01:17:45 -05:00
|
|
|
StateEventType,
|
2023-02-18 13:20:20 +01:00
|
|
|
room::{
|
2023-08-07 17:54:08 +02:00
|
|
|
avatar::RoomAvatarEventContent,
|
2024-06-08 20:52:41 -04:00
|
|
|
canonical_alias::RoomCanonicalAliasEventContent,
|
2024-07-03 12:40:08 -04:00
|
|
|
create::RoomCreateEventContent,
|
|
|
|
|
encryption::RoomEncryptionEventContent,
|
2024-06-08 20:45:17 -04:00
|
|
|
guest_access::{GuestAccess, RoomGuestAccessEventContent},
|
2023-02-18 13:20:20 +01:00
|
|
|
history_visibility::{HistoryVisibility, RoomHistoryVisibilityEventContent},
|
2025-04-04 01:05:43 +00:00
|
|
|
join_rules::{JoinRule, RoomJoinRulesEventContent},
|
2025-02-02 17:27:39 +00:00
|
|
|
member::RoomMemberEventContent,
|
2023-07-06 10:32:25 +02:00
|
|
|
name::RoomNameEventContent,
|
2024-06-08 20:56:51 -04:00
|
|
|
topic::RoomTopicEventContent,
|
2023-02-18 13:20:20 +01:00
|
|
|
},
|
|
|
|
|
},
|
2024-07-03 12:40:08 -04:00
|
|
|
room::RoomType,
|
2023-02-18 13:20:20 +01:00
|
|
|
};
|
2025-04-22 01:41:02 +00:00
|
|
|
use tuwunel_core::{Result, err};
|
|
|
|
|
use tuwunel_database::Map;
|
2022-08-14 13:38:21 +02:00
|
|
|
|
2025-04-02 22:38:47 -04:00
|
|
|
use crate::{Dep, rooms};
|
2022-08-14 13:38:21 +02:00
|
|
|
|
2024-05-09 15:59:08 -07:00
|
|
|
pub struct Service {
|
2025-01-25 23:07:50 +00:00
|
|
|
services: Services,
|
|
|
|
|
db: Data,
|
2022-08-14 13:38:21 +02:00
|
|
|
}
|
|
|
|
|
|
2024-07-18 06:37:47 +00:00
|
|
|
struct Services {
|
2025-01-25 23:07:50 +00:00
|
|
|
short: Dep<rooms::short::Service>,
|
|
|
|
|
state: Dep<rooms::state::Service>,
|
|
|
|
|
state_compressor: Dep<rooms::state_compressor::Service>,
|
2024-07-18 06:37:47 +00:00
|
|
|
state_cache: Dep<rooms::state_cache::Service>,
|
|
|
|
|
timeline: Dep<rooms::timeline::Service>,
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-25 23:07:50 +00:00
|
|
|
struct Data {
|
|
|
|
|
shorteventid_shortstatehash: Arc<Map>,
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-15 04:07:53 +00:00
|
|
|
#[async_trait]
|
2024-07-04 03:26:19 +00:00
|
|
|
impl crate::Service for Service {
|
|
|
|
|
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
|
|
|
|
|
Ok(Arc::new(Self {
|
2025-01-25 23:07:50 +00:00
|
|
|
services: Services {
|
|
|
|
|
state_cache: args.depend::<rooms::state_cache::Service>("rooms::state_cache"),
|
|
|
|
|
timeline: args.depend::<rooms::timeline::Service>("rooms::timeline"),
|
|
|
|
|
short: args.depend::<rooms::short::Service>("rooms::short"),
|
|
|
|
|
state: args.depend::<rooms::state::Service>("rooms::state"),
|
|
|
|
|
state_compressor: args
|
|
|
|
|
.depend::<rooms::state_compressor::Service>("rooms::state_compressor"),
|
|
|
|
|
},
|
|
|
|
|
db: Data {
|
|
|
|
|
shorteventid_shortstatehash: args.db["shorteventid_shortstatehash"].clone(),
|
|
|
|
|
},
|
2024-07-04 03:26:19 +00:00
|
|
|
}))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Service {
|
2024-08-08 17:18:30 +00:00
|
|
|
pub async fn get_name(&self, room_id: &RoomId) -> Result<String> {
|
|
|
|
|
self.room_state_get_content(room_id, &StateEventType::RoomName, "")
|
|
|
|
|
.await
|
|
|
|
|
.map(|c: RoomNameEventContent| c.name)
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-03 09:44:43 +00:00
|
|
|
pub async fn get_avatar(&self, room_id: &RoomId) -> JsOption<RoomAvatarEventContent> {
|
|
|
|
|
let content = self
|
|
|
|
|
.room_state_get_content(room_id, &StateEventType::RoomAvatar, "")
|
2024-08-08 17:18:30 +00:00
|
|
|
.await
|
2024-10-03 09:44:43 +00:00
|
|
|
.ok();
|
|
|
|
|
|
|
|
|
|
JsOption::from_option(content)
|
2023-08-07 17:54:08 +02:00
|
|
|
}
|
2024-03-05 19:48:54 -05:00
|
|
|
|
2024-12-15 00:05:47 -05:00
|
|
|
pub async fn get_member(
|
|
|
|
|
&self,
|
|
|
|
|
room_id: &RoomId,
|
|
|
|
|
user_id: &UserId,
|
|
|
|
|
) -> Result<RoomMemberEventContent> {
|
2024-08-08 17:18:30 +00:00
|
|
|
self.room_state_get_content(room_id, &StateEventType::RoomMember, user_id.as_str())
|
|
|
|
|
.await
|
2023-07-23 21:57:11 +02:00
|
|
|
}
|
2024-04-06 10:13:06 -04:00
|
|
|
|
2024-06-07 01:16:18 -04:00
|
|
|
/// Checks if guests are able to view room content without joining
|
2024-08-08 17:18:30 +00:00
|
|
|
pub async fn is_world_readable(&self, room_id: &RoomId) -> bool {
|
|
|
|
|
self.room_state_get_content(room_id, &StateEventType::RoomHistoryVisibility, "")
|
|
|
|
|
.await
|
2024-12-15 00:05:47 -05:00
|
|
|
.map(|c: RoomHistoryVisibilityEventContent| {
|
|
|
|
|
c.history_visibility == HistoryVisibility::WorldReadable
|
|
|
|
|
})
|
2024-08-08 17:18:30 +00:00
|
|
|
.unwrap_or(false)
|
2024-06-08 20:45:17 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Checks if guests are able to join a given room
|
2024-08-08 17:18:30 +00:00
|
|
|
pub async fn guest_can_join(&self, room_id: &RoomId) -> bool {
|
|
|
|
|
self.room_state_get_content(room_id, &StateEventType::RoomGuestAccess, "")
|
|
|
|
|
.await
|
|
|
|
|
.map(|c: RoomGuestAccessEventContent| c.guest_access == GuestAccess::CanJoin)
|
|
|
|
|
.unwrap_or(false)
|
2024-06-07 01:16:18 -04:00
|
|
|
}
|
2024-06-08 20:52:41 -04:00
|
|
|
|
|
|
|
|
/// Gets the primary alias from canonical alias event
|
2024-08-08 17:18:30 +00:00
|
|
|
pub async fn get_canonical_alias(&self, room_id: &RoomId) -> Result<OwnedRoomAliasId> {
|
|
|
|
|
self.room_state_get_content(room_id, &StateEventType::RoomCanonicalAlias, "")
|
|
|
|
|
.await
|
|
|
|
|
.and_then(|c: RoomCanonicalAliasEventContent| {
|
|
|
|
|
c.alias
|
|
|
|
|
.ok_or_else(|| err!(Request(NotFound("No alias found in event content."))))
|
2024-06-08 20:52:41 -04:00
|
|
|
})
|
|
|
|
|
}
|
2024-06-08 20:56:51 -04:00
|
|
|
|
|
|
|
|
/// Gets the room topic
|
2024-08-08 17:18:30 +00:00
|
|
|
pub async fn get_room_topic(&self, room_id: &RoomId) -> Result<String> {
|
|
|
|
|
self.room_state_get_content(room_id, &StateEventType::RoomTopic, "")
|
|
|
|
|
.await
|
|
|
|
|
.map(|c: RoomTopicEventContent| c.topic)
|
2024-06-08 20:56:51 -04:00
|
|
|
}
|
2024-06-22 21:21:16 +00:00
|
|
|
|
2025-04-02 22:51:17 -04:00
|
|
|
/// Returns the join rules for a given room (`JoinRule` type). Will default
|
|
|
|
|
/// to Invite if doesnt exist or invalid
|
|
|
|
|
pub async fn get_join_rules(&self, room_id: &RoomId) -> JoinRule {
|
|
|
|
|
self.room_state_get_content(room_id, &StateEventType::RoomJoinRules, "")
|
|
|
|
|
.await
|
2025-04-04 01:05:43 +00:00
|
|
|
.map_or(JoinRule::Invite, |c: RoomJoinRulesEventContent| c.join_rule)
|
2024-07-02 16:42:07 -04:00
|
|
|
}
|
2024-07-03 12:40:08 -04:00
|
|
|
|
2024-08-08 17:18:30 +00:00
|
|
|
pub async fn get_room_type(&self, room_id: &RoomId) -> Result<RoomType> {
|
|
|
|
|
self.room_state_get_content(room_id, &StateEventType::RoomCreate, "")
|
|
|
|
|
.await
|
|
|
|
|
.and_then(|content: RoomCreateEventContent| {
|
|
|
|
|
content
|
|
|
|
|
.room_type
|
|
|
|
|
.ok_or_else(|| err!(Request(NotFound("No type found in event content"))))
|
2024-07-03 12:40:08 -04:00
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Gets the room's encryption algorithm if `m.room.encryption` state event
|
|
|
|
|
/// is found
|
2024-12-15 00:05:47 -05:00
|
|
|
pub async fn get_room_encryption(
|
|
|
|
|
&self,
|
|
|
|
|
room_id: &RoomId,
|
|
|
|
|
) -> Result<EventEncryptionAlgorithm> {
|
2024-08-08 17:18:30 +00:00
|
|
|
self.room_state_get_content(room_id, &StateEventType::RoomEncryption, "")
|
|
|
|
|
.await
|
|
|
|
|
.map(|content: RoomEncryptionEventContent| content.algorithm)
|
2024-07-03 12:40:08 -04:00
|
|
|
}
|
2024-10-07 17:54:27 +00:00
|
|
|
|
|
|
|
|
pub async fn is_encrypted_room(&self, room_id: &RoomId) -> bool {
|
|
|
|
|
self.room_state_get(room_id, &StateEventType::RoomEncryption, "")
|
|
|
|
|
.await
|
|
|
|
|
.is_ok()
|
|
|
|
|
}
|
2022-08-14 13:38:21 +02:00
|
|
|
}
|