fix: some compile time errors
Only 174 errors left!
This commit is contained in:
parent
82e7f57b38
commit
057f8364cc
118 changed files with 2139 additions and 2433 deletions
|
@ -8,23 +8,15 @@ use ruma::{
|
|||
use serde::{de::DeserializeOwned, Serialize};
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
use super::abstraction::Tree;
|
||||
|
||||
pub struct AccountData {
|
||||
pub(super) roomuserdataid_accountdata: Arc<dyn Tree>, // RoomUserDataId = Room + User + Count + Type
|
||||
pub(super) roomusertype_roomuserdataid: Arc<dyn Tree>, // RoomUserType = Room + User + Type
|
||||
}
|
||||
|
||||
impl AccountData {
|
||||
/// Places one event in the account data of the user and removes the previous entry.
|
||||
#[tracing::instrument(skip(self, room_id, user_id, event_type, data, globals))]
|
||||
#[tracing::instrument(skip(self, room_id, user_id, event_type, data))]
|
||||
pub fn update<T: Serialize>(
|
||||
&self,
|
||||
room_id: Option<&RoomId>,
|
||||
user_id: &UserId,
|
||||
event_type: RoomAccountDataEventType,
|
||||
data: &T,
|
||||
globals: &super::globals::Globals,
|
||||
) -> Result<()> {
|
||||
let mut prefix = room_id
|
||||
.map(|r| r.to_string())
|
||||
|
@ -36,7 +28,7 @@ impl AccountData {
|
|||
prefix.push(0xff);
|
||||
|
||||
let mut roomuserdataid = prefix.clone();
|
||||
roomuserdataid.extend_from_slice(&globals.next_count()?.to_be_bytes());
|
||||
roomuserdataid.extend_from_slice(&services().globals.next_count()?.to_be_bytes());
|
||||
roomuserdataid.push(0xff);
|
||||
roomuserdataid.extend_from_slice(event_type.to_string().as_bytes());
|
||||
|
||||
|
|
|
@ -5,14 +5,6 @@ use std::{
|
|||
time::Instant,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
client_server::AUTO_GEN_PASSWORD_LENGTH,
|
||||
error::{Error, Result},
|
||||
pdu::PduBuilder,
|
||||
server_server, utils,
|
||||
utils::HtmlEscape,
|
||||
Database, PduEvent,
|
||||
};
|
||||
use clap::Parser;
|
||||
use regex::Regex;
|
||||
use ruma::{
|
||||
|
@ -36,6 +28,10 @@ use ruma::{
|
|||
use serde_json::value::to_raw_value;
|
||||
use tokio::sync::{mpsc, MutexGuard, RwLock, RwLockReadGuard};
|
||||
|
||||
use crate::{services, Error, api::{server_server, client_server::AUTO_GEN_PASSWORD_LENGTH}, PduEvent, utils::{HtmlEscape, self}};
|
||||
|
||||
use super::pdu::PduBuilder;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum AdminRoomEvent {
|
||||
ProcessMessage(String),
|
||||
|
@ -50,22 +46,19 @@ pub struct Admin {
|
|||
impl Admin {
|
||||
pub fn start_handler(
|
||||
&self,
|
||||
db: Arc<RwLock<Database>>,
|
||||
mut receiver: mpsc::UnboundedReceiver<AdminRoomEvent>,
|
||||
) {
|
||||
tokio::spawn(async move {
|
||||
// TODO: Use futures when we have long admin commands
|
||||
//let mut futures = FuturesUnordered::new();
|
||||
|
||||
let guard = db.read().await;
|
||||
|
||||
let conduit_user = UserId::parse(format!("@conduit:{}", guard.globals.server_name()))
|
||||
let conduit_user = UserId::parse(format!("@conduit:{}", services().globals.server_name()))
|
||||
.expect("@conduit:server_name is valid");
|
||||
|
||||
let conduit_room = guard
|
||||
let conduit_room = services()
|
||||
.rooms
|
||||
.id_from_alias(
|
||||
format!("#admins:{}", guard.globals.server_name())
|
||||
format!("#admins:{}", services().globals.server_name())
|
||||
.as_str()
|
||||
.try_into()
|
||||
.expect("#admins:server_name is a valid room alias"),
|
||||
|
@ -73,12 +66,9 @@ impl Admin {
|
|||
.expect("Database data for admin room alias must be valid")
|
||||
.expect("Admin room must exist");
|
||||
|
||||
drop(guard);
|
||||
|
||||
let send_message = |message: RoomMessageEventContent,
|
||||
guard: RwLockReadGuard<'_, Database>,
|
||||
mutex_lock: &MutexGuard<'_, ()>| {
|
||||
guard
|
||||
services()
|
||||
.rooms
|
||||
.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
|
@ -91,7 +81,6 @@ impl Admin {
|
|||
},
|
||||
&conduit_user,
|
||||
&conduit_room,
|
||||
&guard,
|
||||
mutex_lock,
|
||||
)
|
||||
.unwrap();
|
||||
|
@ -100,15 +89,13 @@ impl Admin {
|
|||
loop {
|
||||
tokio::select! {
|
||||
Some(event) = receiver.recv() => {
|
||||
let guard = db.read().await;
|
||||
|
||||
let message_content = match event {
|
||||
AdminRoomEvent::SendMessage(content) => content,
|
||||
AdminRoomEvent::ProcessMessage(room_message) => process_admin_message(&*guard, room_message).await
|
||||
AdminRoomEvent::ProcessMessage(room_message) => process_admin_message(room_message).await
|
||||
};
|
||||
|
||||
let mutex_state = Arc::clone(
|
||||
guard.globals
|
||||
services().globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.unwrap()
|
||||
|
@ -118,7 +105,7 @@ impl Admin {
|
|||
|
||||
let state_lock = mutex_state.lock().await;
|
||||
|
||||
send_message(message_content, guard, &state_lock);
|
||||
send_message(message_content, &state_lock);
|
||||
|
||||
drop(state_lock);
|
||||
}
|
||||
|
@ -141,7 +128,7 @@ impl Admin {
|
|||
}
|
||||
|
||||
// Parse and process a message from the admin room
|
||||
async fn process_admin_message(db: &Database, room_message: String) -> RoomMessageEventContent {
|
||||
async fn process_admin_message(room_message: String) -> RoomMessageEventContent {
|
||||
let mut lines = room_message.lines();
|
||||
let command_line = lines.next().expect("each string has at least one line");
|
||||
let body: Vec<_> = lines.collect();
|
||||
|
@ -149,7 +136,7 @@ async fn process_admin_message(db: &Database, room_message: String) -> RoomMessa
|
|||
let admin_command = match parse_admin_command(&command_line) {
|
||||
Ok(command) => command,
|
||||
Err(error) => {
|
||||
let server_name = db.globals.server_name();
|
||||
let server_name = services().globals.server_name();
|
||||
let message = error
|
||||
.to_string()
|
||||
.replace("server.name", server_name.as_str());
|
||||
|
@ -159,7 +146,7 @@ async fn process_admin_message(db: &Database, room_message: String) -> RoomMessa
|
|||
}
|
||||
};
|
||||
|
||||
match process_admin_command(db, admin_command, body).await {
|
||||
match process_admin_command(admin_command, body).await {
|
||||
Ok(reply_message) => reply_message,
|
||||
Err(error) => {
|
||||
let markdown_message = format!(
|
||||
|
@ -322,7 +309,6 @@ enum AdminCommand {
|
|||
}
|
||||
|
||||
async fn process_admin_command(
|
||||
db: &Database,
|
||||
command: AdminCommand,
|
||||
body: Vec<&str>,
|
||||
) -> Result<RoomMessageEventContent> {
|
||||
|
@ -332,7 +318,7 @@ async fn process_admin_command(
|
|||
let appservice_config = body[1..body.len() - 1].join("\n");
|
||||
let parsed_config = serde_yaml::from_str::<serde_yaml::Value>(&appservice_config);
|
||||
match parsed_config {
|
||||
Ok(yaml) => match db.appservice.register_appservice(yaml) {
|
||||
Ok(yaml) => match services().appservice.register_appservice(yaml) {
|
||||
Ok(id) => RoomMessageEventContent::text_plain(format!(
|
||||
"Appservice registered with ID: {}.",
|
||||
id
|
||||
|
@ -355,7 +341,7 @@ async fn process_admin_command(
|
|||
}
|
||||
AdminCommand::UnregisterAppservice {
|
||||
appservice_identifier,
|
||||
} => match db.appservice.unregister_appservice(&appservice_identifier) {
|
||||
} => match services().appservice.unregister_appservice(&appservice_identifier) {
|
||||
Ok(()) => RoomMessageEventContent::text_plain("Appservice unregistered."),
|
||||
Err(e) => RoomMessageEventContent::text_plain(format!(
|
||||
"Failed to unregister appservice: {}",
|
||||
|
@ -363,7 +349,7 @@ async fn process_admin_command(
|
|||
)),
|
||||
},
|
||||
AdminCommand::ListAppservices => {
|
||||
if let Ok(appservices) = db.appservice.iter_ids().map(|ids| ids.collect::<Vec<_>>()) {
|
||||
if let Ok(appservices) = services().appservice.iter_ids().map(|ids| ids.collect::<Vec<_>>()) {
|
||||
let count = appservices.len();
|
||||
let output = format!(
|
||||
"Appservices ({}): {}",
|
||||
|
@ -380,14 +366,14 @@ async fn process_admin_command(
|
|||
}
|
||||
}
|
||||
AdminCommand::ListRooms => {
|
||||
let room_ids = db.rooms.iter_ids();
|
||||
let room_ids = services().rooms.iter_ids();
|
||||
let output = format!(
|
||||
"Rooms:\n{}",
|
||||
room_ids
|
||||
.filter_map(|r| r.ok())
|
||||
.map(|id| id.to_string()
|
||||
+ "\tMembers: "
|
||||
+ &db
|
||||
+ &services()
|
||||
.rooms
|
||||
.room_joined_count(&id)
|
||||
.ok()
|
||||
|
@ -399,7 +385,7 @@ async fn process_admin_command(
|
|||
);
|
||||
RoomMessageEventContent::text_plain(output)
|
||||
}
|
||||
AdminCommand::ListLocalUsers => match db.users.list_local_users() {
|
||||
AdminCommand::ListLocalUsers => match services().users.list_local_users() {
|
||||
Ok(users) => {
|
||||
let mut msg: String = format!("Found {} local user account(s):\n", users.len());
|
||||
msg += &users.join("\n");
|
||||
|
@ -408,7 +394,7 @@ async fn process_admin_command(
|
|||
Err(e) => RoomMessageEventContent::text_plain(e.to_string()),
|
||||
},
|
||||
AdminCommand::IncomingFederation => {
|
||||
let map = db.globals.roomid_federationhandletime.read().unwrap();
|
||||
let map = services().globals.roomid_federationhandletime.read().unwrap();
|
||||
let mut msg: String = format!("Handling {} incoming pdus:\n", map.len());
|
||||
|
||||
for (r, (e, i)) in map.iter() {
|
||||
|
@ -425,7 +411,7 @@ async fn process_admin_command(
|
|||
}
|
||||
AdminCommand::GetAuthChain { event_id } => {
|
||||
let event_id = Arc::<EventId>::from(event_id);
|
||||
if let Some(event) = db.rooms.get_pdu_json(&event_id)? {
|
||||
if let Some(event) = services().rooms.get_pdu_json(&event_id)? {
|
||||
let room_id_str = event
|
||||
.get("room_id")
|
||||
.and_then(|val| val.as_str())
|
||||
|
@ -435,7 +421,7 @@ async fn process_admin_command(
|
|||
Error::bad_database("Invalid room id field in event in database")
|
||||
})?;
|
||||
let start = Instant::now();
|
||||
let count = server_server::get_auth_chain(room_id, vec![event_id], db)
|
||||
let count = server_server::get_auth_chain(room_id, vec![event_id])
|
||||
.await?
|
||||
.count();
|
||||
let elapsed = start.elapsed();
|
||||
|
@ -486,10 +472,10 @@ async fn process_admin_command(
|
|||
}
|
||||
AdminCommand::GetPdu { event_id } => {
|
||||
let mut outlier = false;
|
||||
let mut pdu_json = db.rooms.get_non_outlier_pdu_json(&event_id)?;
|
||||
let mut pdu_json = services().rooms.get_non_outlier_pdu_json(&event_id)?;
|
||||
if pdu_json.is_none() {
|
||||
outlier = true;
|
||||
pdu_json = db.rooms.get_pdu_json(&event_id)?;
|
||||
pdu_json = services().rooms.get_pdu_json(&event_id)?;
|
||||
}
|
||||
match pdu_json {
|
||||
Some(json) => {
|
||||
|
@ -519,7 +505,7 @@ async fn process_admin_command(
|
|||
None => RoomMessageEventContent::text_plain("PDU not found."),
|
||||
}
|
||||
}
|
||||
AdminCommand::DatabaseMemoryUsage => match db._db.memory_usage() {
|
||||
AdminCommand::DatabaseMemoryUsage => match services()._db.memory_usage() {
|
||||
Ok(response) => RoomMessageEventContent::text_plain(response),
|
||||
Err(e) => RoomMessageEventContent::text_plain(format!(
|
||||
"Failed to get database memory usage: {}",
|
||||
|
@ -528,12 +514,12 @@ async fn process_admin_command(
|
|||
},
|
||||
AdminCommand::ShowConfig => {
|
||||
// Construct and send the response
|
||||
RoomMessageEventContent::text_plain(format!("{}", db.globals.config))
|
||||
RoomMessageEventContent::text_plain(format!("{}", services().globals.config))
|
||||
}
|
||||
AdminCommand::ResetPassword { username } => {
|
||||
let user_id = match UserId::parse_with_server_name(
|
||||
username.as_str().to_lowercase(),
|
||||
db.globals.server_name(),
|
||||
services().globals.server_name(),
|
||||
) {
|
||||
Ok(id) => id,
|
||||
Err(e) => {
|
||||
|
@ -545,10 +531,10 @@ async fn process_admin_command(
|
|||
};
|
||||
|
||||
// Check if the specified user is valid
|
||||
if !db.users.exists(&user_id)?
|
||||
|| db.users.is_deactivated(&user_id)?
|
||||
if !services().users.exists(&user_id)?
|
||||
|| services().users.is_deactivated(&user_id)?
|
||||
|| user_id
|
||||
== UserId::parse_with_server_name("conduit", db.globals.server_name())
|
||||
== UserId::parse_with_server_name("conduit", services().globals.server_name())
|
||||
.expect("conduit user exists")
|
||||
{
|
||||
return Ok(RoomMessageEventContent::text_plain(
|
||||
|
@ -558,7 +544,7 @@ async fn process_admin_command(
|
|||
|
||||
let new_password = utils::random_string(AUTO_GEN_PASSWORD_LENGTH);
|
||||
|
||||
match db.users.set_password(&user_id, Some(new_password.as_str())) {
|
||||
match services().users.set_password(&user_id, Some(new_password.as_str())) {
|
||||
Ok(()) => RoomMessageEventContent::text_plain(format!(
|
||||
"Successfully reset the password for user {}: {}",
|
||||
user_id, new_password
|
||||
|
@ -574,7 +560,7 @@ async fn process_admin_command(
|
|||
// Validate user id
|
||||
let user_id = match UserId::parse_with_server_name(
|
||||
username.as_str().to_lowercase(),
|
||||
db.globals.server_name(),
|
||||
services().globals.server_name(),
|
||||
) {
|
||||
Ok(id) => id,
|
||||
Err(e) => {
|
||||
|
@ -589,21 +575,21 @@ async fn process_admin_command(
|
|||
"userid {user_id} is not allowed due to historical"
|
||||
)));
|
||||
}
|
||||
if db.users.exists(&user_id)? {
|
||||
if services().users.exists(&user_id)? {
|
||||
return Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"userid {user_id} already exists"
|
||||
)));
|
||||
}
|
||||
// Create user
|
||||
db.users.create(&user_id, Some(password.as_str()))?;
|
||||
services().users.create(&user_id, Some(password.as_str()))?;
|
||||
|
||||
// Default to pretty displayname
|
||||
let displayname = format!("{} ⚡️", user_id.localpart());
|
||||
db.users
|
||||
services().users
|
||||
.set_displayname(&user_id, Some(displayname.clone()))?;
|
||||
|
||||
// Initial account data
|
||||
db.account_data.update(
|
||||
services().account_data.update(
|
||||
None,
|
||||
&user_id,
|
||||
ruma::events::GlobalAccountDataEventType::PushRules
|
||||
|
@ -614,24 +600,21 @@ async fn process_admin_command(
|
|||
global: ruma::push::Ruleset::server_default(&user_id),
|
||||
},
|
||||
},
|
||||
&db.globals,
|
||||
)?;
|
||||
|
||||
// we dont add a device since we're not the user, just the creator
|
||||
|
||||
db.flush()?;
|
||||
|
||||
// Inhibit login does not work for guests
|
||||
RoomMessageEventContent::text_plain(format!(
|
||||
"Created user with user_id: {user_id} and password: {password}"
|
||||
))
|
||||
}
|
||||
AdminCommand::DisableRoom { room_id } => {
|
||||
db.rooms.disabledroomids.insert(room_id.as_bytes(), &[])?;
|
||||
services().rooms.disabledroomids.insert(room_id.as_bytes(), &[])?;
|
||||
RoomMessageEventContent::text_plain("Room disabled.")
|
||||
}
|
||||
AdminCommand::EnableRoom { room_id } => {
|
||||
db.rooms.disabledroomids.remove(room_id.as_bytes())?;
|
||||
services().rooms.disabledroomids.remove(room_id.as_bytes())?;
|
||||
RoomMessageEventContent::text_plain("Room enabled.")
|
||||
}
|
||||
AdminCommand::DeactivateUser {
|
||||
|
@ -639,16 +622,16 @@ async fn process_admin_command(
|
|||
user_id,
|
||||
} => {
|
||||
let user_id = Arc::<UserId>::from(user_id);
|
||||
if db.users.exists(&user_id)? {
|
||||
if services().users.exists(&user_id)? {
|
||||
RoomMessageEventContent::text_plain(format!(
|
||||
"Making {} leave all rooms before deactivation...",
|
||||
user_id
|
||||
));
|
||||
|
||||
db.users.deactivate_account(&user_id)?;
|
||||
services().users.deactivate_account(&user_id)?;
|
||||
|
||||
if leave_rooms {
|
||||
db.rooms.leave_all_rooms(&user_id, &db).await?;
|
||||
services().rooms.leave_all_rooms(&user_id).await?;
|
||||
}
|
||||
|
||||
RoomMessageEventContent::text_plain(format!(
|
||||
|
@ -685,7 +668,7 @@ async fn process_admin_command(
|
|||
|
||||
if !force {
|
||||
user_ids.retain(|&user_id| {
|
||||
match db.users.is_admin(user_id, &db.rooms, &db.globals) {
|
||||
match services().users.is_admin(user_id) {
|
||||
Ok(is_admin) => match is_admin {
|
||||
true => {
|
||||
admins.push(user_id.localpart());
|
||||
|
@ -699,7 +682,7 @@ async fn process_admin_command(
|
|||
}
|
||||
|
||||
for &user_id in &user_ids {
|
||||
match db.users.deactivate_account(user_id) {
|
||||
match services().users.deactivate_account(user_id) {
|
||||
Ok(_) => deactivation_count += 1,
|
||||
Err(_) => {}
|
||||
}
|
||||
|
@ -707,7 +690,7 @@ async fn process_admin_command(
|
|||
|
||||
if leave_rooms {
|
||||
for &user_id in &user_ids {
|
||||
let _ = db.rooms.leave_all_rooms(user_id, &db).await;
|
||||
let _ = services().rooms.leave_all_rooms(user_id).await;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -814,13 +797,13 @@ fn usage_to_html(text: &str, server_name: &ServerName) -> String {
|
|||
///
|
||||
/// Users in this room are considered admins by conduit, and the room can be
|
||||
/// used to issue admin commands by talking to the server user inside it.
|
||||
pub(crate) async fn create_admin_room(db: &Database) -> Result<()> {
|
||||
let room_id = RoomId::new(db.globals.server_name());
|
||||
pub(crate) async fn create_admin_room() -> Result<()> {
|
||||
let room_id = RoomId::new(services().globals.server_name());
|
||||
|
||||
db.rooms.get_or_create_shortroomid(&room_id, &db.globals)?;
|
||||
services().rooms.get_or_create_shortroomid(&room_id)?;
|
||||
|
||||
let mutex_state = Arc::clone(
|
||||
db.globals
|
||||
services().globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.unwrap()
|
||||
|
@ -830,10 +813,10 @@ pub(crate) async fn create_admin_room(db: &Database) -> Result<()> {
|
|||
let state_lock = mutex_state.lock().await;
|
||||
|
||||
// Create a user for the server
|
||||
let conduit_user = UserId::parse_with_server_name("conduit", db.globals.server_name())
|
||||
let conduit_user = UserId::parse_with_server_name("conduit", services().globals.server_name())
|
||||
.expect("@conduit:server_name is valid");
|
||||
|
||||
db.users.create(&conduit_user, None)?;
|
||||
services().users.create(&conduit_user, None)?;
|
||||
|
||||
let mut content = RoomCreateEventContent::new(conduit_user.clone());
|
||||
content.federate = true;
|
||||
|
@ -841,7 +824,7 @@ pub(crate) async fn create_admin_room(db: &Database) -> Result<()> {
|
|||
content.room_version = RoomVersionId::V6;
|
||||
|
||||
// 1. The room create event
|
||||
db.rooms.build_and_append_pdu(
|
||||
services().rooms.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: RoomEventType::RoomCreate,
|
||||
content: to_raw_value(&content).expect("event is valid, we just created it"),
|
||||
|
@ -851,12 +834,11 @@ pub(crate) async fn create_admin_room(db: &Database) -> Result<()> {
|
|||
},
|
||||
&conduit_user,
|
||||
&room_id,
|
||||
&db,
|
||||
&state_lock,
|
||||
)?;
|
||||
|
||||
// 2. Make conduit bot join
|
||||
db.rooms.build_and_append_pdu(
|
||||
services().rooms.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: RoomEventType::RoomMember,
|
||||
content: to_raw_value(&RoomMemberEventContent {
|
||||
|
@ -876,7 +858,6 @@ pub(crate) async fn create_admin_room(db: &Database) -> Result<()> {
|
|||
},
|
||||
&conduit_user,
|
||||
&room_id,
|
||||
&db,
|
||||
&state_lock,
|
||||
)?;
|
||||
|
||||
|
@ -884,7 +865,7 @@ pub(crate) async fn create_admin_room(db: &Database) -> Result<()> {
|
|||
let mut users = BTreeMap::new();
|
||||
users.insert(conduit_user.clone(), 100.into());
|
||||
|
||||
db.rooms.build_and_append_pdu(
|
||||
services().rooms.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: RoomEventType::RoomPowerLevels,
|
||||
content: to_raw_value(&RoomPowerLevelsEventContent {
|
||||
|
@ -898,12 +879,11 @@ pub(crate) async fn create_admin_room(db: &Database) -> Result<()> {
|
|||
},
|
||||
&conduit_user,
|
||||
&room_id,
|
||||
&db,
|
||||
&state_lock,
|
||||
)?;
|
||||
|
||||
// 4.1 Join Rules
|
||||
db.rooms.build_and_append_pdu(
|
||||
services().rooms.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: RoomEventType::RoomJoinRules,
|
||||
content: to_raw_value(&RoomJoinRulesEventContent::new(JoinRule::Invite))
|
||||
|
@ -914,12 +894,11 @@ pub(crate) async fn create_admin_room(db: &Database) -> Result<()> {
|
|||
},
|
||||
&conduit_user,
|
||||
&room_id,
|
||||
&db,
|
||||
&state_lock,
|
||||
)?;
|
||||
|
||||
// 4.2 History Visibility
|
||||
db.rooms.build_and_append_pdu(
|
||||
services().rooms.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: RoomEventType::RoomHistoryVisibility,
|
||||
content: to_raw_value(&RoomHistoryVisibilityEventContent::new(
|
||||
|
@ -932,12 +911,11 @@ pub(crate) async fn create_admin_room(db: &Database) -> Result<()> {
|
|||
},
|
||||
&conduit_user,
|
||||
&room_id,
|
||||
&db,
|
||||
&state_lock,
|
||||
)?;
|
||||
|
||||
// 4.3 Guest Access
|
||||
db.rooms.build_and_append_pdu(
|
||||
services().rooms.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: RoomEventType::RoomGuestAccess,
|
||||
content: to_raw_value(&RoomGuestAccessEventContent::new(GuestAccess::Forbidden))
|
||||
|
@ -948,14 +926,13 @@ pub(crate) async fn create_admin_room(db: &Database) -> Result<()> {
|
|||
},
|
||||
&conduit_user,
|
||||
&room_id,
|
||||
&db,
|
||||
&state_lock,
|
||||
)?;
|
||||
|
||||
// 5. Events implied by name and topic
|
||||
let room_name = RoomName::parse(format!("{} Admin Room", db.globals.server_name()))
|
||||
let room_name = RoomName::parse(format!("{} Admin Room", services().globals.server_name()))
|
||||
.expect("Room name is valid");
|
||||
db.rooms.build_and_append_pdu(
|
||||
services().rooms.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: RoomEventType::RoomName,
|
||||
content: to_raw_value(&RoomNameEventContent::new(Some(room_name)))
|
||||
|
@ -966,15 +943,14 @@ pub(crate) async fn create_admin_room(db: &Database) -> Result<()> {
|
|||
},
|
||||
&conduit_user,
|
||||
&room_id,
|
||||
&db,
|
||||
&state_lock,
|
||||
)?;
|
||||
|
||||
db.rooms.build_and_append_pdu(
|
||||
services().rooms.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: RoomEventType::RoomTopic,
|
||||
content: to_raw_value(&RoomTopicEventContent {
|
||||
topic: format!("Manage {}", db.globals.server_name()),
|
||||
topic: format!("Manage {}", services().globals.server_name()),
|
||||
})
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
|
@ -983,16 +959,15 @@ pub(crate) async fn create_admin_room(db: &Database) -> Result<()> {
|
|||
},
|
||||
&conduit_user,
|
||||
&room_id,
|
||||
&db,
|
||||
&state_lock,
|
||||
)?;
|
||||
|
||||
// 6. Room alias
|
||||
let alias: Box<RoomAliasId> = format!("#admins:{}", db.globals.server_name())
|
||||
let alias: Box<RoomAliasId> = format!("#admins:{}", services().globals.server_name())
|
||||
.try_into()
|
||||
.expect("#admins:server_name is a valid alias name");
|
||||
|
||||
db.rooms.build_and_append_pdu(
|
||||
services().rooms.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: RoomEventType::RoomCanonicalAlias,
|
||||
content: to_raw_value(&RoomCanonicalAliasEventContent {
|
||||
|
@ -1006,11 +981,10 @@ pub(crate) async fn create_admin_room(db: &Database) -> Result<()> {
|
|||
},
|
||||
&conduit_user,
|
||||
&room_id,
|
||||
&db,
|
||||
&state_lock,
|
||||
)?;
|
||||
|
||||
db.rooms.set_alias(&alias, Some(&room_id), &db.globals)?;
|
||||
services().rooms.set_alias(&alias, Some(&room_id))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1019,20 +993,19 @@ pub(crate) async fn create_admin_room(db: &Database) -> Result<()> {
|
|||
///
|
||||
/// In conduit, this is equivalent to granting admin privileges.
|
||||
pub(crate) async fn make_user_admin(
|
||||
db: &Database,
|
||||
user_id: &UserId,
|
||||
displayname: String,
|
||||
) -> Result<()> {
|
||||
let admin_room_alias: Box<RoomAliasId> = format!("#admins:{}", db.globals.server_name())
|
||||
let admin_room_alias: Box<RoomAliasId> = format!("#admins:{}", services().globals.server_name())
|
||||
.try_into()
|
||||
.expect("#admins:server_name is a valid alias name");
|
||||
let room_id = db
|
||||
let room_id = services()
|
||||
.rooms
|
||||
.id_from_alias(&admin_room_alias)?
|
||||
.expect("Admin room must exist");
|
||||
|
||||
let mutex_state = Arc::clone(
|
||||
db.globals
|
||||
services().globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.unwrap()
|
||||
|
@ -1042,11 +1015,11 @@ pub(crate) async fn make_user_admin(
|
|||
let state_lock = mutex_state.lock().await;
|
||||
|
||||
// Use the server user to grant the new admin's power level
|
||||
let conduit_user = UserId::parse_with_server_name("conduit", db.globals.server_name())
|
||||
let conduit_user = UserId::parse_with_server_name("conduit", services().globals.server_name())
|
||||
.expect("@conduit:server_name is valid");
|
||||
|
||||
// Invite and join the real user
|
||||
db.rooms.build_and_append_pdu(
|
||||
services().rooms.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: RoomEventType::RoomMember,
|
||||
content: to_raw_value(&RoomMemberEventContent {
|
||||
|
@ -1066,10 +1039,9 @@ pub(crate) async fn make_user_admin(
|
|||
},
|
||||
&conduit_user,
|
||||
&room_id,
|
||||
&db,
|
||||
&state_lock,
|
||||
)?;
|
||||
db.rooms.build_and_append_pdu(
|
||||
services().rooms.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: RoomEventType::RoomMember,
|
||||
content: to_raw_value(&RoomMemberEventContent {
|
||||
|
@ -1089,7 +1061,6 @@ pub(crate) async fn make_user_admin(
|
|||
},
|
||||
&user_id,
|
||||
&room_id,
|
||||
&db,
|
||||
&state_lock,
|
||||
)?;
|
||||
|
||||
|
@ -1098,7 +1069,7 @@ pub(crate) async fn make_user_admin(
|
|||
users.insert(conduit_user.to_owned(), 100.into());
|
||||
users.insert(user_id.to_owned(), 100.into());
|
||||
|
||||
db.rooms.build_and_append_pdu(
|
||||
services().rooms.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: RoomEventType::RoomPowerLevels,
|
||||
content: to_raw_value(&RoomPowerLevelsEventContent {
|
||||
|
@ -1112,17 +1083,16 @@ pub(crate) async fn make_user_admin(
|
|||
},
|
||||
&conduit_user,
|
||||
&room_id,
|
||||
&db,
|
||||
&state_lock,
|
||||
)?;
|
||||
|
||||
// Send welcome message
|
||||
db.rooms.build_and_append_pdu(
|
||||
services().rooms.build_and_append_pdu(
|
||||
PduBuilder {
|
||||
event_type: RoomEventType::RoomMessage,
|
||||
content: to_raw_value(&RoomMessageEventContent::text_html(
|
||||
format!("## Thank you for trying out Conduit!\n\nConduit is currently in Beta. This means you can join and participate in most Matrix rooms, but not all features are supported and you might run into bugs from time to time.\n\nHelpful links:\n> Website: https://conduit.rs\n> Git and Documentation: https://gitlab.com/famedly/conduit\n> Report issues: https://gitlab.com/famedly/conduit/-/issues\n\nFor a list of available commands, send the following message in this room: `@conduit:{}: --help`\n\nHere are some rooms you can join (by typing the command):\n\nConduit room (Ask questions and get notified on updates):\n`/join #conduit:fachschaften.org`\n\nConduit lounge (Off-topic, only Conduit users are allowed to join)\n`/join #conduit-lounge:conduit.rs`", db.globals.server_name()).to_owned(),
|
||||
format!("<h2>Thank you for trying out Conduit!</h2>\n<p>Conduit is currently in Beta. This means you can join and participate in most Matrix rooms, but not all features are supported and you might run into bugs from time to time.</p>\n<p>Helpful links:</p>\n<blockquote>\n<p>Website: https://conduit.rs<br>Git and Documentation: https://gitlab.com/famedly/conduit<br>Report issues: https://gitlab.com/famedly/conduit/-/issues</p>\n</blockquote>\n<p>For a list of available commands, send the following message in this room: <code>@conduit:{}: --help</code></p>\n<p>Here are some rooms you can join (by typing the command):</p>\n<p>Conduit room (Ask questions and get notified on updates):<br><code>/join #conduit:fachschaften.org</code></p>\n<p>Conduit lounge (Off-topic, only Conduit users are allowed to join)<br><code>/join #conduit-lounge:conduit.rs</code></p>\n", db.globals.server_name()).to_owned(),
|
||||
format!("## Thank you for trying out Conduit!\n\nConduit is currently in Beta. This means you can join and participate in most Matrix rooms, but not all features are supported and you might run into bugs from time to time.\n\nHelpful links:\n> Website: https://conduit.rs\n> Git and Documentation: https://gitlab.com/famedly/conduit\n> Report issues: https://gitlab.com/famedly/conduit/-/issues\n\nFor a list of available commands, send the following message in this room: `@conduit:{}: --help`\n\nHere are some rooms you can join (by typing the command):\n\nConduit room (Ask questions and get notified on updates):\n`/join #conduit:fachschaften.org`\n\nConduit lounge (Off-topic, only Conduit users are allowed to join)\n`/join #conduit-lounge:conduit.rs`", services().globals.server_name()).to_owned(),
|
||||
format!("<h2>Thank you for trying out Conduit!</h2>\n<p>Conduit is currently in Beta. This means you can join and participate in most Matrix rooms, but not all features are supported and you might run into bugs from time to time.</p>\n<p>Helpful links:</p>\n<blockquote>\n<p>Website: https://conduit.rs<br>Git and Documentation: https://gitlab.com/famedly/conduit<br>Report issues: https://gitlab.com/famedly/conduit/-/issues</p>\n</blockquote>\n<p>For a list of available commands, send the following message in this room: <code>@conduit:{}: --help</code></p>\n<p>Here are some rooms you can join (by typing the command):</p>\n<p>Conduit room (Ask questions and get notified on updates):<br><code>/join #conduit:fachschaften.org</code></p>\n<p>Conduit lounge (Off-topic, only Conduit users are allowed to join)<br><code>/join #conduit-lounge:conduit.rs</code></p>\n", services().globals.server_name()).to_owned(),
|
||||
))
|
||||
.expect("event is valid, we just created it"),
|
||||
unsigned: None,
|
||||
|
@ -1131,7 +1101,6 @@ pub(crate) async fn make_user_admin(
|
|||
},
|
||||
&conduit_user,
|
||||
&room_id,
|
||||
&db,
|
||||
&state_lock,
|
||||
)?;
|
||||
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
pub trait Data {
|
||||
type Iter: Iterator;
|
||||
/// Registers an appservice and returns the ID to the caller
|
||||
pub fn register_appservice(&self, yaml: serde_yaml::Value) -> Result<String>;
|
||||
fn register_appservice(&self, yaml: serde_yaml::Value) -> Result<String>;
|
||||
|
||||
/// Remove an appservice registration
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `service_name` - the name you send to register the service previously
|
||||
pub fn unregister_appservice(&self, service_name: &str) -> Result<()>;
|
||||
fn unregister_appservice(&self, service_name: &str) -> Result<()>;
|
||||
|
||||
pub fn get_registration(&self, id: &str) -> Result<Option<serde_yaml::Value>>;
|
||||
fn get_registration(&self, id: &str) -> Result<Option<serde_yaml::Value>>;
|
||||
|
||||
pub fn iter_ids(&self) -> Result<impl Iterator<Item = Result<String>> + '_>;
|
||||
fn iter_ids(&self) -> Result<Self::Iter<Item = Result<String>>>;
|
||||
|
||||
pub fn all(&self) -> Result<Vec<(String, serde_yaml::Value)>>;
|
||||
fn all(&self) -> Result<Vec<(String, serde_yaml::Value)>>;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{utils, Error, Result};
|
||||
use crate::{utils, Error, Result, services};
|
||||
use ruma::{
|
||||
api::client::{
|
||||
backup::{BackupAlgorithm, KeyBackupData, RoomKeyBackup},
|
||||
|
@ -9,22 +9,13 @@ use ruma::{
|
|||
};
|
||||
use std::{collections::BTreeMap, sync::Arc};
|
||||
|
||||
use super::abstraction::Tree;
|
||||
|
||||
pub struct KeyBackups {
|
||||
pub(super) backupid_algorithm: Arc<dyn Tree>, // BackupId = UserId + Version(Count)
|
||||
pub(super) backupid_etag: Arc<dyn Tree>, // BackupId = UserId + Version(Count)
|
||||
pub(super) backupkeyid_backup: Arc<dyn Tree>, // BackupKeyId = UserId + Version + RoomId + SessionId
|
||||
}
|
||||
|
||||
impl KeyBackups {
|
||||
pub fn create_backup(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
backup_metadata: &Raw<BackupAlgorithm>,
|
||||
globals: &super::globals::Globals,
|
||||
) -> Result<String> {
|
||||
let version = globals.next_count()?.to_string();
|
||||
let version = services().globals.next_count()?.to_string();
|
||||
|
||||
let mut key = user_id.as_bytes().to_vec();
|
||||
key.push(0xff);
|
||||
|
@ -35,7 +26,7 @@ impl KeyBackups {
|
|||
&serde_json::to_vec(backup_metadata).expect("BackupAlgorithm::to_vec always works"),
|
||||
)?;
|
||||
self.backupid_etag
|
||||
.insert(&key, &globals.next_count()?.to_be_bytes())?;
|
||||
.insert(&key, &services().globals.next_count()?.to_be_bytes())?;
|
||||
Ok(version)
|
||||
}
|
||||
|
||||
|
@ -61,7 +52,6 @@ impl KeyBackups {
|
|||
user_id: &UserId,
|
||||
version: &str,
|
||||
backup_metadata: &Raw<BackupAlgorithm>,
|
||||
globals: &super::globals::Globals,
|
||||
) -> Result<String> {
|
||||
let mut key = user_id.as_bytes().to_vec();
|
||||
key.push(0xff);
|
||||
|
@ -77,7 +67,7 @@ impl KeyBackups {
|
|||
self.backupid_algorithm
|
||||
.insert(&key, backup_metadata.json().get().as_bytes())?;
|
||||
self.backupid_etag
|
||||
.insert(&key, &globals.next_count()?.to_be_bytes())?;
|
||||
.insert(&key, &services().globals.next_count()?.to_be_bytes())?;
|
||||
Ok(version.to_owned())
|
||||
}
|
||||
|
||||
|
@ -157,7 +147,6 @@ impl KeyBackups {
|
|||
room_id: &RoomId,
|
||||
session_id: &str,
|
||||
key_data: &Raw<KeyBackupData>,
|
||||
globals: &super::globals::Globals,
|
||||
) -> Result<()> {
|
||||
let mut key = user_id.as_bytes().to_vec();
|
||||
key.push(0xff);
|
||||
|
@ -171,7 +160,7 @@ impl KeyBackups {
|
|||
}
|
||||
|
||||
self.backupid_etag
|
||||
.insert(&key, &globals.next_count()?.to_be_bytes())?;
|
||||
.insert(&key, &services().globals.next_count()?.to_be_bytes())?;
|
||||
|
||||
key.push(0xff);
|
||||
key.extend_from_slice(room_id.as_bytes());
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use crate::database::globals::Globals;
|
||||
use image::{imageops::FilterType, GenericImageView};
|
||||
|
||||
use super::abstraction::Tree;
|
||||
|
|
28
src/service/mod.rs
Normal file
28
src/service/mod.rs
Normal file
|
@ -0,0 +1,28 @@
|
|||
pub mod pdu;
|
||||
pub mod appservice;
|
||||
pub mod pusher;
|
||||
pub mod rooms;
|
||||
pub mod transaction_ids;
|
||||
pub mod uiaa;
|
||||
pub mod users;
|
||||
pub mod account_data;
|
||||
pub mod admin;
|
||||
pub mod globals;
|
||||
pub mod key_backups;
|
||||
pub mod media;
|
||||
pub mod sending;
|
||||
|
||||
pub struct Services<D> {
|
||||
pub appservice: appservice::Service<D>,
|
||||
pub pusher: pusher::Service<D>,
|
||||
pub rooms: rooms::Service<D>,
|
||||
pub transaction_ids: transaction_ids::Service<D>,
|
||||
pub uiaa: uiaa::Service<D>,
|
||||
pub users: users::Service<D>,
|
||||
//pub account_data: account_data::Service<D>,
|
||||
//pub admin: admin::Service<D>,
|
||||
pub globals: globals::Service<D>,
|
||||
//pub key_backups: key_backups::Service<D>,
|
||||
//pub media: media::Service<D>,
|
||||
//pub sending: sending::Service<D>,
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{Database, Error};
|
||||
use crate::{Database, Error, services};
|
||||
use ruma::{
|
||||
events::{
|
||||
room::member::RoomMemberEventContent, AnyEphemeralRoomEvent, AnyRoomEvent, AnyStateEvent,
|
||||
|
@ -332,7 +332,6 @@ impl Ord for PduEvent {
|
|||
/// Returns a tuple of the new `EventId` and the PDU as a `BTreeMap<String, CanonicalJsonValue>`.
|
||||
pub(crate) fn gen_event_id_canonical_json(
|
||||
pdu: &RawJsonValue,
|
||||
db: &Database,
|
||||
) -> crate::Result<(Box<EventId>, CanonicalJsonObject)> {
|
||||
let value: CanonicalJsonObject = serde_json::from_str(pdu.get()).map_err(|e| {
|
||||
warn!("Error parsing incoming event {:?}: {:?}", pdu, e);
|
||||
|
@ -344,7 +343,7 @@ pub(crate) fn gen_event_id_canonical_json(
|
|||
.and_then(|id| RoomId::parse(id.as_str()?).ok())
|
||||
.ok_or_else(|| Error::bad_database("PDU in db has invalid room_id."))?;
|
||||
|
||||
let room_version_id = db.rooms.get_room_version(&room_id);
|
||||
let room_version_id = services().rooms.get_room_version(&room_id);
|
||||
|
||||
let event_id = format!(
|
||||
"${}",
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
use ruma::{UserId, api::client::push::{set_pusher, get_pushers}};
|
||||
|
||||
pub trait Data {
|
||||
fn set_pusher(&self, sender: &UserId, pusher: set_pusher::v3::Pusher) -> Result<()>;
|
||||
|
||||
pub fn get_pusher(&self, senderkey: &[u8]) -> Result<Option<get_pushers::v3::Pusher>>;
|
||||
fn get_pusher(&self, senderkey: &[u8]) -> Result<Option<get_pushers::v3::Pusher>>;
|
||||
|
||||
pub fn get_pushers(&self, sender: &UserId) -> Result<Vec<get_pushers::v3::Pusher>>;
|
||||
fn get_pushers(&self, sender: &UserId) -> Result<Vec<get_pushers::v3::Pusher>>;
|
||||
|
||||
pub fn get_pusher_senderkeys<'a>(
|
||||
fn get_pusher_senderkeys<'a>(
|
||||
&'a self,
|
||||
sender: &UserId,
|
||||
) -> impl Iterator<Item = Vec<u8>> + 'a;
|
||||
|
|
|
@ -1,7 +1,27 @@
|
|||
mod data;
|
||||
pub use data::Data;
|
||||
|
||||
use crate::service::*;
|
||||
use crate::{services, Error, PduEvent};
|
||||
use bytes::BytesMut;
|
||||
use ruma::{
|
||||
api::{
|
||||
client::push::{get_pushers, set_pusher, PusherKind},
|
||||
push_gateway::send_event_notification::{
|
||||
self,
|
||||
v1::{Device, Notification, NotificationCounts, NotificationPriority},
|
||||
},
|
||||
MatrixVersion, OutgoingRequest, SendAccessToken,
|
||||
},
|
||||
events::{
|
||||
room::{name::RoomNameEventContent, power_levels::RoomPowerLevelsEventContent},
|
||||
AnySyncRoomEvent, RoomEventType, StateEventType,
|
||||
},
|
||||
push::{Action, PushConditionRoomCtx, PushFormat, Ruleset, Tweak},
|
||||
serde::Raw,
|
||||
uint, RoomId, UInt, UserId,
|
||||
};
|
||||
use std::{fmt::Debug, mem};
|
||||
use tracing::{error, info, warn};
|
||||
|
||||
pub struct Service<D: Data> {
|
||||
db: D,
|
||||
|
@ -27,9 +47,8 @@ impl Service<_> {
|
|||
self.db.get_pusher_senderkeys(sender)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(globals, destination, request))]
|
||||
#[tracing::instrument(skip(destination, request))]
|
||||
pub async fn send_request<T: OutgoingRequest>(
|
||||
globals: &crate::database::globals::Globals,
|
||||
destination: &str,
|
||||
request: T,
|
||||
) -> Result<T::IncomingResponse>
|
||||
|
@ -57,7 +76,7 @@ impl Service<_> {
|
|||
//*reqwest_request.timeout_mut() = Some(Duration::from_secs(5));
|
||||
|
||||
let url = reqwest_request.url().clone();
|
||||
let response = globals.default_client().execute(reqwest_request).await;
|
||||
let response = services().globals.default_client().execute(reqwest_request).await;
|
||||
|
||||
match response {
|
||||
Ok(mut response) => {
|
||||
|
@ -105,19 +124,19 @@ impl Service<_> {
|
|||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(user, unread, pusher, ruleset, pdu, db))]
|
||||
#[tracing::instrument(skip(user, unread, pusher, ruleset, pdu))]
|
||||
pub async fn send_push_notice(
|
||||
&self,
|
||||
user: &UserId,
|
||||
unread: UInt,
|
||||
pusher: &get_pushers::v3::Pusher,
|
||||
ruleset: Ruleset,
|
||||
pdu: &PduEvent,
|
||||
db: &Database,
|
||||
) -> Result<()> {
|
||||
let mut notify = None;
|
||||
let mut tweaks = Vec::new();
|
||||
|
||||
let power_levels: RoomPowerLevelsEventContent = db
|
||||
let power_levels: RoomPowerLevelsEventContent = services()
|
||||
.rooms
|
||||
.room_state_get(&pdu.room_id, &StateEventType::RoomPowerLevels, "")?
|
||||
.map(|ev| {
|
||||
|
@ -127,13 +146,12 @@ impl Service<_> {
|
|||
.transpose()?
|
||||
.unwrap_or_default();
|
||||
|
||||
for action in get_actions(
|
||||
for action in self.get_actions(
|
||||
user,
|
||||
&ruleset,
|
||||
&power_levels,
|
||||
&pdu.to_sync_room_event(),
|
||||
&pdu.room_id,
|
||||
db,
|
||||
)? {
|
||||
let n = match action {
|
||||
Action::DontNotify => false,
|
||||
|
@ -155,27 +173,26 @@ impl Service<_> {
|
|||
}
|
||||
|
||||
if notify == Some(true) {
|
||||
send_notice(unread, pusher, tweaks, pdu, db).await?;
|
||||
self.send_notice(unread, pusher, tweaks, pdu).await?;
|
||||
}
|
||||
// Else the event triggered no actions
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(user, ruleset, pdu, db))]
|
||||
#[tracing::instrument(skip(user, ruleset, pdu))]
|
||||
pub fn get_actions<'a>(
|
||||
&self,
|
||||
user: &UserId,
|
||||
ruleset: &'a Ruleset,
|
||||
power_levels: &RoomPowerLevelsEventContent,
|
||||
pdu: &Raw<AnySyncRoomEvent>,
|
||||
room_id: &RoomId,
|
||||
db: &Database,
|
||||
) -> Result<&'a [Action]> {
|
||||
let ctx = PushConditionRoomCtx {
|
||||
room_id: room_id.to_owned(),
|
||||
member_count: 10_u32.into(), // TODO: get member count efficiently
|
||||
user_display_name: db
|
||||
.users
|
||||
user_display_name: services().users
|
||||
.displayname(user)?
|
||||
.unwrap_or_else(|| user.localpart().to_owned()),
|
||||
users_power_levels: power_levels.users.clone(),
|
||||
|
@ -186,13 +203,13 @@ impl Service<_> {
|
|||
Ok(ruleset.get_actions(pdu, &ctx))
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(unread, pusher, tweaks, event, db))]
|
||||
#[tracing::instrument(skip(unread, pusher, tweaks, event))]
|
||||
async fn send_notice(
|
||||
&self,
|
||||
unread: UInt,
|
||||
pusher: &get_pushers::v3::Pusher,
|
||||
tweaks: Vec<Tweak>,
|
||||
event: &PduEvent,
|
||||
db: &Database,
|
||||
) -> Result<()> {
|
||||
// TODO: email
|
||||
if pusher.kind == PusherKind::Email {
|
||||
|
@ -240,12 +257,8 @@ impl Service<_> {
|
|||
}
|
||||
|
||||
if event_id_only {
|
||||
send_request(
|
||||
&db.globals,
|
||||
url,
|
||||
send_event_notification::v1::Request::new(notifi),
|
||||
)
|
||||
.await?;
|
||||
self.send_request(url, send_event_notification::v1::Request::new(notifi))
|
||||
.await?;
|
||||
} else {
|
||||
notifi.sender = Some(&event.sender);
|
||||
notifi.event_type = Some(&event.kind);
|
||||
|
@ -256,11 +269,11 @@ impl Service<_> {
|
|||
notifi.user_is_target = event.state_key.as_deref() == Some(event.sender.as_str());
|
||||
}
|
||||
|
||||
let user_name = db.users.displayname(&event.sender)?;
|
||||
let user_name = services().users.displayname(&event.sender)?;
|
||||
notifi.sender_display_name = user_name.as_deref();
|
||||
|
||||
let room_name = if let Some(room_name_pdu) =
|
||||
db.rooms
|
||||
services().rooms
|
||||
.room_state_get(&event.room_id, &StateEventType::RoomName, "")?
|
||||
{
|
||||
serde_json::from_str::<RoomNameEventContent>(room_name_pdu.content.get())
|
||||
|
@ -272,8 +285,7 @@ impl Service<_> {
|
|||
|
||||
notifi.room_name = room_name.as_deref();
|
||||
|
||||
send_request(
|
||||
&db.globals,
|
||||
self.send_request(
|
||||
url,
|
||||
send_event_notification::v1::Request::new(notifi),
|
||||
)
|
||||
|
|
|
@ -1,22 +1,24 @@
|
|||
use ruma::{RoomId, RoomAliasId};
|
||||
|
||||
pub trait Data {
|
||||
/// Creates or updates the alias to the given room id.
|
||||
pub fn set_alias(
|
||||
fn set_alias(
|
||||
alias: &RoomAliasId,
|
||||
room_id: &RoomId
|
||||
) -> Result<()>;
|
||||
|
||||
/// Forgets about an alias. Returns an error if the alias did not exist.
|
||||
pub fn remove_alias(
|
||||
fn remove_alias(
|
||||
alias: &RoomAliasId,
|
||||
) -> Result<()>;
|
||||
|
||||
/// Looks up the roomid for the given alias.
|
||||
pub fn resolve_local_alias(
|
||||
fn resolve_local_alias(
|
||||
alias: &RoomAliasId,
|
||||
) -> Result<()>;
|
||||
|
||||
/// Returns all local aliases that point to the given room
|
||||
pub fn local_aliases_for_room(
|
||||
fn local_aliases_for_room(
|
||||
alias: &RoomAliasId,
|
||||
) -> Result<()>;
|
||||
}
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
mod data;
|
||||
pub use data::Data;
|
||||
|
||||
use crate::service::*;
|
||||
use ruma::{RoomAliasId, RoomId};
|
||||
|
||||
pub struct Service<D: Data> {
|
||||
db: D,
|
||||
}
|
||||
|
||||
impl Service<_> {
|
||||
#[tracing::instrument(skip(self, globals))]
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn set_alias(
|
||||
&self,
|
||||
alias: &RoomAliasId,
|
||||
|
@ -17,7 +16,7 @@ impl Service<_> {
|
|||
self.db.set_alias(alias, room_id)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self, globals))]
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn remove_alias(
|
||||
&self,
|
||||
alias: &RoomAliasId,
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use std::collections::HashSet;
|
||||
|
||||
pub trait Data {
|
||||
fn get_cached_eventid_authchain<'a>() -> Result<HashSet<u64>>;
|
||||
fn cache_eventid_authchain<'a>(shorteventid: u64, auth_chain: &HashSet<u64>) -> Result<HashSet<u64>>;
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
mod data;
|
||||
use std::{sync::Arc, collections::HashSet};
|
||||
|
||||
pub use data::Data;
|
||||
|
||||
use crate::service::*;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use ruma::RoomId;
|
||||
|
||||
pub trait Data {
|
||||
/// Adds the room to the public room directory
|
||||
fn set_public(room_id: &RoomId) -> Result<()>;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
mod data;
|
||||
pub use data::Data;
|
||||
use ruma::RoomId;
|
||||
|
||||
use crate::service::*;
|
||||
|
||||
|
@ -10,21 +11,21 @@ pub struct Service<D: Data> {
|
|||
impl Service<_> {
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn set_public(&self, room_id: &RoomId) -> Result<()> {
|
||||
self.db.set_public(&self, room_id)
|
||||
self.db.set_public(room_id)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn set_not_public(&self, room_id: &RoomId) -> Result<()> {
|
||||
self.db.set_not_public(&self, room_id)
|
||||
self.db.set_not_public(room_id)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn is_public_room(&self, room_id: &RoomId) -> Result<bool> {
|
||||
self.db.is_public_room(&self, room_id)
|
||||
self.db.is_public_room(room_id)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn public_rooms(&self) -> impl Iterator<Item = Result<Box<RoomId>>> + '_ {
|
||||
self.db.public_rooms(&self, room_id)
|
||||
self.db.public_rooms()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
pub mod presence;
|
||||
pub mod read_receipt;
|
||||
pub mod typing;
|
||||
|
||||
pub struct Service<D> {
|
||||
presence: presence::Service<D>,
|
||||
read_receipt: read_receipt::Service<D>,
|
||||
typing: typing::Service<D>,
|
||||
}
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use ruma::{UserId, RoomId, events::presence::PresenceEvent};
|
||||
|
||||
pub trait Data {
|
||||
/// Adds a presence event which will be saved until a new event replaces it.
|
||||
///
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
mod data;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub use data::Data;
|
||||
use ruma::{RoomId, UserId, events::presence::PresenceEvent};
|
||||
|
||||
use crate::service::*;
|
||||
|
||||
|
@ -108,7 +111,7 @@ impl Service<_> {
|
|||
}*/
|
||||
|
||||
/// Returns the most recent presence updates that happened after the event with id `since`.
|
||||
#[tracing::instrument(skip(self, since, _rooms, _globals))]
|
||||
#[tracing::instrument(skip(self, since, room_id))]
|
||||
pub fn presence_since(
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use ruma::{RoomId, events::receipt::ReceiptEvent, UserId, serde::Raw};
|
||||
|
||||
pub trait Data {
|
||||
/// Replaces the previous read receipt.
|
||||
fn readreceipt_update(
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
mod data;
|
||||
pub use data::Data;
|
||||
|
||||
use crate::service::*;
|
||||
use ruma::{RoomId, UserId, events::receipt::ReceiptEvent, serde::Raw};
|
||||
|
||||
pub struct Service<D: Data> {
|
||||
db: D,
|
||||
|
@ -15,7 +14,7 @@ impl Service<_> {
|
|||
room_id: &RoomId,
|
||||
event: ReceiptEvent,
|
||||
) -> Result<()> {
|
||||
self.db.readreceipt_update(user_id, room_id, event);
|
||||
self.db.readreceipt_update(user_id, room_id, event)
|
||||
}
|
||||
|
||||
/// Returns an iterator over the most recent read_receipts in a room that happened after the event with id `since`.
|
||||
|
@ -35,7 +34,7 @@ impl Service<_> {
|
|||
}
|
||||
|
||||
/// Sets a private read marker at `count`.
|
||||
#[tracing::instrument(skip(self, globals))]
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn private_read_set(&self, room_id: &RoomId, user_id: &UserId, count: u64) -> Result<()> {
|
||||
self.db.private_read_set(room_id, user_id, count)
|
||||
}
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
use std::collections::HashSet;
|
||||
|
||||
use ruma::{UserId, RoomId};
|
||||
|
||||
pub trait Data {
|
||||
/// Sets a user as typing until the timeout timestamp is reached or roomtyping_remove is
|
||||
/// called.
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
mod data;
|
||||
pub use data::Data;
|
||||
use ruma::{UserId, RoomId};
|
||||
|
||||
use crate::service::*;
|
||||
|
||||
|
@ -66,7 +67,6 @@ impl Service<_> {
|
|||
*/
|
||||
|
||||
/// Returns the count of the last typing update in this room.
|
||||
#[tracing::instrument(skip(self, globals))]
|
||||
pub fn last_typing_update(&self, room_id: &RoomId) -> Result<u64> {
|
||||
self.db.last_typing_update(room_id)
|
||||
}
|
||||
|
|
|
@ -1,8 +1,29 @@
|
|||
|
||||
/// An async function that can recursively call itself.
|
||||
type AsyncRecursiveType<'a, T> = Pin<Box<dyn Future<Output = T> + 'a + Send>>;
|
||||
|
||||
use crate::service::*;
|
||||
use std::{
|
||||
collections::{btree_map, hash_map, BTreeMap, HashMap, HashSet},
|
||||
pin::Pin,
|
||||
sync::{Arc, RwLock},
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use futures_util::Future;
|
||||
use ruma::{
|
||||
api::{
|
||||
client::error::ErrorKind,
|
||||
federation::event::{get_event, get_room_state_ids},
|
||||
},
|
||||
events::{room::create::RoomCreateEventContent, StateEventType},
|
||||
int,
|
||||
serde::Base64,
|
||||
signatures::CanonicalJsonValue,
|
||||
state_res::{self, RoomVersion, StateMap},
|
||||
uint, EventId, MilliSecondsSinceUnixEpoch, RoomId, ServerName,
|
||||
};
|
||||
use tracing::{error, info, trace, warn};
|
||||
|
||||
use crate::{service::*, services, Error, PduEvent};
|
||||
|
||||
pub struct Service;
|
||||
|
||||
|
@ -31,45 +52,47 @@ impl Service {
|
|||
/// it
|
||||
/// 14. Use state resolution to find new room state
|
||||
// We use some AsyncRecursiveType hacks here so we can call this async funtion recursively
|
||||
#[tracing::instrument(skip(value, is_timeline_event, db, pub_key_map))]
|
||||
#[tracing::instrument(skip(value, is_timeline_event, pub_key_map))]
|
||||
pub(crate) async fn handle_incoming_pdu<'a>(
|
||||
&self,
|
||||
origin: &'a ServerName,
|
||||
event_id: &'a EventId,
|
||||
room_id: &'a RoomId,
|
||||
value: BTreeMap<String, CanonicalJsonValue>,
|
||||
is_timeline_event: bool,
|
||||
db: &'a Database,
|
||||
pub_key_map: &'a RwLock<BTreeMap<String, BTreeMap<String, Base64>>>,
|
||||
) -> Result<Option<Vec<u8>>> {
|
||||
db.rooms.exists(room_id)?.ok_or(Error::BadRequest(ErrorKind::NotFound, "Room is unknown to this server"))?;
|
||||
services().rooms.exists(room_id)?.ok_or(Error::BadRequest(
|
||||
ErrorKind::NotFound,
|
||||
"Room is unknown to this server",
|
||||
))?;
|
||||
|
||||
services()
|
||||
.rooms
|
||||
.is_disabled(room_id)?
|
||||
.ok_or(Error::BadRequest(
|
||||
ErrorKind::Forbidden,
|
||||
"Federation of this room is currently disabled on this server.",
|
||||
))?;
|
||||
|
||||
db.rooms.is_disabled(room_id)?.ok_or(Error::BadRequest(ErrorKind::Forbidden, "Federation of this room is currently disabled on this server."))?;
|
||||
|
||||
// 1. Skip the PDU if we already have it as a timeline event
|
||||
if let Some(pdu_id) = db.rooms.get_pdu_id(event_id)? {
|
||||
return Some(pdu_id.to_vec());
|
||||
if let Some(pdu_id) = services().rooms.get_pdu_id(event_id)? {
|
||||
return Ok(Some(pdu_id.to_vec()));
|
||||
}
|
||||
|
||||
let create_event = db
|
||||
let create_event = services()
|
||||
.rooms
|
||||
.room_state_get(room_id, &StateEventType::RoomCreate, "")?
|
||||
.ok_or_else(|| Error::bad_database("Failed to find create event in db."))?;
|
||||
|
||||
let first_pdu_in_room = db
|
||||
let first_pdu_in_room = services()
|
||||
.rooms
|
||||
.first_pdu_in_room(room_id)?
|
||||
.ok_or_else(|| Error::bad_database("Failed to find first pdu in db."))?;
|
||||
|
||||
let (incoming_pdu, val) = handle_outlier_pdu(
|
||||
origin,
|
||||
&create_event,
|
||||
event_id,
|
||||
room_id,
|
||||
value,
|
||||
db,
|
||||
pub_key_map,
|
||||
)
|
||||
.await?;
|
||||
let (incoming_pdu, val) = self
|
||||
.handle_outlier_pdu(origin, &create_event, event_id, room_id, value, pub_key_map)
|
||||
.await?;
|
||||
|
||||
// 8. if not timeline event: stop
|
||||
if !is_timeline_event {
|
||||
|
@ -82,15 +105,27 @@ impl Service {
|
|||
}
|
||||
|
||||
// 9. Fetch any missing prev events doing all checks listed here starting at 1. These are timeline events
|
||||
let sorted_prev_events = fetch_unknown_prev_events(incoming_pdu.prev_events.clone());
|
||||
let (sorted_prev_events, eventid_info) = self.fetch_unknown_prev_events(
|
||||
origin,
|
||||
&create_event,
|
||||
room_id,
|
||||
pub_key_map,
|
||||
incoming_pdu.prev_events.clone(),
|
||||
);
|
||||
|
||||
let mut errors = 0;
|
||||
for prev_id in dbg!(sorted) {
|
||||
for prev_id in dbg!(sorted_prev_events) {
|
||||
// Check for disabled again because it might have changed
|
||||
db.rooms.is_disabled(room_id)?.ok_or(Error::BadRequest(ErrorKind::Forbidden, "Federation of
|
||||
this room is currently disabled on this server."))?;
|
||||
services()
|
||||
.rooms
|
||||
.is_disabled(room_id)?
|
||||
.ok_or(Error::BadRequest(
|
||||
ErrorKind::Forbidden,
|
||||
"Federation of
|
||||
this room is currently disabled on this server.",
|
||||
))?;
|
||||
|
||||
if let Some((time, tries)) = db
|
||||
if let Some((time, tries)) = services()
|
||||
.globals
|
||||
.bad_event_ratelimiter
|
||||
.read()
|
||||
|
@ -120,26 +155,27 @@ impl Service {
|
|||
}
|
||||
|
||||
let start_time = Instant::now();
|
||||
db.globals
|
||||
services()
|
||||
.globals
|
||||
.roomid_federationhandletime
|
||||
.write()
|
||||
.unwrap()
|
||||
.insert(room_id.to_owned(), ((*prev_id).to_owned(), start_time));
|
||||
|
||||
if let Err(e) = upgrade_outlier_to_timeline_pdu(
|
||||
pdu,
|
||||
json,
|
||||
&create_event,
|
||||
origin,
|
||||
db,
|
||||
room_id,
|
||||
pub_key_map,
|
||||
)
|
||||
.await
|
||||
if let Err(e) = self
|
||||
.upgrade_outlier_to_timeline_pdu(
|
||||
pdu,
|
||||
json,
|
||||
&create_event,
|
||||
origin,
|
||||
room_id,
|
||||
pub_key_map,
|
||||
)
|
||||
.await
|
||||
{
|
||||
errors += 1;
|
||||
warn!("Prev event {} failed: {}", prev_id, e);
|
||||
match db
|
||||
match services()
|
||||
.globals
|
||||
.bad_event_ratelimiter
|
||||
.write()
|
||||
|
@ -155,7 +191,8 @@ impl Service {
|
|||
}
|
||||
}
|
||||
let elapsed = start_time.elapsed();
|
||||
db.globals
|
||||
services()
|
||||
.globals
|
||||
.roomid_federationhandletime
|
||||
.write()
|
||||
.unwrap()
|
||||
|
@ -172,22 +209,23 @@ impl Service {
|
|||
// Done with prev events, now handling the incoming event
|
||||
|
||||
let start_time = Instant::now();
|
||||
db.globals
|
||||
services()
|
||||
.globals
|
||||
.roomid_federationhandletime
|
||||
.write()
|
||||
.unwrap()
|
||||
.insert(room_id.to_owned(), (event_id.to_owned(), start_time));
|
||||
let r = upgrade_outlier_to_timeline_pdu(
|
||||
let r = services().rooms.event_handler.upgrade_outlier_to_timeline_pdu(
|
||||
incoming_pdu,
|
||||
val,
|
||||
&create_event,
|
||||
origin,
|
||||
db,
|
||||
room_id,
|
||||
pub_key_map,
|
||||
)
|
||||
.await;
|
||||
db.globals
|
||||
services()
|
||||
.globals
|
||||
.roomid_federationhandletime
|
||||
.write()
|
||||
.unwrap()
|
||||
|
@ -196,22 +234,23 @@ impl Service {
|
|||
r
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(create_event, value, db, pub_key_map))]
|
||||
#[tracing::instrument(skip(create_event, value, pub_key_map))]
|
||||
fn handle_outlier_pdu<'a>(
|
||||
&self,
|
||||
origin: &'a ServerName,
|
||||
create_event: &'a PduEvent,
|
||||
event_id: &'a EventId,
|
||||
room_id: &'a RoomId,
|
||||
value: BTreeMap<String, CanonicalJsonValue>,
|
||||
db: &'a Database,
|
||||
pub_key_map: &'a RwLock<BTreeMap<String, BTreeMap<String, Base64>>>,
|
||||
) -> AsyncRecursiveType<'a, Result<(Arc<PduEvent>, BTreeMap<String, CanonicalJsonValue>), String>> {
|
||||
) -> AsyncRecursiveType<'a, Result<(Arc<PduEvent>, BTreeMap<String, CanonicalJsonValue>), String>>
|
||||
{
|
||||
Box::pin(async move {
|
||||
// TODO: For RoomVersion6 we must check that Raw<..> is canonical do we anywhere?: https://matrix.org/docs/spec/rooms/v6#canonical-json
|
||||
|
||||
// We go through all the signatures we see on the value and fetch the corresponding signing
|
||||
// keys
|
||||
fetch_required_signing_keys(&value, pub_key_map, db)
|
||||
self.fetch_required_signing_keys(&value, pub_key_map, db)
|
||||
.await?;
|
||||
|
||||
// 2. Check signatures, otherwise drop
|
||||
|
@ -223,7 +262,8 @@ impl Service {
|
|||
})?;
|
||||
|
||||
let room_version_id = &create_event_content.room_version;
|
||||
let room_version = RoomVersion::new(room_version_id).expect("room version is supported");
|
||||
let room_version =
|
||||
RoomVersion::new(room_version_id).expect("room version is supported");
|
||||
|
||||
let mut val = match ruma::signatures::verify_event(
|
||||
&*pub_key_map.read().map_err(|_| "RwLock is poisoned.")?,
|
||||
|
@ -261,8 +301,7 @@ impl Service {
|
|||
// 5. Reject "due to auth events" if can't get all the auth events or some of the auth events are also rejected "due to auth events"
|
||||
// NOTE: Step 5 is not applied anymore because it failed too often
|
||||
warn!("Fetching auth events for {}", incoming_pdu.event_id);
|
||||
fetch_and_handle_outliers(
|
||||
db,
|
||||
self.fetch_and_handle_outliers(
|
||||
origin,
|
||||
&incoming_pdu
|
||||
.auth_events
|
||||
|
@ -284,7 +323,7 @@ impl Service {
|
|||
// Build map of auth events
|
||||
let mut auth_events = HashMap::new();
|
||||
for id in &incoming_pdu.auth_events {
|
||||
let auth_event = match db.rooms.get_pdu(id)? {
|
||||
let auth_event = match services().rooms.get_pdu(id)? {
|
||||
Some(e) => e,
|
||||
None => {
|
||||
warn!("Could not find auth event {}", id);
|
||||
|
@ -303,8 +342,9 @@ impl Service {
|
|||
v.insert(auth_event);
|
||||
}
|
||||
hash_map::Entry::Occupied(_) => {
|
||||
return Err(Error::BadRequest(ErrorKind::InvalidParam,
|
||||
"Auth event's type and state_key combination exists multiple times."
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Auth event's type and state_key combination exists multiple times.",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -316,7 +356,10 @@ impl Service {
|
|||
.map(|a| a.as_ref())
|
||||
!= Some(create_event)
|
||||
{
|
||||
return Err(Error::BadRequest(ErrorKind::InvalidParam("Incoming event refers to wrong create event.")));
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Incoming event refers to wrong create event.",
|
||||
));
|
||||
}
|
||||
|
||||
if !state_res::event_auth::auth_check(
|
||||
|
@ -325,15 +368,21 @@ impl Service {
|
|||
None::<PduEvent>, // TODO: third party invite
|
||||
|k, s| auth_events.get(&(k.to_string().into(), s.to_owned())),
|
||||
)
|
||||
.map_err(|e| {error!(e); Error::BadRequest(ErrorKind::InvalidParam, "Auth check failed")})?
|
||||
{
|
||||
return Err(Error::BadRequest(ErrorKind::InvalidParam, "Auth check failed"));
|
||||
.map_err(|e| {
|
||||
error!(e);
|
||||
Error::BadRequest(ErrorKind::InvalidParam, "Auth check failed")
|
||||
})? {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Auth check failed",
|
||||
));
|
||||
}
|
||||
|
||||
info!("Validation successful.");
|
||||
|
||||
// 7. Persist the event as an outlier.
|
||||
db.rooms
|
||||
services()
|
||||
.rooms
|
||||
.add_pdu_outlier(&incoming_pdu.event_id, &val)?;
|
||||
|
||||
info!("Added pdu as outlier.");
|
||||
|
@ -342,22 +391,22 @@ impl Service {
|
|||
})
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(incoming_pdu, val, create_event, db, pub_key_map))]
|
||||
async fn upgrade_outlier_to_timeline_pdu(
|
||||
#[tracing::instrument(skip(incoming_pdu, val, create_event, pub_key_map))]
|
||||
pub async fn upgrade_outlier_to_timeline_pdu(
|
||||
&self,
|
||||
incoming_pdu: Arc<PduEvent>,
|
||||
val: BTreeMap<String, CanonicalJsonValue>,
|
||||
create_event: &PduEvent,
|
||||
origin: &ServerName,
|
||||
db: &Database,
|
||||
room_id: &RoomId,
|
||||
pub_key_map: &RwLock<BTreeMap<String, BTreeMap<String, Base64>>>,
|
||||
) -> Result<Option<Vec<u8>>, String> {
|
||||
// Skip the PDU if we already have it as a timeline event
|
||||
if let Ok(Some(pduid)) = db.rooms.get_pdu_id(&incoming_pdu.event_id) {
|
||||
if let Ok(Some(pduid)) = services().rooms.get_pdu_id(&incoming_pdu.event_id) {
|
||||
return Ok(Some(pduid));
|
||||
}
|
||||
|
||||
if db
|
||||
if services()
|
||||
.rooms
|
||||
.is_event_soft_failed(&incoming_pdu.event_id)
|
||||
.map_err(|_| "Failed to ask db for soft fail".to_owned())?
|
||||
|
@ -387,32 +436,32 @@ impl Service {
|
|||
|
||||
if incoming_pdu.prev_events.len() == 1 {
|
||||
let prev_event = &*incoming_pdu.prev_events[0];
|
||||
let prev_event_sstatehash = db
|
||||
let prev_event_sstatehash = services()
|
||||
.rooms
|
||||
.pdu_shortstatehash(prev_event)
|
||||
.map_err(|_| "Failed talking to db".to_owned())?;
|
||||
|
||||
let state = if let Some(shortstatehash) = prev_event_sstatehash {
|
||||
Some(db.rooms.state_full_ids(shortstatehash).await)
|
||||
Some(services().rooms.state_full_ids(shortstatehash).await)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(Ok(mut state)) = state {
|
||||
info!("Using cached state");
|
||||
let prev_pdu =
|
||||
db.rooms.get_pdu(prev_event).ok().flatten().ok_or_else(|| {
|
||||
let prev_pdu = services()
|
||||
.rooms
|
||||
.get_pdu(prev_event)
|
||||
.ok()
|
||||
.flatten()
|
||||
.ok_or_else(|| {
|
||||
"Could not find prev event, but we know the state.".to_owned()
|
||||
})?;
|
||||
|
||||
if let Some(state_key) = &prev_pdu.state_key {
|
||||
let shortstatekey = db
|
||||
let shortstatekey = services()
|
||||
.rooms
|
||||
.get_or_create_shortstatekey(
|
||||
&prev_pdu.kind.to_string().into(),
|
||||
state_key,
|
||||
&db.globals,
|
||||
)
|
||||
.get_or_create_shortstatekey(&prev_pdu.kind.to_string().into(), state_key)
|
||||
.map_err(|_| "Failed to create shortstatekey.".to_owned())?;
|
||||
|
||||
state.insert(shortstatekey, Arc::from(prev_event));
|
||||
|
@ -427,19 +476,20 @@ impl Service {
|
|||
|
||||
let mut okay = true;
|
||||
for prev_eventid in &incoming_pdu.prev_events {
|
||||
let prev_event = if let Ok(Some(pdu)) = db.rooms.get_pdu(prev_eventid) {
|
||||
let prev_event = if let Ok(Some(pdu)) = services().rooms.get_pdu(prev_eventid) {
|
||||
pdu
|
||||
} else {
|
||||
okay = false;
|
||||
break;
|
||||
};
|
||||
|
||||
let sstatehash = if let Ok(Some(s)) = db.rooms.pdu_shortstatehash(prev_eventid) {
|
||||
s
|
||||
} else {
|
||||
okay = false;
|
||||
break;
|
||||
};
|
||||
let sstatehash =
|
||||
if let Ok(Some(s)) = services().rooms.pdu_shortstatehash(prev_eventid) {
|
||||
s
|
||||
} else {
|
||||
okay = false;
|
||||
break;
|
||||
};
|
||||
|
||||
extremity_sstatehashes.insert(sstatehash, prev_event);
|
||||
}
|
||||
|
@ -449,19 +499,18 @@ impl Service {
|
|||
let mut auth_chain_sets = Vec::with_capacity(extremity_sstatehashes.len());
|
||||
|
||||
for (sstatehash, prev_event) in extremity_sstatehashes {
|
||||
let mut leaf_state: BTreeMap<_, _> = db
|
||||
let mut leaf_state: BTreeMap<_, _> = services()
|
||||
.rooms
|
||||
.state_full_ids(sstatehash)
|
||||
.await
|
||||
.map_err(|_| "Failed to ask db for room state.".to_owned())?;
|
||||
|
||||
if let Some(state_key) = &prev_event.state_key {
|
||||
let shortstatekey = db
|
||||
let shortstatekey = services()
|
||||
.rooms
|
||||
.get_or_create_shortstatekey(
|
||||
&prev_event.kind.to_string().into(),
|
||||
state_key,
|
||||
&db.globals,
|
||||
)
|
||||
.map_err(|_| "Failed to create shortstatekey.".to_owned())?;
|
||||
leaf_state.insert(shortstatekey, Arc::from(&*prev_event.event_id));
|
||||
|
@ -472,7 +521,7 @@ impl Service {
|
|||
let mut starting_events = Vec::with_capacity(leaf_state.len());
|
||||
|
||||
for (k, id) in leaf_state {
|
||||
if let Ok((ty, st_key)) = db.rooms.get_statekey_from_short(k) {
|
||||
if let Ok((ty, st_key)) = services().rooms.get_statekey_from_short(k) {
|
||||
// FIXME: Undo .to_string().into() when StateMap
|
||||
// is updated to use StateEventType
|
||||
state.insert((ty.to_string().into(), st_key), id.clone());
|
||||
|
@ -483,7 +532,10 @@ impl Service {
|
|||
}
|
||||
|
||||
auth_chain_sets.push(
|
||||
get_auth_chain(room_id, starting_events, db)
|
||||
services()
|
||||
.rooms
|
||||
.auth_chain
|
||||
.get_auth_chain(room_id, starting_events, services())
|
||||
.await
|
||||
.map_err(|_| "Failed to load auth chain.".to_owned())?
|
||||
.collect(),
|
||||
|
@ -492,15 +544,16 @@ impl Service {
|
|||
fork_states.push(state);
|
||||
}
|
||||
|
||||
let lock = db.globals.stateres_mutex.lock();
|
||||
let lock = services().globals.stateres_mutex.lock();
|
||||
|
||||
let result = state_res::resolve(room_version_id, &fork_states, auth_chain_sets, |id| {
|
||||
let res = db.rooms.get_pdu(id);
|
||||
if let Err(e) = &res {
|
||||
error!("LOOK AT ME Failed to fetch event: {}", e);
|
||||
}
|
||||
res.ok().flatten()
|
||||
});
|
||||
let result =
|
||||
state_res::resolve(room_version_id, &fork_states, auth_chain_sets, |id| {
|
||||
let res = services().rooms.get_pdu(id);
|
||||
if let Err(e) = &res {
|
||||
error!("LOOK AT ME Failed to fetch event: {}", e);
|
||||
}
|
||||
res.ok().flatten()
|
||||
});
|
||||
drop(lock);
|
||||
|
||||
state_at_incoming_event = match result {
|
||||
|
@ -508,14 +561,15 @@ impl Service {
|
|||
new_state
|
||||
.into_iter()
|
||||
.map(|((event_type, state_key), event_id)| {
|
||||
let shortstatekey = db
|
||||
let shortstatekey = services()
|
||||
.rooms
|
||||
.get_or_create_shortstatekey(
|
||||
&event_type.to_string().into(),
|
||||
&state_key,
|
||||
&db.globals,
|
||||
)
|
||||
.map_err(|_| "Failed to get_or_create_shortstatekey".to_owned())?;
|
||||
.map_err(|_| {
|
||||
"Failed to get_or_create_shortstatekey".to_owned()
|
||||
})?;
|
||||
Ok((shortstatekey, event_id))
|
||||
})
|
||||
.collect::<Result<_, String>>()?,
|
||||
|
@ -532,10 +586,9 @@ impl Service {
|
|||
info!("Calling /state_ids");
|
||||
// Call /state_ids to find out what the state at this pdu is. We trust the server's
|
||||
// response to some extend, but we still do a lot of checks on the events
|
||||
match db
|
||||
match services()
|
||||
.sending
|
||||
.send_federation_request(
|
||||
&db.globals,
|
||||
origin,
|
||||
get_room_state_ids::v1::Request {
|
||||
room_id,
|
||||
|
@ -546,18 +599,18 @@ impl Service {
|
|||
{
|
||||
Ok(res) => {
|
||||
info!("Fetching state events at event.");
|
||||
let state_vec = fetch_and_handle_outliers(
|
||||
db,
|
||||
origin,
|
||||
&res.pdu_ids
|
||||
.iter()
|
||||
.map(|x| Arc::from(&**x))
|
||||
.collect::<Vec<_>>(),
|
||||
create_event,
|
||||
room_id,
|
||||
pub_key_map,
|
||||
)
|
||||
.await;
|
||||
let state_vec = self
|
||||
.fetch_and_handle_outliers(
|
||||
origin,
|
||||
&res.pdu_ids
|
||||
.iter()
|
||||
.map(|x| Arc::from(&**x))
|
||||
.collect::<Vec<_>>(),
|
||||
create_event,
|
||||
room_id,
|
||||
pub_key_map,
|
||||
)
|
||||
.await;
|
||||
|
||||
let mut state: BTreeMap<_, Arc<EventId>> = BTreeMap::new();
|
||||
for (pdu, _) in state_vec {
|
||||
|
@ -566,13 +619,9 @@ impl Service {
|
|||
.clone()
|
||||
.ok_or_else(|| "Found non-state pdu in state events.".to_owned())?;
|
||||
|
||||
let shortstatekey = db
|
||||
let shortstatekey = services()
|
||||
.rooms
|
||||
.get_or_create_shortstatekey(
|
||||
&pdu.kind.to_string().into(),
|
||||
&state_key,
|
||||
&db.globals,
|
||||
)
|
||||
.get_or_create_shortstatekey(&pdu.kind.to_string().into(), &state_key)
|
||||
.map_err(|_| "Failed to create shortstatekey.".to_owned())?;
|
||||
|
||||
match state.entry(shortstatekey) {
|
||||
|
@ -587,7 +636,7 @@ impl Service {
|
|||
}
|
||||
|
||||
// The original create event must still be in the state
|
||||
let create_shortstatekey = db
|
||||
let create_shortstatekey = services()
|
||||
.rooms
|
||||
.get_shortstatekey(&StateEventType::RoomCreate, "")
|
||||
.map_err(|_| "Failed to talk to db.")?
|
||||
|
@ -618,12 +667,13 @@ impl Service {
|
|||
&incoming_pdu,
|
||||
None::<PduEvent>, // TODO: third party invite
|
||||
|k, s| {
|
||||
db.rooms
|
||||
services()
|
||||
.rooms
|
||||
.get_shortstatekey(&k.to_string().into(), s)
|
||||
.ok()
|
||||
.flatten()
|
||||
.and_then(|shortstatekey| state_at_incoming_event.get(&shortstatekey))
|
||||
.and_then(|event_id| db.rooms.get_pdu(event_id).ok().flatten())
|
||||
.and_then(|event_id| services().rooms.get_pdu(event_id).ok().flatten())
|
||||
},
|
||||
)
|
||||
.map_err(|_e| "Auth check failed.".to_owned())?;
|
||||
|
@ -636,7 +686,8 @@ impl Service {
|
|||
// We start looking at current room state now, so lets lock the room
|
||||
|
||||
let mutex_state = Arc::clone(
|
||||
db.globals
|
||||
services()
|
||||
.globals
|
||||
.roomid_mutex_state
|
||||
.write()
|
||||
.unwrap()
|
||||
|
@ -648,7 +699,7 @@ impl Service {
|
|||
// Now we calculate the set of extremities this room has after the incoming event has been
|
||||
// applied. We start with the previous extremities (aka leaves)
|
||||
info!("Calculating extremities");
|
||||
let mut extremities = db
|
||||
let mut extremities = services()
|
||||
.rooms
|
||||
.get_pdu_leaves(room_id)
|
||||
.map_err(|_| "Failed to load room leaves".to_owned())?;
|
||||
|
@ -661,14 +712,16 @@ impl Service {
|
|||
}
|
||||
|
||||
// Only keep those extremities were not referenced yet
|
||||
extremities.retain(|id| !matches!(db.rooms.is_event_referenced(room_id, id), Ok(true)));
|
||||
extremities
|
||||
.retain(|id| !matches!(services().rooms.is_event_referenced(room_id, id), Ok(true)));
|
||||
|
||||
info!("Compressing state at event");
|
||||
let state_ids_compressed = state_at_incoming_event
|
||||
.iter()
|
||||
.map(|(shortstatekey, id)| {
|
||||
db.rooms
|
||||
.compress_state_event(*shortstatekey, id, &db.globals)
|
||||
services()
|
||||
.rooms
|
||||
.compress_state_event(*shortstatekey, id)
|
||||
.map_err(|_| "Failed to compress_state_event".to_owned())
|
||||
})
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
@ -676,7 +729,7 @@ impl Service {
|
|||
// 13. Check if the event passes auth based on the "current state" of the room, if not "soft fail" it
|
||||
info!("Starting soft fail auth check");
|
||||
|
||||
let auth_events = db
|
||||
let auth_events = services()
|
||||
.rooms
|
||||
.get_auth_events(
|
||||
room_id,
|
||||
|
@ -696,11 +749,10 @@ impl Service {
|
|||
.map_err(|_e| "Auth check failed.".to_owned())?;
|
||||
|
||||
if soft_fail {
|
||||
append_incoming_pdu(
|
||||
db,
|
||||
self.append_incoming_pdu(
|
||||
&incoming_pdu,
|
||||
val,
|
||||
extremities.iter().map(Deref::deref),
|
||||
extremities.iter().map(std::ops::Deref::deref),
|
||||
state_ids_compressed,
|
||||
soft_fail,
|
||||
&state_lock,
|
||||
|
@ -712,7 +764,8 @@ impl Service {
|
|||
|
||||
// Soft fail, we keep the event as an outlier but don't add it to the timeline
|
||||
warn!("Event was soft failed: {:?}", incoming_pdu);
|
||||
db.rooms
|
||||
services()
|
||||
.rooms
|
||||
.mark_event_soft_failed(&incoming_pdu.event_id)
|
||||
.map_err(|_| "Failed to set soft failed flag".to_owned())?;
|
||||
return Err("Event has been soft failed".into());
|
||||
|
@ -720,13 +773,13 @@ impl Service {
|
|||
|
||||
if incoming_pdu.state_key.is_some() {
|
||||
info!("Loading current room state ids");
|
||||
let current_sstatehash = db
|
||||
let current_sstatehash = services()
|
||||
.rooms
|
||||
.current_shortstatehash(room_id)
|
||||
.map_err(|_| "Failed to load current state hash.".to_owned())?
|
||||
.expect("every room has state");
|
||||
|
||||
let current_state_ids = db
|
||||
let current_state_ids = services()
|
||||
.rooms
|
||||
.state_full_ids(current_sstatehash)
|
||||
.await
|
||||
|
@ -737,14 +790,14 @@ impl Service {
|
|||
|
||||
info!("Loading extremities");
|
||||
for id in dbg!(&extremities) {
|
||||
match db
|
||||
match services()
|
||||
.rooms
|
||||
.get_pdu(id)
|
||||
.map_err(|_| "Failed to ask db for pdu.".to_owned())?
|
||||
{
|
||||
Some(leaf_pdu) => {
|
||||
extremity_sstatehashes.insert(
|
||||
db.rooms
|
||||
services()
|
||||
.pdu_shortstatehash(&leaf_pdu.event_id)
|
||||
.map_err(|_| "Failed to ask db for pdu state hash.".to_owned())?
|
||||
.ok_or_else(|| {
|
||||
|
@ -777,13 +830,9 @@ impl Service {
|
|||
// We also add state after incoming event to the fork states
|
||||
let mut state_after = state_at_incoming_event.clone();
|
||||
if let Some(state_key) = &incoming_pdu.state_key {
|
||||
let shortstatekey = db
|
||||
let shortstatekey = services()
|
||||
.rooms
|
||||
.get_or_create_shortstatekey(
|
||||
&incoming_pdu.kind.to_string().into(),
|
||||
state_key,
|
||||
&db.globals,
|
||||
)
|
||||
.get_or_create_shortstatekey(&incoming_pdu.kind.to_string().into(), state_key)
|
||||
.map_err(|_| "Failed to create shortstatekey.".to_owned())?;
|
||||
|
||||
state_after.insert(shortstatekey, Arc::from(&*incoming_pdu.event_id));
|
||||
|
@ -801,8 +850,9 @@ impl Service {
|
|||
fork_states[0]
|
||||
.iter()
|
||||
.map(|(k, id)| {
|
||||
db.rooms
|
||||
.compress_state_event(*k, id, &db.globals)
|
||||
services()
|
||||
.rooms
|
||||
.compress_state_event(*k, id)
|
||||
.map_err(|_| "Failed to compress_state_event.".to_owned())
|
||||
})
|
||||
.collect::<Result<_, _>>()?
|
||||
|
@ -814,14 +864,16 @@ impl Service {
|
|||
let mut auth_chain_sets = Vec::new();
|
||||
for state in &fork_states {
|
||||
auth_chain_sets.push(
|
||||
get_auth_chain(
|
||||
room_id,
|
||||
state.iter().map(|(_, id)| id.clone()).collect(),
|
||||
db,
|
||||
)
|
||||
.await
|
||||
.map_err(|_| "Failed to load auth chain.".to_owned())?
|
||||
.collect(),
|
||||
services()
|
||||
.rooms
|
||||
.auth_chain
|
||||
.get_auth_chain(
|
||||
room_id,
|
||||
state.iter().map(|(_, id)| id.clone()).collect(),
|
||||
)
|
||||
.await
|
||||
.map_err(|_| "Failed to load auth chain.".to_owned())?
|
||||
.collect(),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -832,7 +884,8 @@ impl Service {
|
|||
.map(|map| {
|
||||
map.into_iter()
|
||||
.filter_map(|(k, id)| {
|
||||
db.rooms
|
||||
services()
|
||||
.rooms
|
||||
.get_statekey_from_short(k)
|
||||
// FIXME: Undo .to_string().into() when StateMap
|
||||
// is updated to use StateEventType
|
||||
|
@ -846,13 +899,13 @@ impl Service {
|
|||
|
||||
info!("Resolving state");
|
||||
|
||||
let lock = db.globals.stateres_mutex.lock();
|
||||
let lock = services().globals.stateres_mutex.lock();
|
||||
let state = match state_res::resolve(
|
||||
room_version_id,
|
||||
&fork_states,
|
||||
auth_chain_sets,
|
||||
|id| {
|
||||
let res = db.rooms.get_pdu(id);
|
||||
let res = services().rooms.get_pdu(id);
|
||||
if let Err(e) = &res {
|
||||
error!("LOOK AT ME Failed to fetch event: {}", e);
|
||||
}
|
||||
|
@ -872,16 +925,13 @@ impl Service {
|
|||
state
|
||||
.into_iter()
|
||||
.map(|((event_type, state_key), event_id)| {
|
||||
let shortstatekey = db
|
||||
let shortstatekey = services()
|
||||
.rooms
|
||||
.get_or_create_shortstatekey(
|
||||
&event_type.to_string().into(),
|
||||
&state_key,
|
||||
&db.globals,
|
||||
)
|
||||
.get_or_create_shortstatekey(&event_type.to_string().into(), &state_key)
|
||||
.map_err(|_| "Failed to get_or_create_shortstatekey".to_owned())?;
|
||||
db.rooms
|
||||
.compress_state_event(shortstatekey, &event_id, &db.globals)
|
||||
services()
|
||||
.rooms
|
||||
.compress_state_event(shortstatekey, &event_id)
|
||||
.map_err(|_| "Failed to compress state event".to_owned())
|
||||
})
|
||||
.collect::<Result<_, _>>()?
|
||||
|
@ -890,8 +940,9 @@ impl Service {
|
|||
// Set the new room state to the resolved state
|
||||
if update_state {
|
||||
info!("Forcing new room state");
|
||||
db.rooms
|
||||
.force_state(room_id, new_room_state, db)
|
||||
services()
|
||||
.rooms
|
||||
.force_state(room_id, new_room_state)
|
||||
.map_err(|_| "Failed to set new room state.".to_owned())?;
|
||||
}
|
||||
}
|
||||
|
@ -903,19 +954,19 @@ impl Service {
|
|||
// We use the `state_at_event` instead of `state_after` so we accurately
|
||||
// represent the state for this event.
|
||||
|
||||
let pdu_id = append_incoming_pdu(
|
||||
db,
|
||||
&incoming_pdu,
|
||||
val,
|
||||
extremities.iter().map(Deref::deref),
|
||||
state_ids_compressed,
|
||||
soft_fail,
|
||||
&state_lock,
|
||||
)
|
||||
.map_err(|e| {
|
||||
warn!("Failed to add pdu to db: {}", e);
|
||||
"Failed to add pdu to db.".to_owned()
|
||||
})?;
|
||||
let pdu_id = self
|
||||
.append_incoming_pdu(
|
||||
&incoming_pdu,
|
||||
val,
|
||||
extremities.iter().map(std::ops::Deref::deref),
|
||||
state_ids_compressed,
|
||||
soft_fail,
|
||||
&state_lock,
|
||||
)
|
||||
.map_err(|e| {
|
||||
warn!("Failed to add pdu to db: {}", e);
|
||||
"Failed to add pdu to db.".to_owned()
|
||||
})?;
|
||||
|
||||
info!("Appended incoming pdu");
|
||||
|
||||
|
@ -935,15 +986,22 @@ impl Service {
|
|||
/// d. TODO: Ask other servers over federation?
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub(crate) fn fetch_and_handle_outliers<'a>(
|
||||
db: &'a Database,
|
||||
&self,
|
||||
origin: &'a ServerName,
|
||||
events: &'a [Arc<EventId>],
|
||||
create_event: &'a PduEvent,
|
||||
room_id: &'a RoomId,
|
||||
pub_key_map: &'a RwLock<BTreeMap<String, BTreeMap<String, Base64>>>,
|
||||
) -> AsyncRecursiveType<'a, Vec<(Arc<PduEvent>, Option<BTreeMap<String, CanonicalJsonValue>>)>> {
|
||||
) -> AsyncRecursiveType<'a, Vec<(Arc<PduEvent>, Option<BTreeMap<String, CanonicalJsonValue>>)>>
|
||||
{
|
||||
Box::pin(async move {
|
||||
let back_off = |id| match db.globals.bad_event_ratelimiter.write().unwrap().entry(id) {
|
||||
let back_off = |id| match services()
|
||||
.globals
|
||||
.bad_event_ratelimiter
|
||||
.write()
|
||||
.unwrap()
|
||||
.entry(id)
|
||||
{
|
||||
hash_map::Entry::Vacant(e) => {
|
||||
e.insert((Instant::now(), 1));
|
||||
}
|
||||
|
@ -952,10 +1010,16 @@ impl Service {
|
|||
|
||||
let mut pdus = vec![];
|
||||
for id in events {
|
||||
if let Some((time, tries)) = db.globals.bad_event_ratelimiter.read().unwrap().get(&**id)
|
||||
if let Some((time, tries)) = services()
|
||||
.globals
|
||||
.bad_event_ratelimiter
|
||||
.read()
|
||||
.unwrap()
|
||||
.get(&**id)
|
||||
{
|
||||
// Exponential backoff
|
||||
let mut min_elapsed_duration = Duration::from_secs(5 * 60) * (*tries) * (*tries);
|
||||
let mut min_elapsed_duration =
|
||||
Duration::from_secs(5 * 60) * (*tries) * (*tries);
|
||||
if min_elapsed_duration > Duration::from_secs(60 * 60 * 24) {
|
||||
min_elapsed_duration = Duration::from_secs(60 * 60 * 24);
|
||||
}
|
||||
|
@ -969,7 +1033,7 @@ impl Service {
|
|||
// a. Look in the main timeline (pduid_pdu tree)
|
||||
// b. Look at outlier pdu tree
|
||||
// (get_pdu_json checks both)
|
||||
if let Ok(Some(local_pdu)) = db.rooms.get_pdu(id) {
|
||||
if let Ok(Some(local_pdu)) = services().rooms.get_pdu(id) {
|
||||
trace!("Found {} in db", id);
|
||||
pdus.push((local_pdu, None));
|
||||
continue;
|
||||
|
@ -992,16 +1056,15 @@ impl Service {
|
|||
tokio::task::yield_now().await;
|
||||
}
|
||||
|
||||
if let Ok(Some(_)) = db.rooms.get_pdu(&next_id) {
|
||||
if let Ok(Some(_)) = services().rooms.get_pdu(&next_id) {
|
||||
trace!("Found {} in db", id);
|
||||
continue;
|
||||
}
|
||||
|
||||
info!("Fetching {} over federation.", next_id);
|
||||
match db
|
||||
match services()
|
||||
.sending
|
||||
.send_federation_request(
|
||||
&db.globals,
|
||||
origin,
|
||||
get_event::v1::Request { event_id: &next_id },
|
||||
)
|
||||
|
@ -1010,7 +1073,7 @@ impl Service {
|
|||
Ok(res) => {
|
||||
info!("Got {} over federation", next_id);
|
||||
let (calculated_event_id, value) =
|
||||
match crate::pdu::gen_event_id_canonical_json(&res.pdu, &db) {
|
||||
match pdu::gen_event_id_canonical_json(&res.pdu) {
|
||||
Ok(t) => t,
|
||||
Err(_) => {
|
||||
back_off((*next_id).to_owned());
|
||||
|
@ -1051,16 +1114,16 @@ impl Service {
|
|||
}
|
||||
|
||||
for (next_id, value) in events_in_reverse_order.iter().rev() {
|
||||
match handle_outlier_pdu(
|
||||
origin,
|
||||
create_event,
|
||||
next_id,
|
||||
room_id,
|
||||
value.clone(),
|
||||
db,
|
||||
pub_key_map,
|
||||
)
|
||||
.await
|
||||
match self
|
||||
.handle_outlier_pdu(
|
||||
origin,
|
||||
create_event,
|
||||
next_id,
|
||||
room_id,
|
||||
value.clone(),
|
||||
pub_key_map,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok((pdu, json)) => {
|
||||
if next_id == id {
|
||||
|
@ -1078,9 +1141,14 @@ impl Service {
|
|||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn fetch_unknown_prev_events(initial_set: Vec<Arc<EventId>>) -> Vec<Arc<EventId>> {
|
||||
async fn fetch_unknown_prev_events(
|
||||
&self,
|
||||
origin: &ServerName,
|
||||
create_event: &PduEvent,
|
||||
room_id: &RoomId,
|
||||
pub_key_map: &RwLock<BTreeMap<String, BTreeMap<String, Base64>>>,
|
||||
initial_set: Vec<Arc<EventId>>,
|
||||
) -> Vec<(Arc<EventId>, HashMap<Arc<EventId>, (Arc<PduEvent>, BTreeMap<String, CanonicalJsonValue>)>)> {
|
||||
let mut graph: HashMap<Arc<EventId>, _> = HashMap::new();
|
||||
let mut eventid_info = HashMap::new();
|
||||
let mut todo_outlier_stack: Vec<Arc<EventId>> = initial_set;
|
||||
|
@ -1088,16 +1156,16 @@ impl Service {
|
|||
let mut amount = 0;
|
||||
|
||||
while let Some(prev_event_id) = todo_outlier_stack.pop() {
|
||||
if let Some((pdu, json_opt)) = fetch_and_handle_outliers(
|
||||
db,
|
||||
origin,
|
||||
&[prev_event_id.clone()],
|
||||
&create_event,
|
||||
room_id,
|
||||
pub_key_map,
|
||||
)
|
||||
.await
|
||||
.pop()
|
||||
if let Some((pdu, json_opt)) = self
|
||||
.fetch_and_handle_outliers(
|
||||
origin,
|
||||
&[prev_event_id.clone()],
|
||||
&create_event,
|
||||
room_id,
|
||||
pub_key_map,
|
||||
)
|
||||
.await
|
||||
.pop()
|
||||
{
|
||||
if amount > 100 {
|
||||
// Max limit reached
|
||||
|
@ -1106,9 +1174,13 @@ impl Service {
|
|||
continue;
|
||||
}
|
||||
|
||||
if let Some(json) =
|
||||
json_opt.or_else(|| db.rooms.get_outlier_pdu_json(&prev_event_id).ok().flatten())
|
||||
{
|
||||
if let Some(json) = json_opt.or_else(|| {
|
||||
services()
|
||||
.rooms
|
||||
.get_outlier_pdu_json(&prev_event_id)
|
||||
.ok()
|
||||
.flatten()
|
||||
}) {
|
||||
if pdu.origin_server_ts > first_pdu_in_room.origin_server_ts {
|
||||
amount += 1;
|
||||
for prev_prev in &pdu.prev_events {
|
||||
|
@ -1153,6 +1225,6 @@ impl Service {
|
|||
})
|
||||
.map_err(|_| "Error sorting prev events".to_owned())?;
|
||||
|
||||
sorted
|
||||
(sorted, eventid_info)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use ruma::{RoomId, DeviceId, UserId};
|
||||
|
||||
pub trait Data {
|
||||
fn lazy_load_was_sent_before(
|
||||
&self,
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
mod data;
|
||||
use std::collections::HashSet;
|
||||
|
||||
pub use data::Data;
|
||||
use ruma::{DeviceId, UserId, RoomId};
|
||||
|
||||
use crate::service::*;
|
||||
|
||||
|
@ -47,7 +50,7 @@ impl Service<_> {
|
|||
room_id: &RoomId,
|
||||
since: u64,
|
||||
) -> Result<()> {
|
||||
self.db.lazy_load_confirm_delivery(user_d, device_id, room_id, since)
|
||||
self.db.lazy_load_confirm_delivery(user_id, device_id, room_id, since)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
|
@ -57,6 +60,6 @@ impl Service<_> {
|
|||
device_id: &DeviceId,
|
||||
room_id: &RoomId,
|
||||
) -> Result<()> {
|
||||
self.db.lazy_load_reset(user_id, device_id, room_id);
|
||||
self.db.lazy_load_reset(user_id, device_id, room_id)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use ruma::RoomId;
|
||||
|
||||
pub trait Data {
|
||||
fn exists(&self, room_id: &RoomId) -> Result<bool>;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
mod data;
|
||||
pub use data::Data;
|
||||
use ruma::RoomId;
|
||||
|
||||
use crate::service::*;
|
||||
|
||||
|
|
|
@ -1,216 +1,37 @@
|
|||
mod edus;
|
||||
|
||||
pub use edus::RoomEdus;
|
||||
|
||||
use crate::{
|
||||
pdu::{EventHash, PduBuilder},
|
||||
utils, Database, Error, PduEvent, Result,
|
||||
};
|
||||
use lru_cache::LruCache;
|
||||
use regex::Regex;
|
||||
use ring::digest;
|
||||
use ruma::{
|
||||
api::{client::error::ErrorKind, federation},
|
||||
events::{
|
||||
direct::DirectEvent,
|
||||
ignored_user_list::IgnoredUserListEvent,
|
||||
push_rules::PushRulesEvent,
|
||||
room::{
|
||||
create::RoomCreateEventContent,
|
||||
member::{MembershipState, RoomMemberEventContent},
|
||||
power_levels::RoomPowerLevelsEventContent,
|
||||
},
|
||||
tag::TagEvent,
|
||||
AnyStrippedStateEvent, AnySyncStateEvent, GlobalAccountDataEventType,
|
||||
RoomAccountDataEventType, RoomEventType, StateEventType,
|
||||
},
|
||||
push::{Action, Ruleset, Tweak},
|
||||
serde::{CanonicalJsonObject, CanonicalJsonValue, Raw},
|
||||
state_res::{self, RoomVersion, StateMap},
|
||||
uint, DeviceId, EventId, RoomAliasId, RoomId, RoomVersionId, ServerName, UserId,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
use serde_json::value::to_raw_value;
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
collections::{hash_map, BTreeMap, HashMap, HashSet},
|
||||
fmt::Debug,
|
||||
iter,
|
||||
mem::size_of,
|
||||
sync::{Arc, Mutex, RwLock},
|
||||
};
|
||||
use tokio::sync::MutexGuard;
|
||||
use tracing::{error, warn};
|
||||
|
||||
use super::{abstraction::Tree, pusher};
|
||||
|
||||
/// The unique identifier of each state group.
|
||||
///
|
||||
/// This is created when a state group is added to the database by
|
||||
/// hashing the entire state.
|
||||
pub type StateHashId = Vec<u8>;
|
||||
pub type CompressedStateEvent = [u8; 2 * size_of::<u64>()];
|
||||
|
||||
pub struct Rooms {
|
||||
pub edus: RoomEdus,
|
||||
pub(super) pduid_pdu: Arc<dyn Tree>, // PduId = ShortRoomId + Count
|
||||
pub(super) eventid_pduid: Arc<dyn Tree>,
|
||||
pub(super) roomid_pduleaves: Arc<dyn Tree>,
|
||||
pub(super) alias_roomid: Arc<dyn Tree>,
|
||||
pub(super) aliasid_alias: Arc<dyn Tree>, // AliasId = RoomId + Count
|
||||
pub(super) publicroomids: Arc<dyn Tree>,
|
||||
|
||||
pub(super) tokenids: Arc<dyn Tree>, // TokenId = ShortRoomId + Token + PduIdCount
|
||||
|
||||
/// Participating servers in a room.
|
||||
pub(super) roomserverids: Arc<dyn Tree>, // RoomServerId = RoomId + ServerName
|
||||
pub(super) serverroomids: Arc<dyn Tree>, // ServerRoomId = ServerName + RoomId
|
||||
|
||||
pub(super) userroomid_joined: Arc<dyn Tree>,
|
||||
pub(super) roomuserid_joined: Arc<dyn Tree>,
|
||||
pub(super) roomid_joinedcount: Arc<dyn Tree>,
|
||||
pub(super) roomid_invitedcount: Arc<dyn Tree>,
|
||||
pub(super) roomuseroncejoinedids: Arc<dyn Tree>,
|
||||
pub(super) userroomid_invitestate: Arc<dyn Tree>, // InviteState = Vec<Raw<Pdu>>
|
||||
pub(super) roomuserid_invitecount: Arc<dyn Tree>, // InviteCount = Count
|
||||
pub(super) userroomid_leftstate: Arc<dyn Tree>,
|
||||
pub(super) roomuserid_leftcount: Arc<dyn Tree>,
|
||||
|
||||
pub(super) disabledroomids: Arc<dyn Tree>, // Rooms where incoming federation handling is disabled
|
||||
|
||||
pub(super) lazyloadedids: Arc<dyn Tree>, // LazyLoadedIds = UserId + DeviceId + RoomId + LazyLoadedUserId
|
||||
|
||||
pub(super) userroomid_notificationcount: Arc<dyn Tree>, // NotifyCount = u64
|
||||
pub(super) userroomid_highlightcount: Arc<dyn Tree>, // HightlightCount = u64
|
||||
|
||||
/// Remember the current state hash of a room.
|
||||
pub(super) roomid_shortstatehash: Arc<dyn Tree>,
|
||||
pub(super) roomsynctoken_shortstatehash: Arc<dyn Tree>,
|
||||
/// Remember the state hash at events in the past.
|
||||
pub(super) shorteventid_shortstatehash: Arc<dyn Tree>,
|
||||
/// StateKey = EventType + StateKey, ShortStateKey = Count
|
||||
pub(super) statekey_shortstatekey: Arc<dyn Tree>,
|
||||
pub(super) shortstatekey_statekey: Arc<dyn Tree>,
|
||||
|
||||
pub(super) roomid_shortroomid: Arc<dyn Tree>,
|
||||
|
||||
pub(super) shorteventid_eventid: Arc<dyn Tree>,
|
||||
pub(super) eventid_shorteventid: Arc<dyn Tree>,
|
||||
|
||||
pub(super) statehash_shortstatehash: Arc<dyn Tree>,
|
||||
pub(super) shortstatehash_statediff: Arc<dyn Tree>, // StateDiff = parent (or 0) + (shortstatekey+shorteventid++) + 0_u64 + (shortstatekey+shorteventid--)
|
||||
|
||||
pub(super) shorteventid_authchain: Arc<dyn Tree>,
|
||||
|
||||
/// RoomId + EventId -> outlier PDU.
|
||||
/// Any pdu that has passed the steps 1-8 in the incoming event /federation/send/txn.
|
||||
pub(super) eventid_outlierpdu: Arc<dyn Tree>,
|
||||
pub(super) softfailedeventids: Arc<dyn Tree>,
|
||||
|
||||
/// RoomId + EventId -> Parent PDU EventId.
|
||||
pub(super) referencedevents: Arc<dyn Tree>,
|
||||
|
||||
pub(super) pdu_cache: Mutex<LruCache<Box<EventId>, Arc<PduEvent>>>,
|
||||
pub(super) shorteventid_cache: Mutex<LruCache<u64, Arc<EventId>>>,
|
||||
pub(super) auth_chain_cache: Mutex<LruCache<Vec<u64>, Arc<HashSet<u64>>>>,
|
||||
pub(super) eventidshort_cache: Mutex<LruCache<Box<EventId>, u64>>,
|
||||
pub(super) statekeyshort_cache: Mutex<LruCache<(StateEventType, String), u64>>,
|
||||
pub(super) shortstatekey_cache: Mutex<LruCache<u64, (StateEventType, String)>>,
|
||||
pub(super) our_real_users_cache: RwLock<HashMap<Box<RoomId>, Arc<HashSet<Box<UserId>>>>>,
|
||||
pub(super) appservice_in_room_cache: RwLock<HashMap<Box<RoomId>, HashMap<String, bool>>>,
|
||||
pub(super) lazy_load_waiting:
|
||||
Mutex<HashMap<(Box<UserId>, Box<DeviceId>, Box<RoomId>, u64), HashSet<Box<UserId>>>>,
|
||||
pub(super) stateinfo_cache: Mutex<
|
||||
LruCache<
|
||||
u64,
|
||||
Vec<(
|
||||
u64, // sstatehash
|
||||
HashSet<CompressedStateEvent>, // full state
|
||||
HashSet<CompressedStateEvent>, // added
|
||||
HashSet<CompressedStateEvent>, // removed
|
||||
)>,
|
||||
>,
|
||||
>,
|
||||
pub(super) lasttimelinecount_cache: Mutex<HashMap<Box<RoomId>, u64>>,
|
||||
}
|
||||
|
||||
impl Rooms {
|
||||
/// Returns true if a given room version is supported
|
||||
#[tracing::instrument(skip(self, db))]
|
||||
pub fn is_supported_version(&self, db: &Database, room_version: &RoomVersionId) -> bool {
|
||||
db.globals.supported_room_versions().contains(room_version)
|
||||
}
|
||||
|
||||
/// This fetches auth events from the current state.
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn get_auth_events(
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
kind: &RoomEventType,
|
||||
sender: &UserId,
|
||||
state_key: Option<&str>,
|
||||
content: &serde_json::value::RawValue,
|
||||
) -> Result<StateMap<Arc<PduEvent>>> {
|
||||
let shortstatehash =
|
||||
if let Some(current_shortstatehash) = self.current_shortstatehash(room_id)? {
|
||||
current_shortstatehash
|
||||
} else {
|
||||
return Ok(HashMap::new());
|
||||
};
|
||||
|
||||
let auth_events = state_res::auth_types_for_event(kind, sender, state_key, content)
|
||||
.expect("content is a valid JSON object");
|
||||
|
||||
let mut sauthevents = auth_events
|
||||
.into_iter()
|
||||
.filter_map(|(event_type, state_key)| {
|
||||
self.get_shortstatekey(&event_type.to_string().into(), &state_key)
|
||||
.ok()
|
||||
.flatten()
|
||||
.map(|s| (s, (event_type, state_key)))
|
||||
})
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
let full_state = self
|
||||
.load_shortstatehash_info(shortstatehash)?
|
||||
.pop()
|
||||
.expect("there is always one layer")
|
||||
.1;
|
||||
|
||||
Ok(full_state
|
||||
.into_iter()
|
||||
.filter_map(|compressed| self.parse_compressed_state_event(compressed).ok())
|
||||
.filter_map(|(shortstatekey, event_id)| {
|
||||
sauthevents.remove(&shortstatekey).map(|k| (k, event_id))
|
||||
})
|
||||
.filter_map(|(k, event_id)| self.get_pdu(&event_id).ok().flatten().map(|pdu| (k, pdu)))
|
||||
.collect())
|
||||
}
|
||||
|
||||
/// Generate a new StateHash.
|
||||
///
|
||||
/// A unique hash made from hashing all PDU ids of the state joined with 0xff.
|
||||
fn calculate_hash(&self, bytes_list: &[&[u8]]) -> StateHashId {
|
||||
// We only hash the pdu's event ids, not the whole pdu
|
||||
let bytes = bytes_list.join(&0xff);
|
||||
let hash = digest::digest(&digest::SHA256, &bytes);
|
||||
hash.as_ref().into()
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn iter_ids(&self) -> impl Iterator<Item = Result<Box<RoomId>>> + '_ {
|
||||
self.roomid_shortroomid.iter().map(|(bytes, _)| {
|
||||
RoomId::parse(
|
||||
utils::string_from_bytes(&bytes).map_err(|_| {
|
||||
Error::bad_database("Room ID in publicroomids is invalid unicode.")
|
||||
})?,
|
||||
)
|
||||
.map_err(|_| Error::bad_database("Room ID in roomid_shortroomid is invalid."))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn is_disabled(&self, room_id: &RoomId) -> Result<bool> {
|
||||
Ok(self.disabledroomids.get(room_id.as_bytes())?.is_some())
|
||||
}
|
||||
pub mod alias;
|
||||
pub mod auth_chain;
|
||||
pub mod directory;
|
||||
pub mod edus;
|
||||
pub mod event_handler;
|
||||
pub mod lazy_loading;
|
||||
pub mod metadata;
|
||||
pub mod outlier;
|
||||
pub mod pdu_metadata;
|
||||
pub mod search;
|
||||
pub mod short;
|
||||
pub mod state;
|
||||
pub mod state_accessor;
|
||||
pub mod state_cache;
|
||||
pub mod state_compressor;
|
||||
pub mod timeline;
|
||||
pub mod user;
|
||||
|
||||
pub struct Service<D> {
|
||||
pub alias: alias::Service<D>,
|
||||
pub auth_chain: auth_chain::Service<D>,
|
||||
pub directory: directory::Service<D>,
|
||||
pub edus: edus::Service<D>,
|
||||
pub event_handler: event_handler::Service,
|
||||
pub lazy_loading: lazy_loading::Service<D>,
|
||||
pub metadata: metadata::Service<D>,
|
||||
pub outlier: outlier::Service<D>,
|
||||
pub pdu_metadata: pdu_metadata::Service<D>,
|
||||
pub search: search::Service<D>,
|
||||
pub short: short::Service<D>,
|
||||
pub state: state::Service<D>,
|
||||
pub state_accessor: state_accessor::Service<D>,
|
||||
pub state_cache: state_cache::Service<D>,
|
||||
pub state_compressor: state_compressor::Service<D>,
|
||||
pub timeline: timeline::Service<D>,
|
||||
pub user: user::Service<D>,
|
||||
}
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
use ruma::{EventId, signatures::CanonicalJsonObject};
|
||||
|
||||
use crate::PduEvent;
|
||||
|
||||
pub trait Data {
|
||||
fn get_outlier_pdu_json(&self, event_id: &EventId) -> Result<Option<CanonicalJsonObject>>;
|
||||
fn get_outlier_pdu(&self, event_id: &EventId) -> Result<Option<PduEvent>>;
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
mod data;
|
||||
pub use data::Data;
|
||||
use ruma::{EventId, signatures::CanonicalJsonObject};
|
||||
|
||||
use crate::service::*;
|
||||
use crate::{service::*, PduEvent};
|
||||
|
||||
pub struct Service<D: Data> {
|
||||
db: D,
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use ruma::{EventId, RoomId};
|
||||
|
||||
pub trait Data {
|
||||
fn mark_as_referenced(&self, room_id: &RoomId, event_ids: &[Arc<EventId>]) -> Result<()>;
|
||||
fn is_event_referenced(&self, room_id: &RoomId, event_id: &EventId) -> Result<bool>;
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
mod data;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub use data::Data;
|
||||
use ruma::{RoomId, EventId};
|
||||
|
||||
use crate::service::*;
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
pub trait Data {
|
||||
pub fn index_pdu<'a>(&self, room_id: &RoomId, pdu_id: u64, message_body: String) -> Result<()>;
|
||||
use ruma::RoomId;
|
||||
|
||||
pub fn search_pdus<'a>(
|
||||
pub trait Data {
|
||||
fn index_pdu<'a>(&self, room_id: &RoomId, pdu_id: u64, message_body: String) -> Result<()>;
|
||||
|
||||
fn search_pdus<'a>(
|
||||
&'a self,
|
||||
room_id: &RoomId,
|
||||
search_string: &str,
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
mod data;
|
||||
pub use data::Data;
|
||||
|
||||
use crate::service::*;
|
||||
use ruma::RoomId;
|
||||
|
||||
pub struct Service<D: Data> {
|
||||
db: D,
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
mod data;
|
||||
pub use data::Data;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::service::*;
|
||||
pub use data::Data;
|
||||
use ruma::{EventId, events::StateEventType};
|
||||
|
||||
use crate::{service::*, Error, utils};
|
||||
|
||||
pub struct Service<D: Data> {
|
||||
db: D,
|
||||
|
@ -188,7 +191,6 @@ impl Service<_> {
|
|||
fn get_or_create_shortstatehash(
|
||||
&self,
|
||||
state_hash: &StateHashId,
|
||||
globals: &super::globals::Globals,
|
||||
) -> Result<(u64, bool)> {
|
||||
Ok(match self.statehash_shortstatehash.get(state_hash)? {
|
||||
Some(shortstatehash) => (
|
||||
|
|
|
@ -1,14 +1,20 @@
|
|||
use std::sync::Arc;
|
||||
use std::{sync::MutexGuard, collections::HashSet};
|
||||
use std::fmt::Debug;
|
||||
|
||||
use ruma::{EventId, RoomId};
|
||||
|
||||
pub trait Data {
|
||||
/// Returns the last state hash key added to the db for the given room.
|
||||
fn get_room_shortstatehash(room_id: &RoomId);
|
||||
|
||||
/// Update the current state of the room.
|
||||
fn set_room_state(room_id: &RoomId, new_shortstatehash: u64
|
||||
fn set_room_state(room_id: &RoomId, new_shortstatehash: u64,
|
||||
_mutex_lock: &MutexGuard<'_, StateLock>, // Take mutex guard to make sure users get the room state mutex
|
||||
);
|
||||
|
||||
/// Associates a state with an event.
|
||||
fn set_event_state(shorteventid: u64, shortstatehash: u64) -> Result<()> {
|
||||
fn set_event_state(shorteventid: u64, shortstatehash: u64) -> Result<()>;
|
||||
|
||||
/// Returns all events we would send as the prev_events of the next event.
|
||||
fn get_forward_extremities(room_id: &RoomId) -> Result<HashSet<Arc<EventId>>>;
|
||||
|
@ -18,7 +24,7 @@ pub trait Data {
|
|||
room_id: &RoomId,
|
||||
event_ids: impl IntoIterator<Item = &'_ EventId> + Debug,
|
||||
_mutex_lock: &MutexGuard<'_, StateLock>, // Take mutex guard to make sure users get the room state mutex
|
||||
) -> Result<()> {
|
||||
) -> Result<()>;
|
||||
}
|
||||
|
||||
pub struct StateLock;
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
mod data;
|
||||
pub use data::Data;
|
||||
use std::collections::HashSet;
|
||||
|
||||
use crate::service::*;
|
||||
pub use data::Data;
|
||||
use ruma::{RoomId, events::{room::{member::MembershipState, create::RoomCreateEventContent}, AnyStrippedStateEvent, StateEventType}, UserId, EventId, serde::Raw, RoomVersionId};
|
||||
use serde::Deserialize;
|
||||
use tracing::warn;
|
||||
|
||||
use crate::{service::*, SERVICE, PduEvent, Error, utils::calculate_hash};
|
||||
|
||||
pub struct Service<D: Data> {
|
||||
db: D,
|
||||
|
@ -9,22 +14,20 @@ pub struct Service<D: Data> {
|
|||
|
||||
impl Service<_> {
|
||||
/// Set the room to the given statehash and update caches.
|
||||
#[tracing::instrument(skip(self, new_state_ids_compressed, db))]
|
||||
pub fn force_state(
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
shortstatehash: u64,
|
||||
statediffnew: HashSet<CompressedStateEvent>,
|
||||
statediffremoved: HashSet<CompressedStateEvent>,
|
||||
db: &Database,
|
||||
) -> Result<()> {
|
||||
|
||||
for event_id in statediffnew.into_iter().filter_map(|new| {
|
||||
state_compressor::parse_compressed_state_event(new)
|
||||
SERVICE.rooms.state_compressor.parse_compressed_state_event(new)
|
||||
.ok()
|
||||
.map(|(_, id)| id)
|
||||
}) {
|
||||
let pdu = match timeline::get_pdu_json(&event_id)? {
|
||||
let pdu = match SERVICE.rooms.timeline.get_pdu_json(&event_id)? {
|
||||
Some(pdu) => pdu,
|
||||
None => continue,
|
||||
};
|
||||
|
@ -60,12 +63,12 @@ impl Service<_> {
|
|||
Err(_) => continue,
|
||||
};
|
||||
|
||||
room::state_cache::update_membership(room_id, &user_id, membership, &pdu.sender, None, db, false)?;
|
||||
SERVICE.room.state_cache.update_membership(room_id, &user_id, membership, &pdu.sender, None, false)?;
|
||||
}
|
||||
|
||||
room::state_cache::update_joined_count(room_id, db)?;
|
||||
SERVICE.room.state_cache.update_joined_count(room_id)?;
|
||||
|
||||
db.set_room_state(room_id, new_shortstatehash);
|
||||
self.db.set_room_state(room_id, shortstatehash);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -74,19 +77,18 @@ impl Service<_> {
|
|||
///
|
||||
/// This adds all current state events (not including the incoming event)
|
||||
/// to `stateid_pduid` and adds the incoming event to `eventid_statehash`.
|
||||
#[tracing::instrument(skip(self, state_ids_compressed, globals))]
|
||||
#[tracing::instrument(skip(self, state_ids_compressed))]
|
||||
pub fn set_event_state(
|
||||
&self,
|
||||
event_id: &EventId,
|
||||
room_id: &RoomId,
|
||||
state_ids_compressed: HashSet<CompressedStateEvent>,
|
||||
globals: &super::globals::Globals,
|
||||
) -> Result<()> {
|
||||
let shorteventid = short::get_or_create_shorteventid(event_id, globals)?;
|
||||
let shorteventid = SERVICE.short.get_or_create_shorteventid(event_id)?;
|
||||
|
||||
let previous_shortstatehash = db.get_room_shortstatehash(room_id)?;
|
||||
let previous_shortstatehash = self.db.get_room_shortstatehash(room_id)?;
|
||||
|
||||
let state_hash = super::calculate_hash(
|
||||
let state_hash = calculate_hash(
|
||||
&state_ids_compressed
|
||||
.iter()
|
||||
.map(|s| &s[..])
|
||||
|
@ -94,11 +96,11 @@ impl Service<_> {
|
|||
);
|
||||
|
||||
let (shortstatehash, already_existed) =
|
||||
short::get_or_create_shortstatehash(&state_hash, globals)?;
|
||||
SERVICE.short.get_or_create_shortstatehash(&state_hash)?;
|
||||
|
||||
if !already_existed {
|
||||
let states_parents = previous_shortstatehash
|
||||
.map_or_else(|| Ok(Vec::new()), |p| room::state_compressor.load_shortstatehash_info(p))?;
|
||||
.map_or_else(|| Ok(Vec::new()), |p| SERVICE.room.state_compressor.load_shortstatehash_info(p))?;
|
||||
|
||||
let (statediffnew, statediffremoved) =
|
||||
if let Some(parent_stateinfo) = states_parents.last() {
|
||||
|
@ -117,7 +119,7 @@ impl Service<_> {
|
|||
} else {
|
||||
(state_ids_compressed, HashSet::new())
|
||||
};
|
||||
state_compressor::save_state_from_diff(
|
||||
SERVICE.room.state_compressor.save_state_from_diff(
|
||||
shortstatehash,
|
||||
statediffnew,
|
||||
statediffremoved,
|
||||
|
@ -126,7 +128,7 @@ impl Service<_> {
|
|||
)?;
|
||||
}
|
||||
|
||||
db.set_event_state(&shorteventid.to_be_bytes(), &shortstatehash.to_be_bytes())?;
|
||||
self.db.set_event_state(&shorteventid.to_be_bytes(), &shortstatehash.to_be_bytes())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -135,13 +137,12 @@ impl Service<_> {
|
|||
///
|
||||
/// This adds all current state events (not including the incoming event)
|
||||
/// to `stateid_pduid` and adds the incoming event to `eventid_statehash`.
|
||||
#[tracing::instrument(skip(self, new_pdu, globals))]
|
||||
#[tracing::instrument(skip(self, new_pdu))]
|
||||
pub fn append_to_state(
|
||||
&self,
|
||||
new_pdu: &PduEvent,
|
||||
globals: &super::globals::Globals,
|
||||
) -> Result<u64> {
|
||||
let shorteventid = self.get_or_create_shorteventid(&new_pdu.event_id, globals)?;
|
||||
let shorteventid = self.get_or_create_shorteventid(&new_pdu.event_id)?;
|
||||
|
||||
let previous_shortstatehash = self.get_room_shortstatehash(&new_pdu.room_id)?;
|
||||
|
||||
|
@ -157,10 +158,9 @@ impl Service<_> {
|
|||
let shortstatekey = self.get_or_create_shortstatekey(
|
||||
&new_pdu.kind.to_string().into(),
|
||||
state_key,
|
||||
globals,
|
||||
)?;
|
||||
|
||||
let new = self.compress_state_event(shortstatekey, &new_pdu.event_id, globals)?;
|
||||
let new = self.compress_state_event(shortstatekey, &new_pdu.event_id)?;
|
||||
|
||||
let replaces = states_parents
|
||||
.last()
|
||||
|
@ -176,7 +176,7 @@ impl Service<_> {
|
|||
}
|
||||
|
||||
// TODO: statehash with deterministic inputs
|
||||
let shortstatehash = globals.next_count()?;
|
||||
let shortstatehash = SERVICE.globals.next_count()?;
|
||||
|
||||
let mut statediffnew = HashSet::new();
|
||||
statediffnew.insert(new);
|
||||
|
@ -254,7 +254,23 @@ impl Service<_> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn db(&self) -> D {
|
||||
&self.db
|
||||
/// Returns the room's version.
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn get_room_version(&self, room_id: &RoomId) -> Result<RoomVersionId> {
|
||||
let create_event = self.room_state_get(room_id, &StateEventType::RoomCreate, "")?;
|
||||
|
||||
let create_event_content: Option<RoomCreateEventContent> = create_event
|
||||
.as_ref()
|
||||
.map(|create_event| {
|
||||
serde_json::from_str(create_event.content.get()).map_err(|e| {
|
||||
warn!("Invalid create event: {}", e);
|
||||
Error::bad_database("Invalid create event in db.")
|
||||
})
|
||||
})
|
||||
.transpose()?;
|
||||
let room_version = create_event_content
|
||||
.map(|create_event| create_event.room_version)
|
||||
.ok_or_else(|| Error::BadDatabase("Invalid room version"))?;
|
||||
Ok(room_version)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
use std::{sync::Arc, collections::HashMap};
|
||||
|
||||
use ruma::{EventId, events::StateEventType, RoomId};
|
||||
|
||||
use crate::PduEvent;
|
||||
|
||||
pub trait Data {
|
||||
/// Builds a StateMap by iterating over all keys that start
|
||||
/// with state_hash, this gives the full state for the given state_hash.
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
mod data;
|
||||
pub use data::Data;
|
||||
use std::{sync::Arc, collections::{HashMap, BTreeMap}};
|
||||
|
||||
use crate::service::*;
|
||||
pub use data::Data;
|
||||
use ruma::{events::StateEventType, RoomId, EventId};
|
||||
|
||||
use crate::{service::*, PduEvent};
|
||||
|
||||
pub struct Service<D: Data> {
|
||||
db: D,
|
||||
|
@ -42,7 +45,7 @@ impl Service<_> {
|
|||
event_type: &StateEventType,
|
||||
state_key: &str,
|
||||
) -> Result<Option<Arc<PduEvent>>> {
|
||||
self.db.pdu_state_get(event_id)
|
||||
self.db.pdu_state_get(shortstatehash, event_type, state_key)
|
||||
}
|
||||
|
||||
/// Returns the state hash for this pdu.
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use ruma::{UserId, RoomId};
|
||||
|
||||
pub trait Data {
|
||||
fn mark_as_once_joined(user_id: &UserId, room_id: &RoomId) -> Result<()>;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
mod data;
|
||||
pub use data::Data;
|
||||
use std::{collections::HashSet, sync::Arc};
|
||||
|
||||
use crate::service::*;
|
||||
pub use data::Data;
|
||||
use regex::Regex;
|
||||
use ruma::{RoomId, UserId, events::{room::{member::MembershipState, create::RoomCreateEventContent}, AnyStrippedStateEvent, StateEventType, tag::TagEvent, RoomAccountDataEventType, GlobalAccountDataEventType, direct::DirectEvent, ignored_user_list::IgnoredUserListEvent, AnySyncStateEvent}, serde::Raw, ServerName};
|
||||
|
||||
use crate::{service::*, SERVICE, utils, Error};
|
||||
|
||||
pub struct Service<D: Data> {
|
||||
db: D,
|
||||
|
@ -9,7 +13,7 @@ pub struct Service<D: Data> {
|
|||
|
||||
impl Service<_> {
|
||||
/// Update current membership data.
|
||||
#[tracing::instrument(skip(self, last_state, db))]
|
||||
#[tracing::instrument(skip(self, last_state))]
|
||||
pub fn update_membership(
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
|
@ -17,12 +21,11 @@ impl Service<_> {
|
|||
membership: MembershipState,
|
||||
sender: &UserId,
|
||||
last_state: Option<Vec<Raw<AnyStrippedStateEvent>>>,
|
||||
db: &Database,
|
||||
update_joined_count: bool,
|
||||
) -> Result<()> {
|
||||
// Keep track what remote users exist by adding them as "deactivated" users
|
||||
if user_id.server_name() != db.globals.server_name() {
|
||||
db.users.create(user_id, None)?;
|
||||
if user_id.server_name() != SERVICE.globals.server_name() {
|
||||
SERVICE.users.create(user_id, None)?;
|
||||
// TODO: displayname, avatar url
|
||||
}
|
||||
|
||||
|
@ -82,7 +85,7 @@ impl Service<_> {
|
|||
user_id,
|
||||
RoomAccountDataEventType::Tag,
|
||||
)? {
|
||||
db.account_data
|
||||
SERVICE.account_data
|
||||
.update(
|
||||
Some(room_id),
|
||||
user_id,
|
||||
|
@ -94,7 +97,7 @@ impl Service<_> {
|
|||
};
|
||||
|
||||
// Copy direct chat flag
|
||||
if let Some(mut direct_event) = db.account_data.get::<DirectEvent>(
|
||||
if let Some(mut direct_event) = SERVICE.account_data.get::<DirectEvent>(
|
||||
None,
|
||||
user_id,
|
||||
GlobalAccountDataEventType::Direct.to_string().into(),
|
||||
|
@ -109,12 +112,11 @@ impl Service<_> {
|
|||
}
|
||||
|
||||
if room_ids_updated {
|
||||
db.account_data.update(
|
||||
SERVICE.account_data.update(
|
||||
None,
|
||||
user_id,
|
||||
GlobalAccountDataEventType::Direct.to_string().into(),
|
||||
&direct_event,
|
||||
&db.globals,
|
||||
)?;
|
||||
}
|
||||
};
|
||||
|
@ -130,7 +132,7 @@ impl Service<_> {
|
|||
}
|
||||
MembershipState::Invite => {
|
||||
// We want to know if the sender is ignored by the receiver
|
||||
let is_ignored = db
|
||||
let is_ignored = SERVICE
|
||||
.account_data
|
||||
.get::<IgnoredUserListEvent>(
|
||||
None, // Ignored users are in global account data
|
||||
|
@ -186,7 +188,7 @@ impl Service<_> {
|
|||
}
|
||||
|
||||
#[tracing::instrument(skip(self, room_id, db))]
|
||||
pub fn update_joined_count(&self, room_id: &RoomId, db: &Database) -> Result<()> {
|
||||
pub fn update_joined_count(&self, room_id: &RoomId) -> Result<()> {
|
||||
let mut joinedcount = 0_u64;
|
||||
let mut invitedcount = 0_u64;
|
||||
let mut joined_servers = HashSet::new();
|
||||
|
@ -226,11 +228,10 @@ impl Service<_> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self, room_id, db))]
|
||||
#[tracing::instrument(skip(self, room_id))]
|
||||
pub fn get_our_real_users(
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
db: &Database,
|
||||
) -> Result<Arc<HashSet<Box<UserId>>>> {
|
||||
let maybe = self
|
||||
.our_real_users_cache
|
||||
|
@ -241,7 +242,7 @@ impl Service<_> {
|
|||
if let Some(users) = maybe {
|
||||
Ok(users)
|
||||
} else {
|
||||
self.update_joined_count(room_id, db)?;
|
||||
self.update_joined_count(room_id)?;
|
||||
Ok(Arc::clone(
|
||||
self.our_real_users_cache
|
||||
.read()
|
||||
|
@ -252,12 +253,11 @@ impl Service<_> {
|
|||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self, room_id, appservice, db))]
|
||||
#[tracing::instrument(skip(self, room_id, appservice))]
|
||||
pub fn appservice_in_room(
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
appservice: &(String, serde_yaml::Value),
|
||||
db: &Database,
|
||||
) -> Result<bool> {
|
||||
let maybe = self
|
||||
.appservice_in_room_cache
|
||||
|
@ -285,7 +285,7 @@ impl Service<_> {
|
|||
.get("sender_localpart")
|
||||
.and_then(|string| string.as_str())
|
||||
.and_then(|string| {
|
||||
UserId::parse_with_server_name(string, db.globals.server_name()).ok()
|
||||
UserId::parse_with_server_name(string, SERVICE.globals.server_name()).ok()
|
||||
});
|
||||
|
||||
let in_room = bridge_user_id
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
struct StateDiff {
|
||||
use crate::service::rooms::CompressedStateEvent;
|
||||
|
||||
pub struct StateDiff {
|
||||
parent: Option<u64>,
|
||||
added: Vec<CompressedStateEvent>,
|
||||
removed: Vec<CompressedStateEvent>,
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
mod data;
|
||||
pub use data::Data;
|
||||
pub mod data;
|
||||
use std::{mem::size_of, sync::Arc, collections::HashSet};
|
||||
|
||||
use crate::service::*;
|
||||
pub use data::Data;
|
||||
use ruma::{EventId, RoomId};
|
||||
|
||||
use crate::{service::*, utils};
|
||||
|
||||
use self::data::StateDiff;
|
||||
|
||||
pub struct Service<D: Data> {
|
||||
db: D,
|
||||
|
@ -30,9 +35,9 @@ impl Service<_> {
|
|||
return Ok(r.clone());
|
||||
}
|
||||
|
||||
self.db.get_statediff(shortstatehash)?;
|
||||
let StateDiff { parent, added, removed } = self.db.get_statediff(shortstatehash)?;
|
||||
|
||||
if parent != 0_u64 {
|
||||
if let Some(parent) = parent {
|
||||
let mut response = self.load_shortstatehash_info(parent)?;
|
||||
let mut state = response.last().unwrap().1.clone();
|
||||
state.extend(added.iter().copied());
|
||||
|
@ -155,7 +160,7 @@ impl Service<_> {
|
|||
|
||||
if parent_states.is_empty() {
|
||||
// There is no parent layer, create a new state
|
||||
self.db.save_statediff(shortstatehash, StateDiff { parent: 0, new: statediffnew, removed: statediffremoved })?;
|
||||
self.db.save_statediff(shortstatehash, StateDiff { parent: None, added: statediffnew, removed: statediffremoved })?;
|
||||
|
||||
return Ok(());
|
||||
};
|
||||
|
@ -197,7 +202,7 @@ impl Service<_> {
|
|||
)?;
|
||||
} else {
|
||||
// Diff small enough, we add diff as layer on top of parent
|
||||
self.db.save_statediff(shortstatehash, StateDiff { parent: parent.0, new: statediffnew, removed: statediffremoved })?;
|
||||
self.db.save_statediff(shortstatehash, StateDiff { parent: Some(parent.0), added: statediffnew, removed: statediffremoved })?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use ruma::{signatures::CanonicalJsonObject, EventId, UserId, RoomId};
|
||||
|
||||
use crate::PduEvent;
|
||||
|
||||
pub trait Data {
|
||||
fn last_timeline_count(&self, sender_user: &UserId, room_id: &RoomId) -> Result<u64>;
|
||||
|
||||
|
@ -5,34 +11,37 @@ pub trait Data {
|
|||
fn get_pdu_count(&self, event_id: &EventId) -> Result<Option<u64>>;
|
||||
|
||||
/// Returns the json of a pdu.
|
||||
pub fn get_pdu_json(&self, event_id: &EventId) -> Result<Option<CanonicalJsonObject>>;
|
||||
fn get_pdu_json(&self, event_id: &EventId) -> Result<Option<CanonicalJsonObject>>;
|
||||
|
||||
/// Returns the json of a pdu.
|
||||
pub fn get_non_outlier_pdu_json(
|
||||
fn get_non_outlier_pdu_json(
|
||||
&self,
|
||||
event_id: &EventId,
|
||||
) -> Result<Option<CanonicalJsonObject>>;
|
||||
|
||||
/// Returns the pdu's id.
|
||||
pub fn get_pdu_id(&self, event_id: &EventId) -> Result<Option<Vec<u8>>>;
|
||||
fn get_pdu_id(&self, event_id: &EventId) -> Result<Option<Vec<u8>>>;
|
||||
|
||||
/// Returns the pdu.
|
||||
///
|
||||
/// Checks the `eventid_outlierpdu` Tree if not found in the timeline.
|
||||
pub fn get_non_outlier_pdu(&self, event_id: &EventId) -> Result<Option<PduEvent>>;
|
||||
fn get_non_outlier_pdu(&self, event_id: &EventId) -> Result<Option<PduEvent>>;
|
||||
|
||||
/// Returns the pdu.
|
||||
///
|
||||
/// Checks the `eventid_outlierpdu` Tree if not found in the timeline.
|
||||
pub fn get_pdu(&self, event_id: &EventId) -> Result<Option<Arc<PduEvent>>>;
|
||||
fn get_pdu(&self, event_id: &EventId) -> Result<Option<Arc<PduEvent>>>;
|
||||
|
||||
/// Returns the pdu.
|
||||
///
|
||||
/// This does __NOT__ check the outliers `Tree`.
|
||||
pub fn get_pdu_from_id(&self, pdu_id: &[u8]) -> Result<Option<PduEvent>>;
|
||||
fn get_pdu_from_id(&self, pdu_id: &[u8]) -> Result<Option<PduEvent>>;
|
||||
|
||||
/// Returns the pdu as a `BTreeMap<String, CanonicalJsonValue>`.
|
||||
pub fn get_pdu_json_from_id(&self, pdu_id: &[u8]) -> Result<Option<CanonicalJsonObject>>;
|
||||
fn get_pdu_json_from_id(&self, pdu_id: &[u8]) -> Result<Option<CanonicalJsonObject>>;
|
||||
|
||||
/// Returns the `count` of this pdu's id.
|
||||
pub fn pdu_count(&self, pdu_id: &[u8]) -> Result<u64>;
|
||||
fn pdu_count(&self, pdu_id: &[u8]) -> Result<u64>;
|
||||
|
||||
/// Removes a pdu and creates a new one with the same id.
|
||||
fn replace_pdu(&self, pdu_id: &[u8], pdu: &PduEvent) -> Result<()>;
|
||||
|
@ -40,7 +49,7 @@ pub trait Data {
|
|||
/// Returns an iterator over all events in a room that happened after the event with id `since`
|
||||
/// in chronological order.
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn pdus_since<'a>(
|
||||
fn pdus_since<'a>(
|
||||
&'a self,
|
||||
user_id: &UserId,
|
||||
room_id: &RoomId,
|
||||
|
@ -50,14 +59,14 @@ pub trait Data {
|
|||
/// Returns an iterator over all events and their tokens in a room that happened before the
|
||||
/// event with id `until` in reverse-chronological order.
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub fn pdus_until<'a>(
|
||||
fn pdus_until<'a>(
|
||||
&'a self,
|
||||
user_id: &UserId,
|
||||
room_id: &RoomId,
|
||||
until: u64,
|
||||
) -> Result<impl Iterator<Item = Result<(Vec<u8>, PduEvent)>> + 'a>;
|
||||
|
||||
pub fn pdus_after<'a>(
|
||||
fn pdus_after<'a>(
|
||||
&'a self,
|
||||
user_id: &UserId,
|
||||
room_id: &RoomId,
|
||||
|
|
|
@ -1,7 +1,17 @@
|
|||
mod data;
|
||||
pub use data::Data;
|
||||
use std::{sync::MutexGuard, iter, collections::HashSet};
|
||||
use std::fmt::Debug;
|
||||
|
||||
use crate::service::*;
|
||||
pub use data::Data;
|
||||
use regex::Regex;
|
||||
use ruma::signatures::CanonicalJsonValue;
|
||||
use ruma::{EventId, signatures::CanonicalJsonObject, push::{Action, Tweak}, events::{push_rules::PushRulesEvent, GlobalAccountDataEventType, RoomEventType, room::{member::MembershipState, create::RoomCreateEventContent}, StateEventType}, UserId, RoomAliasId, RoomId, uint, state_res, api::client::error::ErrorKind, serde::to_canonical_value, ServerName};
|
||||
use serde::Deserialize;
|
||||
use serde_json::value::to_raw_value;
|
||||
use tracing::{warn, error};
|
||||
|
||||
use crate::SERVICE;
|
||||
use crate::{service::{*, pdu::{PduBuilder, EventHash}}, Error, PduEvent, utils};
|
||||
|
||||
pub struct Service<D: Data> {
|
||||
db: D,
|
||||
|
@ -126,13 +136,12 @@ impl Service<_> {
|
|||
/// in `append_pdu`.
|
||||
///
|
||||
/// Returns pdu id
|
||||
#[tracing::instrument(skip(self, pdu, pdu_json, leaves, db))]
|
||||
#[tracing::instrument(skip(self, pdu, pdu_json, leaves))]
|
||||
pub fn append_pdu<'a>(
|
||||
&self,
|
||||
pdu: &PduEvent,
|
||||
mut pdu_json: CanonicalJsonObject,
|
||||
leaves: impl IntoIterator<Item = &'a EventId> + Debug,
|
||||
db: &Database,
|
||||
) -> Result<Vec<u8>> {
|
||||
let shortroomid = self.get_shortroomid(&pdu.room_id)?.expect("room exists");
|
||||
|
||||
|
@ -249,7 +258,6 @@ impl Service<_> {
|
|||
&power_levels,
|
||||
&sync_pdu,
|
||||
&pdu.room_id,
|
||||
db,
|
||||
)? {
|
||||
match action {
|
||||
Action::DontNotify => notify = false,
|
||||
|
@ -446,9 +454,8 @@ impl Service<_> {
|
|||
pdu_builder: PduBuilder,
|
||||
sender: &UserId,
|
||||
room_id: &RoomId,
|
||||
db: &Database,
|
||||
_mutex_lock: &MutexGuard<'_, ()>, // Take mutex guard to make sure users get the room state mutex
|
||||
) -> (PduEvent, CanonicalJsonObj) {
|
||||
) -> (PduEvent, CanonicalJsonObject) {
|
||||
let PduBuilder {
|
||||
event_type,
|
||||
content,
|
||||
|
@ -457,14 +464,14 @@ impl Service<_> {
|
|||
redacts,
|
||||
} = pdu_builder;
|
||||
|
||||
let prev_events: Vec<_> = db
|
||||
let prev_events: Vec<_> = SERVICE
|
||||
.rooms
|
||||
.get_pdu_leaves(room_id)?
|
||||
.into_iter()
|
||||
.take(20)
|
||||
.collect();
|
||||
|
||||
let create_event = db
|
||||
let create_event = SERVICE
|
||||
.rooms
|
||||
.room_state_get(room_id, &StateEventType::RoomCreate, "")?;
|
||||
|
||||
|
@ -481,7 +488,7 @@ impl Service<_> {
|
|||
// If there was no create event yet, assume we are creating a room with the default
|
||||
// version right now
|
||||
let room_version_id = create_event_content
|
||||
.map_or(db.globals.default_room_version(), |create_event| {
|
||||
.map_or(SERVICE.globals.default_room_version(), |create_event| {
|
||||
create_event.room_version
|
||||
});
|
||||
let room_version =
|
||||
|
@ -575,8 +582,8 @@ impl Service<_> {
|
|||
);
|
||||
|
||||
match ruma::signatures::hash_and_sign_event(
|
||||
db.globals.server_name().as_str(),
|
||||
db.globals.keypair(),
|
||||
SERVICE.globals.server_name().as_str(),
|
||||
SERVICE.globals.keypair(),
|
||||
&mut pdu_json,
|
||||
&room_version_id,
|
||||
) {
|
||||
|
@ -614,22 +621,21 @@ impl Service<_> {
|
|||
|
||||
/// Creates a new persisted data unit and adds it to a room. This function takes a
|
||||
/// roomid_mutex_state, meaning that only this function is able to mutate the room state.
|
||||
#[tracing::instrument(skip(self, db, _mutex_lock))]
|
||||
#[tracing::instrument(skip(self, _mutex_lock))]
|
||||
pub fn build_and_append_pdu(
|
||||
&self,
|
||||
pdu_builder: PduBuilder,
|
||||
sender: &UserId,
|
||||
room_id: &RoomId,
|
||||
db: &Database,
|
||||
_mutex_lock: &MutexGuard<'_, ()>, // Take mutex guard to make sure users get the room state mutex
|
||||
) -> Result<Arc<EventId>> {
|
||||
|
||||
let (pdu, pdu_json) = create_hash_and_sign_event()?;
|
||||
let (pdu, pdu_json) = self.create_hash_and_sign_event()?;
|
||||
|
||||
|
||||
// We append to state before appending the pdu, so we don't have a moment in time with the
|
||||
// pdu without it's state. This is okay because append_pdu can't fail.
|
||||
let statehashid = self.append_to_state(&pdu, &db.globals)?;
|
||||
let statehashid = self.append_to_state(&pdu)?;
|
||||
|
||||
let pdu_id = self.append_pdu(
|
||||
&pdu,
|
||||
|
@ -637,7 +643,6 @@ impl Service<_> {
|
|||
// Since this PDU references all pdu_leaves we can update the leaves
|
||||
// of the room
|
||||
iter::once(&*pdu.event_id),
|
||||
db,
|
||||
)?;
|
||||
|
||||
// We set the room state after inserting the pdu, so that we never have a moment in time
|
||||
|
@ -659,9 +664,9 @@ impl Service<_> {
|
|||
}
|
||||
|
||||
// Remove our server from the server list since it will be added to it by room_servers() and/or the if statement above
|
||||
servers.remove(db.globals.server_name());
|
||||
servers.remove(SERVICE.globals.server_name());
|
||||
|
||||
db.sending.send_pdu(servers.into_iter(), &pdu_id)?;
|
||||
SERVICE.sending.send_pdu(servers.into_iter(), &pdu_id)?;
|
||||
|
||||
Ok(pdu.event_id)
|
||||
}
|
||||
|
@ -670,7 +675,6 @@ impl Service<_> {
|
|||
/// server that sent the event.
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn append_incoming_pdu<'a>(
|
||||
db: &Database,
|
||||
pdu: &PduEvent,
|
||||
pdu_json: CanonicalJsonObject,
|
||||
new_room_leaves: impl IntoIterator<Item = &'a EventId> + Clone + Debug,
|
||||
|
@ -680,21 +684,20 @@ impl Service<_> {
|
|||
) -> Result<Option<Vec<u8>>> {
|
||||
// We append to state before appending the pdu, so we don't have a moment in time with the
|
||||
// pdu without it's state. This is okay because append_pdu can't fail.
|
||||
db.rooms.set_event_state(
|
||||
SERVICE.rooms.set_event_state(
|
||||
&pdu.event_id,
|
||||
&pdu.room_id,
|
||||
state_ids_compressed,
|
||||
&db.globals,
|
||||
)?;
|
||||
|
||||
if soft_fail {
|
||||
db.rooms
|
||||
SERVICE.rooms
|
||||
.mark_as_referenced(&pdu.room_id, &pdu.prev_events)?;
|
||||
db.rooms.replace_pdu_leaves(&pdu.room_id, new_room_leaves)?;
|
||||
SERVICE.rooms.replace_pdu_leaves(&pdu.room_id, new_room_leaves)?;
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let pdu_id = db.rooms.append_pdu(pdu, pdu_json, new_room_leaves, db)?;
|
||||
let pdu_id = SERVICE.rooms.append_pdu(pdu, pdu_json, new_room_leaves)?;
|
||||
|
||||
Ok(Some(pdu_id))
|
||||
}
|
||||
|
@ -756,4 +759,4 @@ impl Service<_> {
|
|||
// If event does not exist, just noop
|
||||
Ok(())
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
mod data;
|
||||
pub use data::Data;
|
||||
use ruma::{RoomId, UserId};
|
||||
|
||||
use crate::service::*;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
pub trait Data {
|
||||
pub fn add_txnid(
|
||||
fn add_txnid(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
device_id: Option<&DeviceId>,
|
||||
|
@ -7,7 +7,7 @@ pub trait Data {
|
|||
data: &[u8],
|
||||
) -> Result<()>;
|
||||
|
||||
pub fn existing_txnid(
|
||||
fn existing_txnid(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
device_id: Option<&DeviceId>,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
mod data;
|
||||
pub use data::Data;
|
||||
use ruma::{UserId, DeviceId, TransactionId};
|
||||
|
||||
use crate::service::*;
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use ruma::{api::client::uiaa::UiaaInfo, DeviceId, UserId, signatures::CanonicalJsonValue};
|
||||
|
||||
pub trait Data {
|
||||
fn set_uiaa_request(
|
||||
&self,
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
mod data;
|
||||
pub use data::Data;
|
||||
use ruma::{api::client::{uiaa::{UiaaInfo, IncomingAuthData, IncomingPassword, AuthType}, error::ErrorKind}, DeviceId, UserId, signatures::CanonicalJsonValue};
|
||||
use tracing::error;
|
||||
|
||||
use crate::service::*;
|
||||
use crate::{service::*, utils, Error, SERVICE};
|
||||
|
||||
pub struct Service<D: Data> {
|
||||
db: D,
|
||||
|
@ -36,8 +38,6 @@ impl Service<_> {
|
|||
device_id: &DeviceId,
|
||||
auth: &IncomingAuthData,
|
||||
uiaainfo: &UiaaInfo,
|
||||
users: &super::users::Users,
|
||||
globals: &super::globals::Globals,
|
||||
) -> Result<(bool, UiaaInfo)> {
|
||||
let mut uiaainfo = auth
|
||||
.session()
|
||||
|
@ -66,13 +66,13 @@ impl Service<_> {
|
|||
};
|
||||
|
||||
let user_id =
|
||||
UserId::parse_with_server_name(username.clone(), globals.server_name())
|
||||
UserId::parse_with_server_name(username.clone(), SERVICE.globals.server_name())
|
||||
.map_err(|_| {
|
||||
Error::BadRequest(ErrorKind::InvalidParam, "User ID is invalid.")
|
||||
})?;
|
||||
|
||||
// Check if password is correct
|
||||
if let Some(hash) = users.password_hash(&user_id)? {
|
||||
if let Some(hash) = SERVICE.users.password_hash(&user_id)? {
|
||||
let hash_matches =
|
||||
argon2::verify_encoded(&hash, password.as_bytes()).unwrap_or(false);
|
||||
|
||||
|
|
|
@ -1,34 +1,27 @@
|
|||
pub trait Data {
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use ruma::{UserId, DeviceId, DeviceKeyAlgorithm, DeviceKeyId, serde::Raw, encryption::{OneTimeKey, DeviceKeys, CrossSigningKey}, UInt, events::AnyToDeviceEvent, api::client::{device::Device, filter::IncomingFilterDefinition}, MxcUri};
|
||||
|
||||
trait Data {
|
||||
/// Check if a user has an account on this homeserver.
|
||||
pub fn exists(&self, user_id: &UserId) -> Result<bool>;
|
||||
fn exists(&self, user_id: &UserId) -> Result<bool>;
|
||||
|
||||
/// Check if account is deactivated
|
||||
pub fn is_deactivated(&self, user_id: &UserId) -> Result<bool>;
|
||||
|
||||
/// Check if a user is an admin
|
||||
pub fn is_admin(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
rooms: &super::rooms::Rooms,
|
||||
globals: &super::globals::Globals,
|
||||
) -> Result<bool>;
|
||||
|
||||
/// Create a new user account on this homeserver.
|
||||
pub fn create(&self, user_id: &UserId, password: Option<&str>) -> Result<()>;
|
||||
fn is_deactivated(&self, user_id: &UserId) -> Result<bool>;
|
||||
|
||||
/// Returns the number of users registered on this server.
|
||||
pub fn count(&self) -> Result<usize>;
|
||||
fn count(&self) -> Result<usize>;
|
||||
|
||||
/// Find out which user an access token belongs to.
|
||||
pub fn find_from_token(&self, token: &str) -> Result<Option<(Box<UserId>, String)>>;
|
||||
fn find_from_token(&self, token: &str) -> Result<Option<(Box<UserId>, String)>>;
|
||||
|
||||
/// Returns an iterator over all users on this homeserver.
|
||||
pub fn iter(&self) -> impl Iterator<Item = Result<Box<UserId>>> + '_;
|
||||
fn iter(&self) -> impl Iterator<Item = Result<Box<UserId>>> + '_;
|
||||
|
||||
/// Returns a list of local users as list of usernames.
|
||||
///
|
||||
/// A user account is considered `local` if the length of it's password is greater then zero.
|
||||
pub fn list_local_users(&self) -> Result<Vec<String>>;
|
||||
fn list_local_users(&self) -> Result<Vec<String>>;
|
||||
|
||||
/// Will only return with Some(username) if the password was not empty and the
|
||||
/// username could be successfully parsed.
|
||||
|
@ -37,31 +30,31 @@ pub trait Data {
|
|||
fn get_username_with_valid_password(&self, username: &[u8], password: &[u8]) -> Option<String>;
|
||||
|
||||
/// Returns the password hash for the given user.
|
||||
pub fn password_hash(&self, user_id: &UserId) -> Result<Option<String>>;
|
||||
fn password_hash(&self, user_id: &UserId) -> Result<Option<String>>;
|
||||
|
||||
/// Hash and set the user's password to the Argon2 hash
|
||||
pub fn set_password(&self, user_id: &UserId, password: Option<&str>) -> Result<()>;
|
||||
fn set_password(&self, user_id: &UserId, password: Option<&str>) -> Result<()>;
|
||||
|
||||
/// Returns the displayname of a user on this homeserver.
|
||||
pub fn displayname(&self, user_id: &UserId) -> Result<Option<String>>;
|
||||
fn displayname(&self, user_id: &UserId) -> Result<Option<String>>;
|
||||
|
||||
/// Sets a new displayname or removes it if displayname is None. You still need to nofify all rooms of this change.
|
||||
pub fn set_displayname(&self, user_id: &UserId, displayname: Option<String>) -> Result<()>;
|
||||
fn set_displayname(&self, user_id: &UserId, displayname: Option<String>) -> Result<()>;
|
||||
|
||||
/// Get the avatar_url of a user.
|
||||
pub fn avatar_url(&self, user_id: &UserId) -> Result<Option<Box<MxcUri>>>;
|
||||
fn avatar_url(&self, user_id: &UserId) -> Result<Option<Box<MxcUri>>>;
|
||||
|
||||
/// Sets a new avatar_url or removes it if avatar_url is None.
|
||||
pub fn set_avatar_url(&self, user_id: &UserId, avatar_url: Option<Box<MxcUri>>) -> Result<()>;
|
||||
fn set_avatar_url(&self, user_id: &UserId, avatar_url: Option<Box<MxcUri>>) -> Result<()>;
|
||||
|
||||
/// Get the blurhash of a user.
|
||||
pub fn blurhash(&self, user_id: &UserId) -> Result<Option<String>>;
|
||||
fn blurhash(&self, user_id: &UserId) -> Result<Option<String>>;
|
||||
|
||||
/// Sets a new avatar_url or removes it if avatar_url is None.
|
||||
pub fn set_blurhash(&self, user_id: &UserId, blurhash: Option<String>) -> Result<()>;
|
||||
fn set_blurhash(&self, user_id: &UserId, blurhash: Option<String>) -> Result<()>;
|
||||
|
||||
/// Adds a new device to a user.
|
||||
pub fn create_device(
|
||||
fn create_device(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
device_id: &DeviceId,
|
||||
|
@ -70,129 +63,118 @@ pub trait Data {
|
|||
) -> Result<()>;
|
||||
|
||||
/// Removes a device from a user.
|
||||
pub fn remove_device(&self, user_id: &UserId, device_id: &DeviceId) -> Result<()>;
|
||||
fn remove_device(&self, user_id: &UserId, device_id: &DeviceId) -> Result<()>;
|
||||
|
||||
/// Returns an iterator over all device ids of this user.
|
||||
pub fn all_device_ids<'a>(
|
||||
fn all_device_ids<'a>(
|
||||
&'a self,
|
||||
user_id: &UserId,
|
||||
) -> impl Iterator<Item = Result<Box<DeviceId>>> + 'a;
|
||||
|
||||
/// Replaces the access token of one device.
|
||||
pub fn set_token(&self, user_id: &UserId, device_id: &DeviceId, token: &str) -> Result<()>;
|
||||
fn set_token(&self, user_id: &UserId, device_id: &DeviceId, token: &str) -> Result<()>;
|
||||
|
||||
pub fn add_one_time_key(
|
||||
fn add_one_time_key(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
device_id: &DeviceId,
|
||||
one_time_key_key: &DeviceKeyId,
|
||||
one_time_key_value: &Raw<OneTimeKey>,
|
||||
globals: &super::globals::Globals,
|
||||
) -> Result<()>;
|
||||
|
||||
pub fn last_one_time_keys_update(&self, user_id: &UserId) -> Result<u64>;
|
||||
fn last_one_time_keys_update(&self, user_id: &UserId) -> Result<u64>;
|
||||
|
||||
pub fn take_one_time_key(
|
||||
fn take_one_time_key(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
device_id: &DeviceId,
|
||||
key_algorithm: &DeviceKeyAlgorithm,
|
||||
globals: &super::globals::Globals,
|
||||
) -> Result<Option<(Box<DeviceKeyId>, Raw<OneTimeKey>)>>;
|
||||
|
||||
pub fn count_one_time_keys(
|
||||
fn count_one_time_keys(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
device_id: &DeviceId,
|
||||
) -> Result<BTreeMap<DeviceKeyAlgorithm, UInt>>;
|
||||
|
||||
pub fn add_device_keys(
|
||||
fn add_device_keys(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
device_id: &DeviceId,
|
||||
device_keys: &Raw<DeviceKeys>,
|
||||
rooms: &super::rooms::Rooms,
|
||||
globals: &super::globals::Globals,
|
||||
) -> Result<()>;
|
||||
|
||||
pub fn add_cross_signing_keys(
|
||||
fn add_cross_signing_keys(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
master_key: &Raw<CrossSigningKey>,
|
||||
self_signing_key: &Option<Raw<CrossSigningKey>>,
|
||||
user_signing_key: &Option<Raw<CrossSigningKey>>,
|
||||
rooms: &super::rooms::Rooms,
|
||||
globals: &super::globals::Globals,
|
||||
) -> Result<()>;
|
||||
|
||||
pub fn sign_key(
|
||||
fn sign_key(
|
||||
&self,
|
||||
target_id: &UserId,
|
||||
key_id: &str,
|
||||
signature: (String, String),
|
||||
sender_id: &UserId,
|
||||
rooms: &super::rooms::Rooms,
|
||||
globals: &super::globals::Globals,
|
||||
) -> Result<()>;
|
||||
|
||||
pub fn keys_changed<'a>(
|
||||
fn keys_changed<'a>(
|
||||
&'a self,
|
||||
user_or_room_id: &str,
|
||||
from: u64,
|
||||
to: Option<u64>,
|
||||
) -> impl Iterator<Item = Result<Box<UserId>>> + 'a;
|
||||
|
||||
pub fn mark_device_key_update(
|
||||
fn mark_device_key_update(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
rooms: &super::rooms::Rooms,
|
||||
globals: &super::globals::Globals,
|
||||
) -> Result<()>;
|
||||
|
||||
pub fn get_device_keys(
|
||||
fn get_device_keys(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
device_id: &DeviceId,
|
||||
) -> Result<Option<Raw<DeviceKeys>>>;
|
||||
|
||||
pub fn get_master_key<F: Fn(&UserId) -> bool>(
|
||||
fn get_master_key<F: Fn(&UserId) -> bool>(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
allowed_signatures: F,
|
||||
) -> Result<Option<Raw<CrossSigningKey>>>;
|
||||
|
||||
pub fn get_self_signing_key<F: Fn(&UserId) -> bool>(
|
||||
fn get_self_signing_key<F: Fn(&UserId) -> bool>(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
allowed_signatures: F,
|
||||
) -> Result<Option<Raw<CrossSigningKey>>>;
|
||||
|
||||
pub fn get_user_signing_key(&self, user_id: &UserId) -> Result<Option<Raw<CrossSigningKey>>>;
|
||||
fn get_user_signing_key(&self, user_id: &UserId) -> Result<Option<Raw<CrossSigningKey>>>;
|
||||
|
||||
pub fn add_to_device_event(
|
||||
fn add_to_device_event(
|
||||
&self,
|
||||
sender: &UserId,
|
||||
target_user_id: &UserId,
|
||||
target_device_id: &DeviceId,
|
||||
event_type: &str,
|
||||
content: serde_json::Value,
|
||||
globals: &super::globals::Globals,
|
||||
) -> Result<()>;
|
||||
|
||||
pub fn get_to_device_events(
|
||||
fn get_to_device_events(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
device_id: &DeviceId,
|
||||
) -> Result<Vec<Raw<AnyToDeviceEvent>>>;
|
||||
|
||||
pub fn remove_to_device_events(
|
||||
fn remove_to_device_events(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
device_id: &DeviceId,
|
||||
until: u64,
|
||||
) -> Result<()>;
|
||||
|
||||
pub fn update_device_metadata(
|
||||
fn update_device_metadata(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
device_id: &DeviceId,
|
||||
|
@ -200,27 +182,27 @@ pub trait Data {
|
|||
) -> Result<()>;
|
||||
|
||||
/// Get device metadata.
|
||||
pub fn get_device_metadata(
|
||||
fn get_device_metadata(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
device_id: &DeviceId,
|
||||
) -> Result<Option<Device>>;
|
||||
|
||||
pub fn get_devicelist_version(&self, user_id: &UserId) -> Result<Option<u64>>;
|
||||
fn get_devicelist_version(&self, user_id: &UserId) -> Result<Option<u64>>;
|
||||
|
||||
pub fn all_devices_metadata<'a>(
|
||||
fn all_devices_metadata<'a>(
|
||||
&'a self,
|
||||
user_id: &UserId,
|
||||
) -> impl Iterator<Item = Result<Device>> + 'a;
|
||||
|
||||
/// Creates a new sync filter. Returns the filter id.
|
||||
pub fn create_filter(
|
||||
fn create_filter(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
filter: &IncomingFilterDefinition,
|
||||
) -> Result<String>;
|
||||
|
||||
pub fn get_filter(
|
||||
fn get_filter(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
filter_id: &str,
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
mod data;
|
||||
pub use data::Data;
|
||||
use std::{collections::BTreeMap, mem};
|
||||
|
||||
use crate::service::*;
|
||||
pub use data::Data;
|
||||
use ruma::{UserId, MxcUri, DeviceId, DeviceKeyId, serde::Raw, encryption::{OneTimeKey, CrossSigningKey, DeviceKeys}, DeviceKeyAlgorithm, UInt, events::AnyToDeviceEvent, api::client::{device::Device, filter::IncomingFilterDefinition}};
|
||||
|
||||
use crate::{service::*, Error};
|
||||
|
||||
pub struct Service<D: Data> {
|
||||
db: D,
|
||||
|
@ -19,18 +22,24 @@ impl Service<_> {
|
|||
}
|
||||
|
||||
/// Check if a user is an admin
|
||||
pub fn is_admin(
|
||||
fn is_admin(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
) -> Result<bool> {
|
||||
self.db.is_admin(user_id)
|
||||
let admin_room_alias_id = RoomAliasId::parse(format!("#admins:{}", globals.server_name()))
|
||||
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Invalid alias."))?;
|
||||
let admin_room_id = rooms.id_from_alias(&admin_room_alias_id)?.unwrap();
|
||||
|
||||
rooms.is_joined(user_id, &admin_room_id)
|
||||
}
|
||||
|
||||
/// Create a new user account on this homeserver.
|
||||
pub fn create(&self, user_id: &UserId, password: Option<&str>) -> Result<()> {
|
||||
self.db.set_password(user_id, password)
|
||||
fn create(&self, user_id: &UserId, password: Option<&str>) -> Result<()> {
|
||||
self.db.set_password(user_id, password)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
/// Returns the number of users registered on this server.
|
||||
pub fn count(&self) -> Result<usize> {
|
||||
self.db.count()
|
||||
|
@ -136,7 +145,6 @@ impl Service<_> {
|
|||
device_id: &DeviceId,
|
||||
one_time_key_key: &DeviceKeyId,
|
||||
one_time_key_value: &Raw<OneTimeKey>,
|
||||
globals: &super::globals::Globals,
|
||||
) -> Result<()> {
|
||||
self.db.add_one_time_key(user_id, device_id, one_time_key_key, one_time_key_value)
|
||||
}
|
||||
|
@ -220,7 +228,7 @@ impl Service<_> {
|
|||
user_id: &UserId,
|
||||
allowed_signatures: F,
|
||||
) -> Result<Option<Raw<CrossSigningKey>>> {
|
||||
self.db.get_master_key(user_id, allow_signatures)
|
||||
self.db.get_master_key(user_id, allowed_signatures)
|
||||
}
|
||||
|
||||
pub fn get_self_signing_key<F: Fn(&UserId) -> bool>(
|
||||
|
@ -327,7 +335,7 @@ impl Service<_> {
|
|||
}
|
||||
|
||||
/// Ensure that a user only sees signatures from themselves and the target user
|
||||
fn clean_signatures<F: Fn(&UserId) -> bool>(
|
||||
pub fn clean_signatures<F: Fn(&UserId) -> bool>(
|
||||
cross_signing_key: &mut serde_json::Value,
|
||||
user_id: &UserId,
|
||||
allowed_signatures: F,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue