(BROKEN) initial work on postgres

This commit is contained in:
tezlm 2024-01-26 17:32:10 -08:00
parent f2acf11ca9
commit b2c4fd3a17
Signed by: tezlm
GPG key ID: 649733FCD94AFBBA
69 changed files with 2376 additions and 1930 deletions

13
Cargo.lock generated
View file

@ -134,6 +134,7 @@ checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf"
dependencies = [
"async-trait",
"axum-core",
"axum-macros",
"bitflags 1.3.2",
"bytes",
"futures-util",
@ -175,6 +176,18 @@ dependencies = [
"tower-service",
]
[[package]]
name = "axum-macros"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdca6a10ecad987bda04e95606ef85a5417dcaac1a78455242d72e031e2b6b62"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 2.0.46",
]
[[package]]
name = "axum-server"
version = "0.5.1"

View file

@ -19,7 +19,7 @@ rust-version = "1.70.0"
[dependencies]
# Web framework
axum = { version = "0.6.18", default-features = false, features = ["form", "headers", "http1", "http2", "json", "matched-path"], optional = true }
axum = { version = "0.6.18", default-features = false, features = ["form", "headers", "http1", "http2", "json", "matched-path", "macros"], optional = true }
axum-server = { version = "0.5.1", features = ["tls-rustls"] }
tower = { version = "0.4.13", features = ["util"] }
tower-http = { version = "0.4.1", features = ["add-extension", "cors", "sensitive-headers", "trace", "util"] }

View file

@ -73,6 +73,7 @@ pub async fn get_register_available_route(
/// - If type is not guest and no username is given: Always fails after UIAA check
/// - Creates a new account and populates it with default account data
/// - If `inhibit_login` is false: Creates a device and returns device id and access_token
// #[axum::debug_handler]
pub async fn register_route(body: Ruma<register::v3::Request>) -> Result<register::v3::Response> {
if !services().globals.allow_registration()
&& !body.from_appservice
@ -144,7 +145,7 @@ pub async fn register_route(body: Ruma<register::v3::Request>) -> Result<registe
"".into(),
auth,
&uiaainfo,
)?;
).await?;
if !worked {
return Err(Error::Uiaa(uiaainfo));
}
@ -171,7 +172,7 @@ pub async fn register_route(body: Ruma<register::v3::Request>) -> Result<registe
};
// Create user
services().users.create(&user_id, password)?;
services().users.create(&user_id, password).await?;
// Default to pretty displayname
let mut displayname = user_id.localpart().to_owned();
@ -183,7 +184,7 @@ pub async fn register_route(body: Ruma<register::v3::Request>) -> Result<registe
services()
.users
.set_displayname(&user_id, Some(displayname.clone()))?;
.set_displayname(&user_id, Some(displayname.clone())).await?;
// Initial account data
services().account_data.update(
@ -208,7 +209,7 @@ pub async fn register_route(body: Ruma<register::v3::Request>) -> Result<registe
expires_in: None,
});
}
// Generate new device id if the user didn't specify one
let device_id = if is_guest {
None
@ -226,7 +227,7 @@ pub async fn register_route(body: Ruma<register::v3::Request>) -> Result<registe
&device_id,
&token,
body.initial_device_display_name.clone(),
)?;
).await?;
info!("New user {} registered on this server.", user_id);
if !body.from_appservice && !is_guest {
@ -239,7 +240,7 @@ pub async fn register_route(body: Ruma<register::v3::Request>) -> Result<registe
// If this is the first real user, grant them admin privileges
// Note: the server user, @conduit:servername, is generated first
if services().users.count()? == 2 {
if services().users.count().await? == 2 {
services()
.admin
.make_user_admin(&user_id, displayname)
@ -248,13 +249,15 @@ pub async fn register_route(body: Ruma<register::v3::Request>) -> Result<registe
warn!("Granting {} admin privileges as the first user", user_id);
}
Ok(register::v3::Response {
access_token: Some(token),
user_id,
device_id: Some(device_id),
refresh_token: None,
expires_in: None,
})
todo!()
// Ok(register::v3::Response {
// access_token: Some(token),
// user_id,
// device_id: Some(device_id),
// refresh_token: None,
// expires_in: None,
// })
}
/// # `POST /_matrix/client/r0/account/password`
@ -291,7 +294,7 @@ pub async fn change_password_route(
let (worked, uiaainfo) =
services()
.uiaa
.try_auth(sender_user, sender_device, auth, &uiaainfo)?;
.try_auth(sender_user, sender_device, auth, &uiaainfo).await?;
if !worked {
return Err(Error::Uiaa(uiaainfo));
}
@ -308,17 +311,18 @@ pub async fn change_password_route(
services()
.users
.set_password(sender_user, Some(&body.new_password))?;
.set_password(sender_user, Some(&body.new_password)).await?;
if body.logout_devices {
// Logout all devices except the current one
for id in services()
.users
.all_device_ids(sender_user)
.await
.filter_map(|id| id.ok())
.filter(|id| id != sender_device)
{
services().users.remove_device(sender_user, &id)?;
services().users.remove_device(sender_user, &id).await?;
}
}
@ -344,7 +348,7 @@ pub async fn whoami_route(body: Ruma<whoami::v3::Request>) -> Result<whoami::v3:
Ok(whoami::v3::Response {
user_id: sender_user.clone(),
device_id,
is_guest: services().users.is_deactivated(sender_user)? && !body.from_appservice,
is_guest: services().users.is_deactivated(sender_user).await? && !body.from_appservice,
})
}
@ -378,7 +382,7 @@ pub async fn deactivate_route(
let (worked, uiaainfo) =
services()
.uiaa
.try_auth(sender_user, sender_device, auth, &uiaainfo)?;
.try_auth(sender_user, sender_device, auth, &uiaainfo).await?;
if !worked {
return Err(Error::Uiaa(uiaainfo));
}
@ -397,7 +401,7 @@ pub async fn deactivate_route(
client_server::leave_all_rooms(sender_user).await?;
// Remove devices and mark account as deactivated
services().users.deactivate_account(sender_user)?;
services().users.deactivate_account(sender_user).await?;
info!("User {} deactivated their account.", sender_user);
services()

View file

@ -18,6 +18,7 @@ pub async fn get_devices_route(
let devices: Vec<device::Device> = services()
.users
.all_devices_metadata(sender_user)
.await
.filter_map(|r| r.ok()) // Filter out buggy devices
.collect();
@ -34,7 +35,7 @@ pub async fn get_device_route(
let device = services()
.users
.get_device_metadata(sender_user, &body.body.device_id)?
.get_device_metadata(sender_user, &body.body.device_id).await?
.ok_or(Error::BadRequest(ErrorKind::NotFound, "Device not found."))?;
Ok(get_device::v3::Response { device })
@ -50,14 +51,14 @@ pub async fn update_device_route(
let mut device = services()
.users
.get_device_metadata(sender_user, &body.device_id)?
.get_device_metadata(sender_user, &body.device_id).await?
.ok_or(Error::BadRequest(ErrorKind::NotFound, "Device not found."))?;
device.display_name = body.display_name.clone();
services()
.users
.update_device_metadata(sender_user, &body.device_id, &device)?;
.update_device_metadata(sender_user, &body.device_id, &device).await?;
Ok(update_device::v3::Response {})
}
@ -92,7 +93,8 @@ pub async fn delete_device_route(
let (worked, uiaainfo) =
services()
.uiaa
.try_auth(sender_user, sender_device, auth, &uiaainfo)?;
.try_auth(sender_user, sender_device, auth, &uiaainfo)
.await?;
if !worked {
return Err(Error::Uiaa(uiaainfo));
}
@ -109,7 +111,8 @@ pub async fn delete_device_route(
services()
.users
.remove_device(sender_user, &body.device_id)?;
.remove_device(sender_user, &body.device_id)
.await?;
Ok(delete_device::v3::Response {})
}
@ -146,7 +149,8 @@ pub async fn delete_devices_route(
let (worked, uiaainfo) =
services()
.uiaa
.try_auth(sender_user, sender_device, auth, &uiaainfo)?;
.try_auth(sender_user, sender_device, auth, &uiaainfo)
.await?;
if !worked {
return Err(Error::Uiaa(uiaainfo));
}
@ -162,7 +166,7 @@ pub async fn delete_devices_route(
}
for device_id in &body.devices {
services().users.remove_device(sender_user, device_id)?
services().users.remove_device(sender_user, device_id).await?
}
Ok(delete_devices::v3::Response {})

View file

@ -13,7 +13,7 @@ pub async fn get_filter_route(
body: Ruma<get_filter::v3::Request>,
) -> Result<get_filter::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
let filter = match services().users.get_filter(sender_user, &body.filter_id)? {
let filter = match services().users.get_filter(sender_user, &body.filter_id).await? {
Some(filter) => filter,
None => return Err(Error::BadRequest(ErrorKind::NotFound, "Filter not found.")),
};
@ -29,6 +29,6 @@ pub async fn create_filter_route(
) -> Result<create_filter::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
Ok(create_filter::v3::Response::new(
services().users.create_filter(sender_user, &body.filter)?,
services().users.create_filter(sender_user, &body.filter).await?,
))
}

View file

@ -38,7 +38,7 @@ pub async fn upload_keys_route(
for (key_key, key_value) in &body.one_time_keys {
services()
.users
.add_one_time_key(sender_user, sender_device, key_key, key_value)?;
.add_one_time_key(sender_user, sender_device, key_key, key_value).await?;
}
if let Some(device_keys) = &body.device_keys {
@ -46,19 +46,19 @@ pub async fn upload_keys_route(
// This check is needed to assure that signatures are kept
if services()
.users
.get_device_keys(sender_user, sender_device)?
.get_device_keys(sender_user, sender_device).await?
.is_none()
{
services()
.users
.add_device_keys(sender_user, sender_device, device_keys)?;
.add_device_keys(sender_user, sender_device, device_keys).await?;
}
}
Ok(upload_keys::v3::Response {
one_time_key_counts: services()
.users
.count_one_time_keys(sender_user, sender_device)?,
.count_one_time_keys(sender_user, sender_device).await?,
})
}
@ -115,7 +115,7 @@ pub async fn upload_signing_keys_route(
let (worked, uiaainfo) =
services()
.uiaa
.try_auth(sender_user, sender_device, auth, &uiaainfo)?;
.try_auth(sender_user, sender_device, auth, &uiaainfo).await?;
if !worked {
return Err(Error::Uiaa(uiaainfo));
}
@ -137,7 +137,7 @@ pub async fn upload_signing_keys_route(
&body.self_signing_key,
&body.user_signing_key,
true, // notify so that other users see the new keys
)?;
).await?;
}
Ok(upload_signing_keys::v3::Response {})
@ -189,7 +189,7 @@ pub async fn upload_signatures_route(
);
services()
.users
.sign_key(user_id, key_id, signature, sender_user)?;
.sign_key(user_id, key_id, signature, sender_user).await?;
}
}
}
@ -225,6 +225,7 @@ pub async fn get_key_changes_route(
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Invalid `to`."))?,
),
)
.await
.filter_map(|r| r.ok()),
);
@ -246,6 +247,7 @@ pub async fn get_key_changes_route(
Error::BadRequest(ErrorKind::InvalidParam, "Invalid `to`.")
})?),
)
.await
.filter_map(|r| r.ok()),
);
}
@ -255,7 +257,7 @@ pub async fn get_key_changes_route(
})
}
pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool>(
pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool + Sync>(
sender_user: Option<&UserId>,
device_keys_input: &BTreeMap<OwnedUserId, Vec<OwnedDeviceId>>,
allowed_signatures: F,
@ -280,12 +282,12 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool>(
if device_ids.is_empty() {
let mut container = BTreeMap::new();
for device_id in services().users.all_device_ids(user_id) {
for device_id in services().users.all_device_ids(user_id).await {
let device_id = device_id?;
if let Some(mut keys) = services().users.get_device_keys(user_id, &device_id)? {
if let Some(mut keys) = services().users.get_device_keys(user_id, &device_id).await? {
let metadata = services()
.users
.get_device_metadata(user_id, &device_id)?
.get_device_metadata(user_id, &device_id).await?
.ok_or_else(|| {
Error::bad_database("all_device_keys contained nonexistent device.")
})?;
@ -299,10 +301,10 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool>(
} else {
for device_id in device_ids {
let mut container = BTreeMap::new();
if let Some(mut keys) = services().users.get_device_keys(user_id, device_id)? {
if let Some(mut keys) = services().users.get_device_keys(user_id, device_id).await? {
let metadata = services()
.users
.get_device_metadata(user_id, device_id)?
.get_device_metadata(user_id, device_id).await?
.ok_or(Error::BadRequest(
ErrorKind::InvalidParam,
"Tried to get keys for nonexistent device.",
@ -319,19 +321,19 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool>(
if let Some(master_key) =
services()
.users
.get_master_key(sender_user, user_id, &allowed_signatures)?
.get_master_key(sender_user, user_id, &allowed_signatures).await?
{
master_keys.insert(user_id.to_owned(), master_key);
}
if let Some(self_signing_key) =
services()
.users
.get_self_signing_key(sender_user, user_id, &allowed_signatures)?
.get_self_signing_key(sender_user, user_id, &allowed_signatures).await?
{
self_signing_keys.insert(user_id.to_owned(), self_signing_key);
}
if Some(user_id) == sender_user {
if let Some(user_signing_key) = services().users.get_user_signing_key(user_id)? {
if let Some(user_signing_key) = services().users.get_user_signing_key(user_id).await? {
user_signing_keys.insert(user_id.to_owned(), user_signing_key);
}
}
@ -403,16 +405,16 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool>(
Ok(Ok(response)) => {
for (user, masterkey) in response.master_keys {
let (master_key_id, mut master_key) =
services().users.parse_master_key(&user, &masterkey)?;
services().users.parse_master_key(&user, &masterkey).await?;
if let Some(our_master_key) = services().users.get_key(
&master_key_id,
sender_user,
&user,
&allowed_signatures,
)? {
).await? {
let (_, our_master_key) =
services().users.parse_master_key(&user, &our_master_key)?;
services().users.parse_master_key(&user, &our_master_key).await?;
master_key.signatures.extend(our_master_key.signatures);
}
let json = serde_json::to_value(master_key).expect("to_value always works");
@ -420,7 +422,7 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool>(
services().users.add_cross_signing_keys(
&user, &raw, &None, &None,
false, // Dont notify. A notification would trigger another key request resulting in an endless loop
)?;
).await?;
master_keys.insert(user, raw);
}
@ -481,7 +483,7 @@ pub(crate) async fn claim_keys_helper(
if let Some(one_time_keys) =
services()
.users
.take_one_time_key(user_id, device_id, key_algorithm)?
.take_one_time_key(user_id, device_id, key_algorithm).await?
{
let mut c = BTreeMap::new();
c.insert(one_time_keys.0, one_time_keys.1);

View file

@ -223,7 +223,7 @@ pub async fn kick_user_route(
sender_user,
&body.room_id,
&state_lock,
)?;
).await?;
drop(state_lock);
@ -247,11 +247,11 @@ pub async fn ban_user_route(body: Ruma<ban_user::v3::Request>) -> Result<ban_use
.map_or(
Ok(RoomMemberEventContent {
membership: MembershipState::Ban,
displayname: services().users.displayname(&body.user_id)?,
avatar_url: services().users.avatar_url(&body.user_id)?,
displayname: services().users.displayname(&body.user_id).await?,
avatar_url: services().users.avatar_url(&body.user_id).await?,
is_direct: None,
third_party_invite: None,
blurhash: services().users.blurhash(&body.user_id)?,
blurhash: services().users.blurhash(&body.user_id).await?,
reason: body.reason.clone(),
join_authorized_via_users_server: None,
}),
@ -287,7 +287,7 @@ pub async fn ban_user_route(body: Ruma<ban_user::v3::Request>) -> Result<ban_use
sender_user,
&body.room_id,
&state_lock,
)?;
).await?;
drop(state_lock);
@ -345,7 +345,7 @@ pub async fn unban_user_route(
sender_user,
&body.room_id,
&state_lock,
)?;
).await?;
drop(state_lock);
@ -454,8 +454,8 @@ pub async fn joined_members_route(
.room_members(&body.room_id)
.filter_map(|r| r.ok())
{
let display_name = services().users.displayname(&user_id)?;
let avatar_url = services().users.avatar_url(&user_id)?;
let display_name = services().users.displayname(&user_id).await?;
let avatar_url = services().users.avatar_url(&user_id).await?;
joined.insert(
user_id,
@ -545,11 +545,11 @@ async fn join_room_by_id_helper(
"content".to_owned(),
to_canonical_value(RoomMemberEventContent {
membership: MembershipState::Join,
displayname: services().users.displayname(sender_user)?,
avatar_url: services().users.avatar_url(sender_user)?,
displayname: services().users.displayname(sender_user).await?,
avatar_url: services().users.avatar_url(sender_user).await?,
is_direct: None,
third_party_invite: None,
blurhash: services().users.blurhash(sender_user)?,
blurhash: services().users.blurhash(sender_user).await?,
reason,
join_authorized_via_users_server,
})
@ -769,7 +769,7 @@ async fn join_room_by_id_helper(
.await?;
info!("Updating joined counts for new room");
services().rooms.state_cache.update_joined_count(room_id)?;
services().rooms.state_cache.update_joined_count(room_id).await?;
// 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.
@ -781,7 +781,7 @@ async fn join_room_by_id_helper(
join_event,
vec![(*parsed_join_pdu.event_id).to_owned()],
&state_lock,
)?;
).await?;
info!("Setting final room state for new room");
// We set the room state after inserting the pdu, so that we never have a moment in time
@ -884,11 +884,11 @@ async fn join_room_by_id_helper(
let event = RoomMemberEventContent {
membership: MembershipState::Join,
displayname: services().users.displayname(sender_user)?,
avatar_url: services().users.avatar_url(sender_user)?,
displayname: services().users.displayname(sender_user).await?,
avatar_url: services().users.avatar_url(sender_user).await?,
is_direct: None,
third_party_invite: None,
blurhash: services().users.blurhash(sender_user)?,
blurhash: services().users.blurhash(sender_user).await?,
reason: reason.clone(),
join_authorized_via_users_server: authorized_user,
};
@ -905,7 +905,7 @@ async fn join_room_by_id_helper(
sender_user,
room_id,
&state_lock,
) {
).await {
Ok(_event_id) => return Ok(join_room_by_id::v3::Response::new(room_id.to_owned())),
Err(e) => e,
};
@ -963,11 +963,11 @@ async fn join_room_by_id_helper(
"content".to_owned(),
to_canonical_value(RoomMemberEventContent {
membership: MembershipState::Join,
displayname: services().users.displayname(sender_user)?,
avatar_url: services().users.avatar_url(sender_user)?,
displayname: services().users.displayname(sender_user).await?,
avatar_url: services().users.avatar_url(sender_user).await?,
is_direct: None,
third_party_invite: None,
blurhash: services().users.blurhash(sender_user)?,
blurhash: services().users.blurhash(sender_user).await?,
reason,
join_authorized_via_users_server,
})
@ -1315,11 +1315,11 @@ pub(crate) async fn invite_helper<'a>(
event_type: TimelineEventType::RoomMember,
content: to_raw_value(&RoomMemberEventContent {
membership: MembershipState::Invite,
displayname: services().users.displayname(user_id)?,
avatar_url: services().users.avatar_url(user_id)?,
displayname: services().users.displayname(user_id).await?,
avatar_url: services().users.avatar_url(user_id).await?,
is_direct: Some(is_direct),
third_party_invite: None,
blurhash: services().users.blurhash(user_id)?,
blurhash: services().users.blurhash(user_id).await?,
reason,
join_authorized_via_users_server: None,
})
@ -1331,7 +1331,7 @@ pub(crate) async fn invite_helper<'a>(
sender_user,
room_id,
&state_lock,
)?;
).await?;
drop(state_lock);
@ -1392,7 +1392,7 @@ pub async fn leave_room(user_id: &UserId, room_id: &RoomId, reason: Option<Strin
user_id,
last_state,
true,
)?;
).await?;
} else {
let mutex_state = Arc::clone(
services()
@ -1423,7 +1423,7 @@ pub async fn leave_room(user_id: &UserId, room_id: &RoomId, reason: Option<Strin
user_id,
None,
true,
)?;
).await?;
return Ok(());
}
Some(e) => e,
@ -1446,7 +1446,7 @@ pub async fn leave_room(user_id: &UserId, room_id: &RoomId, reason: Option<Strin
user_id,
room_id,
&state_lock,
)?;
).await?;
}
Ok(())

View file

@ -85,7 +85,7 @@ pub async fn send_message_event_route(
sender_user,
&body.room_id,
&state_lock,
)?;
).await?;
services().transaction_ids.add_txnid(
sender_user,

View file

@ -18,9 +18,9 @@ pub async fn set_presence_route(
&room_id,
ruma::events::presence::PresenceEvent {
content: ruma::events::presence::PresenceEventContent {
avatar_url: services().users.avatar_url(sender_user)?,
avatar_url: services().users.avatar_url(sender_user).await?,
currently_active: None,
displayname: services().users.displayname(sender_user)?,
displayname: services().users.displayname(sender_user).await?,
last_active_ago: Some(
utils::millis_since_unix_epoch()
.try_into()

View file

@ -26,7 +26,8 @@ pub async fn set_displayname_route(
services()
.users
.set_displayname(sender_user, body.displayname.clone())?;
.set_displayname(sender_user, body.displayname.clone())
.await?;
// Send a new membership event and presence update into all joined rooms
let all_rooms_joined: Vec<_> = services()
@ -96,9 +97,9 @@ pub async fn set_displayname_route(
&room_id,
ruma::events::presence::PresenceEvent {
content: ruma::events::presence::PresenceEventContent {
avatar_url: services().users.avatar_url(sender_user)?,
avatar_url: services().users.avatar_url(sender_user).await?,
currently_active: None,
displayname: services().users.displayname(sender_user)?,
displayname: services().users.displayname(sender_user).await?,
last_active_ago: Some(
utils::millis_since_unix_epoch()
.try_into()
@ -141,7 +142,7 @@ pub async fn get_displayname_route(
}
Ok(get_display_name::v3::Response {
displayname: services().users.displayname(&body.user_id)?,
displayname: services().users.displayname(&body.user_id).await?,
})
}
@ -157,11 +158,11 @@ pub async fn set_avatar_url_route(
services()
.users
.set_avatar_url(sender_user, body.avatar_url.clone())?;
.set_avatar_url(sender_user, body.avatar_url.clone()).await?;
services()
.users
.set_blurhash(sender_user, body.blurhash.clone())?;
.set_blurhash(sender_user, body.blurhash.clone()).await?;
// Send a new membership event and presence update into all joined rooms
let all_joined_rooms: Vec<_> = services()
@ -231,9 +232,9 @@ pub async fn set_avatar_url_route(
&room_id,
ruma::events::presence::PresenceEvent {
content: ruma::events::presence::PresenceEventContent {
avatar_url: services().users.avatar_url(sender_user)?,
avatar_url: services().users.avatar_url(sender_user).await?,
currently_active: None,
displayname: services().users.displayname(sender_user)?,
displayname: services().users.displayname(sender_user).await?,
last_active_ago: Some(
utils::millis_since_unix_epoch()
.try_into()
@ -277,8 +278,8 @@ pub async fn get_avatar_url_route(
}
Ok(get_avatar_url::v3::Response {
avatar_url: services().users.avatar_url(&body.user_id)?,
blurhash: services().users.blurhash(&body.user_id)?,
avatar_url: services().users.avatar_url(&body.user_id).await?,
blurhash: services().users.blurhash(&body.user_id).await?,
})
}
@ -318,8 +319,8 @@ pub async fn get_profile_route(
}
Ok(get_profile::v3::Response {
avatar_url: services().users.avatar_url(&body.user_id)?,
blurhash: services().users.blurhash(&body.user_id)?,
displayname: services().users.displayname(&body.user_id)?,
avatar_url: services().users.avatar_url(&body.user_id).await?,
blurhash: services().users.blurhash(&body.user_id).await?,
displayname: services().users.displayname(&body.user_id).await?,
})
}

View file

@ -45,7 +45,7 @@ pub async fn redact_event_route(
sender_user,
&body.room_id,
&state_lock,
)?;
).await?;
drop(state_lock);

View file

@ -183,7 +183,7 @@ pub async fn create_room_route(
sender_user,
&room_id,
&state_lock,
)?;
).await?;
// 2. Let the room creator join
services().rooms.timeline.build_and_append_pdu(
@ -191,11 +191,11 @@ pub async fn create_room_route(
event_type: TimelineEventType::RoomMember,
content: to_raw_value(&RoomMemberEventContent {
membership: MembershipState::Join,
displayname: services().users.displayname(sender_user)?,
avatar_url: services().users.avatar_url(sender_user)?,
displayname: services().users.displayname(sender_user).await?,
avatar_url: services().users.avatar_url(sender_user).await?,
is_direct: Some(body.is_direct),
third_party_invite: None,
blurhash: services().users.blurhash(sender_user)?,
blurhash: services().users.blurhash(sender_user).await?,
reason: None,
join_authorized_via_users_server: None,
})
@ -207,7 +207,7 @@ pub async fn create_room_route(
sender_user,
&room_id,
&state_lock,
)?;
).await?;
// 3. Power levels
@ -256,7 +256,7 @@ pub async fn create_room_route(
sender_user,
&room_id,
&state_lock,
)?;
).await?;
// 4. Canonical room alias
if let Some(room_alias_id) = &alias {
@ -275,7 +275,7 @@ pub async fn create_room_route(
sender_user,
&room_id,
&state_lock,
)?;
).await?;
}
// 5. Events set by preset
@ -297,7 +297,7 @@ pub async fn create_room_route(
sender_user,
&room_id,
&state_lock,
)?;
).await?;
// 5.3 Guest Access
services().rooms.timeline.build_and_append_pdu(
@ -315,7 +315,7 @@ pub async fn create_room_route(
sender_user,
&room_id,
&state_lock,
)?;
).await?;
// 6. Events listed in initial_state
for event in &body.initial_state {
@ -339,7 +339,7 @@ pub async fn create_room_route(
sender_user,
&room_id,
&state_lock,
)?;
).await?;
}
// 7. Events implied by name and topic
@ -356,7 +356,7 @@ pub async fn create_room_route(
sender_user,
&room_id,
&state_lock,
)?;
).await?;
}
if let Some(topic) = &body.topic {
@ -374,7 +374,7 @@ pub async fn create_room_route(
sender_user,
&room_id,
&state_lock,
)?;
).await?;
}
// 8. Events implied by invite (and TODO: invite_3pid)
@ -517,7 +517,7 @@ pub async fn upgrade_room_route(
sender_user,
&body.room_id,
&state_lock,
)?;
).await?;
// Change lock to replacement room
drop(state_lock);
@ -596,7 +596,7 @@ pub async fn upgrade_room_route(
sender_user,
&replacement_room,
&state_lock,
)?;
).await?;
// Join the new room
services().rooms.timeline.build_and_append_pdu(
@ -604,11 +604,11 @@ pub async fn upgrade_room_route(
event_type: TimelineEventType::RoomMember,
content: to_raw_value(&RoomMemberEventContent {
membership: MembershipState::Join,
displayname: services().users.displayname(sender_user)?,
avatar_url: services().users.avatar_url(sender_user)?,
displayname: services().users.displayname(sender_user).await?,
avatar_url: services().users.avatar_url(sender_user).await?,
is_direct: None,
third_party_invite: None,
blurhash: services().users.blurhash(sender_user)?,
blurhash: services().users.blurhash(sender_user).await?,
reason: None,
join_authorized_via_users_server: None,
})
@ -620,7 +620,7 @@ pub async fn upgrade_room_route(
sender_user,
&replacement_room,
&state_lock,
)?;
).await?;
// Recommended transferable state events list from the specs
let transferable_state_events = vec![
@ -657,7 +657,7 @@ pub async fn upgrade_room_route(
sender_user,
&replacement_room,
&state_lock,
)?;
).await?;
}
// Moves any local aliases to the new room
@ -703,7 +703,7 @@ pub async fn upgrade_room_route(
sender_user,
&body.room_id,
&state_lock,
)?;
).await?;
drop(state_lock);

View file

@ -126,7 +126,9 @@ pub async fn search_users_route(
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
let limit = u64::from(body.limit) as usize;
let mut users = services().users.iter().filter_map(|user_id| {
let mut users = vec![];
for user_id in services().users.iter().await {
let user_id = user_id.ok().expect(
"Invalid user id in database! This may be corruption but is a bug you should report.",
);
@ -134,8 +136,8 @@ pub async fn search_users_route(
let user = search_users::v3::User {
// FIXME: add user_id
user_id: user_id.clone(),
displayname: services().users.displayname(&user_id).ok()?,
avatar_url: services().users.avatar_url(&user_id).ok()?,
displayname: services().users.displayname(&user_id).await?,
avatar_url: services().users.avatar_url(&user_id).await?,
blurhash: None,
};
@ -152,7 +154,7 @@ pub async fn search_users_route(
.is_some();
if !user_id_matches && !user_displayname_matches {
return None;
continue;
}
let user_is_in_public_rooms = services()
@ -176,25 +178,23 @@ pub async fn search_users_route(
});
if user_is_in_public_rooms {
return Some(user);
users.push(user);
continue;
}
let user_is_in_shared_rooms = services()
.rooms
.user
.get_shared_rooms(vec![sender_user.clone(), user_id])
.ok()?
.get_shared_rooms(vec![sender_user.clone(), user_id])?
.next()
.is_some();
if user_is_in_shared_rooms {
return Some(user);
users.push(user);
}
}
None
});
let chunk = users.by_ref().take(limit).collect();
let chunk = users.into_iter().take(limit).collect();
Ok(search_users::v3::Response {
chunk,

View file

@ -62,7 +62,7 @@ pub async fn login_route(body: Ruma<login::v3::Request>) -> Result<login::v3::Re
})?;
let hash = services()
.users
.password_hash(&user_id)?
.password_hash(&user_id).await?
.ok_or(Error::BadRequest(
ErrorKind::Forbidden,
"Wrong username or password.",
@ -141,22 +141,26 @@ pub async fn login_route(body: Ruma<login::v3::Request>) -> Result<login::v3::Re
let token = utils::random_string(TOKEN_LENGTH);
// Determine if device_id was provided and exists in the db for this user
let device_exists = body.device_id.as_ref().map_or(false, |device_id| {
services()
.users
.all_device_ids(&user_id)
.any(|x| x.as_ref().map_or(false, |v| v == device_id))
});
let device_exists = match body.device_id.as_ref() {
None => false,
Some(device_id) => {
services()
.users
.all_device_ids(&user_id)
.await
.any(|x| x.as_ref().map_or(false, |v| v == device_id))
}
};
if device_exists {
services().users.set_token(&user_id, &device_id, &token)?;
services().users.set_token(&user_id, &device_id, &token).await?;
} else {
services().users.create_device(
&user_id,
&device_id,
&token,
body.initial_device_display_name.clone(),
)?;
).await?;
}
info!("{} logged in", user_id);
@ -184,7 +188,7 @@ pub async fn logout_route(body: Ruma<logout::v3::Request>) -> Result<logout::v3:
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
let sender_device = body.sender_device.as_ref().expect("user is authenticated");
services().users.remove_device(sender_user, sender_device)?;
services().users.remove_device(sender_user, sender_device).await?;
Ok(logout::v3::Response::new())
}
@ -205,8 +209,8 @@ pub async fn logout_all_route(
) -> Result<logout_all::v3::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
for device_id in services().users.all_device_ids(sender_user).flatten() {
services().users.remove_device(sender_user, &device_id)?;
for device_id in services().users.all_device_ids(sender_user).await.flatten() {
services().users.remove_device(sender_user, &device_id).await?;
}
Ok(logout_all::v3::Response::new())

View file

@ -211,7 +211,7 @@ async fn send_state_event_for_key_helper(
sender_user,
room_id,
&state_lock,
)?;
).await?;
Ok(event_id)
}

View file

@ -187,7 +187,7 @@ async fn sync_helper(
Some(Filter::FilterDefinition(filter)) => filter,
Some(Filter::FilterId(filter_id)) => services()
.users
.get_filter(&sender_user, &filter_id)?
.get_filter(&sender_user, &filter_id).await?
.unwrap_or_default(),
};
@ -218,6 +218,7 @@ async fn sync_helper(
services()
.users
.keys_changed(sender_user.as_ref(), since, None)
.await
.filter_map(|r| r.ok()),
);
@ -307,7 +308,7 @@ async fn sync_helper(
.entry(room_id.clone())
.or_default(),
);
let insert_lock = mutex_insert.lock().unwrap();
let insert_lock = mutex_insert.lock().await;
drop(insert_lock);
}
@ -439,7 +440,7 @@ async fn sync_helper(
.entry(room_id.clone())
.or_default(),
);
let insert_lock = mutex_insert.lock().unwrap();
let insert_lock = mutex_insert.lock().await;
drop(insert_lock);
}
@ -490,7 +491,7 @@ async fn sync_helper(
// Remove all to-device events the device received *last time*
services()
.users
.remove_to_device_events(&sender_user, &sender_device, since)?;
.remove_to_device_events(&sender_user, &sender_device, since).await?;
let response = sync_events::v3::Response {
next_batch: next_batch_string,
@ -524,11 +525,11 @@ async fn sync_helper(
},
device_one_time_keys_count: services()
.users
.count_one_time_keys(&sender_user, &sender_device)?,
.count_one_time_keys(&sender_user, &sender_device).await?,
to_device: ToDevice {
events: services()
.users
.get_to_device_events(&sender_user, &sender_device)?,
.get_to_device_events(&sender_user, &sender_device).await?,
},
// Fallback keys are not yet supported
device_unused_fallback_key_types: None,
@ -581,7 +582,7 @@ async fn load_joined_room(
.entry(room_id.to_owned())
.or_default(),
);
let insert_lock = mutex_insert.lock().unwrap();
let insert_lock = mutex_insert.lock().await;
drop(insert_lock);
}
@ -991,6 +992,7 @@ async fn load_joined_room(
services()
.users
.keys_changed(room_id.as_ref(), since, None)
.await
.filter_map(|r| r.ok()),
);
@ -1199,7 +1201,8 @@ pub async fn sync_events_v4_route(
if body.extensions.to_device.enabled.unwrap_or(false) {
services()
.users
.remove_to_device_events(&sender_user, &sender_device, globalsince)?;
.remove_to_device_events(&sender_user, &sender_device, globalsince)
.await?;
}
let mut left_encrypted_users = HashSet::new(); // Users that have left any encrypted rooms the sender was in
@ -1212,6 +1215,7 @@ pub async fn sync_events_v4_route(
services()
.users
.keys_changed(sender_user.as_ref(), globalsince, None)
.await
.filter_map(|r| r.ok()),
);
@ -1357,6 +1361,7 @@ pub async fn sync_events_v4_route(
services()
.users
.keys_changed(room_id.as_ref(), globalsince, None)
.await
.filter_map(|r| r.ok()),
);
}
@ -1754,7 +1759,7 @@ pub async fn sync_events_v4_route(
Some(sync_events::v4::ToDevice {
events: services()
.users
.get_to_device_events(&sender_user, &sender_device)?,
.get_to_device_events(&sender_user, &sender_device).await?,
next_batch: next_batch.to_string(),
})
} else {
@ -1767,7 +1772,7 @@ pub async fn sync_events_v4_route(
},
device_one_time_keys_count: services()
.users
.count_one_time_keys(&sender_user, &sender_device)?,
.count_one_time_keys(&sender_user, &sender_device).await?,
// Fallback keys are not yet supported
device_unused_fallback_key_types: None,
},

View file

@ -63,11 +63,11 @@ pub async fn send_event_to_device_route(
event.deserialize_as().map_err(|_| {
Error::BadRequest(ErrorKind::InvalidParam, "Event is invalid")
})?,
)?
).await?
}
DeviceIdOrAllDevices::AllDevices => {
for target_device_id in services().users.all_device_ids(target_user_id) {
for target_device_id in services().users.all_device_ids(target_user_id).await {
services().users.add_to_device_event(
sender_user,
target_user_id,
@ -76,7 +76,7 @@ pub async fn send_event_to_device_route(
event.deserialize_as().map_err(|_| {
Error::BadRequest(ErrorKind::InvalidParam, "Event is invalid")
})?,
)?;
).await?;
}
}
}

View file

@ -133,7 +133,7 @@ where
}
};
match services().users.find_from_token(token).unwrap() {
match services().users.find_from_token(token).await.unwrap() {
None => {
return Err(Error::BadRequest(
ErrorKind::UnknownToken { soft_logout: false },

View file

@ -5,7 +5,8 @@ use crate::{
service::pdu::{gen_event_id_canonical_json, PduBuilder},
services, utils, Error, PduEvent, Result, Ruma,
};
use axum::{response::IntoResponse, Json};
use axum::{response::IntoResponse, Json, body::StreamBody};
use futures_util::Stream;
use get_profile_information::v1::ProfileField;
use http::header::{HeaderValue, AUTHORIZATION};
@ -809,7 +810,7 @@ pub async fn send_transaction_message_route(
}
}
Edu::DeviceListUpdate(DeviceListUpdateContent { user_id, .. }) => {
services().users.mark_device_key_update(&user_id)?;
services().users.mark_device_key_update(&user_id).await?;
}
Edu::DirectToDevice(DirectDeviceContent {
sender,
@ -842,12 +843,12 @@ pub async fn send_transaction_message_route(
"Event is invalid",
)
})?,
)?
).await?
}
DeviceIdOrAllDevices::AllDevices => {
for target_device_id in
services().users.all_device_ids(target_user_id)
services().users.all_device_ids(target_user_id).await
{
services().users.add_to_device_event(
&sender,
@ -860,7 +861,7 @@ pub async fn send_transaction_message_route(
"Event is invalid",
)
})?,
)?;
).await?;
}
}
}
@ -887,7 +888,7 @@ pub async fn send_transaction_message_route(
&self_signing_key,
&None,
true,
)?;
).await?;
}
}
Edu::_Custom(_) => {}
@ -1708,7 +1709,7 @@ pub async fn create_invite_route(
&sender,
Some(invite_state),
true,
)?;
).await?;
}
Ok(create_invite::v2::Response {
@ -1731,37 +1732,42 @@ pub async fn get_devices_route(
.as_ref()
.expect("server is authenticated");
let mut devices = vec![];
for device in services()
.users
.all_devices_metadata(&body.user_id)
.await {
if let Ok(metadata) = device {
if let Some(keys) = services()
.users
.get_device_keys(&body.user_id, &metadata.device_id)
.await? {
devices.push(UserDevice {
keys,
device_id: metadata.device_id,
device_display_name: metadata.display_name,
});
}
}
}
Ok(get_devices::v1::Response {
user_id: body.user_id.clone(),
stream_id: services()
.users
.get_devicelist_version(&body.user_id)?
.get_devicelist_version(&body.user_id).await?
.unwrap_or(0)
.try_into()
.expect("version will not grow that large"),
devices: services()
.users
.all_devices_metadata(&body.user_id)
.filter_map(|r| r.ok())
.filter_map(|metadata| {
Some(UserDevice {
keys: services()
.users
.get_device_keys(&body.user_id, &metadata.device_id)
.ok()??,
device_id: metadata.device_id,
device_display_name: metadata.display_name,
})
})
.collect(),
devices,
master_key: services().users.get_master_key(None, &body.user_id, &|u| {
u.server_name() == sender_servername
})?,
}).await?,
self_signing_key: services()
.users
.get_self_signing_key(None, &body.user_id, &|u| {
u.server_name() == sender_servername
})?,
}).await?,
})
}
@ -1806,18 +1812,18 @@ pub async fn get_profile_information_route(
match &body.field {
Some(ProfileField::DisplayName) => {
displayname = services().users.displayname(&body.user_id)?
displayname = services().users.displayname(&body.user_id).await?
}
Some(ProfileField::AvatarUrl) => {
avatar_url = services().users.avatar_url(&body.user_id)?;
blurhash = services().users.blurhash(&body.user_id)?
avatar_url = services().users.avatar_url(&body.user_id).await?;
blurhash = services().users.blurhash(&body.user_id).await?
}
// TODO: what to do with custom
Some(_) => {}
None => {
displayname = services().users.displayname(&body.user_id)?;
avatar_url = services().users.avatar_url(&body.user_id)?;
blurhash = services().users.blurhash(&body.user_id)?;
displayname = services().users.displayname(&body.user_id).await?;
avatar_url = services().users.avatar_url(&body.user_id).await?;
blurhash = services().users.blurhash(&body.user_id).await?;
}
}

View file

@ -71,7 +71,7 @@ pub trait KvTree: Send + Sync {
fn scan_prefix<'a>(
&'a self,
prefix: Vec<u8>,
) -> Box<dyn Iterator<Item = (Vec<u8>, Vec<u8>)> + 'a>;
) -> Box<dyn Iterator<Item = (Vec<u8>, Vec<u8>)> + Send + 'a>;
fn watch_prefix<'a>(&'a self, prefix: &[u8]) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>>;

View file

@ -247,7 +247,7 @@ impl KvTree for RocksDbEngineTree<'_> {
fn scan_prefix<'a>(
&'a self,
prefix: Vec<u8>,
) -> Box<dyn Iterator<Item = (Vec<u8>, Vec<u8>)> + 'a> {
) -> Box<dyn Iterator<Item = (Vec<u8>, Vec<u8>)> + Send + 'a> {
Box::new(
self.db
.rocks

View file

@ -9,6 +9,7 @@ use ruma::{
use crate::{database::KeyValueDatabase, service, services, utils, Error, Result};
#[async_trait::async_trait]
impl service::rooms::state_cache::Data for KeyValueDatabase {
fn mark_as_once_joined(&self, user_id: &UserId, room_id: &RoomId) -> Result<()> {
let mut userroom_id = user_id.as_bytes().to_vec();
@ -92,7 +93,7 @@ impl service::rooms::state_cache::Data for KeyValueDatabase {
Ok(())
}
fn update_joined_count(&self, room_id: &RoomId) -> Result<()> {
async 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();
@ -101,7 +102,7 @@ impl service::rooms::state_cache::Data for KeyValueDatabase {
for joined in self.room_members(room_id).filter_map(|r| r.ok()) {
joined_servers.insert(joined.server_name().to_owned());
if joined.server_name() == services().globals.server_name()
&& !services().users.is_deactivated(&joined).unwrap_or(true)
&& !services().users.is_deactivated(&joined).await.unwrap_or(true)
{
real_users.insert(joined);
}
@ -161,8 +162,9 @@ impl service::rooms::state_cache::Data for KeyValueDatabase {
Ok(())
}
#[tracing::instrument(skip(self, room_id))]
fn get_our_real_users(&self, room_id: &RoomId) -> Result<Arc<HashSet<OwnedUserId>>> {
// #[tracing::instrument(skip(self, room_id))]
#[tracing::instrument(skip(self))]
async fn get_our_real_users(&self, room_id: &RoomId) -> Result<Arc<HashSet<OwnedUserId>>> {
let maybe = self
.our_real_users_cache
.read()
@ -172,7 +174,7 @@ impl service::rooms::state_cache::Data for KeyValueDatabase {
if let Some(users) = maybe {
Ok(users)
} else {
self.update_joined_count(room_id)?;
self.update_joined_count(room_id).await?;
Ok(Arc::clone(
self.our_real_users_cache
.read()
@ -294,7 +296,7 @@ impl service::rooms::state_cache::Data for KeyValueDatabase {
fn server_rooms<'a>(
&'a self,
server: &ServerName,
) -> Box<dyn Iterator<Item = Result<OwnedRoomId>> + 'a> {
) -> Box<dyn Iterator<Item = Result<OwnedRoomId>> + Send + 'a> {
let mut prefix = server.as_bytes().to_vec();
prefix.push(0xff);
@ -316,7 +318,7 @@ impl service::rooms::state_cache::Data for KeyValueDatabase {
fn room_members<'a>(
&'a self,
room_id: &RoomId,
) -> Box<dyn Iterator<Item = Result<OwnedUserId>> + 'a> {
) -> Box<dyn Iterator<Item = Result<OwnedUserId>> + Send + 'a> {
let mut prefix = room_id.as_bytes().to_vec();
prefix.push(0xff);

View file

@ -1,5 +1,6 @@
use std::{collections::BTreeMap, mem::size_of};
use std::{collections::BTreeMap, mem, mem::size_of, pin::Pin};
use futures_util::Future;
use ruma::{
api::client::{device::Device, error::ErrorKind, filter::FilterDefinition},
encryption::{CrossSigningKey, DeviceKeys, OneTimeKey},
@ -24,7 +25,7 @@ impl service::users::Data for KeyValueDatabase {
}
/// Check if account is deactivated
fn is_deactivated(&self, user_id: &UserId) -> Result<bool> {
async fn is_deactivated(&self, user_id: &UserId) -> Result<bool> {
Ok(self
.userid_password
.get(user_id.as_bytes())?
@ -36,12 +37,12 @@ impl service::users::Data for KeyValueDatabase {
}
/// Returns the number of users registered on this server.
fn count(&self) -> Result<usize> {
async fn count(&self) -> Result<usize> {
Ok(self.userid_password.iter().count())
}
/// Find out which user an access token belongs to.
fn find_from_token(&self, token: &str) -> Result<Option<(OwnedUserId, String)>> {
async fn find_from_token(&self, token: &str) -> Result<Option<(OwnedUserId, String)>> {
self.token_userdeviceid
.get(token.as_bytes())?
.map_or(Ok(None), |bytes| {
@ -68,7 +69,7 @@ impl service::users::Data for KeyValueDatabase {
}
/// Returns an iterator over all users on this homeserver.
fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = Result<OwnedUserId>> + 'a> {
async fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = Result<OwnedUserId>> + 'a> {
Box::new(self.userid_password.iter().map(|(bytes, _)| {
UserId::parse(utils::string_from_bytes(&bytes).map_err(|_| {
Error::bad_database("User ID in userid_password is invalid unicode.")
@ -80,7 +81,7 @@ impl service::users::Data for KeyValueDatabase {
/// 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.
fn list_local_users(&self) -> Result<Vec<String>> {
async fn list_local_users(&self) -> Result<Vec<String>> {
let users: Vec<String> = self
.userid_password
.iter()
@ -90,7 +91,7 @@ impl service::users::Data for KeyValueDatabase {
}
/// Returns the password hash for the given user.
fn password_hash(&self, user_id: &UserId) -> Result<Option<String>> {
async fn password_hash(&self, user_id: &UserId) -> Result<Option<String>> {
self.userid_password
.get(user_id.as_bytes())?
.map_or(Ok(None), |bytes| {
@ -101,7 +102,7 @@ impl service::users::Data for KeyValueDatabase {
}
/// Hash and set the user's password to the Argon2 hash
fn set_password(&self, user_id: &UserId, password: Option<&str>) -> Result<()> {
async fn set_password(&self, user_id: &UserId, password: Option<&str>) -> Result<()> {
if let Some(password) = password {
if let Ok(hash) = utils::calculate_password_hash(password) {
self.userid_password
@ -120,7 +121,7 @@ impl service::users::Data for KeyValueDatabase {
}
/// Returns the displayname of a user on this homeserver.
fn displayname(&self, user_id: &UserId) -> Result<Option<String>> {
async fn displayname(&self, user_id: &UserId) -> Result<Option<String>> {
self.userid_displayname
.get(user_id.as_bytes())?
.map_or(Ok(None), |bytes| {
@ -131,7 +132,7 @@ impl service::users::Data for KeyValueDatabase {
}
/// Sets a new displayname or removes it if displayname is None. You still need to nofify all rooms of this change.
fn set_displayname(&self, user_id: &UserId, displayname: Option<String>) -> Result<()> {
async fn set_displayname(&self, user_id: &UserId, displayname: Option<String>) -> Result<()> {
if let Some(displayname) = displayname {
self.userid_displayname
.insert(user_id.as_bytes(), displayname.as_bytes())?;
@ -143,7 +144,7 @@ impl service::users::Data for KeyValueDatabase {
}
/// Get the avatar_url of a user.
fn avatar_url(&self, user_id: &UserId) -> Result<Option<OwnedMxcUri>> {
async fn avatar_url(&self, user_id: &UserId) -> Result<Option<OwnedMxcUri>> {
self.userid_avatarurl
.get(user_id.as_bytes())?
.map(|bytes| {
@ -156,7 +157,11 @@ impl service::users::Data for KeyValueDatabase {
}
/// Sets a new avatar_url or removes it if avatar_url is None.
fn set_avatar_url(&self, user_id: &UserId, avatar_url: Option<OwnedMxcUri>) -> Result<()> {
async fn set_avatar_url(
&self,
user_id: &UserId,
avatar_url: Option<OwnedMxcUri>,
) -> Result<()> {
if let Some(avatar_url) = avatar_url {
self.userid_avatarurl
.insert(user_id.as_bytes(), avatar_url.to_string().as_bytes())?;
@ -168,7 +173,7 @@ impl service::users::Data for KeyValueDatabase {
}
/// Get the blurhash of a user.
fn blurhash(&self, user_id: &UserId) -> Result<Option<String>> {
async fn blurhash(&self, user_id: &UserId) -> Result<Option<String>> {
self.userid_blurhash
.get(user_id.as_bytes())?
.map(|bytes| {
@ -181,7 +186,7 @@ impl service::users::Data for KeyValueDatabase {
}
/// Sets a new avatar_url or removes it if avatar_url is None.
fn set_blurhash(&self, user_id: &UserId, blurhash: Option<String>) -> Result<()> {
async fn set_blurhash(&self, user_id: &UserId, blurhash: Option<String>) -> Result<()> {
if let Some(blurhash) = blurhash {
self.userid_blurhash
.insert(user_id.as_bytes(), blurhash.as_bytes())?;
@ -193,7 +198,7 @@ impl service::users::Data for KeyValueDatabase {
}
/// Adds a new device to a user.
fn create_device(
async fn create_device(
&self,
user_id: &UserId,
device_id: &DeviceId,
@ -222,13 +227,13 @@ impl service::users::Data for KeyValueDatabase {
.expect("Device::to_string never fails."),
)?;
self.set_token(user_id, device_id, token)?;
self.set_token(user_id, device_id, token).await?;
Ok(())
}
/// Removes a device from a user.
fn remove_device(&self, user_id: &UserId, device_id: &DeviceId) -> Result<()> {
async fn remove_device(&self, user_id: &UserId, device_id: &DeviceId) -> Result<()> {
let mut userdeviceid = user_id.as_bytes().to_vec();
userdeviceid.push(0xff);
userdeviceid.extend_from_slice(device_id.as_bytes());
@ -258,10 +263,10 @@ impl service::users::Data for KeyValueDatabase {
}
/// Returns an iterator over all device ids of this user.
fn all_device_ids<'a>(
async fn all_device_ids<'a>(
&'a self,
user_id: &UserId,
) -> Box<dyn Iterator<Item = Result<OwnedDeviceId>> + 'a> {
) -> Box<dyn Iterator<Item = Result<OwnedDeviceId>> + Send + 'a> {
let mut prefix = user_id.as_bytes().to_vec();
prefix.push(0xff);
// All devices have metadata
@ -283,7 +288,7 @@ impl service::users::Data for KeyValueDatabase {
}
/// Replaces the access token of one device.
fn set_token(&self, user_id: &UserId, device_id: &DeviceId, token: &str) -> Result<()> {
async fn set_token(&self, user_id: &UserId, device_id: &DeviceId, token: &str) -> Result<()> {
let mut userdeviceid = user_id.as_bytes().to_vec();
userdeviceid.push(0xff);
userdeviceid.extend_from_slice(device_id.as_bytes());
@ -306,7 +311,7 @@ impl service::users::Data for KeyValueDatabase {
Ok(())
}
fn add_one_time_key(
async fn add_one_time_key(
&self,
user_id: &UserId,
device_id: &DeviceId,
@ -343,7 +348,7 @@ impl service::users::Data for KeyValueDatabase {
Ok(())
}
fn last_one_time_keys_update(&self, user_id: &UserId) -> Result<u64> {
async fn last_one_time_keys_update(&self, user_id: &UserId) -> Result<u64> {
self.userid_lastonetimekeyupdate
.get(user_id.as_bytes())?
.map(|bytes| {
@ -354,7 +359,7 @@ impl service::users::Data for KeyValueDatabase {
.unwrap_or(Ok(0))
}
fn take_one_time_key(
async fn take_one_time_key(
&self,
user_id: &UserId,
device_id: &DeviceId,
@ -393,7 +398,7 @@ impl service::users::Data for KeyValueDatabase {
.transpose()
}
fn count_one_time_keys(
async fn count_one_time_keys(
&self,
user_id: &UserId,
device_id: &DeviceId,
@ -425,7 +430,7 @@ impl service::users::Data for KeyValueDatabase {
Ok(counts)
}
fn add_device_keys(
async fn add_device_keys(
&self,
user_id: &UserId,
device_id: &DeviceId,
@ -440,12 +445,12 @@ impl service::users::Data for KeyValueDatabase {
&serde_json::to_vec(&device_keys).expect("DeviceKeys::to_vec always works"),
)?;
self.mark_device_key_update(user_id)?;
self.mark_device_key_update(user_id).await?;
Ok(())
}
fn add_cross_signing_keys(
async fn add_cross_signing_keys(
&self,
user_id: &UserId,
master_key: &Raw<CrossSigningKey>,
@ -457,7 +462,7 @@ impl service::users::Data for KeyValueDatabase {
let mut prefix = user_id.as_bytes().to_vec();
prefix.push(0xff);
let (master_key_key, _) = self.parse_master_key(user_id, master_key)?;
let (master_key_key, _) = self.parse_master_key(user_id, master_key).await?;
self.keyid_key
.insert(&master_key_key, master_key.json().get().as_bytes())?;
@ -534,13 +539,13 @@ impl service::users::Data for KeyValueDatabase {
}
if notify {
self.mark_device_key_update(user_id)?;
self.mark_device_key_update(user_id).await?;
}
Ok(())
}
fn sign_key(
async fn sign_key(
&self,
target_id: &UserId,
key_id: &str,
@ -576,12 +581,12 @@ impl service::users::Data for KeyValueDatabase {
&serde_json::to_vec(&cross_signing_key).expect("CrossSigningKey::to_vec always works"),
)?;
self.mark_device_key_update(target_id)?;
self.mark_device_key_update(target_id).await?;
Ok(())
}
fn keys_changed<'a>(
async fn keys_changed<'a>(
&'a self,
user_or_room_id: &str,
from: u64,
@ -625,7 +630,7 @@ impl service::users::Data for KeyValueDatabase {
)
}
fn mark_device_key_update(&self, user_id: &UserId) -> Result<()> {
async fn mark_device_key_update(&self, user_id: &UserId) -> Result<()> {
let count = services().globals.next_count()?.to_be_bytes();
for room_id in services()
.rooms
@ -658,7 +663,7 @@ impl service::users::Data for KeyValueDatabase {
Ok(())
}
fn get_device_keys(
async fn get_device_keys(
&self,
user_id: &UserId,
device_id: &DeviceId,
@ -674,7 +679,7 @@ impl service::users::Data for KeyValueDatabase {
})
}
fn parse_master_key(
async fn parse_master_key(
&self,
user_id: &UserId,
master_key: &Raw<CrossSigningKey>,
@ -701,57 +706,106 @@ impl service::users::Data for KeyValueDatabase {
Ok((master_key_key, master_key))
}
fn get_key(
&self,
key: &[u8],
sender_user: Option<&UserId>,
user_id: &UserId,
allowed_signatures: &dyn Fn(&UserId) -> bool,
) -> Result<Option<Raw<CrossSigningKey>>> {
self.keyid_key.get(key)?.map_or(Ok(None), |bytes| {
let mut cross_signing_key = serde_json::from_slice::<serde_json::Value>(&bytes)
.map_err(|_| Error::bad_database("CrossSigningKey in db is invalid."))?;
clean_signatures(
&mut cross_signing_key,
sender_user,
user_id,
allowed_signatures,
)?;
// async fn get_key(
// &self,
// key: &[u8],
// sender_user: Option<&UserId>,
// user_id: &UserId,
// allowed_signatures: &(dyn (Fn(&UserId) -> bool) + Sync),
// ) -> Result<Option<Raw<CrossSigningKey>>> {
fn get_key<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
key: &'life1 [u8],
sender_user: Option<&'life2 UserId>,
user_id: &'life3 UserId,
allowed_signatures: &'life4 (dyn (Fn(&UserId) -> bool) + Sync),
) -> Pin<Box<dyn Future<Output = Result<Option<Raw<CrossSigningKey>>>> + Send + 'async_trait>>
where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
Self: 'async_trait {
Box::pin(async move {
self.keyid_key.get(key)?.map_or(Ok(None), |bytes| {
let mut cross_signing_key = serde_json::from_slice::<serde_json::Value>(&bytes)
.map_err(|_| Error::bad_database("CrossSigningKey in db is invalid."))?;
Ok(Some(Raw::from_json(
serde_json::value::to_raw_value(&cross_signing_key)
.expect("Value to RawValue serialization"),
)))
if let Some(signatures) = cross_signing_key
.get_mut("signatures")
.and_then(|v| v.as_object_mut())
{
// Don't allocate for the full size of the current signatures, but require
// at most one resize if nothing is dropped
let new_capacity = signatures.len() / 2;
for (user, signature) in
mem::replace(signatures, serde_json::Map::with_capacity(new_capacity))
{
let sid = <&UserId>::try_from(user.as_str())
.map_err(|_| Error::bad_database("Invalid user ID in database."))?;
if sender_user == Some(user_id) || sid == user_id || allowed_signatures(sid) {
// signatures.insert(user, signature);
}
drop(sid);
}
}
Ok(Some(Raw::from_json(
serde_json::value::to_raw_value(&cross_signing_key)
.expect("Value to RawValue serialization"),
)))
})
})
}
fn get_master_key(
&self,
sender_user: Option<&UserId>,
user_id: &UserId,
allowed_signatures: &dyn Fn(&UserId) -> bool,
) -> Result<Option<Raw<CrossSigningKey>>> {
self.userid_masterkeyid
.get(user_id.as_bytes())?
.map_or(Ok(None), |key| {
self.get_key(&key, sender_user, user_id, allowed_signatures)
})
fn get_master_key<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
sender_user: Option<&'life1 UserId>,
user_id: &'life2 UserId,
allowed_signatures: &'life3 (dyn (Fn(&UserId) -> bool) + Sync),
) -> Pin<Box<dyn Future<Output = Result<Option<Raw<CrossSigningKey>>>> + Send + 'async_trait>>
where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Self: 'async_trait {
Box::pin(async move {
match self.userid_masterkeyid.get(user_id.as_bytes())? {
None => Ok(None),
Some(key) => {
self.get_key(&key, sender_user, user_id, allowed_signatures)
.await
}
}
})
}
fn get_self_signing_key(
&self,
sender_user: Option<&UserId>,
user_id: &UserId,
allowed_signatures: &dyn Fn(&UserId) -> bool,
) -> Result<Option<Raw<CrossSigningKey>>> {
self.userid_selfsigningkeyid
.get(user_id.as_bytes())?
.map_or(Ok(None), |key| {
self.get_key(&key, sender_user, user_id, allowed_signatures)
})
fn get_self_signing_key<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
sender_user: Option<&'life1 UserId>,
user_id: &'life2 UserId,
allowed_signatures: &'life3 (dyn (Fn(&UserId) -> bool) + Sync),
) -> Pin<Box<dyn Future<Output = Result<Option<Raw<CrossSigningKey>>>> + Send + 'async_trait>>
where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Self: 'async_trait {
Box::pin(async move {
match self.userid_selfsigningkeyid.get(user_id.as_bytes())? {
None => Ok(None),
Some(key) => {
self.get_key(&key, sender_user, user_id, allowed_signatures)
.await
}
}
})
}
fn get_user_signing_key(&self, user_id: &UserId) -> Result<Option<Raw<CrossSigningKey>>> {
async fn get_user_signing_key(&self, user_id: &UserId) -> Result<Option<Raw<CrossSigningKey>>> {
self.userid_usersigningkeyid
.get(user_id.as_bytes())?
.map_or(Ok(None), |key| {
@ -763,7 +817,7 @@ impl service::users::Data for KeyValueDatabase {
})
}
fn add_to_device_event(
async fn add_to_device_event(
&self,
sender: &UserId,
target_user_id: &UserId,
@ -789,7 +843,7 @@ impl service::users::Data for KeyValueDatabase {
Ok(())
}
fn get_to_device_events(
async fn get_to_device_events(
&self,
user_id: &UserId,
device_id: &DeviceId,
@ -811,7 +865,7 @@ impl service::users::Data for KeyValueDatabase {
Ok(events)
}
fn remove_to_device_events(
async fn remove_to_device_events(
&self,
user_id: &UserId,
device_id: &DeviceId,
@ -845,7 +899,7 @@ impl service::users::Data for KeyValueDatabase {
Ok(())
}
fn update_device_metadata(
async fn update_device_metadata(
&self,
user_id: &UserId,
device_id: &DeviceId,
@ -870,7 +924,7 @@ impl service::users::Data for KeyValueDatabase {
}
/// Get device metadata.
fn get_device_metadata(
async fn get_device_metadata(
&self,
user_id: &UserId,
device_id: &DeviceId,
@ -888,7 +942,7 @@ impl service::users::Data for KeyValueDatabase {
})
}
fn get_devicelist_version(&self, user_id: &UserId) -> Result<Option<u64>> {
async fn get_devicelist_version(&self, user_id: &UserId) -> Result<Option<u64>> {
self.userid_devicelistversion
.get(user_id.as_bytes())?
.map_or(Ok(None), |bytes| {
@ -898,7 +952,7 @@ impl service::users::Data for KeyValueDatabase {
})
}
fn all_devices_metadata<'a>(
async fn all_devices_metadata<'a>(
&'a self,
user_id: &UserId,
) -> Box<dyn Iterator<Item = Result<Device>> + 'a> {
@ -917,7 +971,7 @@ impl service::users::Data for KeyValueDatabase {
}
/// Creates a new sync filter. Returns the filter id.
fn create_filter(&self, user_id: &UserId, filter: &FilterDefinition) -> Result<String> {
async fn create_filter(&self, user_id: &UserId, filter: &FilterDefinition) -> Result<String> {
let filter_id = utils::random_string(4);
let mut key = user_id.as_bytes().to_vec();
@ -932,7 +986,11 @@ impl service::users::Data for KeyValueDatabase {
Ok(filter_id)
}
fn get_filter(&self, user_id: &UserId, filter_id: &str) -> Result<Option<FilterDefinition>> {
async fn get_filter(
&self,
user_id: &UserId,
filter_id: &str,
) -> Result<Option<FilterDefinition>> {
let mut key = user_id.as_bytes().to_vec();
key.push(0xff);
key.extend_from_slice(filter_id.as_bytes());
@ -948,8 +1006,6 @@ impl service::users::Data for KeyValueDatabase {
}
}
impl KeyValueDatabase {}
/// Will only return with Some(username) if the password was not empty and the
/// username could be successfully parsed.
/// If utils::string_from_bytes(...) returns an error that username will be skipped

View file

@ -355,7 +355,7 @@ impl KeyValueDatabase {
// Matrix resource ownership is based on the server name; changing it
// requires recreating the database from scratch.
if services().users.count()? > 0 {
if services().users.count().await? > 0 {
let conduit_user =
UserId::parse_with_server_name("conduit", services().globals.server_name())
.expect("@conduit:server_name is valid");
@ -374,7 +374,7 @@ impl KeyValueDatabase {
// If the database has any data, perform data migrations before starting
let latest_database_version = 1;
if services().users.count()? > 0 {
if services().users.count().await? > 0 {
// MIGRATIONS
// if services().globals.database_version()? < 1 {
// services().globals.bump_database_version(2)?;
@ -412,7 +412,7 @@ impl KeyValueDatabase {
services().admin.start_handler();
// Set emergency access for the conduit user
match set_emergency_access() {
match set_emergency_access().await {
Ok(pwd_set) => {
if pwd_set {
warn!("The Conduit account emergency password is set! Please unset it as soon as you finish admin account recovery!");
@ -566,18 +566,19 @@ impl RelationalDatabase {
error!(?config.max_request_size, "Max request size is less than 1KB. Please increase it.");
}
sqlx::migrate!("./migrations").run(builder.conn()).await?;
let db_raw = Box::new(RelationalDatabase { _db: builder });
let db = Box::leak(db_raw);
// let services_raw = Box::new(Services::build(db, config)?);
let services_raw = Box::new(Services::build::<KeyValueDatabase>(todo!(), config)?);
let services_raw = Box::new(Services::build(db, config)?);
// This is the first and only time we initialize the SERVICE static
*SERVICES.write().unwrap() = Some(Box::leak(services_raw));
// Matrix resource ownership is based on the server name; changing it
// requires recreating the database from scratch.
if services().users.count()? > 0 {
if services().users.count().await? > 0 {
let conduit_user =
UserId::parse_with_server_name("conduit", services().globals.server_name())
.expect("@conduit:server_name is valid");
@ -593,15 +594,13 @@ impl RelationalDatabase {
}
}
sqlx::migrate!("./migrations").run(builder.conn()).await?;
// This data is probably outdated
// db.presenceid_presence.clear()?;
services().admin.start_handler();
// Set emergency access for the conduit user
match set_emergency_access() {
match set_emergency_access().await {
Ok(pwd_set) => {
if pwd_set {
warn!("The Conduit account emergency password is set! Please unset it as soon as you finish admin account recovery!");
@ -628,14 +627,14 @@ impl RelationalDatabase {
}
/// Sets the emergency password and push rules for the @conduit account in case emergency password is set
fn set_emergency_access() -> Result<bool> {
async fn set_emergency_access() -> Result<bool> {
let conduit_user = UserId::parse_with_server_name("conduit", services().globals.server_name())
.expect("@conduit:server_name is a valid UserId");
services().users.set_password(
&conduit_user,
services().globals.emergency_password().as_deref(),
)?;
).await?;
let res = services().globals.emergency_password().is_some();

View file

@ -0,0 +1,32 @@
use crate::{database::RelationalDatabase, service};
impl service::account_data::Data for RelationalDatabase {
fn update(
&self,
room_id: Option<&ruma::RoomId>,
user_id: &ruma::UserId,
event_type: ruma::events::RoomAccountDataEventType,
data: &serde_json::Value,
) -> crate::Result<()> {
todo!()
}
fn get(
&self,
room_id: Option<&ruma::RoomId>,
user_id: &ruma::UserId,
kind: ruma::events::RoomAccountDataEventType,
) -> crate::Result<Option<Box<serde_json::value::RawValue>>> {
todo!()
}
fn changes_since(
&self,
room_id: Option<&ruma::RoomId>,
user_id: &ruma::UserId,
since: u64,
) -> crate::Result<std::collections::HashMap<ruma::events::RoomAccountDataEventType, ruma::serde::Raw<ruma::events::AnyEphemeralRoomEvent>>> {
todo!()
}
}

View file

@ -0,0 +1,23 @@
use crate::{service, RelationalDatabase};
impl service::appservice::Data for RelationalDatabase {
fn register_appservice(&self, yaml: serde_yaml::Value) -> crate::Result<String> {
todo!()
}
fn unregister_appservice(&self, service_name: &str) -> crate::Result<()> {
todo!()
}
fn get_registration(&self, id: &str) -> crate::Result<Option<serde_yaml::Value>> {
todo!()
}
fn iter_ids<'a>(&'a self) -> crate::Result<Box<dyn Iterator<Item = crate::Result<String>> + 'a>> {
todo!()
}
fn all(&self) -> crate::Result<Vec<(String, serde_yaml::Value)>> {
todo!()
}
}

View file

@ -0,0 +1,67 @@
use std::collections::BTreeMap;
use ruma::{UserId, DeviceId, OwnedServerSigningKeyId, api::federation::discovery::{VerifyKey, ServerSigningKeys}, signatures::Ed25519KeyPair, ServerName};
use crate::{database::RelationalDatabase, service, Result};
impl service::globals::Data for RelationalDatabase {
fn next_count(&self) -> Result<u64> {
todo!()
}
fn current_count(&self) -> Result<u64> {
todo!()
}
fn last_check_for_updates_id(&self) -> Result<u64> {
todo!()
}
fn update_check_for_updates_id(&self,id:u64) -> Result<()> {
todo!()
}
#[must_use]
#[allow(clippy::type_complexity,clippy::type_repetition_in_bounds)]
fn watch<'life0,'life1,'life2,'async_trait>(&'life0 self,user_id: &'life1 UserId,device_id: &'life2 DeviceId) -> ::core::pin::Pin<Box<dyn ::core::future::Future<Output = Result<()> > + ::core::marker::Send+'async_trait> >where 'life0:'async_trait,'life1:'async_trait,'life2:'async_trait,Self:'async_trait {
todo!()
}
fn cleanup(&self) -> Result<()> {
todo!()
}
fn memory_usage(&self) -> String {
todo!()
}
fn clear_caches(&self,amount:u32) {
todo!()
}
fn load_keypair(&self) -> Result<Ed25519KeyPair> {
todo!()
}
fn remove_keypair(&self) -> Result<()> {
todo!()
}
fn add_signing_key(&self,origin: &ServerName,new_keys:ServerSigningKeys,) -> Result<BTreeMap<OwnedServerSigningKeyId,VerifyKey> > {
todo!()
}
#[doc = r" This returns an empty `Ok(BTreeMap<..>)` when there are no keys found for the server."]
fn signing_keys_for(&self,origin: &ServerName,) -> Result<BTreeMap<OwnedServerSigningKeyId,VerifyKey> > {
todo!()
}
fn database_version(&self) -> Result<u64> {
todo!()
}
fn bump_database_version(&self,new_version:u64) -> Result<()> {
todo!()
}
}

View file

@ -0,0 +1,102 @@
use crate::{database::RelationalDatabase, service};
impl service::key_backups::Data for RelationalDatabase {
fn create_backup(
&self,
user_id: &ruma::UserId,
backup_metadata: &ruma::serde::Raw<ruma::api::client::backup::BackupAlgorithm>,
) -> crate::Result<String> {
todo!()
}
fn delete_backup(&self, user_id: &ruma::UserId, version: &str) -> crate::Result<()> {
todo!()
}
fn update_backup(
&self,
user_id: &ruma::UserId,
version: &str,
backup_metadata: &ruma::serde::Raw<ruma::api::client::backup::BackupAlgorithm>,
) -> crate::Result<String> {
todo!()
}
fn get_latest_backup_version(&self, user_id: &ruma::UserId) -> crate::Result<Option<String>> {
todo!()
}
fn get_latest_backup(&self, user_id: &ruma::UserId)
-> crate::Result<Option<(String, ruma::serde::Raw<ruma::api::client::backup::BackupAlgorithm>)>> {
todo!()
}
fn get_backup(&self, user_id: &ruma::UserId, version: &str) -> crate::Result<Option<ruma::serde::Raw<ruma::api::client::backup::BackupAlgorithm>>> {
todo!()
}
fn add_key(
&self,
user_id: &ruma::UserId,
version: &str,
room_id: &ruma::RoomId,
session_id: &str,
key_data: &ruma::serde::Raw<ruma::api::client::backup::KeyBackupData>,
) -> crate::Result<()> {
todo!()
}
fn count_keys(&self, user_id: &ruma::UserId, version: &str) -> crate::Result<usize> {
todo!()
}
fn get_etag(&self, user_id: &ruma::UserId, version: &str) -> crate::Result<String> {
todo!()
}
fn get_all(
&self,
user_id: &ruma::UserId,
version: &str,
) -> crate::Result<std::collections::BTreeMap<ruma::OwnedRoomId, ruma::api::client::backup::RoomKeyBackup>> {
todo!()
}
fn get_room(
&self,
user_id: &ruma::UserId,
version: &str,
room_id: &ruma::RoomId,
) -> crate::Result<std::collections::BTreeMap<String, ruma::serde::Raw<ruma::api::client::backup::KeyBackupData>>> {
todo!()
}
fn get_session(
&self,
user_id: &ruma::UserId,
version: &str,
room_id: &ruma::RoomId,
session_id: &str,
) -> crate::Result<Option<ruma::serde::Raw<ruma::api::client::backup::KeyBackupData>>> {
todo!()
}
fn delete_all_keys(&self, user_id: &ruma::UserId, version: &str) -> crate::Result<()> {
todo!()
}
fn delete_room_keys(&self, user_id: &ruma::UserId, version: &str, room_id: &ruma::RoomId) -> crate::Result<()> {
todo!()
}
fn delete_room_key(
&self,
user_id: &ruma::UserId,
version: &str,
room_id: &ruma::RoomId,
session_id: &str,
) -> crate::Result<()> {
todo!()
}
}

View file

@ -0,0 +1,23 @@
use crate::{service, RelationalDatabase};
impl service::media::Data for RelationalDatabase {
fn create_file_metadata(
&self,
mxc: String,
width: u32,
height: u32,
content_disposition: Option<&str>,
content_type: Option<&str>,
) -> crate::Result<Vec<u8>> {
todo!()
}
fn search_file_metadata(
&self,
mxc: String,
width: u32,
height: u32,
) -> crate::Result<(Option<String>, Option<String>, Vec<u8>)> {
todo!()
}
}

View file

@ -1 +1,11 @@
mod account_data;
mod appservice;
mod users;
mod globals;
mod key_backups;
mod media;
mod pusher;
mod rooms;
mod sending;
mod transaction_ids;
mod uiaa;

View file

@ -0,0 +1,20 @@
use crate::{service, RelationalDatabase};
impl service::pusher::Data for RelationalDatabase {
fn set_pusher(&self, sender: &ruma::UserId, pusher: ruma::api::client::push::set_pusher::v3::PusherAction) -> crate::Result<()> {
todo!()
}
fn get_pusher(&self, sender: &ruma::UserId, pushkey: &str) -> crate::Result<Option<ruma::api::client::push::Pusher>> {
todo!()
}
fn get_pushers(&self, sender: &ruma::UserId) -> crate::Result<Vec<ruma::api::client::push::Pusher>> {
todo!()
}
fn get_pushkeys<'a>(&'a self, sender: &ruma::UserId)
-> Box<dyn Iterator<Item = crate::Result<String>> + 'a> {
todo!()
}
}

View file

@ -0,0 +1,21 @@
mod alias;
mod auth_chain;
mod directory;
mod edus;
mod lazy_load;
mod metadata;
mod outlier;
mod pdu_metadata;
mod search;
mod short;
mod state;
mod state_accessor;
mod state_cache;
mod state_compressor;
mod threads;
mod timeline;
mod user;
use crate::{database::RelationalDatabase, service};
impl service::rooms::Data for RelationalDatabase {}

View file

@ -0,0 +1,23 @@
use crate::{database::RelationalDatabase, service};
impl service::rooms::alias::Data for RelationalDatabase {
fn set_alias(&self, alias: &ruma::RoomAliasId, room_id: &ruma::RoomId) -> crate::Result<()> {
todo!()
}
fn remove_alias(&self, alias: &ruma::RoomAliasId) -> crate::Result<()> {
todo!()
}
fn resolve_local_alias(&self, alias: &ruma::RoomAliasId) -> crate::Result<Option<ruma::OwnedRoomId>> {
todo!()
}
fn local_aliases_for_room<'a>(
&'a self,
room_id: &ruma::RoomId,
) -> Box<dyn Iterator<Item = crate::Result<ruma::OwnedRoomAliasId>> + 'a> {
todo!()
}
}

View file

@ -0,0 +1,15 @@
use crate::{database::RelationalDatabase, service};
impl service::rooms::auth_chain::Data for RelationalDatabase {
fn get_cached_eventid_authchain(
&self,
shorteventid: &[u64],
) -> crate::Result<Option<std::sync::Arc<std::collections::HashSet<u64>>>> {
todo!()
}
fn cache_auth_chain(&self, shorteventid: Vec<u64>, auth_chain: std::sync::Arc<std::collections::HashSet<u64>>)
-> crate::Result<()> {
todo!()
}
}

View file

@ -0,0 +1,19 @@
use crate::{database::RelationalDatabase, service};
impl service::rooms::directory::Data for RelationalDatabase {
fn set_public(&self, room_id: &ruma::RoomId) -> crate::Result<()> {
todo!()
}
fn set_not_public(&self, room_id: &ruma::RoomId) -> crate::Result<()> {
todo!()
}
fn is_public_room(&self, room_id: &ruma::RoomId) -> crate::Result<bool> {
todo!()
}
fn public_rooms<'a>(&'a self) -> Box<dyn Iterator<Item = crate::Result<ruma::OwnedRoomId>> + 'a> {
todo!()
}
}

View file

@ -0,0 +1,7 @@
mod presence;
mod read_receipt;
mod typing;
use crate::{database::RelationalDatabase, service};
impl service::rooms::edus::Data for RelationalDatabase {}

View file

@ -0,0 +1,38 @@
use crate::{database::RelationalDatabase, service};
impl service::rooms::edus::presence::Data for RelationalDatabase {
fn update_presence(
&self,
user_id: &ruma::UserId,
room_id: &ruma::RoomId,
presence: ruma::events::presence::PresenceEvent,
) -> crate::Result<()> {
todo!()
}
fn ping_presence(&self, user_id: &ruma::UserId) -> crate::Result<()> {
todo!()
}
fn last_presence_update(&self, user_id: &ruma::UserId) -> crate::Result<Option<u64>> {
todo!()
}
fn get_presence_event(
&self,
room_id: &ruma::RoomId,
user_id: &ruma::UserId,
count: u64,
) -> crate::Result<Option<ruma::events::presence::PresenceEvent>> {
todo!()
}
fn presence_since(
&self,
room_id: &ruma::RoomId,
since: u64,
) -> crate::Result<std::collections::HashMap<ruma::OwnedUserId, ruma::events::presence::PresenceEvent>> {
todo!()
}
}

View file

@ -0,0 +1 @@

View file

@ -0,0 +1,23 @@
use crate::{database::RelationalDatabase, service};
impl service::rooms::edus::typing::Data for RelationalDatabase {
fn typing_add(&self, user_id: &ruma::UserId, room_id: &ruma::RoomId, timeout: u64) -> crate::Result<()> {
todo!()
}
fn typing_remove(&self, user_id: &ruma::UserId, room_id: &ruma::RoomId) -> crate::Result<()> {
todo!()
}
fn typings_maintain(&self, room_id: &ruma::RoomId) -> crate::Result<()> {
todo!()
}
fn last_typing_update(&self, room_id: &ruma::RoomId) -> crate::Result<u64> {
todo!()
}
fn typings_all(&self, room_id: &ruma::RoomId) -> crate::Result<std::collections::HashSet<ruma::OwnedUserId>> {
todo!()
}
}

View file

@ -0,0 +1,32 @@
use crate::{database::RelationalDatabase, service};
impl service::rooms::lazy_loading::Data for RelationalDatabase {
fn lazy_load_was_sent_before(
&self,
user_id: &ruma::UserId,
device_id: &ruma::DeviceId,
room_id: &ruma::RoomId,
ll_user: &ruma::UserId,
) -> crate::Result<bool> {
todo!()
}
fn lazy_load_confirm_delivery(
&self,
user_id: &ruma::UserId,
device_id: &ruma::DeviceId,
room_id: &ruma::RoomId,
confirmed_user_ids: &mut dyn Iterator<Item = &ruma::UserId>,
) -> crate::Result<()> {
todo!()
}
fn lazy_load_reset(
&self,
user_id: &ruma::UserId,
device_id: &ruma::DeviceId,
room_id: &ruma::RoomId,
) -> crate::Result<()> {
todo!()
}
}

View file

@ -0,0 +1,19 @@
use crate::{database::RelationalDatabase, service};
impl service::rooms::metadata::Data for RelationalDatabase {
fn exists(&self, room_id: &ruma::RoomId) -> crate::Result<bool> {
todo!()
}
fn iter_ids<'a>(&'a self) -> Box<dyn Iterator<Item = crate::Result<ruma::OwnedRoomId>> + 'a> {
todo!()
}
fn is_disabled(&self, room_id: &ruma::RoomId) -> crate::Result<bool> {
todo!()
}
fn disable_room(&self, room_id: &ruma::RoomId, disabled: bool) -> crate::Result<()> {
todo!()
}
}

View file

@ -0,0 +1,15 @@
use crate::{database::RelationalDatabase, service};
impl service::rooms::outlier::Data for RelationalDatabase {
fn get_outlier_pdu_json(&self, event_id: &ruma::EventId) -> crate::Result<Option<ruma::CanonicalJsonObject>> {
todo!()
}
fn get_outlier_pdu(&self, event_id: &ruma::EventId) -> crate::Result<Option<crate::PduEvent>> {
todo!()
}
fn add_pdu_outlier(&self, event_id: &ruma::EventId, pdu: &ruma::CanonicalJsonObject) -> crate::Result<()> {
todo!()
}
}

View file

@ -0,0 +1,43 @@
use crate::{database::RelationalDatabase, service};
impl service::rooms::pdu_metadata::Data for RelationalDatabase {
fn add_relation(&self, from: u64, to: u64) -> crate::Result<()> {
todo!()
}
fn relations_until<'a>(
&'a self,
user_id: &'a ruma::UserId,
room_id: u64,
target: u64,
until: service::rooms::timeline::PduCount,
) -> crate::Result<Box<dyn Iterator<Item = crate::Result<(service::rooms::timeline::PduCount, crate::PduEvent)>> + 'a>> {
todo!()
}
fn relations_after<'a>(
&'a self,
user_id: &'a ruma::UserId,
room_id: u64,
target: u64,
after: service::rooms::timeline::PduCount,
) -> crate::Result<Box<dyn Iterator<Item = crate::Result<(service::rooms::timeline::PduCount, crate::PduEvent)>> + 'a>> {
todo!()
}
fn mark_as_referenced(&self, room_id: &ruma::RoomId, event_ids: &[std::sync::Arc<ruma::EventId>]) -> crate::Result<()> {
todo!()
}
fn is_event_referenced(&self, room_id: &ruma::RoomId, event_id: &ruma::EventId) -> crate::Result<bool> {
todo!()
}
fn mark_event_soft_failed(&self, event_id: &ruma::EventId) -> crate::Result<()> {
todo!()
}
fn is_event_soft_failed(&self, event_id: &ruma::EventId) -> crate::Result<bool> {
todo!()
}
}

View file

@ -0,0 +1,15 @@
use crate::{database::RelationalDatabase, service};
impl service::rooms::search::Data for RelationalDatabase {
fn index_pdu(&self, shortroomid: u64, pdu_id: &[u8], message_body: &str) -> crate::Result<()> {
todo!()
}
fn search_pdus<'a>(
&'a self,
room_id: &ruma::RoomId,
search_string: &str,
) -> crate::Result<Option<(Box<dyn Iterator<Item = Vec<u8>> + 'a>, Vec<String>)>> {
todo!()
}
}

View file

@ -0,0 +1,43 @@
use crate::{database::RelationalDatabase, service};
impl service::rooms::short::Data for RelationalDatabase {
fn get_or_create_shorteventid(&self, event_id: &ruma::EventId) -> crate::Result<u64> {
todo!()
}
fn get_shortstatekey(
&self,
event_type: &ruma::events::StateEventType,
state_key: &str,
) -> crate::Result<Option<u64>> {
todo!()
}
fn get_or_create_shortstatekey(
&self,
event_type: &ruma::events::StateEventType,
state_key: &str,
) -> crate::Result<u64> {
todo!()
}
fn get_eventid_from_short(&self, shorteventid: u64) -> crate::Result<std::sync::Arc<ruma::EventId>> {
todo!()
}
fn get_statekey_from_short(&self, shortstatekey: u64) -> crate::Result<(ruma::events::StateEventType, String)> {
todo!()
}
fn get_or_create_shortstatehash(&self, state_hash: &[u8]) -> crate::Result<(u64, bool)> {
todo!()
}
fn get_shortroomid(&self, room_id: &ruma::RoomId) -> crate::Result<Option<u64>> {
todo!()
}
fn get_or_create_shortroomid(&self, room_id: &ruma::RoomId) -> crate::Result<u64> {
todo!()
}
}

View file

@ -0,0 +1,33 @@
use crate::{database::RelationalDatabase, service};
impl service::rooms::state::Data for RelationalDatabase {
fn get_room_shortstatehash(&self, room_id: &ruma::RoomId) -> crate::Result<Option<u64>> {
todo!()
}
fn set_room_state(
&self,
room_id: &ruma::RoomId,
new_shortstatehash: u64,
_mutex_lock: &tokio::sync::MutexGuard<'_, ()>, // Take mutex guard to make sure users get the room state mutex
) -> crate::Result<()> {
todo!()
}
fn set_event_state(&self, shorteventid: u64, shortstatehash: u64) -> crate::Result<()> {
todo!()
}
fn get_forward_extremities(&self, room_id: &ruma::RoomId) -> crate::Result<std::collections::HashSet<std::sync::Arc<ruma::EventId>>> {
todo!()
}
fn set_forward_extremities(
&self,
room_id: &ruma::RoomId,
event_ids: Vec<ruma::OwnedEventId>,
_mutex_lock: &tokio::sync::MutexGuard<'_, ()>, // Take mutex guard to make sure users get the room state mutex
) -> crate::Result<()> {
todo!()
}
}

View file

@ -0,0 +1,58 @@
use std::{collections::HashMap, sync::Arc};
use ruma::{events::StateEventType, RoomId, EventId};
use crate::{database::RelationalDatabase, service, Result, PduEvent};
impl service::rooms::state_accessor::Data for RelationalDatabase {
#[doc = r" Builds a StateMap by iterating over all keys that start"]
#[doc = r" with state_hash, this gives the full state for the given state_hash."]
#[must_use]
#[allow(clippy::type_complexity,clippy::type_repetition_in_bounds)]
fn state_full_ids<'life0,'async_trait>(&'life0 self,shortstatehash:u64) -> ::core::pin::Pin<Box<dyn ::core::future::Future<Output = Result<HashMap<u64,Arc<EventId> > > > + ::core::marker::Send+'async_trait> >where 'life0:'async_trait,Self:'async_trait {
todo!()
}
#[must_use]
#[allow(clippy::type_complexity,clippy::type_repetition_in_bounds)]
fn state_full<'life0,'async_trait>(&'life0 self,shortstatehash:u64,) -> ::core::pin::Pin<Box<dyn ::core::future::Future<Output = Result<HashMap<(StateEventType,String),Arc<PduEvent> > > > + ::core::marker::Send+'async_trait> >where 'life0:'async_trait,Self:'async_trait {
todo!()
}
#[doc = r" Returns a single PDU from `room_id` with key (`event_type`, `state_key`)."]
fn state_get_id(&self,shortstatehash:u64,event_type: &StateEventType,state_key: &str,) -> Result<Option<Arc<EventId> > > {
todo!()
}
#[doc = r" Returns a single PDU from `room_id` with key (`event_type`, `state_key`)."]
fn state_get(&self,shortstatehash:u64,event_type: &StateEventType,state_key: &str,) -> Result<Option<Arc<PduEvent> > > {
todo!()
}
#[doc = r" Returns the state hash for this pdu."]
fn pdu_shortstatehash(&self,event_id: &EventId) -> Result<Option<u64> > {
todo!()
}
#[doc = r" Returns the full room state."]
#[must_use]
#[allow(clippy::type_complexity,clippy::type_repetition_in_bounds)]
fn room_state_full<'life0,'life1,'async_trait>(&'life0 self,room_id: &'life1 RoomId,) -> ::core::pin::Pin<Box<dyn ::core::future::Future<Output = Result<HashMap<(StateEventType,String),Arc<PduEvent> > > > + ::core::marker::Send+'async_trait> >where 'life0:'async_trait,'life1:'async_trait,Self:'async_trait {
todo!()
}
#[doc = r" Returns a single PDU from `room_id` with key (`event_type`, `state_key`)."]
fn room_state_get_id(&self,room_id: &RoomId,event_type: &StateEventType,state_key: &str,) -> Result<Option<Arc<EventId> > > {
todo!()
}
#[doc = r" Returns a single PDU from `room_id` with key (`event_type`, `state_key`)."]
fn room_state_get(&self,room_id: &RoomId,event_type: &StateEventType,state_key: &str,) -> Result<Option<Arc<PduEvent> > > {
todo!()
}
#[doc = r" Returns an iterator over PDUs with matching event_type"]
fn room_state_get_all_keys(&self,room_id: &RoomId,event_type: &StateEventType,) -> Result<Box<dyn Iterator<Item = Arc<PduEvent> > > > {
todo!()
}
}

View file

@ -0,0 +1,170 @@
use std::{collections::HashSet, sync::Arc};
use ruma::{
events::{AnyStrippedStateEvent, AnySyncStateEvent},
serde::Raw,
OwnedRoomId, OwnedServerName, OwnedUserId, RoomId, ServerName, UserId,
};
use crate::{database::RelationalDatabase, service, Result};
#[async_trait::async_trait]
impl service::rooms::state_cache::Data for RelationalDatabase {
fn mark_as_once_joined(&self, user_id: &UserId, room_id: &RoomId) -> Result<()> {
todo!()
}
fn mark_as_joined(&self, user_id: &UserId, room_id: &RoomId) -> Result<()> {
todo!()
}
fn mark_as_invited(
&self,
user_id: &UserId,
room_id: &RoomId,
last_state: Option<Vec<Raw<AnyStrippedStateEvent>>>,
) -> Result<()> {
todo!()
}
fn mark_as_left(&self, user_id: &UserId, room_id: &RoomId) -> Result<()> {
todo!()
}
async fn update_joined_count(&self, room_id: &RoomId) -> Result<()> {
todo!()
}
async fn get_our_real_users(&self, room_id: &RoomId) -> Result<Arc<HashSet<OwnedUserId>>> {
todo!()
}
fn appservice_in_room(
&self,
room_id: &RoomId,
appservice: &(String, serde_yaml::Value),
) -> Result<bool> {
todo!()
}
#[doc = r" Makes a user forget a room."]
fn forget(&self, room_id: &RoomId, user_id: &UserId) -> Result<()> {
todo!()
}
#[doc = r" Returns an iterator of all servers participating in this room."]
fn room_servers<'a>(
&'a self,
room_id: &RoomId,
) -> Box<dyn Iterator<Item = Result<OwnedServerName>> + 'a> {
todo!()
}
fn server_in_room(&self, server: &ServerName, room_id: &RoomId) -> Result<bool> {
todo!()
}
#[doc = r" Returns an iterator of all rooms a server participates in (as far as we know)."]
fn server_rooms<'a>(
&'a self,
server: &ServerName,
) -> Box<dyn Iterator<Item = Result<OwnedRoomId>> + Send + 'a> {
todo!()
}
#[doc = r" Returns an iterator over all joined members of a room."]
fn room_members<'a>(
&'a self,
room_id: &RoomId,
) -> Box<dyn Iterator<Item = Result<OwnedUserId>> + Send + 'a> {
todo!()
}
fn room_joined_count(&self, room_id: &RoomId) -> Result<Option<u64>> {
todo!()
}
fn room_invited_count(&self, room_id: &RoomId) -> Result<Option<u64>> {
todo!()
}
#[doc = r" Returns an iterator over all User IDs who ever joined a room."]
fn room_useroncejoined<'a>(
&'a self,
room_id: &RoomId,
) -> Box<dyn Iterator<Item = Result<OwnedUserId>> + 'a> {
todo!()
}
#[doc = r" Returns an iterator over all invited members of a room."]
fn room_members_invited<'a>(
&'a self,
room_id: &RoomId,
) -> Box<dyn Iterator<Item = Result<OwnedUserId>> + 'a> {
todo!()
}
fn get_invite_count(&self, room_id: &RoomId, user_id: &UserId) -> Result<Option<u64>> {
todo!()
}
fn get_left_count(&self, room_id: &RoomId, user_id: &UserId) -> Result<Option<u64>> {
todo!()
}
#[doc = r" Returns an iterator over all rooms this user joined."]
fn rooms_joined<'a>(
&'a self,
user_id: &UserId,
) -> Box<dyn Iterator<Item = Result<OwnedRoomId>> + 'a> {
todo!()
}
#[doc = r" Returns an iterator over all rooms a user was invited to."]
fn rooms_invited<'a>(
&'a self,
user_id: &UserId,
) -> Box<dyn Iterator<Item = Result<(OwnedRoomId, Vec<Raw<AnyStrippedStateEvent>>)>> + 'a> {
todo!()
}
fn invite_state(
&self,
user_id: &UserId,
room_id: &RoomId,
) -> Result<Option<Vec<Raw<AnyStrippedStateEvent>>>> {
todo!()
}
fn left_state(
&self,
user_id: &UserId,
room_id: &RoomId,
) -> Result<Option<Vec<Raw<AnyStrippedStateEvent>>>> {
todo!()
}
#[doc = r" Returns an iterator over all rooms a user left."]
fn rooms_left<'a>(
&'a self,
user_id: &UserId,
) -> Box<dyn Iterator<Item = Result<(OwnedRoomId, Vec<Raw<AnySyncStateEvent>>)>> + 'a> {
todo!()
}
fn once_joined(&self, user_id: &UserId, room_id: &RoomId) -> Result<bool> {
todo!()
}
fn is_joined(&self, user_id: &UserId, room_id: &RoomId) -> Result<bool> {
todo!()
}
fn is_invited(&self, user_id: &UserId, room_id: &RoomId) -> Result<bool> {
todo!()
}
fn is_left(&self, user_id: &UserId, room_id: &RoomId) -> Result<bool> {
todo!()
}
}

View file

@ -0,0 +1,11 @@
use crate::{database::RelationalDatabase, service};
impl service::rooms::state_compressor::Data for RelationalDatabase {
fn get_statediff(&self, shortstatehash: u64) -> crate::Result<service::rooms::state_compressor::data::StateDiff> {
todo!()
}
fn save_statediff(&self, shortstatehash: u64, diff: service::rooms::state_compressor::data::StateDiff) -> crate::Result<()> {
todo!()
}
}

View file

@ -0,0 +1,21 @@
use crate::{database::RelationalDatabase, service};
impl service::rooms::threads::Data for RelationalDatabase {
fn threads_until<'a>(
&'a self,
user_id: &'a ruma::UserId,
room_id: &'a ruma::RoomId,
until: u64,
include: &'a ruma::api::client::threads::get_threads::v1::IncludeThreads,
) -> crate::Result<Box<dyn Iterator<Item = crate::Result<(u64, crate::PduEvent)>> + 'a>> {
todo!()
}
fn update_participants(&self, root_id: &[u8], participants: &[ruma::OwnedUserId]) -> crate::Result<()> {
todo!()
}
fn get_participants(&self, root_id: &[u8]) -> crate::Result<Option<Vec<ruma::OwnedUserId>>> {
todo!()
}
}

View file

@ -0,0 +1,94 @@
use crate::{database::RelationalDatabase, service};
impl service::rooms::timeline::Data for RelationalDatabase {
fn last_timeline_count(&self, sender_user: &ruma::UserId, room_id: &ruma::RoomId) -> crate::Result<service::rooms::timeline::PduCount> {
todo!()
}
fn get_pdu_count(&self, event_id: &ruma::EventId) -> crate::Result<Option<service::rooms::timeline::PduCount>> {
todo!()
}
fn get_pdu_json(&self, event_id: &ruma::EventId) -> crate::Result<Option<ruma::CanonicalJsonObject>> {
todo!()
}
fn get_non_outlier_pdu_json(&self, event_id: &ruma::EventId) -> crate::Result<Option<ruma::CanonicalJsonObject>> {
todo!()
}
fn get_pdu_id(&self, event_id: &ruma::EventId) -> crate::Result<Option<Vec<u8>>> {
todo!()
}
fn get_non_outlier_pdu(&self, event_id: &ruma::EventId) -> crate::Result<Option<crate::PduEvent>> {
todo!()
}
fn get_pdu(&self, event_id: &ruma::EventId) -> crate::Result<Option<std::sync::Arc<crate::PduEvent>>> {
todo!()
}
fn get_pdu_from_id(&self, pdu_id: &[u8]) -> crate::Result<Option<crate::PduEvent>> {
todo!()
}
fn get_pdu_json_from_id(&self, pdu_id: &[u8]) -> crate::Result<Option<ruma::CanonicalJsonObject>> {
todo!()
}
fn append_pdu(
&self,
pdu_id: &[u8],
pdu: &crate::PduEvent,
json: &ruma::CanonicalJsonObject,
count: u64,
) -> crate::Result<()> {
todo!()
}
fn prepend_backfill_pdu(
&self,
pdu_id: &[u8],
event_id: &ruma::EventId,
json: &ruma::CanonicalJsonObject,
) -> crate::Result<()> {
todo!()
}
fn replace_pdu(
&self,
pdu_id: &[u8],
pdu_json: &ruma::CanonicalJsonObject,
pdu: &crate::PduEvent,
) -> crate::Result<()> {
todo!()
}
fn pdus_until<'a>(
&'a self,
user_id: &ruma::UserId,
room_id: &ruma::RoomId,
until: service::rooms::timeline::PduCount,
) -> crate::Result<Box<dyn Iterator<Item = crate::Result<(service::rooms::timeline::PduCount, crate::PduEvent)>> + 'a>> {
todo!()
}
fn pdus_after<'a>(
&'a self,
user_id: &ruma::UserId,
room_id: &ruma::RoomId,
from: service::rooms::timeline::PduCount,
) -> crate::Result<Box<dyn Iterator<Item = crate::Result<(service::rooms::timeline::PduCount, crate::PduEvent)>> + 'a>> {
todo!()
}
fn increment_notification_counts(
&self,
room_id: &ruma::RoomId,
thread_id: Option<&ruma::EventId>,
users: std::collections::HashMap<ruma::OwnedUserId, (bool, bool, bool)>,
) -> crate::Result<()> {
todo!()
}
}

View file

@ -0,0 +1,52 @@
use crate::{database::RelationalDatabase, service};
impl service::rooms::user::Data for RelationalDatabase {
fn set_counts(
&self,
user_id: &ruma::UserId,
room_id: &ruma::RoomId,
thread_id: Option<&ruma::EventId>,
last_read_event: Option<u64>,
counts: (u64, u64, u64, u64),
) -> crate::Result<()> {
todo!()
}
fn get_counts(
&self,
user_id: &ruma::UserId,
room_id: &ruma::RoomId,
thread_id: Option<&ruma::EventId>,
) -> crate::Result<(u64, u64, u64, u64)> {
todo!()
}
fn last_notification_read(
&self,
user_id: &ruma::UserId,
room_id: &ruma::RoomId,
thread_id: Option<&ruma::EventId>,
) -> crate::Result<Option<u64>> {
todo!()
}
fn associate_token_shortstatehash(
&self,
room_id: &ruma::RoomId,
token: u64,
shortstatehash: u64,
) -> crate::Result<()> {
todo!()
}
fn get_token_shortstatehash(&self, room_id: &ruma::RoomId, token: u64) -> crate::Result<Option<u64>> {
todo!()
}
fn get_shared_rooms<'a>(
&'a self,
users: Vec<ruma::OwnedUserId>,
) -> crate::Result<Box<dyn Iterator<Item = crate::Result<ruma::OwnedRoomId>> + 'a>> {
todo!()
}
}

View file

@ -0,0 +1,55 @@
use crate::{database::RelationalDatabase, service};
impl service::sending::Data for RelationalDatabase {
fn active_requests<'a>(
&'a self,
) -> Box<dyn Iterator<Item = crate::Result<(Vec<u8>, service::sending::OutgoingKind, service::sending::SendingEventType)>> + 'a> {
todo!()
}
fn active_requests_for<'a>(
&'a self,
outgoing_kind: &service::sending::OutgoingKind,
) -> Box<dyn Iterator<Item = crate::Result<(Vec<u8>, service::sending::SendingEventType)>> + 'a> {
todo!()
}
fn delete_active_request(&self, key: Vec<u8>) -> crate::Result<()> {
todo!()
}
fn delete_all_active_requests_for(&self, outgoing_kind: &service::sending::OutgoingKind) -> crate::Result<()> {
todo!()
}
fn delete_all_requests_for(&self, outgoing_kind: &service::sending::OutgoingKind) -> crate::Result<()> {
todo!()
}
fn queue_requests(
&self,
requests: &[(&service::sending::OutgoingKind, service::sending::SendingEventType)],
) -> crate::Result<Vec<Vec<u8>>> {
todo!()
}
fn queued_requests<'a>(
&'a self,
outgoing_kind: &service::sending::OutgoingKind,
) -> Box<dyn Iterator<Item = crate::Result<(service::sending::SendingEventType, Vec<u8>)>> + 'a> {
todo!()
}
fn mark_as_active(&self, events: &[(service::sending::SendingEventType, Vec<u8>)]) -> crate::Result<()> {
todo!()
}
fn set_latest_educount(&self, server_name: &ruma::ServerName, educount: u64) -> crate::Result<()> {
todo!()
}
fn get_latest_educount(&self, server_name: &ruma::ServerName) -> crate::Result<u64> {
todo!()
}
}

View file

@ -0,0 +1,22 @@
use crate::{database::RelationalDatabase, service};
impl service::transaction_ids::Data for RelationalDatabase {
fn add_txnid(
&self,
user_id: &ruma::UserId,
device_id: Option<&ruma::DeviceId>,
txn_id: &ruma::TransactionId,
data: &[u8],
) -> crate::Result<()> {
todo!()
}
fn existing_txnid(
&self,
user_id: &ruma::UserId,
device_id: Option<&ruma::DeviceId>,
txn_id: &ruma::TransactionId,
) -> crate::Result<Option<Vec<u8>>> {
todo!()
}
}

View file

@ -0,0 +1,41 @@
use crate::{service, RelationalDatabase};
impl service::uiaa::Data for RelationalDatabase {
fn set_uiaa_request(
&self,
user_id: &ruma::UserId,
device_id: &ruma::DeviceId,
session: &str,
request: &ruma::CanonicalJsonValue,
) -> crate::Result<()> {
todo!()
}
fn get_uiaa_request(
&self,
user_id: &ruma::UserId,
device_id: &ruma::DeviceId,
session: &str,
) -> Option<ruma::CanonicalJsonValue> {
todo!()
}
fn update_uiaa_session(
&self,
user_id: &ruma::UserId,
device_id: &ruma::DeviceId,
session: &str,
uiaainfo: Option<&ruma::api::client::uiaa::UiaaInfo>,
) -> crate::Result<()> {
todo!()
}
fn get_uiaa_session(
&self,
user_id: &ruma::UserId,
device_id: &ruma::DeviceId,
session: &str,
) -> crate::Result<ruma::api::client::uiaa::UiaaInfo> {
todo!()
}
}

File diff suppressed because it is too large Load diff

View file

@ -136,17 +136,17 @@ async fn main() {
maximize_fd_limit().expect("should be able to increase the soft limit to the hard limit");
info!("Loading database");
// if let Err(error) = RelationalDatabase::load_or_create(config).await {
// error!(?error, "The database couldn't be loaded or created");
// std::process::exit(1);
// };
if let Err(error) = KeyValueDatabase::load_or_create(config).await {
if let Err(error) = RelationalDatabase::load_or_create(config).await {
error!(?error, "The database couldn't be loaded or created");
std::process::exit(1);
};
// if let Err(error) = KeyValueDatabase::load_or_create(config).await {
// error!(?error, "The database couldn't be loaded or created");
// std::process::exit(1);
// };
let config = &services().globals.config;
info!("Starting server");

View file

@ -200,9 +200,10 @@ impl Service {
pub fn start_handler(self: &Arc<Self>) {
let self2 = Arc::clone(self);
tokio::spawn(async move {
self2.handler().await;
});
// TODO: get admin working
// tokio::spawn(async move {
// self2.handler().await;
// });
}
async fn handler(&self) {
@ -225,26 +226,6 @@ impl Service {
.expect("Database data for admin room alias must be valid")
.expect("Admin room must exist");
let send_message = |message: MessageEventContent, mutex_lock: &MutexGuard<'_, ()>| {
services()
.rooms
.timeline
.build_and_append_pdu(
PduBuilder {
event_type: TimelineEventType::Message,
content: to_raw_value(&message)
.expect("event is valid, we just created it"),
unsigned: None,
state_key: None,
redacts: None,
},
&conduit_user,
&conduit_room,
mutex_lock,
)
.unwrap();
};
loop {
tokio::select! {
Some(event) = receiver.recv() => {
@ -263,9 +244,24 @@ impl Service {
);
let state_lock = mutex_state.lock().await;
send_message(message_content, &state_lock);
services()
.rooms
.timeline
.build_and_append_pdu(
PduBuilder {
event_type: TimelineEventType::Message,
content: to_raw_value(&message_content)
.expect("event is valid, we just created it"),
unsigned: None,
state_key: None,
redacts: None,
},
&conduit_user,
&conduit_room,
&state_lock,
)
.await
.unwrap();
drop(state_lock);
}
}
@ -424,7 +420,7 @@ impl Service {
);
MessageEventContent::plain(output)
}
AdminCommand::ListLocalUsers => match services().users.list_local_users() {
AdminCommand::ListLocalUsers => match services().users.list_local_users().await {
Ok(users) => {
let mut msg: String = format!("Found {} local user account(s):\n", users.len());
msg += &users.join("\n");
@ -604,6 +600,7 @@ impl Service {
match services()
.users
.set_password(&user_id, Some(new_password.as_str()))
.await
{
Ok(()) => MessageEventContent::plain(format!(
"Successfully reset the password for user {user_id}: {new_password}"
@ -639,7 +636,10 @@ impl Service {
)));
}
// Create user
services().users.create(&user_id, Some(password.as_str()))?;
services()
.users
.create(&user_id, Some(password.as_str()))
.await?;
// Default to pretty displayname
let mut displayname = user_id.localpart().to_owned();
@ -651,7 +651,8 @@ impl Service {
services()
.users
.set_displayname(&user_id, Some(displayname))?;
.set_displayname(&user_id, Some(displayname))
.await?;
// Initial account data
services().account_data.update(
@ -693,7 +694,7 @@ impl Service {
"Making {user_id} leave all rooms before deactivation..."
));
services().users.deactivate_account(&user_id)?;
services().users.deactivate_account(&user_id).await?;
if leave_rooms {
leave_all_rooms(&user_id).await?;
@ -741,7 +742,7 @@ impl Service {
}
for &user_id in &user_ids {
if services().users.deactivate_account(user_id).is_ok() {
if services().users.deactivate_account(user_id).await.is_ok() {
deactivation_count += 1
}
}
@ -927,7 +928,7 @@ impl Service {
UserId::parse_with_server_name("conduit", services().globals.server_name())
.expect("@conduit:server_name is valid");
services().users.create(&conduit_user, None)?;
services().users.create(&conduit_user, None).await?;
let mut content = RoomCreateEventContent::new_v1(conduit_user.clone());
content.federate = true;
@ -935,147 +936,181 @@ impl Service {
content.room_version = services().globals.default_room_version();
// 1. The room create event
services().rooms.timeline.build_and_append_pdu(
PduBuilder {
event_type: TimelineEventType::RoomCreate,
content: to_raw_value(&content).expect("event is valid, we just created it"),
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
&conduit_user,
&room_id,
&state_lock,
)?;
services()
.rooms
.timeline
.build_and_append_pdu(
PduBuilder {
event_type: TimelineEventType::RoomCreate,
content: to_raw_value(&content).expect("event is valid, we just created it"),
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
&conduit_user,
&room_id,
&state_lock,
)
.await?;
// 2. Make conduit bot join
services().rooms.timeline.build_and_append_pdu(
PduBuilder {
event_type: TimelineEventType::RoomMember,
content: to_raw_value(&RoomMemberEventContent {
membership: MembershipState::Join,
displayname: None,
avatar_url: None,
is_direct: None,
third_party_invite: None,
blurhash: None,
reason: None,
join_authorized_via_users_server: None,
})
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some(conduit_user.to_string()),
redacts: None,
},
&conduit_user,
&room_id,
&state_lock,
)?;
services()
.rooms
.timeline
.build_and_append_pdu(
PduBuilder {
event_type: TimelineEventType::RoomMember,
content: to_raw_value(&RoomMemberEventContent {
membership: MembershipState::Join,
displayname: None,
avatar_url: None,
is_direct: None,
third_party_invite: None,
blurhash: None,
reason: None,
join_authorized_via_users_server: None,
})
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some(conduit_user.to_string()),
redacts: None,
},
&conduit_user,
&room_id,
&state_lock,
)
.await?;
// 3. Power levels
let mut users = BTreeMap::new();
users.insert(conduit_user.clone(), 100.into());
services().rooms.timeline.build_and_append_pdu(
PduBuilder {
event_type: TimelineEventType::RoomPowerLevels,
content: to_raw_value(&RoomPowerLevelsEventContent {
users,
..Default::default()
})
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
&conduit_user,
&room_id,
&state_lock,
)?;
services()
.rooms
.timeline
.build_and_append_pdu(
PduBuilder {
event_type: TimelineEventType::RoomPowerLevels,
content: to_raw_value(&RoomPowerLevelsEventContent {
users,
..Default::default()
})
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
&conduit_user,
&room_id,
&state_lock,
)
.await?;
// 4.1 Join Rules
services().rooms.timeline.build_and_append_pdu(
PduBuilder {
event_type: TimelineEventType::RoomJoinRules,
content: to_raw_value(&RoomJoinRulesEventContent::new(JoinRule::Invite))
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
&conduit_user,
&room_id,
&state_lock,
)?;
services()
.rooms
.timeline
.build_and_append_pdu(
PduBuilder {
event_type: TimelineEventType::RoomJoinRules,
content: to_raw_value(&RoomJoinRulesEventContent::new(JoinRule::Invite))
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
&conduit_user,
&room_id,
&state_lock,
)
.await?;
// 4.3 Guest Access
services().rooms.timeline.build_and_append_pdu(
PduBuilder {
event_type: TimelineEventType::RoomGuestAccess,
content: to_raw_value(&RoomGuestAccessEventContent::new(GuestAccess::Forbidden))
services()
.rooms
.timeline
.build_and_append_pdu(
PduBuilder {
event_type: TimelineEventType::RoomGuestAccess,
content: to_raw_value(&RoomGuestAccessEventContent::new(
GuestAccess::Forbidden,
))
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
&conduit_user,
&room_id,
&state_lock,
)?;
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
&conduit_user,
&room_id,
&state_lock,
)
.await?;
// 5. Events implied by name and topic
let room_name = format!("{} Admin Room", services().globals.server_name());
services().rooms.timeline.build_and_append_pdu(
PduBuilder {
event_type: TimelineEventType::RoomName,
content: to_raw_value(&RoomNameEventContent::new(room_name))
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
&conduit_user,
&room_id,
&state_lock,
)?;
services()
.rooms
.timeline
.build_and_append_pdu(
PduBuilder {
event_type: TimelineEventType::RoomName,
content: to_raw_value(&RoomNameEventContent::new(room_name))
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
&conduit_user,
&room_id,
&state_lock,
)
.await?;
services().rooms.timeline.build_and_append_pdu(
PduBuilder {
event_type: TimelineEventType::RoomTopic,
content: to_raw_value(&RoomTopicEventContent {
topic: format!("Manage {}", services().globals.server_name()),
})
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
&conduit_user,
&room_id,
&state_lock,
)?;
services()
.rooms
.timeline
.build_and_append_pdu(
PduBuilder {
event_type: TimelineEventType::RoomTopic,
content: to_raw_value(&RoomTopicEventContent {
topic: format!("Manage {}", services().globals.server_name()),
})
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
&conduit_user,
&room_id,
&state_lock,
)
.await?;
// 6. Room alias
let alias: OwnedRoomAliasId = format!("#admins:{}", services().globals.server_name())
.try_into()
.expect("#admins:server_name is a valid alias name");
services().rooms.timeline.build_and_append_pdu(
PduBuilder {
event_type: TimelineEventType::RoomCanonicalAlias,
content: to_raw_value(&RoomCanonicalAliasEventContent {
alias: Some(alias.clone()),
alt_aliases: Vec::new(),
})
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
&conduit_user,
&room_id,
&state_lock,
)?;
services()
.rooms
.timeline
.build_and_append_pdu(
PduBuilder {
event_type: TimelineEventType::RoomCanonicalAlias,
content: to_raw_value(&RoomCanonicalAliasEventContent {
alias: Some(alias.clone()),
alt_aliases: Vec::new(),
})
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
&conduit_user,
&room_id,
&state_lock,
)
.await?;
services().rooms.alias.set_alias(&alias, &room_id)?;
@ -1117,90 +1152,102 @@ impl Service {
.expect("@conduit:server_name is valid");
// Invite and join the real user
services().rooms.timeline.build_and_append_pdu(
PduBuilder {
event_type: TimelineEventType::RoomMember,
content: to_raw_value(&RoomMemberEventContent {
membership: MembershipState::Invite,
displayname: None,
avatar_url: None,
is_direct: None,
third_party_invite: None,
blurhash: None,
reason: None,
join_authorized_via_users_server: None,
})
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some(user_id.to_string()),
redacts: None,
},
&conduit_user,
&room_id,
&state_lock,
)?;
services().rooms.timeline.build_and_append_pdu(
PduBuilder {
event_type: TimelineEventType::RoomMember,
content: to_raw_value(&RoomMemberEventContent {
membership: MembershipState::Join,
displayname: Some(displayname),
avatar_url: None,
is_direct: None,
third_party_invite: None,
blurhash: None,
reason: None,
join_authorized_via_users_server: None,
})
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some(user_id.to_string()),
redacts: None,
},
user_id,
&room_id,
&state_lock,
)?;
services()
.rooms
.timeline
.build_and_append_pdu(
PduBuilder {
event_type: TimelineEventType::RoomMember,
content: to_raw_value(&RoomMemberEventContent {
membership: MembershipState::Invite,
displayname: None,
avatar_url: None,
is_direct: None,
third_party_invite: None,
blurhash: None,
reason: None,
join_authorized_via_users_server: None,
})
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some(user_id.to_string()),
redacts: None,
},
&conduit_user,
&room_id,
&state_lock,
)
.await?;
// services()
// .rooms
// .timeline
// .build_and_append_pdu(
// PduBuilder {
// event_type: TimelineEventType::RoomMember,
// content: to_raw_value(&RoomMemberEventContent {
// membership: MembershipState::Join,
// displayname: Some(displayname),
// avatar_url: None,
// is_direct: None,
// third_party_invite: None,
// blurhash: None,
// reason: None,
// join_authorized_via_users_server: None,
// })
// .expect("event is valid, we just created it"),
// unsigned: None,
// state_key: Some(user_id.to_string()),
// redacts: None,
// },
// user_id,
// &room_id,
// &state_lock,
// )
// .await?;
// Set power level
let mut users = BTreeMap::new();
users.insert(conduit_user.to_owned(), 100.into());
users.insert(user_id.to_owned(), 100.into());
// // Set power level
// let mut users = BTreeMap::new();
// users.insert(conduit_user.to_owned(), 100.into());
// users.insert(user_id.to_owned(), 100.into());
services().rooms.timeline.build_and_append_pdu(
PduBuilder {
event_type: TimelineEventType::RoomPowerLevels,
content: to_raw_value(&RoomPowerLevelsEventContent {
users,
..Default::default()
})
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
&conduit_user,
&room_id,
&state_lock,
)?;
// services()
// .rooms
// .timeline
// .build_and_append_pdu(
// PduBuilder {
// event_type: TimelineEventType::RoomPowerLevels,
// content: to_raw_value(&RoomPowerLevelsEventContent {
// users,
// ..Default::default()
// })
// .expect("event is valid, we just created it"),
// unsigned: None,
// state_key: Some("".to_owned()),
// redacts: None,
// },
// &conduit_user,
// &room_id,
// &state_lock,
// )
// .await?;
// Send welcome message
services().rooms.timeline.build_and_append_pdu(
PduBuilder {
event_type: TimelineEventType::Message,
content: to_raw_value(&MessageEventContent::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`", services().globals.server_name()),
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()),
))
.expect("event is valid, we just created it"),
unsigned: None,
state_key: None,
redacts: None,
},
&conduit_user,
&room_id,
&state_lock,
)?;
// // Send welcome message
// services().rooms.timeline.build_and_append_pdu(
// PduBuilder {
// event_type: TimelineEventType::Message,
// content: to_raw_value(&MessageEventContent::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`", services().globals.server_name()),
// 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()),
// ))
// .expect("event is valid, we just created it"),
// unsigned: None,
// state_key: None,
// redacts: None,
// },
// &conduit_user,
// &room_id,
// &state_lock,
// ).await?;
Ok(())
}

View file

@ -28,7 +28,7 @@ use std::{
},
time::{Duration, Instant},
};
use tokio::sync::{broadcast, watch::Receiver, Mutex as TokioMutex, Semaphore};
use tokio::sync::{broadcast, watch::Receiver, Mutex as TokioMutex, RwLock as TokioRwLock, Semaphore};
use tracing::{error, info};
use trust_dns_resolver::TokioAsyncResolver;
@ -60,7 +60,7 @@ pub struct Service {
pub bad_query_ratelimiter: Arc<RwLock<HashMap<OwnedServerName, RateLimitState>>>,
pub servername_ratelimiter: Arc<RwLock<HashMap<OwnedServerName, Arc<Semaphore>>>>,
pub sync_receivers: RwLock<HashMap<(OwnedUserId, OwnedDeviceId), SyncHandle>>,
pub roomid_mutex_insert: RwLock<HashMap<OwnedRoomId, Arc<Mutex<()>>>>,
pub roomid_mutex_insert: RwLock<HashMap<OwnedRoomId, Arc<TokioMutex<()>>>>,
pub roomid_mutex_state: RwLock<HashMap<OwnedRoomId, Arc<TokioMutex<()>>>>,
pub roomid_mutex_federation: RwLock<HashMap<OwnedRoomId, Arc<TokioMutex<()>>>>, // this lock will be held longer
pub roomid_federationhandletime: RwLock<HashMap<OwnedRoomId, (OwnedEventId, Instant)>>,

View file

@ -875,7 +875,7 @@ impl Service {
state_ids_compressed,
soft_fail,
&state_lock,
)?;
).await?;
// Soft fail, we keep the event as an outlier but don't add it to the timeline
warn!("Event was soft failed: {:?}", incoming_pdu);
@ -903,7 +903,7 @@ impl Service {
state_ids_compressed,
soft_fail,
&state_lock,
)?;
).await?;
debug!("Appended incoming pdu");

View file

@ -87,7 +87,7 @@ impl Service {
&pdu.sender,
None,
false,
)?;
).await?;
}
TimelineEventType::SpaceChild => {
services()
@ -102,7 +102,7 @@ impl Service {
}
}
services().rooms.state_cache.update_joined_count(room_id)?;
services().rooms.state_cache.update_joined_count(room_id).await?;
self.db
.set_room_state(room_id, shortstatehash, state_lock)?;

View file

@ -7,6 +7,7 @@ use ruma::{
OwnedRoomId, OwnedServerName, OwnedUserId, RoomId, ServerName, UserId,
};
#[async_trait::async_trait]
pub trait Data: Send + Sync {
fn mark_as_once_joined(&self, user_id: &UserId, room_id: &RoomId) -> Result<()>;
fn mark_as_joined(&self, user_id: &UserId, room_id: &RoomId) -> Result<()>;
@ -18,9 +19,9 @@ pub trait Data: Send + Sync {
) -> Result<()>;
fn mark_as_left(&self, user_id: &UserId, room_id: &RoomId) -> Result<()>;
fn update_joined_count(&self, room_id: &RoomId) -> Result<()>;
async fn update_joined_count(&self, room_id: &RoomId) -> Result<()>;
fn get_our_real_users(&self, room_id: &RoomId) -> Result<Arc<HashSet<OwnedUserId>>>;
async fn get_our_real_users(&self, room_id: &RoomId) -> Result<Arc<HashSet<OwnedUserId>>>;
fn appservice_in_room(
&self,
@ -43,13 +44,13 @@ pub trait Data: Send + Sync {
fn server_rooms<'a>(
&'a self,
server: &ServerName,
) -> Box<dyn Iterator<Item = Result<OwnedRoomId>> + 'a>;
) -> Box<dyn Iterator<Item = Result<OwnedRoomId>> + Send + 'a>;
/// Returns an iterator over all joined members of a room.
fn room_members<'a>(
&'a self,
room_id: &RoomId,
) -> Box<dyn Iterator<Item = Result<OwnedUserId>> + 'a>;
) -> Box<dyn Iterator<Item = Result<OwnedUserId>> + Send + 'a>;
fn room_joined_count(&self, room_id: &RoomId) -> Result<Option<u64>>;

View file

@ -24,7 +24,7 @@ pub struct Service {
impl Service {
/// Update current membership data.
#[tracing::instrument(skip(self, last_state))]
pub fn update_membership(
pub async fn update_membership(
&self,
room_id: &RoomId,
user_id: &UserId,
@ -35,7 +35,7 @@ impl Service {
) -> Result<()> {
// Keep track what remote users exist by adding them as "deactivated" users
if user_id.server_name() != services().globals.server_name() {
services().users.create(user_id, None)?;
services().users.create(user_id, None).await?;
// TODO: displayname, avatar url
}
@ -185,20 +185,20 @@ impl Service {
}
if update_joined_count {
self.update_joined_count(room_id)?;
self.update_joined_count(room_id).await?;
}
Ok(())
}
#[tracing::instrument(skip(self, room_id))]
pub fn update_joined_count(&self, room_id: &RoomId) -> Result<()> {
self.db.update_joined_count(room_id)
pub async fn update_joined_count(&self, room_id: &RoomId) -> Result<()> {
self.db.update_joined_count(room_id).await
}
#[tracing::instrument(skip(self, room_id))]
pub fn get_our_real_users(&self, room_id: &RoomId) -> Result<Arc<HashSet<OwnedUserId>>> {
self.db.get_our_real_users(room_id)
pub async fn get_our_real_users(&self, room_id: &RoomId) -> Result<Arc<HashSet<OwnedUserId>>> {
self.db.get_our_real_users(room_id).await
}
#[tracing::instrument(skip(self, room_id, appservice))]
@ -235,7 +235,7 @@ impl Service {
pub fn server_rooms<'a>(
&'a self,
server: &ServerName,
) -> impl Iterator<Item = Result<OwnedRoomId>> + 'a {
) -> impl Iterator<Item = Result<OwnedRoomId>> + Send + 'a {
self.db.server_rooms(server)
}

View file

@ -227,7 +227,7 @@ impl Service {
///
/// Returns pdu id
#[tracing::instrument(skip(self, pdu, pdu_json, leaves))]
pub fn append_pdu<'a>(
pub async fn append_pdu<'a>(
&self,
pdu: &PduEvent,
mut pdu_json: CanonicalJsonObject,
@ -293,7 +293,7 @@ impl Service {
.entry(pdu.room_id.clone())
.or_default(),
);
let insert_lock = mutex_insert.lock().unwrap();
let insert_lock = mutex_insert.lock().await;
// // Mark as read first so the sending client doesn't get a notification even if appending
// // fails
@ -323,7 +323,6 @@ impl Service {
.transpose()?
.unwrap_or_default();
let mut unreads = HashMap::new();
let thread_id = if let Ok(ExtractRelations { relations }) =
serde_json::from_str::<ExtractRelations>(pdu.content.get())
{
@ -339,118 +338,121 @@ impl Service {
None
};
for user in services()
// let mut unreads = HashMap::new();
let users = services()
.rooms
.state_cache
.get_our_real_users(&pdu.room_id)?
.iter()
.get_our_real_users(&pdu.room_id)
.await;
drop(users);
// for user in users.iter()
{
let (mention_user, mention_bulk, _message, notify) =
services().pusher.get_actions(&user, &pdu, &power_levels)?;
// let (mention_user, mention_bulk, _message, notify) =
// services().pusher.get_actions(&user, &pdu, &power_levels)?;
if notify {
for push_key in services().pusher.get_pushkeys(user) {
services().sending.send_push_pdu(&pdu_id, user, push_key?)?;
}
}
// if notify {
// for push_key in services().pusher.get_pushkeys(user) {
// services().sending.send_push_pdu(&pdu_id, user, push_key?)?;
// }
// }
unreads.insert(user.clone(), (mention_user, mention_bulk, notify));
// unreads.insert(user.clone(), (mention_user, mention_bulk, notify));
}
self.db
.increment_notification_counts(&pdu.room_id, thread_id.as_deref(), dbg!(unreads))?;
// self.db
// .increment_notification_counts(&pdu.room_id, thread_id.as_deref(), dbg!(unreads))?;
match pdu.kind {
TimelineEventType::RoomRedaction => {
if let Some(redact_id) = &pdu.redacts {
self.redact_pdu(redact_id, pdu)?;
}
}
TimelineEventType::SpaceChild => {
if let Some(_state_key) = &pdu.state_key {
services()
.rooms
.spaces
.roomid_spacechunk_cache
.lock()
.unwrap()
.remove(&pdu.room_id);
}
}
TimelineEventType::RoomMember => {
if let Some(state_key) = &pdu.state_key {
#[derive(Deserialize)]
struct ExtractMembership {
membership: MembershipState,
}
// match pdu.kind {
// TimelineEventType::RoomRedaction => {
// if let Some(redact_id) = &pdu.redacts {
// self.redact_pdu(redact_id, pdu)?;
// }
// }
// TimelineEventType::SpaceChild => {
// if let Some(_state_key) = &pdu.state_key {
// services()
// .rooms
// .spaces
// .roomid_spacechunk_cache
// .lock()
// .unwrap()
// .remove(&pdu.room_id);
// }
// }
// TimelineEventType::RoomMember => {
// if let Some(state_key) = &pdu.state_key {
// #[derive(Deserialize)]
// struct ExtractMembership {
// membership: MembershipState,
// }
// if the state_key fails
let target_user_id = UserId::parse(state_key.clone())
.expect("This state_key was previously validated");
// // if the state_key fails
// let target_user_id = UserId::parse(state_key.clone())
// .expect("This state_key was previously validated");
let content = serde_json::from_str::<ExtractMembership>(pdu.content.get())
.map_err(|_| Error::bad_database("Invalid content in pdu."))?;
// let content = serde_json::from_str::<ExtractMembership>(pdu.content.get())
// .map_err(|_| Error::bad_database("Invalid content in pdu."))?;
let invite_state = match content.membership {
MembershipState::Invite => {
let state = services().rooms.state.calculate_invite_state(pdu)?;
Some(state)
}
_ => None,
};
// let invite_state = match content.membership {
// MembershipState::Invite => {
// let state = services().rooms.state.calculate_invite_state(pdu)?;
// Some(state)
// }
// _ => None,
// };
// Update our membership info, we do this here incase a user is invited
// and immediately leaves we need the DB to record the invite event for auth
services().rooms.state_cache.update_membership(
&pdu.room_id,
&target_user_id,
content.membership,
&pdu.sender,
invite_state,
true,
)?;
}
}
TimelineEventType::Message => {
#[derive(Debug, Deserialize)]
struct ExtractBody {
body: Option<String>,
}
// // Update our membership info, we do this here incase a user is invited
// // and immediately leaves we need the DB to record the invite event for auth
// services().rooms.state_cache.update_membership(
// &pdu.room_id,
// &target_user_id,
// content.membership,
// &pdu.sender,
// invite_state,
// true,
// ).await?;
// }
// }
// TimelineEventType::Message => {
// #[derive(Debug, Deserialize)]
// struct ExtractBody {
// body: Option<String>,
// }
let content = serde_json::from_str::<ExtractBody>(pdu.content.get())
.map_err(|_| Error::bad_database("Invalid content in pdu."))?;
// let content = serde_json::from_str::<ExtractBody>(pdu.content.get())
// .map_err(|_| Error::bad_database("Invalid content in pdu."))?;
if let Some(body) = content.body {
services()
.rooms
.search
.index_pdu(shortroomid, &pdu_id, &body)?;
// if let Some(body) = content.body {
// services()
// .rooms
// .search
// .index_pdu(shortroomid, &pdu_id, &body)?;
let admin_room = services().rooms.alias.resolve_local_alias(
<&RoomAliasId>::try_from(
format!("#admins:{}", services().globals.server_name()).as_str(),
)
.expect("#admins:server_name is a valid room alias"),
)?;
let server_user = format!("@conduit:{}", services().globals.server_name());
// let admin_room = services().rooms.alias.resolve_local_alias(
// <&RoomAliasId>::try_from(
// format!("#admins:{}", services().globals.server_name()).as_str(),
// )
// .expect("#admins:server_name is a valid room alias"),
// )?;
// let server_user = format!("@conduit:{}", services().globals.server_name());
let to_conduit = body.starts_with(&format!("{server_user}: "))
|| body.starts_with(&format!("{server_user} "))
|| body == format!("{server_user}:")
|| body == server_user;
// let to_conduit = body.starts_with(&format!("{server_user}: "))
// || body.starts_with(&format!("{server_user} "))
// || body == format!("{server_user}:")
// || body == server_user;
// This will evaluate to false if the emergency password is set up so that
// the administrator can execute commands as conduit
let from_conduit = pdu.sender == server_user
&& services().globals.emergency_password().is_none();
// // This will evaluate to false if the emergency password is set up so that
// // the administrator can execute commands as conduit
// let from_conduit = pdu.sender == server_user
// && services().globals.emergency_password().is_none();
if to_conduit && !from_conduit && admin_room.as_ref() == Some(&pdu.room_id) {
services().admin.process_message(body);
}
}
}
_ => {}
}
// if to_conduit && !from_conduit && admin_room.as_ref() == Some(&pdu.room_id) {
// services().admin.process_message(body);
// }
// }
// }
// _ => {}
// }
// Update Relationships
#[derive(Debug, Deserialize)]
@ -465,126 +467,128 @@ impl Service {
relations: Vec<ExtractRelation>,
}
if let Ok(ExtractRelations { relations }) =
serde_json::from_str::<ExtractRelations>(pdu.content.get())
{
for relation in relations {
if let Some(related_pducount) = services()
.rooms
.timeline
.get_pdu_count(&relation.event_id)?
{
services()
.rooms
.pdu_metadata
.add_relation(PduCount::Normal(count), related_pducount)?;
}
// if let Ok(ExtractRelations { relations }) =
// serde_json::from_str::<ExtractRelations>(pdu.content.get())
// {
// for relation in relations {
// if let Some(related_pducount) = services()
// .rooms
// .timeline
// .get_pdu_count(&relation.event_id)?
// {
// services()
// .rooms
// .pdu_metadata
// .add_relation(PduCount::Normal(count), related_pducount)?;
// }
match relation.rel_type.as_str() {
"m.thread" => {
services()
.rooms
.threads
.add_to_thread(&relation.event_id, pdu)?;
}
_ => {
// TODO: Aggregate other types
}
}
}
}
// match relation.rel_type.as_str() {
// "m.thread" => {
// services()
// .rooms
// .threads
// .add_to_thread(&relation.event_id, pdu)?;
// }
// _ => {
// // TODO: Aggregate other types
// }
// }
// }
// }
for appservice in services().appservice.all()? {
if services()
.rooms
.state_cache
.appservice_in_room(&pdu.room_id, &appservice)?
{
services()
.sending
.send_pdu_appservice(appservice.0, pdu_id.clone())?;
continue;
}
// for appservice in services().appservice.all()? {
// if services()
// .rooms
// .state_cache
// .appservice_in_room(&pdu.room_id, &appservice)?
// {
// services()
// .sending
// .send_pdu_appservice(appservice.0, pdu_id.clone())?;
// continue;
// }
// If the RoomMember event has a non-empty state_key, it is targeted at someone.
// If it is our appservice user, we send this PDU to it.
if pdu.kind == TimelineEventType::RoomMember {
if let Some(state_key_uid) = &pdu
.state_key
.as_ref()
.and_then(|state_key| UserId::parse(state_key.as_str()).ok())
{
if let Some(appservice_uid) = appservice
.1
.get("sender_localpart")
.and_then(|string| string.as_str())
.and_then(|string| {
UserId::parse_with_server_name(string, services().globals.server_name())
.ok()
})
{
if state_key_uid == &appservice_uid {
services()
.sending
.send_pdu_appservice(appservice.0, pdu_id.clone())?;
continue;
}
}
}
}
// // If the RoomMember event has a non-empty state_key, it is targeted at someone.
// // If it is our appservice user, we send this PDU to it.
// if pdu.kind == TimelineEventType::RoomMember {
// if let Some(state_key_uid) = &pdu
// .state_key
// .as_ref()
// .and_then(|state_key| UserId::parse(state_key.as_str()).ok())
// {
// if let Some(appservice_uid) = appservice
// .1
// .get("sender_localpart")
// .and_then(|string| string.as_str())
// .and_then(|string| {
// UserId::parse_with_server_name(string, services().globals.server_name())
// .ok()
// })
// {
// if state_key_uid == &appservice_uid {
// services()
// .sending
// .send_pdu_appservice(appservice.0, pdu_id.clone())?;
// continue;
// }
// }
// }
// }
if let Some(namespaces) = appservice.1.get("namespaces") {
let users = namespaces
.get("users")
.and_then(|users| users.as_sequence())
.map_or_else(Vec::new, |users| {
users
.iter()
.filter_map(|users| Regex::new(users.get("regex")?.as_str()?).ok())
.collect::<Vec<_>>()
});
let aliases = namespaces
.get("aliases")
.and_then(|aliases| aliases.as_sequence())
.map_or_else(Vec::new, |aliases| {
aliases
.iter()
.filter_map(|aliases| Regex::new(aliases.get("regex")?.as_str()?).ok())
.collect::<Vec<_>>()
});
let rooms = namespaces
.get("rooms")
.and_then(|rooms| rooms.as_sequence());
// if let Some(namespaces) = appservice.1.get("namespaces") {
// let users = namespaces
// .get("users")
// .and_then(|users| users.as_sequence())
// .map_or_else(Vec::new, |users| {
// users
// .iter()
// .filter_map(|users| Regex::new(users.get("regex")?.as_str()?).ok())
// .collect::<Vec<_>>()
// });
// let aliases = namespaces
// .get("aliases")
// .and_then(|aliases| aliases.as_sequence())
// .map_or_else(Vec::new, |aliases| {
// aliases
// .iter()
// .filter_map(|aliases| Regex::new(aliases.get("regex")?.as_str()?).ok())
// .collect::<Vec<_>>()
// });
// let rooms = namespaces
// .get("rooms")
// .and_then(|rooms| rooms.as_sequence());
let matching_users = |users: &Regex| {
users.is_match(pdu.sender.as_str())
|| pdu.kind == TimelineEventType::RoomMember
&& pdu
.state_key
.as_ref()
.map_or(false, |state_key| users.is_match(state_key))
};
let matching_aliases = |aliases: &Regex| {
services()
.rooms
.alias
.local_aliases_for_room(&pdu.room_id)
.filter_map(|r| r.ok())
.any(|room_alias| aliases.is_match(room_alias.as_str()))
};
// let matching_users = |users: &Regex| {
// users.is_match(pdu.sender.as_str())
// || pdu.kind == TimelineEventType::RoomMember
// && pdu
// .state_key
// .as_ref()
// .map_or(false, |state_key| users.is_match(state_key))
// };
// let matching_aliases = |aliases: &Regex| {
// services()
// .rooms
// .alias
// .local_aliases_for_room(&pdu.room_id)
// .filter_map(|r| r.ok())
// .any(|room_alias| aliases.is_match(room_alias.as_str()))
// };
if aliases.iter().any(matching_aliases)
|| rooms.map_or(false, |rooms| rooms.contains(&pdu.room_id.as_str().into()))
|| users.iter().any(matching_users)
{
services()
.sending
.send_pdu_appservice(appservice.0, pdu_id.clone())?;
}
}
}
// if aliases.iter().any(matching_aliases)
// || rooms.map_or(false, |rooms| rooms.contains(&pdu.room_id.as_str().into()))
// || users.iter().any(matching_users)
// {
// services()
// .sending
// .send_pdu_appservice(appservice.0, pdu_id.clone())?;
// }
// }
// }
Ok(pdu_id)
// Ok(pdu_id)
todo!()
}
pub fn create_hash_and_sign_event(
@ -774,7 +778,7 @@ 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, state_lock))]
pub fn build_and_append_pdu(
pub async fn build_and_append_pdu(
&self,
pdu_builder: PduBuilder,
sender: &UserId,
@ -881,45 +885,47 @@ impl Service {
// of the room
vec![(*pdu.event_id).to_owned()],
state_lock,
)?;
).await?;
// We set the room state after inserting the pdu, so that we never have a moment in time
// where events in the current room state do not exist
services()
.rooms
.state
.set_room_state(room_id, statehashid, state_lock)?;
// // We set the room state after inserting the pdu, so that we never have a moment in time
// // where events in the current room state do not exist
// services()
// .rooms
// .state
// .set_room_state(room_id, statehashid, state_lock)?;
let mut servers: HashSet<OwnedServerName> = services()
.rooms
.state_cache
.room_servers(room_id)
.filter_map(|r| r.ok())
.collect();
// let mut servers: HashSet<OwnedServerName> = services()
// .rooms
// .state_cache
// .room_servers(room_id)
// .filter_map(|r| r.ok())
// .collect();
// In case we are kicking or banning a user, we need to inform their server of the change
if pdu.kind == TimelineEventType::RoomMember {
if let Some(state_key_uid) = &pdu
.state_key
.as_ref()
.and_then(|state_key| UserId::parse(state_key.as_str()).ok())
{
servers.insert(state_key_uid.server_name().to_owned());
}
}
// // In case we are kicking or banning a user, we need to inform their server of the change
// if pdu.kind == TimelineEventType::RoomMember {
// if let Some(state_key_uid) = &pdu
// .state_key
// .as_ref()
// .and_then(|state_key| UserId::parse(state_key.as_str()).ok())
// {
// servers.insert(state_key_uid.server_name().to_owned());
// }
// }
// 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(services().globals.server_name());
// // 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(services().globals.server_name());
services().sending.send_pdu(servers.into_iter(), &pdu_id)?;
// services().sending.send_pdu(servers.into_iter(), &pdu_id)?;
Ok(pdu.event_id)
// Ok(pdu.event_id)
todo!()
}
/// Append the incoming event setting the state snapshot to the state from the
/// server that sent the event.
#[tracing::instrument(skip_all)]
pub fn append_incoming_pdu<'a>(
pub async fn append_incoming_pdu<'a>(
&self,
pdu: &PduEvent,
pdu_json: CanonicalJsonObject,
@ -953,7 +959,7 @@ impl Service {
services()
.rooms
.timeline
.append_pdu(pdu, pdu_json, new_room_leaves, state_lock)?;
.append_pdu(pdu, pdu_json, new_room_leaves, state_lock).await?;
Ok(Some(pdu_id))
}
@ -1128,7 +1134,7 @@ impl Service {
.entry(room_id.clone())
.or_default(),
);
let insert_lock = mutex_insert.lock().unwrap();
let insert_lock = mutex_insert.lock().await;
let count = services().globals.next_count()?;
let mut pdu_id = shortroomid.to_be_bytes().to_vec();

View file

@ -186,7 +186,7 @@ impl Service {
&outgoing_kind,
vec![(event, key)],
&mut current_transaction_status,
) {
).await {
futures.push(Self::handle_events(outgoing_kind, events));
}
}
@ -195,7 +195,7 @@ impl Service {
}
#[tracing::instrument(skip(self, outgoing_kind, new_events, current_transaction_status))]
fn select_events(
async fn select_events(
&self,
outgoing_kind: &OutgoingKind,
new_events: Vec<(SendingEventType, Vec<u8>)>, // Events we want to send: event and full key
@ -250,7 +250,7 @@ impl Service {
}
if let OutgoingKind::Normal(server_name) = outgoing_kind {
if let Ok((select_edus, last_count)) = self.select_edus(server_name) {
if let Ok((select_edus, last_count)) = self.select_edus(server_name).await {
events.extend(select_edus.into_iter().map(SendingEventType::Edu));
self.db.set_latest_educount(server_name, last_count)?;
@ -262,7 +262,7 @@ impl Service {
}
#[tracing::instrument(skip(self, server_name))]
pub fn select_edus(&self, server_name: &ServerName) -> Result<(Vec<Vec<u8>>, u64)> {
pub async fn select_edus(&self, server_name: &ServerName) -> Result<(Vec<Vec<u8>>, u64)> {
// u64: count of last edu
let since = self.db.get_latest_educount(server_name)?;
let mut events = Vec::new();
@ -276,6 +276,7 @@ impl Service {
services()
.users
.keys_changed(room_id.as_ref(), since, None)
.await
.filter_map(|r| r.ok())
.filter(|user_id| user_id.server_name() == services().globals.server_name()),
);

View file

@ -40,7 +40,7 @@ impl Service {
)
}
pub fn try_auth(
pub async fn try_auth(
&self,
user_id: &UserId,
device_id: &DeviceId,
@ -80,7 +80,7 @@ impl Service {
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "User ID is invalid."))?;
// Check if password is correct
if let Some(hash) = services().users.password_hash(&user_id)? {
if let Some(hash) = services().users.password_hash(&user_id).await? {
let hash_matches =
argon2::verify_encoded(&hash, password.as_bytes()).unwrap_or(false);

View file

@ -1,4 +1,5 @@
use crate::Result;
use futures_util::Future;
use ruma::{
api::client::{device::Device, filter::FilterDefinition},
encryption::{CrossSigningKey, DeviceKeys, OneTimeKey},
@ -7,7 +8,7 @@ use ruma::{
DeviceId, DeviceKeyAlgorithm, DeviceKeyId, OwnedDeviceId, OwnedDeviceKeyId, OwnedMxcUri,
OwnedUserId, UInt, UserId,
};
use std::collections::BTreeMap;
use std::{collections::BTreeMap, pin::Pin};
#[async_trait::async_trait]
pub trait Data: Send + Sync {
@ -15,48 +16,48 @@ pub trait Data: Send + Sync {
async fn exists(&self, user_id: &UserId) -> Result<bool>;
/// Check if account is deactivated
fn is_deactivated(&self, user_id: &UserId) -> Result<bool>;
async fn is_deactivated(&self, user_id: &UserId) -> Result<bool>;
/// Returns the number of users registered on this server.
fn count(&self) -> Result<usize>;
async fn count(&self) -> Result<usize>;
/// Find out which user an access token belongs to.
fn find_from_token(&self, token: &str) -> Result<Option<(OwnedUserId, String)>>;
async fn find_from_token(&self, token: &str) -> Result<Option<(OwnedUserId, String)>>;
/// Returns an iterator over all users on this homeserver.
fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = Result<OwnedUserId>> + 'a>;
async fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = Result<OwnedUserId>> + 'a>;
/// 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.
fn list_local_users(&self) -> Result<Vec<String>>;
async fn list_local_users(&self) -> Result<Vec<String>>;
/// Returns the password hash for the given user.
fn password_hash(&self, user_id: &UserId) -> Result<Option<String>>;
async fn password_hash(&self, user_id: &UserId) -> Result<Option<String>>;
/// Hash and set the user's password to the Argon2 hash
fn set_password(&self, user_id: &UserId, password: Option<&str>) -> Result<()>;
async fn set_password(&self, user_id: &UserId, password: Option<&str>) -> Result<()>;
/// Returns the displayname of a user on this homeserver.
fn displayname(&self, user_id: &UserId) -> Result<Option<String>>;
async 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.
fn set_displayname(&self, user_id: &UserId, displayname: Option<String>) -> Result<()>;
async fn set_displayname(&self, user_id: &UserId, displayname: Option<String>) -> Result<()>;
/// Get the avatar_url of a user.
fn avatar_url(&self, user_id: &UserId) -> Result<Option<OwnedMxcUri>>;
async fn avatar_url(&self, user_id: &UserId) -> Result<Option<OwnedMxcUri>>;
/// Sets a new avatar_url or removes it if avatar_url is None.
fn set_avatar_url(&self, user_id: &UserId, avatar_url: Option<OwnedMxcUri>) -> Result<()>;
async fn set_avatar_url(&self, user_id: &UserId, avatar_url: Option<OwnedMxcUri>) -> Result<()>;
/// Get the blurhash of a user.
fn blurhash(&self, user_id: &UserId) -> Result<Option<String>>;
async fn blurhash(&self, user_id: &UserId) -> Result<Option<String>>;
/// Sets a new avatar_url or removes it if avatar_url is None.
fn set_blurhash(&self, user_id: &UserId, blurhash: Option<String>) -> Result<()>;
async fn set_blurhash(&self, user_id: &UserId, blurhash: Option<String>) -> Result<()>;
/// Adds a new device to a user.
fn create_device(
async fn create_device(
&self,
user_id: &UserId,
device_id: &DeviceId,
@ -65,18 +66,18 @@ pub trait Data: Send + Sync {
) -> Result<()>;
/// Removes a device from a user.
fn remove_device(&self, user_id: &UserId, device_id: &DeviceId) -> Result<()>;
async fn remove_device(&self, user_id: &UserId, device_id: &DeviceId) -> Result<()>;
/// Returns an iterator over all device ids of this user.
fn all_device_ids<'a>(
async fn all_device_ids<'a>(
&'a self,
user_id: &UserId,
) -> Box<dyn Iterator<Item = Result<OwnedDeviceId>> + 'a>;
) -> Box<dyn Iterator<Item = Result<OwnedDeviceId>> + Send + 'a>;
/// Replaces the access token of one device.
fn set_token(&self, user_id: &UserId, device_id: &DeviceId, token: &str) -> Result<()>;
async fn set_token(&self, user_id: &UserId, device_id: &DeviceId, token: &str) -> Result<()>;
fn add_one_time_key(
async fn add_one_time_key(
&self,
user_id: &UserId,
device_id: &DeviceId,
@ -84,29 +85,29 @@ pub trait Data: Send + Sync {
one_time_key_value: &Raw<OneTimeKey>,
) -> Result<()>;
fn last_one_time_keys_update(&self, user_id: &UserId) -> Result<u64>;
async fn last_one_time_keys_update(&self, user_id: &UserId) -> Result<u64>;
fn take_one_time_key(
async fn take_one_time_key(
&self,
user_id: &UserId,
device_id: &DeviceId,
key_algorithm: &DeviceKeyAlgorithm,
) -> Result<Option<(OwnedDeviceKeyId, Raw<OneTimeKey>)>>;
fn count_one_time_keys(
async fn count_one_time_keys(
&self,
user_id: &UserId,
device_id: &DeviceId,
) -> Result<BTreeMap<DeviceKeyAlgorithm, UInt>>;
fn add_device_keys(
async fn add_device_keys(
&self,
user_id: &UserId,
device_id: &DeviceId,
device_keys: &Raw<DeviceKeys>,
) -> Result<()>;
fn add_cross_signing_keys(
async fn add_cross_signing_keys(
&self,
user_id: &UserId,
master_key: &Raw<CrossSigningKey>,
@ -115,7 +116,7 @@ pub trait Data: Send + Sync {
notify: bool,
) -> Result<()>;
fn sign_key(
async fn sign_key(
&self,
target_id: &UserId,
key_id: &str,
@ -123,52 +124,93 @@ pub trait Data: Send + Sync {
sender_id: &UserId,
) -> Result<()>;
fn keys_changed<'a>(
async fn keys_changed<'a>(
&'a self,
user_or_room_id: &str,
from: u64,
to: Option<u64>,
) -> Box<dyn Iterator<Item = Result<OwnedUserId>> + 'a>;
fn mark_device_key_update(&self, user_id: &UserId) -> Result<()>;
async fn mark_device_key_update(&self, user_id: &UserId) -> Result<()>;
fn get_device_keys(
async fn get_device_keys(
&self,
user_id: &UserId,
device_id: &DeviceId,
) -> Result<Option<Raw<DeviceKeys>>>;
fn parse_master_key(
async fn parse_master_key(
&self,
user_id: &UserId,
master_key: &Raw<CrossSigningKey>,
) -> Result<(Vec<u8>, CrossSigningKey)>;
fn get_key(
&self,
key: &[u8],
sender_user: Option<&UserId>,
user_id: &UserId,
allowed_signatures: &dyn Fn(&UserId) -> bool,
) -> Result<Option<Raw<CrossSigningKey>>>;
fn get_key<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
key: &'life1 [u8],
sender_user: Option<&'life2 UserId>,
user_id: &'life3 UserId,
allowed_signatures: &'life4 (dyn (Fn(&UserId) -> bool) + Sync),
) -> Pin<Box<dyn Future<Output = Result<Option<Raw<CrossSigningKey>>>> + Send + 'async_trait>>
where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
Self: 'async_trait;
fn get_master_key(
&self,
sender_user: Option<&UserId>,
user_id: &UserId,
allowed_signatures: &dyn Fn(&UserId) -> bool,
) -> Result<Option<Raw<CrossSigningKey>>>;
fn get_master_key<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
sender_user: Option<&'life1 UserId>,
user_id: &'life2 UserId,
allowed_signatures: &'life3 (dyn (Fn(&UserId) -> bool) + Sync),
) -> Pin<Box<dyn Future<Output = Result<Option<Raw<CrossSigningKey>>>> + Send + 'async_trait>>
where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Self: 'async_trait;
fn get_self_signing_key(
&self,
sender_user: Option<&UserId>,
user_id: &UserId,
allowed_signatures: &dyn Fn(&UserId) -> bool,
) -> Result<Option<Raw<CrossSigningKey>>>;
fn get_self_signing_key<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
sender_user: Option<&'life1 UserId>,
user_id: &'life2 UserId,
allowed_signatures: &'life3 (dyn (Fn(&UserId) -> bool) + Sync),
) -> Pin<Box<dyn Future<Output = Result<Option<Raw<CrossSigningKey>>>> + Send + 'async_trait>>
where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Self: 'async_trait;
fn get_user_signing_key(&self, user_id: &UserId) -> Result<Option<Raw<CrossSigningKey>>>;
// async fn get_key(
// &self,
// key: &[u8],
// sender_user: Option<&UserId>,
// user_id: &UserId,
// allowed_signatures: &(dyn (Fn(&UserId) -> bool) + Sync),
// ) -> Result<Option<Raw<CrossSigningKey>>>;
fn add_to_device_event(
// async fn get_master_key(
// &self,
// sender_user: Option<&UserId>,
// user_id: &UserId,
// allowed_signatures: &(dyn (Fn(&UserId) -> bool) + Sync),
// ) -> Result<Option<Raw<CrossSigningKey>>>;
// async fn get_self_signing_key(
// &self,
// sender_user: Option<&UserId>,
// user_id: &UserId,
// allowed_signatures: &(dyn (Fn(&UserId) -> bool) + Sync),
// ) -> Result<Option<Raw<CrossSigningKey>>>;
async fn get_user_signing_key(&self, user_id: &UserId) -> Result<Option<Raw<CrossSigningKey>>>;
async fn add_to_device_event(
&self,
sender: &UserId,
target_user_id: &UserId,
@ -177,20 +219,20 @@ pub trait Data: Send + Sync {
content: serde_json::Value,
) -> Result<()>;
fn get_to_device_events(
async fn get_to_device_events(
&self,
user_id: &UserId,
device_id: &DeviceId,
) -> Result<Vec<Raw<AnyToDeviceEvent>>>;
fn remove_to_device_events(
async fn remove_to_device_events(
&self,
user_id: &UserId,
device_id: &DeviceId,
until: u64,
) -> Result<()>;
fn update_device_metadata(
async fn update_device_metadata(
&self,
user_id: &UserId,
device_id: &DeviceId,
@ -198,18 +240,18 @@ pub trait Data: Send + Sync {
) -> Result<()>;
/// Get device metadata.
fn get_device_metadata(&self, user_id: &UserId, device_id: &DeviceId)
async fn get_device_metadata(&self, user_id: &UserId, device_id: &DeviceId)
-> Result<Option<Device>>;
fn get_devicelist_version(&self, user_id: &UserId) -> Result<Option<u64>>;
async fn get_devicelist_version(&self, user_id: &UserId) -> Result<Option<u64>>;
fn all_devices_metadata<'a>(
async fn all_devices_metadata<'a>(
&'a self,
user_id: &UserId,
) -> Box<dyn Iterator<Item = Result<Device>> + 'a>;
/// Creates a new sync filter. Returns the filter id.
fn create_filter(&self, user_id: &UserId, filter: &FilterDefinition) -> Result<String>;
async fn create_filter(&self, user_id: &UserId, filter: &FilterDefinition) -> Result<String>;
fn get_filter(&self, user_id: &UserId, filter_id: &str) -> Result<Option<FilterDefinition>>;
async fn get_filter(&self, user_id: &UserId, filter_id: &str) -> Result<Option<FilterDefinition>>;
}

View file

@ -262,8 +262,8 @@ impl Service {
}
/// Check if account is deactivated
pub fn is_deactivated(&self, user_id: &UserId) -> Result<bool> {
self.db.is_deactivated(user_id)
pub async fn is_deactivated(&self, user_id: &UserId) -> Result<bool> {
self.db.is_deactivated(user_id).await
}
/// Check if a user is an admin
@ -284,75 +284,75 @@ impl Service {
}
/// 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)?;
pub async fn create(&self, user_id: &UserId, password: Option<&str>) -> Result<()> {
self.db.set_password(user_id, password).await?;
Ok(())
}
/// Returns the number of users registered on this server.
pub fn count(&self) -> Result<usize> {
self.db.count()
pub async fn count(&self) -> Result<usize> {
self.db.count().await
}
/// Find out which user an access token belongs to.
pub fn find_from_token(&self, token: &str) -> Result<Option<(OwnedUserId, String)>> {
self.db.find_from_token(token)
pub async fn find_from_token(&self, token: &str) -> Result<Option<(OwnedUserId, String)>> {
self.db.find_from_token(token).await
}
/// Returns an iterator over all users on this homeserver.
pub fn iter(&self) -> impl Iterator<Item = Result<OwnedUserId>> + '_ {
self.db.iter()
pub async fn iter(&self) -> impl Iterator<Item = Result<OwnedUserId>> + '_ {
self.db.iter().await
}
/// 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>> {
self.db.list_local_users()
pub async fn list_local_users(&self) -> Result<Vec<String>> {
self.db.list_local_users().await
}
/// Returns the password hash for the given user.
pub fn password_hash(&self, user_id: &UserId) -> Result<Option<String>> {
self.db.password_hash(user_id)
pub async fn password_hash(&self, user_id: &UserId) -> Result<Option<String>> {
self.db.password_hash(user_id).await
}
/// Hash and set the user's password to the Argon2 hash
pub fn set_password(&self, user_id: &UserId, password: Option<&str>) -> Result<()> {
self.db.set_password(user_id, password)
pub async fn set_password(&self, user_id: &UserId, password: Option<&str>) -> Result<()> {
self.db.set_password(user_id, password).await
}
/// Returns the displayname of a user on this homeserver.
pub fn displayname(&self, user_id: &UserId) -> Result<Option<String>> {
self.db.displayname(user_id)
pub async fn displayname(&self, user_id: &UserId) -> Result<Option<String>> {
self.db.displayname(user_id).await
}
/// 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<()> {
self.db.set_displayname(user_id, displayname)
pub async fn set_displayname(&self, user_id: &UserId, displayname: Option<String>) -> Result<()> {
self.db.set_displayname(user_id, displayname).await
}
/// Get the avatar_url of a user.
pub fn avatar_url(&self, user_id: &UserId) -> Result<Option<OwnedMxcUri>> {
self.db.avatar_url(user_id)
pub async fn avatar_url(&self, user_id: &UserId) -> Result<Option<OwnedMxcUri>> {
self.db.avatar_url(user_id).await
}
/// 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<OwnedMxcUri>) -> Result<()> {
self.db.set_avatar_url(user_id, avatar_url)
pub async fn set_avatar_url(&self, user_id: &UserId, avatar_url: Option<OwnedMxcUri>) -> Result<()> {
self.db.set_avatar_url(user_id, avatar_url).await
}
/// Get the blurhash of a user.
pub fn blurhash(&self, user_id: &UserId) -> Result<Option<String>> {
self.db.blurhash(user_id)
pub async fn blurhash(&self, user_id: &UserId) -> Result<Option<String>> {
self.db.blurhash(user_id).await
}
/// 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<()> {
self.db.set_blurhash(user_id, blurhash)
pub async fn set_blurhash(&self, user_id: &UserId, blurhash: Option<String>) -> Result<()> {
self.db.set_blurhash(user_id, blurhash).await
}
/// Adds a new device to a user.
pub fn create_device(
pub async fn create_device(
&self,
user_id: &UserId,
device_id: &DeviceId,
@ -360,28 +360,28 @@ impl Service {
initial_device_display_name: Option<String>,
) -> Result<()> {
self.db
.create_device(user_id, device_id, token, initial_device_display_name)
.create_device(user_id, device_id, token, initial_device_display_name).await
}
/// Removes a device from a user.
pub fn remove_device(&self, user_id: &UserId, device_id: &DeviceId) -> Result<()> {
self.db.remove_device(user_id, device_id)
pub async fn remove_device(&self, user_id: &UserId, device_id: &DeviceId) -> Result<()> {
self.db.remove_device(user_id, device_id).await
}
/// Returns an iterator over all device ids of this user.
pub fn all_device_ids<'a>(
pub async fn all_device_ids<'a>(
&'a self,
user_id: &UserId,
) -> impl Iterator<Item = Result<OwnedDeviceId>> + 'a {
self.db.all_device_ids(user_id)
) -> impl Iterator<Item = Result<OwnedDeviceId>> + Send + 'a {
self.db.all_device_ids(user_id).await
}
/// Replaces the access token of one device.
pub fn set_token(&self, user_id: &UserId, device_id: &DeviceId, token: &str) -> Result<()> {
self.db.set_token(user_id, device_id, token)
pub async fn set_token(&self, user_id: &UserId, device_id: &DeviceId, token: &str) -> Result<()> {
self.db.set_token(user_id, device_id, token).await
}
pub fn add_one_time_key(
pub async fn add_one_time_key(
&self,
user_id: &UserId,
device_id: &DeviceId,
@ -389,40 +389,40 @@ impl Service {
one_time_key_value: &Raw<OneTimeKey>,
) -> Result<()> {
self.db
.add_one_time_key(user_id, device_id, one_time_key_key, one_time_key_value)
.add_one_time_key(user_id, device_id, one_time_key_key, one_time_key_value).await
}
pub fn last_one_time_keys_update(&self, user_id: &UserId) -> Result<u64> {
self.db.last_one_time_keys_update(user_id)
pub async fn last_one_time_keys_update(&self, user_id: &UserId) -> Result<u64> {
self.db.last_one_time_keys_update(user_id).await
}
pub fn take_one_time_key(
pub async fn take_one_time_key(
&self,
user_id: &UserId,
device_id: &DeviceId,
key_algorithm: &DeviceKeyAlgorithm,
) -> Result<Option<(OwnedDeviceKeyId, Raw<OneTimeKey>)>> {
self.db.take_one_time_key(user_id, device_id, key_algorithm)
self.db.take_one_time_key(user_id, device_id, key_algorithm).await
}
pub fn count_one_time_keys(
pub async fn count_one_time_keys(
&self,
user_id: &UserId,
device_id: &DeviceId,
) -> Result<BTreeMap<DeviceKeyAlgorithm, UInt>> {
self.db.count_one_time_keys(user_id, device_id)
self.db.count_one_time_keys(user_id, device_id).await
}
pub fn add_device_keys(
pub async fn add_device_keys(
&self,
user_id: &UserId,
device_id: &DeviceId,
device_keys: &Raw<DeviceKeys>,
) -> Result<()> {
self.db.add_device_keys(user_id, device_id, device_keys)
self.db.add_device_keys(user_id, device_id, device_keys).await
}
pub fn add_cross_signing_keys(
pub async fn add_cross_signing_keys(
&self,
user_id: &UserId,
master_key: &Raw<CrossSigningKey>,
@ -436,84 +436,84 @@ impl Service {
self_signing_key,
user_signing_key,
notify,
)
).await
}
pub fn sign_key(
pub async fn sign_key(
&self,
target_id: &UserId,
key_id: &str,
signature: (String, String),
sender_id: &UserId,
) -> Result<()> {
self.db.sign_key(target_id, key_id, signature, sender_id)
self.db.sign_key(target_id, key_id, signature, sender_id).await
}
pub fn keys_changed<'a>(
pub async fn keys_changed<'a>(
&'a self,
user_or_room_id: &str,
from: u64,
to: Option<u64>,
) -> impl Iterator<Item = Result<OwnedUserId>> + 'a {
self.db.keys_changed(user_or_room_id, from, to)
self.db.keys_changed(user_or_room_id, from, to).await
}
pub fn mark_device_key_update(&self, user_id: &UserId) -> Result<()> {
self.db.mark_device_key_update(user_id)
pub async fn mark_device_key_update(&self, user_id: &UserId) -> Result<()> {
self.db.mark_device_key_update(user_id).await
}
pub fn get_device_keys(
pub async fn get_device_keys(
&self,
user_id: &UserId,
device_id: &DeviceId,
) -> Result<Option<Raw<DeviceKeys>>> {
self.db.get_device_keys(user_id, device_id)
self.db.get_device_keys(user_id, device_id).await
}
pub fn parse_master_key(
pub async fn parse_master_key(
&self,
user_id: &UserId,
master_key: &Raw<CrossSigningKey>,
) -> Result<(Vec<u8>, CrossSigningKey)> {
self.db.parse_master_key(user_id, master_key)
self.db.parse_master_key(user_id, master_key).await
}
pub fn get_key(
pub async fn get_key(
&self,
key: &[u8],
sender_user: Option<&UserId>,
user_id: &UserId,
allowed_signatures: &dyn Fn(&UserId) -> bool,
allowed_signatures: &(dyn (Fn(&UserId) -> bool) + Sync),
) -> Result<Option<Raw<CrossSigningKey>>> {
self.db
.get_key(key, sender_user, user_id, allowed_signatures)
.get_key(key, sender_user, user_id, allowed_signatures).await
}
pub fn get_master_key(
pub async fn get_master_key(
&self,
sender_user: Option<&UserId>,
user_id: &UserId,
allowed_signatures: &dyn Fn(&UserId) -> bool,
allowed_signatures: &(dyn (Fn(&UserId) -> bool) + Sync),
) -> Result<Option<Raw<CrossSigningKey>>> {
self.db
.get_master_key(sender_user, user_id, allowed_signatures)
.get_master_key(sender_user, user_id, allowed_signatures).await
}
pub fn get_self_signing_key(
pub async fn get_self_signing_key(
&self,
sender_user: Option<&UserId>,
user_id: &UserId,
allowed_signatures: &dyn Fn(&UserId) -> bool,
allowed_signatures: &(dyn (Fn(&UserId) -> bool) + Sync),
) -> Result<Option<Raw<CrossSigningKey>>> {
self.db
.get_self_signing_key(sender_user, user_id, allowed_signatures)
.get_self_signing_key(sender_user, user_id, allowed_signatures).await
}
pub fn get_user_signing_key(&self, user_id: &UserId) -> Result<Option<Raw<CrossSigningKey>>> {
self.db.get_user_signing_key(user_id)
pub async fn get_user_signing_key(&self, user_id: &UserId) -> Result<Option<Raw<CrossSigningKey>>> {
self.db.get_user_signing_key(user_id).await
}
pub fn add_to_device_event(
pub async fn add_to_device_event(
&self,
sender: &UserId,
target_user_id: &UserId,
@ -527,91 +527,91 @@ impl Service {
target_device_id,
event_type,
content,
)
).await
}
pub fn get_to_device_events(
pub async fn get_to_device_events(
&self,
user_id: &UserId,
device_id: &DeviceId,
) -> Result<Vec<Raw<AnyToDeviceEvent>>> {
self.db.get_to_device_events(user_id, device_id)
self.db.get_to_device_events(user_id, device_id).await
}
pub fn remove_to_device_events(
pub async fn remove_to_device_events(
&self,
user_id: &UserId,
device_id: &DeviceId,
until: u64,
) -> Result<()> {
self.db.remove_to_device_events(user_id, device_id, until)
self.db.remove_to_device_events(user_id, device_id, until).await
}
pub fn update_device_metadata(
pub async fn update_device_metadata(
&self,
user_id: &UserId,
device_id: &DeviceId,
device: &Device,
) -> Result<()> {
self.db.update_device_metadata(user_id, device_id, device)
self.db.update_device_metadata(user_id, device_id, device).await
}
/// Get device metadata.
pub fn get_device_metadata(
pub async fn get_device_metadata(
&self,
user_id: &UserId,
device_id: &DeviceId,
) -> Result<Option<Device>> {
self.db.get_device_metadata(user_id, device_id)
self.db.get_device_metadata(user_id, device_id).await
}
pub fn get_devicelist_version(&self, user_id: &UserId) -> Result<Option<u64>> {
self.db.get_devicelist_version(user_id)
pub async fn get_devicelist_version(&self, user_id: &UserId) -> Result<Option<u64>> {
self.db.get_devicelist_version(user_id).await
}
pub fn all_devices_metadata<'a>(
pub async fn all_devices_metadata<'a>(
&'a self,
user_id: &UserId,
) -> impl Iterator<Item = Result<Device>> + 'a {
self.db.all_devices_metadata(user_id)
self.db.all_devices_metadata(user_id).await
}
/// Deactivate account
pub fn deactivate_account(&self, user_id: &UserId) -> Result<()> {
pub async fn deactivate_account(&self, user_id: &UserId) -> Result<()> {
// Remove all associated devices
for device_id in self.all_device_ids(user_id) {
self.remove_device(user_id, &device_id?)?;
for device_id in self.all_device_ids(user_id).await {
self.remove_device(user_id, &device_id?).await?;
}
// Set the password to "" to indicate a deactivated account. Hashes will never result in an
// empty string, so the user will not be able to log in again. Systems like changing the
// password without logging in should check if the account is deactivated.
self.db.set_password(user_id, None)?;
self.db.set_password(user_id, None).await?;
// TODO: Unhook 3PID
Ok(())
}
/// Creates a new sync filter. Returns the filter id.
pub fn create_filter(&self, user_id: &UserId, filter: &FilterDefinition) -> Result<String> {
self.db.create_filter(user_id, filter)
pub async fn create_filter(&self, user_id: &UserId, filter: &FilterDefinition) -> Result<String> {
self.db.create_filter(user_id, filter).await
}
pub fn get_filter(
pub async fn get_filter(
&self,
user_id: &UserId,
filter_id: &str,
) -> Result<Option<FilterDefinition>> {
self.db.get_filter(user_id, filter_id)
self.db.get_filter(user_id, filter_id).await
}
}
/// Ensure that a user only sees signatures from themselves and the target user
pub fn clean_signatures<F: Fn(&UserId) -> bool>(
pub fn clean_signatures(
cross_signing_key: &mut serde_json::Value,
sender_user: Option<&UserId>,
user_id: &UserId,
allowed_signatures: F,
allowed_signatures: &(dyn (Fn(&UserId) -> bool) + Sync),
) -> Result<(), Error> {
if let Some(signatures) = cross_signing_key
.get_mut("signatures")

View file

@ -187,7 +187,7 @@ impl From<Infallible> for Error {
}
}
#[cfg(feature = "conduit_bin")]
// #[cfg(feature = "conduit_bin")]
impl axum::response::IntoResponse for Error {
fn into_response(self) -> axum::response::Response {
self.to_response().into_response()