refactor: use async-aware RwLocks and Mutexes where possible

This commit is contained in:
Matthias Ahouansou 2024-03-05 14:22:54 +00:00
parent 57575b7c6f
commit becaad677f
No known key found for this signature in database
21 changed files with 1171 additions and 1006 deletions

12
Cargo.lock generated
View file

@ -80,6 +80,17 @@ version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f093eed78becd229346bf859eec0aa4dd7ddde0757287b2b4107a1f09c80002" checksum = "5f093eed78becd229346bf859eec0aa4dd7ddde0757287b2b4107a1f09c80002"
[[package]]
name = "async-recursion"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.48",
]
[[package]] [[package]]
name = "async-trait" name = "async-trait"
version = "0.1.77" version = "0.1.77"
@ -374,6 +385,7 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
name = "conduit" name = "conduit"
version = "0.7.0-alpha" version = "0.7.0-alpha"
dependencies = [ dependencies = [
"async-recursion",
"async-trait", "async-trait",
"axum", "axum",
"axum-server", "axum-server",

View file

@ -115,6 +115,7 @@ lazy_static = "1.4.0"
async-trait = "0.1.68" async-trait = "0.1.68"
sd-notify = { version = "0.4.1", optional = true } sd-notify = { version = "0.4.1", optional = true }
async-recursion = "1.0.5"
[target.'cfg(unix)'.dependencies] [target.'cfg(unix)'.dependencies]
nix = { version = "0.26.2", features = ["resource"] } nix = { version = "0.26.2", features = ["resource"] }

View file

@ -339,17 +339,19 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool>(
let mut failures = BTreeMap::new(); let mut failures = BTreeMap::new();
let back_off = |id| match services() let back_off = |id| async {
.globals match services()
.bad_query_ratelimiter .globals
.write() .bad_query_ratelimiter
.unwrap() .write()
.entry(id) .await
{ .entry(id)
hash_map::Entry::Vacant(e) => { {
e.insert((Instant::now(), 1)); hash_map::Entry::Vacant(e) => {
e.insert((Instant::now(), 1));
}
hash_map::Entry::Occupied(mut e) => *e.get_mut() = (Instant::now(), e.get().1 + 1),
} }
hash_map::Entry::Occupied(mut e) => *e.get_mut() = (Instant::now(), e.get().1 + 1),
}; };
let mut futures: FuturesUnordered<_> = get_over_federation let mut futures: FuturesUnordered<_> = get_over_federation
@ -359,7 +361,7 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool>(
.globals .globals
.bad_query_ratelimiter .bad_query_ratelimiter
.read() .read()
.unwrap() .await
.get(server) .get(server)
{ {
// Exponential backoff // Exponential backoff
@ -428,7 +430,8 @@ pub(crate) async fn get_keys_helper<F: Fn(&UserId) -> bool>(
device_keys.extend(response.device_keys); device_keys.extend(response.device_keys);
} }
_ => { _ => {
back_off(server.to_owned()); back_off(server.to_owned()).await;
failures.insert(server.to_string(), json!({})); failures.insert(server.to_string(), json!({}));
} }
} }

View file

@ -26,9 +26,10 @@ use ruma::{
use serde_json::value::{to_raw_value, RawValue as RawJsonValue}; use serde_json::value::{to_raw_value, RawValue as RawJsonValue};
use std::{ use std::{
collections::{hash_map::Entry, BTreeMap, HashMap, HashSet}, collections::{hash_map::Entry, BTreeMap, HashMap, HashSet},
sync::{Arc, RwLock}, sync::Arc,
time::{Duration, Instant}, time::{Duration, Instant},
}; };
use tokio::sync::RwLock;
use tracing::{debug, error, info, warn}; use tracing::{debug, error, info, warn};
use crate::{ use crate::{
@ -212,24 +213,28 @@ pub async fn kick_user_route(
.globals .globals
.roomid_mutex_state .roomid_mutex_state
.write() .write()
.unwrap() .await
.entry(body.room_id.clone()) .entry(body.room_id.clone())
.or_default(), .or_default(),
); );
let state_lock = mutex_state.lock().await; let state_lock = mutex_state.lock().await;
services().rooms.timeline.build_and_append_pdu( services()
PduBuilder { .rooms
event_type: TimelineEventType::RoomMember, .timeline
content: to_raw_value(&event).expect("event is valid, we just created it"), .build_and_append_pdu(
unsigned: None, PduBuilder {
state_key: Some(body.user_id.to_string()), event_type: TimelineEventType::RoomMember,
redacts: None, content: to_raw_value(&event).expect("event is valid, we just created it"),
}, unsigned: None,
sender_user, state_key: Some(body.user_id.to_string()),
&body.room_id, redacts: None,
&state_lock, },
)?; sender_user,
&body.room_id,
&state_lock,
)
.await?;
drop(state_lock); drop(state_lock);
@ -276,24 +281,28 @@ pub async fn ban_user_route(body: Ruma<ban_user::v3::Request>) -> Result<ban_use
.globals .globals
.roomid_mutex_state .roomid_mutex_state
.write() .write()
.unwrap() .await
.entry(body.room_id.clone()) .entry(body.room_id.clone())
.or_default(), .or_default(),
); );
let state_lock = mutex_state.lock().await; let state_lock = mutex_state.lock().await;
services().rooms.timeline.build_and_append_pdu( services()
PduBuilder { .rooms
event_type: TimelineEventType::RoomMember, .timeline
content: to_raw_value(&event).expect("event is valid, we just created it"), .build_and_append_pdu(
unsigned: None, PduBuilder {
state_key: Some(body.user_id.to_string()), event_type: TimelineEventType::RoomMember,
redacts: None, content: to_raw_value(&event).expect("event is valid, we just created it"),
}, unsigned: None,
sender_user, state_key: Some(body.user_id.to_string()),
&body.room_id, redacts: None,
&state_lock, },
)?; sender_user,
&body.room_id,
&state_lock,
)
.await?;
drop(state_lock); drop(state_lock);
@ -334,24 +343,28 @@ pub async fn unban_user_route(
.globals .globals
.roomid_mutex_state .roomid_mutex_state
.write() .write()
.unwrap() .await
.entry(body.room_id.clone()) .entry(body.room_id.clone())
.or_default(), .or_default(),
); );
let state_lock = mutex_state.lock().await; let state_lock = mutex_state.lock().await;
services().rooms.timeline.build_and_append_pdu( services()
PduBuilder { .rooms
event_type: TimelineEventType::RoomMember, .timeline
content: to_raw_value(&event).expect("event is valid, we just created it"), .build_and_append_pdu(
unsigned: None, PduBuilder {
state_key: Some(body.user_id.to_string()), event_type: TimelineEventType::RoomMember,
redacts: None, content: to_raw_value(&event).expect("event is valid, we just created it"),
}, unsigned: None,
sender_user, state_key: Some(body.user_id.to_string()),
&body.room_id, redacts: None,
&state_lock, },
)?; sender_user,
&body.room_id,
&state_lock,
)
.await?;
drop(state_lock); drop(state_lock);
@ -489,7 +502,7 @@ async fn join_room_by_id_helper(
.globals .globals
.roomid_mutex_state .roomid_mutex_state
.write() .write()
.unwrap() .await
.entry(room_id.to_owned()) .entry(room_id.to_owned())
.or_default(), .or_default(),
); );
@ -680,7 +693,7 @@ async fn join_room_by_id_helper(
.iter() .iter()
.map(|pdu| validate_and_add_event_id(pdu, &room_version_id, &pub_key_map)) .map(|pdu| validate_and_add_event_id(pdu, &room_version_id, &pub_key_map))
{ {
let (event_id, value) = match result { let (event_id, value) = match result.await {
Ok(t) => t, Ok(t) => t,
Err(_) => continue, Err(_) => continue,
}; };
@ -710,7 +723,7 @@ async fn join_room_by_id_helper(
.iter() .iter()
.map(|pdu| validate_and_add_event_id(pdu, &room_version_id, &pub_key_map)) .map(|pdu| validate_and_add_event_id(pdu, &room_version_id, &pub_key_map))
{ {
let (event_id, value) = match result { let (event_id, value) = match result.await {
Ok(t) => t, Ok(t) => t,
Err(_) => continue, Err(_) => continue,
}; };
@ -784,12 +797,16 @@ async fn join_room_by_id_helper(
let statehash_after_join = services().rooms.state.append_to_state(&parsed_join_pdu)?; let statehash_after_join = services().rooms.state.append_to_state(&parsed_join_pdu)?;
info!("Appending new room join event"); info!("Appending new room join event");
services().rooms.timeline.append_pdu( services()
&parsed_join_pdu, .rooms
join_event, .timeline
vec![(*parsed_join_pdu.event_id).to_owned()], .append_pdu(
&state_lock, &parsed_join_pdu,
)?; join_event,
vec![(*parsed_join_pdu.event_id).to_owned()],
&state_lock,
)
.await?;
info!("Setting final room state for new room"); 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 // We set the room state after inserting the pdu, so that we never have a moment in time
@ -902,18 +919,23 @@ async fn join_room_by_id_helper(
}; };
// Try normal join first // Try normal join first
let error = match services().rooms.timeline.build_and_append_pdu( let error = match services()
PduBuilder { .rooms
event_type: TimelineEventType::RoomMember, .timeline
content: to_raw_value(&event).expect("event is valid, we just created it"), .build_and_append_pdu(
unsigned: None, PduBuilder {
state_key: Some(sender_user.to_string()), event_type: TimelineEventType::RoomMember,
redacts: None, content: to_raw_value(&event).expect("event is valid, we just created it"),
}, unsigned: None,
sender_user, state_key: Some(sender_user.to_string()),
room_id, redacts: None,
&state_lock, },
) { sender_user,
room_id,
&state_lock,
)
.await
{
Ok(_event_id) => return Ok(join_room_by_id::v3::Response::new(room_id.to_owned())), Ok(_event_id) => return Ok(join_room_by_id::v3::Response::new(room_id.to_owned())),
Err(e) => e, Err(e) => e,
}; };
@ -1109,7 +1131,7 @@ async fn make_join_request(
make_join_response_and_server make_join_response_and_server
} }
fn validate_and_add_event_id( async fn validate_and_add_event_id(
pdu: &RawJsonValue, pdu: &RawJsonValue,
room_version: &RoomVersionId, room_version: &RoomVersionId,
pub_key_map: &RwLock<BTreeMap<String, BTreeMap<String, Base64>>>, pub_key_map: &RwLock<BTreeMap<String, BTreeMap<String, Base64>>>,
@ -1125,24 +1147,26 @@ fn validate_and_add_event_id(
)) ))
.expect("ruma's reference hashes are valid event ids"); .expect("ruma's reference hashes are valid event ids");
let back_off = |id| match services() let back_off = |id| async {
.globals match services()
.bad_event_ratelimiter .globals
.write() .bad_event_ratelimiter
.unwrap() .write()
.entry(id) .await
{ .entry(id)
Entry::Vacant(e) => { {
e.insert((Instant::now(), 1)); Entry::Vacant(e) => {
e.insert((Instant::now(), 1));
}
Entry::Occupied(mut e) => *e.get_mut() = (Instant::now(), e.get().1 + 1),
} }
Entry::Occupied(mut e) => *e.get_mut() = (Instant::now(), e.get().1 + 1),
}; };
if let Some((time, tries)) = services() if let Some((time, tries)) = services()
.globals .globals
.bad_event_ratelimiter .bad_event_ratelimiter
.read() .read()
.unwrap() .await
.get(&event_id) .get(&event_id)
{ {
// Exponential backoff // Exponential backoff
@ -1157,15 +1181,10 @@ fn validate_and_add_event_id(
} }
} }
if let Err(e) = ruma::signatures::verify_event( if let Err(e) = ruma::signatures::verify_event(&*pub_key_map.read().await, &value, room_version)
&*pub_key_map {
.read()
.map_err(|_| Error::bad_database("RwLock is poisoned."))?,
&value,
room_version,
) {
warn!("Event {} failed verification {:?} {}", event_id, pdu, e); warn!("Event {} failed verification {:?} {}", event_id, pdu, e);
back_off(event_id); back_off(event_id).await;
return Err(Error::BadServerResponse("Event failed verification.")); return Err(Error::BadServerResponse("Event failed verification."));
} }
@ -1191,7 +1210,7 @@ pub(crate) async fn invite_helper<'a>(
.globals .globals
.roomid_mutex_state .roomid_mutex_state
.write() .write()
.unwrap() .await
.entry(room_id.to_owned()) .entry(room_id.to_owned())
.or_default(), .or_default(),
); );
@ -1312,34 +1331,38 @@ pub(crate) async fn invite_helper<'a>(
.globals .globals
.roomid_mutex_state .roomid_mutex_state
.write() .write()
.unwrap() .await
.entry(room_id.to_owned()) .entry(room_id.to_owned())
.or_default(), .or_default(),
); );
let state_lock = mutex_state.lock().await; let state_lock = mutex_state.lock().await;
services().rooms.timeline.build_and_append_pdu( services()
PduBuilder { .rooms
event_type: TimelineEventType::RoomMember, .timeline
content: to_raw_value(&RoomMemberEventContent { .build_and_append_pdu(
membership: MembershipState::Invite, PduBuilder {
displayname: services().users.displayname(user_id)?, event_type: TimelineEventType::RoomMember,
avatar_url: services().users.avatar_url(user_id)?, content: to_raw_value(&RoomMemberEventContent {
is_direct: Some(is_direct), membership: MembershipState::Invite,
third_party_invite: None, displayname: services().users.displayname(user_id)?,
blurhash: services().users.blurhash(user_id)?, avatar_url: services().users.avatar_url(user_id)?,
reason, is_direct: Some(is_direct),
join_authorized_via_users_server: None, third_party_invite: None,
}) blurhash: services().users.blurhash(user_id)?,
.expect("event is valid, we just created it"), reason,
unsigned: None, join_authorized_via_users_server: None,
state_key: Some(user_id.to_string()), })
redacts: None, .expect("event is valid, we just created it"),
}, unsigned: None,
sender_user, state_key: Some(user_id.to_string()),
room_id, redacts: None,
&state_lock, },
)?; sender_user,
room_id,
&state_lock,
)
.await?;
drop(state_lock); drop(state_lock);
@ -1407,7 +1430,7 @@ pub async fn leave_room(user_id: &UserId, room_id: &RoomId, reason: Option<Strin
.globals .globals
.roomid_mutex_state .roomid_mutex_state
.write() .write()
.unwrap() .await
.entry(room_id.to_owned()) .entry(room_id.to_owned())
.or_default(), .or_default(),
); );
@ -1443,18 +1466,22 @@ pub async fn leave_room(user_id: &UserId, room_id: &RoomId, reason: Option<Strin
event.membership = MembershipState::Leave; event.membership = MembershipState::Leave;
event.reason = reason; event.reason = reason;
services().rooms.timeline.build_and_append_pdu( services()
PduBuilder { .rooms
event_type: TimelineEventType::RoomMember, .timeline
content: to_raw_value(&event).expect("event is valid, we just created it"), .build_and_append_pdu(
unsigned: None, PduBuilder {
state_key: Some(user_id.to_string()), event_type: TimelineEventType::RoomMember,
redacts: None, content: to_raw_value(&event).expect("event is valid, we just created it"),
}, unsigned: None,
user_id, state_key: Some(user_id.to_string()),
room_id, redacts: None,
&state_lock, },
)?; user_id,
room_id,
&state_lock,
)
.await?;
} }
Ok(()) Ok(())

View file

@ -32,7 +32,7 @@ pub async fn send_message_event_route(
.globals .globals
.roomid_mutex_state .roomid_mutex_state
.write() .write()
.unwrap() .await
.entry(body.room_id.clone()) .entry(body.room_id.clone())
.or_default(), .or_default(),
); );
@ -73,19 +73,23 @@ pub async fn send_message_event_route(
let mut unsigned = BTreeMap::new(); let mut unsigned = BTreeMap::new();
unsigned.insert("transaction_id".to_owned(), body.txn_id.to_string().into()); unsigned.insert("transaction_id".to_owned(), body.txn_id.to_string().into());
let event_id = services().rooms.timeline.build_and_append_pdu( let event_id = services()
PduBuilder { .rooms
event_type: body.event_type.to_string().into(), .timeline
content: serde_json::from_str(body.body.body.json().get()) .build_and_append_pdu(
.map_err(|_| Error::BadRequest(ErrorKind::BadJson, "Invalid JSON body."))?, PduBuilder {
unsigned: Some(unsigned), event_type: body.event_type.to_string().into(),
state_key: None, content: serde_json::from_str(body.body.body.json().get())
redacts: None, .map_err(|_| Error::BadRequest(ErrorKind::BadJson, "Invalid JSON body."))?,
}, unsigned: Some(unsigned),
sender_user, state_key: None,
&body.room_id, redacts: None,
&state_lock, },
)?; sender_user,
&body.room_id,
&state_lock,
)
.await?;
services().transaction_ids.add_txnid( services().transaction_ids.add_txnid(
sender_user, sender_user,
@ -126,12 +130,11 @@ pub async fn get_message_events_route(
.as_ref() .as_ref()
.and_then(|t| PduCount::try_from_string(t).ok()); .and_then(|t| PduCount::try_from_string(t).ok());
services().rooms.lazy_loading.lazy_load_confirm_delivery( services()
sender_user, .rooms
sender_device, .lazy_loading
&body.room_id, .lazy_load_confirm_delivery(sender_user, sender_device, &body.room_id, from)
from, .await?;
)?;
let limit = u64::from(body.limit).min(100) as usize; let limit = u64::from(body.limit).min(100) as usize;

View file

@ -77,18 +77,17 @@ pub async fn set_displayname_route(
.globals .globals
.roomid_mutex_state .roomid_mutex_state
.write() .write()
.unwrap() .await
.entry(room_id.clone()) .entry(room_id.clone())
.or_default(), .or_default(),
); );
let state_lock = mutex_state.lock().await; let state_lock = mutex_state.lock().await;
let _ = services().rooms.timeline.build_and_append_pdu( let _ = services()
pdu_builder, .rooms
sender_user, .timeline
&room_id, .build_and_append_pdu(pdu_builder, sender_user, &room_id, &state_lock)
&state_lock, .await;
);
// Presence update // Presence update
services().rooms.edus.presence.update_presence( services().rooms.edus.presence.update_presence(
@ -212,18 +211,17 @@ pub async fn set_avatar_url_route(
.globals .globals
.roomid_mutex_state .roomid_mutex_state
.write() .write()
.unwrap() .await
.entry(room_id.clone()) .entry(room_id.clone())
.or_default(), .or_default(),
); );
let state_lock = mutex_state.lock().await; let state_lock = mutex_state.lock().await;
let _ = services().rooms.timeline.build_and_append_pdu( let _ = services()
pdu_builder, .rooms
sender_user, .timeline
&room_id, .build_and_append_pdu(pdu_builder, sender_user, &room_id, &state_lock)
&state_lock, .await;
);
// Presence update // Presence update
services().rooms.edus.presence.update_presence( services().rooms.edus.presence.update_presence(

View file

@ -24,28 +24,32 @@ pub async fn redact_event_route(
.globals .globals
.roomid_mutex_state .roomid_mutex_state
.write() .write()
.unwrap() .await
.entry(body.room_id.clone()) .entry(body.room_id.clone())
.or_default(), .or_default(),
); );
let state_lock = mutex_state.lock().await; let state_lock = mutex_state.lock().await;
let event_id = services().rooms.timeline.build_and_append_pdu( let event_id = services()
PduBuilder { .rooms
event_type: TimelineEventType::RoomRedaction, .timeline
content: to_raw_value(&RoomRedactionEventContent { .build_and_append_pdu(
redacts: Some(body.event_id.clone()), PduBuilder {
reason: body.reason.clone(), event_type: TimelineEventType::RoomRedaction,
}) content: to_raw_value(&RoomRedactionEventContent {
.expect("event is valid, we just created it"), redacts: Some(body.event_id.clone()),
unsigned: None, reason: body.reason.clone(),
state_key: None, })
redacts: Some(body.event_id.into()), .expect("event is valid, we just created it"),
}, unsigned: None,
sender_user, state_key: None,
&body.room_id, redacts: Some(body.event_id.into()),
&state_lock, },
)?; sender_user,
&body.room_id,
&state_lock,
)
.await?;
drop(state_lock); drop(state_lock);

View file

@ -61,7 +61,7 @@ pub async fn create_room_route(
.globals .globals
.roomid_mutex_state .roomid_mutex_state
.write() .write()
.unwrap() .await
.entry(room_id.clone()) .entry(room_id.clone())
.or_default(), .or_default(),
); );
@ -174,42 +174,50 @@ pub async fn create_room_route(
} }
// 1. The room create event // 1. The room create event
services().rooms.timeline.build_and_append_pdu( services()
PduBuilder { .rooms
event_type: TimelineEventType::RoomCreate, .timeline
content: to_raw_value(&content).expect("event is valid, we just created it"), .build_and_append_pdu(
unsigned: None, PduBuilder {
state_key: Some("".to_owned()), event_type: TimelineEventType::RoomCreate,
redacts: None, content: to_raw_value(&content).expect("event is valid, we just created it"),
}, unsigned: None,
sender_user, state_key: Some("".to_owned()),
&room_id, redacts: None,
&state_lock, },
)?; sender_user,
&room_id,
&state_lock,
)
.await?;
// 2. Let the room creator join // 2. Let the room creator join
services().rooms.timeline.build_and_append_pdu( services()
PduBuilder { .rooms
event_type: TimelineEventType::RoomMember, .timeline
content: to_raw_value(&RoomMemberEventContent { .build_and_append_pdu(
membership: MembershipState::Join, PduBuilder {
displayname: services().users.displayname(sender_user)?, event_type: TimelineEventType::RoomMember,
avatar_url: services().users.avatar_url(sender_user)?, content: to_raw_value(&RoomMemberEventContent {
is_direct: Some(body.is_direct), membership: MembershipState::Join,
third_party_invite: None, displayname: services().users.displayname(sender_user)?,
blurhash: services().users.blurhash(sender_user)?, avatar_url: services().users.avatar_url(sender_user)?,
reason: None, is_direct: Some(body.is_direct),
join_authorized_via_users_server: None, third_party_invite: None,
}) blurhash: services().users.blurhash(sender_user)?,
.expect("event is valid, we just created it"), reason: None,
unsigned: None, join_authorized_via_users_server: None,
state_key: Some(sender_user.to_string()), })
redacts: None, .expect("event is valid, we just created it"),
}, unsigned: None,
sender_user, state_key: Some(sender_user.to_string()),
&room_id, redacts: None,
&state_lock, },
)?; sender_user,
&room_id,
&state_lock,
)
.await?;
// 3. Power levels // 3. Power levels
@ -246,30 +254,14 @@ pub async fn create_room_route(
} }
} }
services().rooms.timeline.build_and_append_pdu( services()
PduBuilder { .rooms
event_type: TimelineEventType::RoomPowerLevels, .timeline
content: to_raw_value(&power_levels_content) .build_and_append_pdu(
.expect("to_raw_value always works on serde_json::Value"),
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
sender_user,
&room_id,
&state_lock,
)?;
// 4. Canonical room alias
if let Some(room_alias_id) = &alias {
services().rooms.timeline.build_and_append_pdu(
PduBuilder { PduBuilder {
event_type: TimelineEventType::RoomCanonicalAlias, event_type: TimelineEventType::RoomPowerLevels,
content: to_raw_value(&RoomCanonicalAliasEventContent { content: to_raw_value(&power_levels_content)
alias: Some(room_alias_id.to_owned()), .expect("to_raw_value always works on serde_json::Value"),
alt_aliases: vec![],
})
.expect("We checked that alias earlier, it must be fine"),
unsigned: None, unsigned: None,
state_key: Some("".to_owned()), state_key: Some("".to_owned()),
redacts: None, redacts: None,
@ -277,64 +269,100 @@ pub async fn create_room_route(
sender_user, sender_user,
&room_id, &room_id,
&state_lock, &state_lock,
)?; )
.await?;
// 4. Canonical room alias
if let Some(room_alias_id) = &alias {
services()
.rooms
.timeline
.build_and_append_pdu(
PduBuilder {
event_type: TimelineEventType::RoomCanonicalAlias,
content: to_raw_value(&RoomCanonicalAliasEventContent {
alias: Some(room_alias_id.to_owned()),
alt_aliases: vec![],
})
.expect("We checked that alias earlier, it must be fine"),
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
sender_user,
&room_id,
&state_lock,
)
.await?;
} }
// 5. Events set by preset // 5. Events set by preset
// 5.1 Join Rules // 5.1 Join Rules
services().rooms.timeline.build_and_append_pdu( services()
PduBuilder { .rooms
event_type: TimelineEventType::RoomJoinRules, .timeline
content: to_raw_value(&RoomJoinRulesEventContent::new(match preset { .build_and_append_pdu(
RoomPreset::PublicChat => JoinRule::Public, PduBuilder {
// according to spec "invite" is the default event_type: TimelineEventType::RoomJoinRules,
_ => JoinRule::Invite, content: to_raw_value(&RoomJoinRulesEventContent::new(match preset {
})) RoomPreset::PublicChat => JoinRule::Public,
.expect("event is valid, we just created it"), // according to spec "invite" is the default
unsigned: None, _ => JoinRule::Invite,
state_key: Some("".to_owned()), }))
redacts: None, .expect("event is valid, we just created it"),
}, unsigned: None,
sender_user, state_key: Some("".to_owned()),
&room_id, redacts: None,
&state_lock, },
)?; sender_user,
&room_id,
&state_lock,
)
.await?;
// 5.2 History Visibility // 5.2 History Visibility
services().rooms.timeline.build_and_append_pdu( services()
PduBuilder { .rooms
event_type: TimelineEventType::RoomHistoryVisibility, .timeline
content: to_raw_value(&RoomHistoryVisibilityEventContent::new( .build_and_append_pdu(
HistoryVisibility::Shared, PduBuilder {
)) event_type: TimelineEventType::RoomHistoryVisibility,
.expect("event is valid, we just created it"), content: to_raw_value(&RoomHistoryVisibilityEventContent::new(
unsigned: None, HistoryVisibility::Shared,
state_key: Some("".to_owned()), ))
redacts: None, .expect("event is valid, we just created it"),
}, unsigned: None,
sender_user, state_key: Some("".to_owned()),
&room_id, redacts: None,
&state_lock, },
)?; sender_user,
&room_id,
&state_lock,
)
.await?;
// 5.3 Guest Access // 5.3 Guest Access
services().rooms.timeline.build_and_append_pdu( services()
PduBuilder { .rooms
event_type: TimelineEventType::RoomGuestAccess, .timeline
content: to_raw_value(&RoomGuestAccessEventContent::new(match preset { .build_and_append_pdu(
RoomPreset::PublicChat => GuestAccess::Forbidden, PduBuilder {
_ => GuestAccess::CanJoin, event_type: TimelineEventType::RoomGuestAccess,
})) content: to_raw_value(&RoomGuestAccessEventContent::new(match preset {
.expect("event is valid, we just created it"), RoomPreset::PublicChat => GuestAccess::Forbidden,
unsigned: None, _ => GuestAccess::CanJoin,
state_key: Some("".to_owned()), }))
redacts: None, .expect("event is valid, we just created it"),
}, unsigned: None,
sender_user, state_key: Some("".to_owned()),
&room_id, redacts: None,
&state_lock, },
)?; sender_user,
&room_id,
&state_lock,
)
.await?;
// 6. Events listed in initial_state // 6. Events listed in initial_state
for event in &body.initial_state { for event in &body.initial_state {
@ -353,47 +381,54 @@ pub async fn create_room_route(
continue; continue;
} }
services().rooms.timeline.build_and_append_pdu( services()
pdu_builder, .rooms
sender_user, .timeline
&room_id, .build_and_append_pdu(pdu_builder, sender_user, &room_id, &state_lock)
&state_lock, .await?;
)?;
} }
// 7. Events implied by name and topic // 7. Events implied by name and topic
if let Some(name) = &body.name { if let Some(name) = &body.name {
services().rooms.timeline.build_and_append_pdu( services()
PduBuilder { .rooms
event_type: TimelineEventType::RoomName, .timeline
content: to_raw_value(&RoomNameEventContent::new(name.clone())) .build_and_append_pdu(
.expect("event is valid, we just created it"), PduBuilder {
unsigned: None, event_type: TimelineEventType::RoomName,
state_key: Some("".to_owned()), content: to_raw_value(&RoomNameEventContent::new(name.clone()))
redacts: None, .expect("event is valid, we just created it"),
}, unsigned: None,
sender_user, state_key: Some("".to_owned()),
&room_id, redacts: None,
&state_lock, },
)?; sender_user,
&room_id,
&state_lock,
)
.await?;
} }
if let Some(topic) = &body.topic { if let Some(topic) = &body.topic {
services().rooms.timeline.build_and_append_pdu( services()
PduBuilder { .rooms
event_type: TimelineEventType::RoomTopic, .timeline
content: to_raw_value(&RoomTopicEventContent { .build_and_append_pdu(
topic: topic.clone(), PduBuilder {
}) event_type: TimelineEventType::RoomTopic,
.expect("event is valid, we just created it"), content: to_raw_value(&RoomTopicEventContent {
unsigned: None, topic: topic.clone(),
state_key: Some("".to_owned()), })
redacts: None, .expect("event is valid, we just created it"),
}, unsigned: None,
sender_user, state_key: Some("".to_owned()),
&room_id, redacts: None,
&state_lock, },
)?; sender_user,
&room_id,
&state_lock,
)
.await?;
} }
// 8. Events implied by invite (and TODO: invite_3pid) // 8. Events implied by invite (and TODO: invite_3pid)
@ -523,7 +558,7 @@ pub async fn upgrade_room_route(
.globals .globals
.roomid_mutex_state .roomid_mutex_state
.write() .write()
.unwrap() .await
.entry(body.room_id.clone()) .entry(body.room_id.clone())
.or_default(), .or_default(),
); );
@ -531,22 +566,26 @@ pub async fn upgrade_room_route(
// Send a m.room.tombstone event to the old room to indicate that it is not intended to be used any further // Send a m.room.tombstone event to the old room to indicate that it is not intended to be used any further
// Fail if the sender does not have the required permissions // Fail if the sender does not have the required permissions
let tombstone_event_id = services().rooms.timeline.build_and_append_pdu( let tombstone_event_id = services()
PduBuilder { .rooms
event_type: TimelineEventType::RoomTombstone, .timeline
content: to_raw_value(&RoomTombstoneEventContent { .build_and_append_pdu(
body: "This room has been replaced".to_owned(), PduBuilder {
replacement_room: replacement_room.clone(), event_type: TimelineEventType::RoomTombstone,
}) content: to_raw_value(&RoomTombstoneEventContent {
.expect("event is valid, we just created it"), body: "This room has been replaced".to_owned(),
unsigned: None, replacement_room: replacement_room.clone(),
state_key: Some("".to_owned()), })
redacts: None, .expect("event is valid, we just created it"),
}, unsigned: None,
sender_user, state_key: Some("".to_owned()),
&body.room_id, redacts: None,
&state_lock, },
)?; sender_user,
&body.room_id,
&state_lock,
)
.await?;
// Change lock to replacement room // Change lock to replacement room
drop(state_lock); drop(state_lock);
@ -555,7 +594,7 @@ pub async fn upgrade_room_route(
.globals .globals
.roomid_mutex_state .roomid_mutex_state
.write() .write()
.unwrap() .await
.entry(replacement_room.clone()) .entry(replacement_room.clone())
.or_default(), .or_default(),
); );
@ -613,43 +652,51 @@ pub async fn upgrade_room_route(
)); ));
} }
services().rooms.timeline.build_and_append_pdu( services()
PduBuilder { .rooms
event_type: TimelineEventType::RoomCreate, .timeline
content: to_raw_value(&create_event_content) .build_and_append_pdu(
.expect("event is valid, we just created it"), PduBuilder {
unsigned: None, event_type: TimelineEventType::RoomCreate,
state_key: Some("".to_owned()), content: to_raw_value(&create_event_content)
redacts: None, .expect("event is valid, we just created it"),
}, unsigned: None,
sender_user, state_key: Some("".to_owned()),
&replacement_room, redacts: None,
&state_lock, },
)?; sender_user,
&replacement_room,
&state_lock,
)
.await?;
// Join the new room // Join the new room
services().rooms.timeline.build_and_append_pdu( services()
PduBuilder { .rooms
event_type: TimelineEventType::RoomMember, .timeline
content: to_raw_value(&RoomMemberEventContent { .build_and_append_pdu(
membership: MembershipState::Join, PduBuilder {
displayname: services().users.displayname(sender_user)?, event_type: TimelineEventType::RoomMember,
avatar_url: services().users.avatar_url(sender_user)?, content: to_raw_value(&RoomMemberEventContent {
is_direct: None, membership: MembershipState::Join,
third_party_invite: None, displayname: services().users.displayname(sender_user)?,
blurhash: services().users.blurhash(sender_user)?, avatar_url: services().users.avatar_url(sender_user)?,
reason: None, is_direct: None,
join_authorized_via_users_server: None, third_party_invite: None,
}) blurhash: services().users.blurhash(sender_user)?,
.expect("event is valid, we just created it"), reason: None,
unsigned: None, join_authorized_via_users_server: None,
state_key: Some(sender_user.to_string()), })
redacts: None, .expect("event is valid, we just created it"),
}, unsigned: None,
sender_user, state_key: Some(sender_user.to_string()),
&replacement_room, redacts: None,
&state_lock, },
)?; sender_user,
&replacement_room,
&state_lock,
)
.await?;
// Recommended transferable state events list from the specs // Recommended transferable state events list from the specs
let transferable_state_events = vec![ let transferable_state_events = vec![
@ -676,18 +723,22 @@ pub async fn upgrade_room_route(
None => continue, // Skipping missing events. None => continue, // Skipping missing events.
}; };
services().rooms.timeline.build_and_append_pdu( services()
PduBuilder { .rooms
event_type: event_type.to_string().into(), .timeline
content: event_content, .build_and_append_pdu(
unsigned: None, PduBuilder {
state_key: Some("".to_owned()), event_type: event_type.to_string().into(),
redacts: None, content: event_content,
}, unsigned: None,
sender_user, state_key: Some("".to_owned()),
&replacement_room, redacts: None,
&state_lock, },
)?; sender_user,
&replacement_room,
&state_lock,
)
.await?;
} }
// Moves any local aliases to the new room // Moves any local aliases to the new room
@ -721,19 +772,23 @@ pub async fn upgrade_room_route(
power_levels_event_content.invite = new_level; power_levels_event_content.invite = new_level;
// Modify the power levels in the old room to prevent sending of events and inviting new users // Modify the power levels in the old room to prevent sending of events and inviting new users
let _ = services().rooms.timeline.build_and_append_pdu( let _ = services()
PduBuilder { .rooms
event_type: TimelineEventType::RoomPowerLevels, .timeline
content: to_raw_value(&power_levels_event_content) .build_and_append_pdu(
.expect("event is valid, we just created it"), PduBuilder {
unsigned: None, event_type: TimelineEventType::RoomPowerLevels,
state_key: Some("".to_owned()), content: to_raw_value(&power_levels_event_content)
redacts: None, .expect("event is valid, we just created it"),
}, unsigned: None,
sender_user, state_key: Some("".to_owned()),
&body.room_id, redacts: None,
&state_lock, },
)?; sender_user,
&body.room_id,
&state_lock,
)
.await?;
drop(state_lock); drop(state_lock);

View file

@ -227,24 +227,28 @@ async fn send_state_event_for_key_helper(
.globals .globals
.roomid_mutex_state .roomid_mutex_state
.write() .write()
.unwrap() .await
.entry(room_id.to_owned()) .entry(room_id.to_owned())
.or_default(), .or_default(),
); );
let state_lock = mutex_state.lock().await; let state_lock = mutex_state.lock().await;
let event_id = services().rooms.timeline.build_and_append_pdu( let event_id = services()
PduBuilder { .rooms
event_type: event_type.to_string().into(), .timeline
content: serde_json::from_str(json.json().get()).expect("content is valid json"), .build_and_append_pdu(
unsigned: None, PduBuilder {
state_key: Some(state_key), event_type: event_type.to_string().into(),
redacts: None, content: serde_json::from_str(json.json().get()).expect("content is valid json"),
}, unsigned: None,
sender_user, state_key: Some(state_key),
room_id, redacts: None,
&state_lock, },
)?; sender_user,
room_id,
&state_lock,
)
.await?;
Ok(event_id) Ok(event_id)
} }

View file

@ -1,6 +1,7 @@
use crate::{ use crate::{
service::rooms::timeline::PduCount, services, Error, PduEvent, Result, Ruma, RumaResponse, service::rooms::timeline::PduCount, services, Error, PduEvent, Result, Ruma, RumaResponse,
}; };
use ruma::{ use ruma::{
api::client::{ api::client::{
filter::{FilterDefinition, LazyLoadOptions}, filter::{FilterDefinition, LazyLoadOptions},
@ -75,7 +76,7 @@ pub async fn sync_events_route(
.globals .globals
.sync_receivers .sync_receivers
.write() .write()
.unwrap() .await
.entry((sender_user.clone(), sender_device.clone())) .entry((sender_user.clone(), sender_device.clone()))
{ {
Entry::Vacant(v) => { Entry::Vacant(v) => {
@ -147,7 +148,7 @@ async fn sync_helper_wrapper(
.globals .globals
.sync_receivers .sync_receivers
.write() .write()
.unwrap() .await
.entry((sender_user, sender_device)) .entry((sender_user, sender_device))
{ {
Entry::Occupied(o) => { Entry::Occupied(o) => {
@ -302,11 +303,11 @@ async fn sync_helper(
.globals .globals
.roomid_mutex_insert .roomid_mutex_insert
.write() .write()
.unwrap() .await
.entry(room_id.clone()) .entry(room_id.clone())
.or_default(), .or_default(),
); );
let insert_lock = mutex_insert.lock().unwrap(); let insert_lock = mutex_insert.lock().await;
drop(insert_lock); drop(insert_lock);
} }
@ -434,11 +435,11 @@ async fn sync_helper(
.globals .globals
.roomid_mutex_insert .roomid_mutex_insert
.write() .write()
.unwrap() .await
.entry(room_id.clone()) .entry(room_id.clone())
.or_default(), .or_default(),
); );
let insert_lock = mutex_insert.lock().unwrap(); let insert_lock = mutex_insert.lock().await;
drop(insert_lock); drop(insert_lock);
} }
@ -577,11 +578,11 @@ async fn load_joined_room(
.globals .globals
.roomid_mutex_insert .roomid_mutex_insert
.write() .write()
.unwrap() .await
.entry(room_id.to_owned()) .entry(room_id.to_owned())
.or_default(), .or_default(),
); );
let insert_lock = mutex_insert.lock().unwrap(); let insert_lock = mutex_insert.lock().await;
drop(insert_lock); drop(insert_lock);
} }
@ -599,12 +600,11 @@ async fn load_joined_room(
timeline_users.insert(event.sender.as_str().to_owned()); timeline_users.insert(event.sender.as_str().to_owned());
} }
services().rooms.lazy_loading.lazy_load_confirm_delivery( services()
sender_user, .rooms
sender_device, .lazy_loading
room_id, .lazy_load_confirm_delivery(sender_user, sender_device, room_id, sincecount)
sincecount, .await?;
)?;
// Database queries: // Database queries:
@ -797,13 +797,17 @@ async fn load_joined_room(
// The state_events above should contain all timeline_users, let's mark them as lazy // The state_events above should contain all timeline_users, let's mark them as lazy
// loaded. // loaded.
services().rooms.lazy_loading.lazy_load_mark_sent( services()
sender_user, .rooms
sender_device, .lazy_loading
room_id, .lazy_load_mark_sent(
lazy_loaded, sender_user,
next_batchcount, sender_device,
); room_id,
lazy_loaded,
next_batchcount,
)
.await;
( (
heroes, heroes,
@ -884,13 +888,17 @@ async fn load_joined_room(
} }
} }
services().rooms.lazy_loading.lazy_load_mark_sent( services()
sender_user, .rooms
sender_device, .lazy_loading
room_id, .lazy_load_mark_sent(
lazy_loaded, sender_user,
next_batchcount, sender_device,
); room_id,
lazy_loaded,
next_batchcount,
)
.await;
let encrypted_room = services() let encrypted_room = services()
.rooms .rooms
@ -1189,11 +1197,14 @@ pub async fn sync_events_v4_route(
if globalsince == 0 { if globalsince == 0 {
if let Some(conn_id) = &body.conn_id { if let Some(conn_id) = &body.conn_id {
services().users.forget_sync_request_connection( services()
sender_user.clone(), .users
sender_device.clone(), .forget_sync_request_connection(
conn_id.clone(), sender_user.clone(),
) sender_device.clone(),
conn_id.clone(),
)
.await
} }
} }
@ -1463,14 +1474,17 @@ pub async fn sync_events_v4_route(
); );
if let Some(conn_id) = &body.conn_id { if let Some(conn_id) = &body.conn_id {
services().users.update_sync_known_rooms( services()
sender_user.clone(), .users
sender_device.clone(), .update_sync_known_rooms(
conn_id.clone(), sender_user.clone(),
list_id, sender_device.clone(),
new_known_rooms, conn_id.clone(),
globalsince, list_id,
); new_known_rooms,
globalsince,
)
.await;
} }
} }
@ -1502,23 +1516,29 @@ pub async fn sync_events_v4_route(
} }
if let Some(conn_id) = &body.conn_id { if let Some(conn_id) = &body.conn_id {
services().users.update_sync_known_rooms( services()
sender_user.clone(), .users
sender_device.clone(), .update_sync_known_rooms(
conn_id.clone(), sender_user.clone(),
"subscriptions".to_owned(), sender_device.clone(),
known_subscription_rooms, conn_id.clone(),
globalsince, "subscriptions".to_owned(),
); known_subscription_rooms,
globalsince,
)
.await;
} }
if let Some(conn_id) = &body.conn_id { if let Some(conn_id) = &body.conn_id {
services().users.update_sync_subscriptions( services()
sender_user.clone(), .users
sender_device.clone(), .update_sync_subscriptions(
conn_id.clone(), sender_user.clone(),
body.room_subscriptions, sender_device.clone(),
); conn_id.clone(),
body.room_subscriptions,
)
.await;
} }
let mut rooms = BTreeMap::new(); let mut rooms = BTreeMap::new();

View file

@ -51,9 +51,10 @@ use std::{
fmt::Debug, fmt::Debug,
mem, mem,
net::{IpAddr, SocketAddr}, net::{IpAddr, SocketAddr},
sync::{Arc, RwLock}, sync::Arc,
time::{Duration, Instant, SystemTime}, time::{Duration, Instant, SystemTime},
}; };
use tokio::sync::RwLock;
use tracing::{debug, error, warn}; use tracing::{debug, error, warn};
@ -137,7 +138,7 @@ where
.globals .globals
.actual_destination_cache .actual_destination_cache
.read() .read()
.unwrap() .await
.get(destination) .get(destination)
.cloned(); .cloned();
@ -290,7 +291,7 @@ where
.globals .globals
.actual_destination_cache .actual_destination_cache
.write() .write()
.unwrap() .await
.insert( .insert(
OwnedServerName::from(destination), OwnedServerName::from(destination),
(actual_destination, host), (actual_destination, host),
@ -740,7 +741,7 @@ pub async fn send_transaction_message_route(
.globals .globals
.roomid_mutex_federation .roomid_mutex_federation
.write() .write()
.unwrap() .await
.entry(room_id.to_owned()) .entry(room_id.to_owned())
.or_default(), .or_default(),
); );
@ -1409,7 +1410,7 @@ pub async fn create_join_event_template_route(
.globals .globals
.roomid_mutex_state .roomid_mutex_state
.write() .write()
.unwrap() .await
.entry(body.room_id.to_owned()) .entry(body.room_id.to_owned())
.or_default(), .or_default(),
); );
@ -1579,7 +1580,7 @@ async fn create_join_event(
.globals .globals
.roomid_mutex_federation .roomid_mutex_federation
.write() .write()
.unwrap() .await
.entry(room_id.to_owned()) .entry(room_id.to_owned())
.or_default(), .or_default(),
); );

View file

@ -4,6 +4,9 @@ mod database;
mod service; mod service;
mod utils; mod utils;
// Not async due to services() being used in many closures, and async colsures are not stable as of writing
// This is the case for every other occurence of sync Mutex/RwLock, except for database related ones, where
// the current maintainer (Timo) as asked to not modify those
use std::sync::RwLock; use std::sync::RwLock;
pub use api::ruma_wrapper::{Ruma, RumaResponse}; pub use api::ruma_wrapper::{Ruma, RumaResponse};

View file

@ -1,7 +1,7 @@
use std::{ use std::{
collections::BTreeMap, collections::BTreeMap,
convert::{TryFrom, TryInto}, convert::{TryFrom, TryInto},
sync::{Arc, RwLock}, sync::Arc,
time::Instant, time::Instant,
}; };
@ -26,7 +26,7 @@ use ruma::{
EventId, OwnedRoomAliasId, OwnedRoomId, RoomAliasId, RoomId, RoomVersionId, ServerName, UserId, EventId, OwnedRoomAliasId, OwnedRoomId, RoomAliasId, RoomId, RoomVersionId, ServerName, UserId,
}; };
use serde_json::value::to_raw_value; use serde_json::value::to_raw_value;
use tokio::sync::{mpsc, Mutex, MutexGuard}; use tokio::sync::{mpsc, Mutex, RwLock};
use crate::{ use crate::{
api::client_server::{leave_all_rooms, AUTO_GEN_PASSWORD_LENGTH}, api::client_server::{leave_all_rooms, AUTO_GEN_PASSWORD_LENGTH},
@ -215,27 +215,6 @@ impl Service {
.expect("@conduit:server_name is valid"); .expect("@conduit:server_name is valid");
if let Ok(Some(conduit_room)) = services().admin.get_admin_room() { if let Ok(Some(conduit_room)) = services().admin.get_admin_room() {
let send_message = |message: RoomMessageEventContent,
mutex_lock: &MutexGuard<'_, ()>| {
services()
.rooms
.timeline
.build_and_append_pdu(
PduBuilder {
event_type: TimelineEventType::RoomMessage,
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 { loop {
tokio::select! { tokio::select! {
Some(event) = receiver.recv() => { Some(event) = receiver.recv() => {
@ -248,16 +227,30 @@ impl Service {
services().globals services().globals
.roomid_mutex_state .roomid_mutex_state
.write() .write()
.unwrap() .await
.entry(conduit_room.to_owned()) .entry(conduit_room.to_owned())
.or_default(), .or_default(),
); );
let state_lock = mutex_state.lock().await; let state_lock = mutex_state.lock().await;
send_message(message_content, &state_lock); services()
.rooms
drop(state_lock); .timeline
.build_and_append_pdu(
PduBuilder {
event_type: TimelineEventType::RoomMessage,
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();
} }
} }
} }
@ -425,11 +418,7 @@ impl Service {
Err(e) => RoomMessageEventContent::text_plain(e.to_string()), Err(e) => RoomMessageEventContent::text_plain(e.to_string()),
}, },
AdminCommand::IncomingFederation => { AdminCommand::IncomingFederation => {
let map = services() let map = services().globals.roomid_federationhandletime.read().await;
.globals
.roomid_federationhandletime
.read()
.unwrap();
let mut msg: String = format!("Handling {} incoming pdus:\n", map.len()); let mut msg: String = format!("Handling {} incoming pdus:\n", map.len());
for (r, (e, i)) in map.iter() { for (r, (e, i)) in map.iter() {
@ -543,7 +532,7 @@ impl Service {
} }
} }
AdminCommand::MemoryUsage => { AdminCommand::MemoryUsage => {
let response1 = services().memory_usage(); let response1 = services().memory_usage().await;
let response2 = services().globals.db.memory_usage(); let response2 = services().globals.db.memory_usage();
RoomMessageEventContent::text_plain(format!( RoomMessageEventContent::text_plain(format!(
@ -556,7 +545,7 @@ impl Service {
RoomMessageEventContent::text_plain("Done.") RoomMessageEventContent::text_plain("Done.")
} }
AdminCommand::ClearServiceCaches { amount } => { AdminCommand::ClearServiceCaches { amount } => {
services().clear_caches(amount); services().clear_caches(amount).await;
RoomMessageEventContent::text_plain("Done.") RoomMessageEventContent::text_plain("Done.")
} }
@ -797,7 +786,7 @@ impl Service {
.fetch_required_signing_keys(&value, &pub_key_map) .fetch_required_signing_keys(&value, &pub_key_map)
.await?; .await?;
let pub_key_map = pub_key_map.read().unwrap(); let pub_key_map = pub_key_map.read().await;
match ruma::signatures::verify_json(&pub_key_map, &value) { match ruma::signatures::verify_json(&pub_key_map, &value) {
Ok(_) => RoomMessageEventContent::text_plain("Signature correct"), Ok(_) => RoomMessageEventContent::text_plain("Signature correct"),
Err(e) => RoomMessageEventContent::text_plain(format!( Err(e) => RoomMessageEventContent::text_plain(format!(
@ -913,7 +902,7 @@ impl Service {
.globals .globals
.roomid_mutex_state .roomid_mutex_state
.write() .write()
.unwrap() .await
.entry(room_id.clone()) .entry(room_id.clone())
.or_default(), .or_default(),
); );
@ -932,164 +921,202 @@ impl Service {
content.room_version = services().globals.default_room_version(); content.room_version = services().globals.default_room_version();
// 1. The room create event // 1. The room create event
services().rooms.timeline.build_and_append_pdu( services()
PduBuilder { .rooms
event_type: TimelineEventType::RoomCreate, .timeline
content: to_raw_value(&content).expect("event is valid, we just created it"), .build_and_append_pdu(
unsigned: None, PduBuilder {
state_key: Some("".to_owned()), event_type: TimelineEventType::RoomCreate,
redacts: None, content: to_raw_value(&content).expect("event is valid, we just created it"),
}, unsigned: None,
&conduit_user, state_key: Some("".to_owned()),
&room_id, redacts: None,
&state_lock, },
)?; &conduit_user,
&room_id,
&state_lock,
)
.await?;
// 2. Make conduit bot join // 2. Make conduit bot join
services().rooms.timeline.build_and_append_pdu( services()
PduBuilder { .rooms
event_type: TimelineEventType::RoomMember, .timeline
content: to_raw_value(&RoomMemberEventContent { .build_and_append_pdu(
membership: MembershipState::Join, PduBuilder {
displayname: None, event_type: TimelineEventType::RoomMember,
avatar_url: None, content: to_raw_value(&RoomMemberEventContent {
is_direct: None, membership: MembershipState::Join,
third_party_invite: None, displayname: None,
blurhash: None, avatar_url: None,
reason: None, is_direct: None,
join_authorized_via_users_server: None, third_party_invite: None,
}) blurhash: None,
.expect("event is valid, we just created it"), reason: None,
unsigned: None, join_authorized_via_users_server: None,
state_key: Some(conduit_user.to_string()), })
redacts: None, .expect("event is valid, we just created it"),
}, unsigned: None,
&conduit_user, state_key: Some(conduit_user.to_string()),
&room_id, redacts: None,
&state_lock, },
)?; &conduit_user,
&room_id,
&state_lock,
)
.await?;
// 3. Power levels // 3. Power levels
let mut users = BTreeMap::new(); let mut users = BTreeMap::new();
users.insert(conduit_user.clone(), 100.into()); users.insert(conduit_user.clone(), 100.into());
services().rooms.timeline.build_and_append_pdu( services()
PduBuilder { .rooms
event_type: TimelineEventType::RoomPowerLevels, .timeline
content: to_raw_value(&RoomPowerLevelsEventContent { .build_and_append_pdu(
users, PduBuilder {
..Default::default() event_type: TimelineEventType::RoomPowerLevels,
}) content: to_raw_value(&RoomPowerLevelsEventContent {
.expect("event is valid, we just created it"), users,
unsigned: None, ..Default::default()
state_key: Some("".to_owned()), })
redacts: None, .expect("event is valid, we just created it"),
}, unsigned: None,
&conduit_user, state_key: Some("".to_owned()),
&room_id, redacts: None,
&state_lock, },
)?; &conduit_user,
&room_id,
&state_lock,
)
.await?;
// 4.1 Join Rules // 4.1 Join Rules
services().rooms.timeline.build_and_append_pdu( services()
PduBuilder { .rooms
event_type: TimelineEventType::RoomJoinRules, .timeline
content: to_raw_value(&RoomJoinRulesEventContent::new(JoinRule::Invite)) .build_and_append_pdu(
.expect("event is valid, we just created it"), PduBuilder {
unsigned: None, event_type: TimelineEventType::RoomJoinRules,
state_key: Some("".to_owned()), content: to_raw_value(&RoomJoinRulesEventContent::new(JoinRule::Invite))
redacts: None, .expect("event is valid, we just created it"),
}, unsigned: None,
&conduit_user, state_key: Some("".to_owned()),
&room_id, redacts: None,
&state_lock, },
)?; &conduit_user,
&room_id,
&state_lock,
)
.await?;
// 4.2 History Visibility // 4.2 History Visibility
services().rooms.timeline.build_and_append_pdu( services()
PduBuilder { .rooms
event_type: TimelineEventType::RoomHistoryVisibility, .timeline
content: to_raw_value(&RoomHistoryVisibilityEventContent::new( .build_and_append_pdu(
HistoryVisibility::Shared, PduBuilder {
)) event_type: TimelineEventType::RoomHistoryVisibility,
.expect("event is valid, we just created it"), content: to_raw_value(&RoomHistoryVisibilityEventContent::new(
unsigned: None, HistoryVisibility::Shared,
state_key: Some("".to_owned()), ))
redacts: None, .expect("event is valid, we just created it"),
}, unsigned: None,
&conduit_user, state_key: Some("".to_owned()),
&room_id, redacts: None,
&state_lock, },
)?; &conduit_user,
&room_id,
&state_lock,
)
.await?;
// 4.3 Guest Access // 4.3 Guest Access
services().rooms.timeline.build_and_append_pdu( services()
PduBuilder { .rooms
event_type: TimelineEventType::RoomGuestAccess, .timeline
content: to_raw_value(&RoomGuestAccessEventContent::new(GuestAccess::Forbidden)) .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"), .expect("event is valid, we just created it"),
unsigned: None, unsigned: None,
state_key: Some("".to_owned()), state_key: Some("".to_owned()),
redacts: None, redacts: None,
}, },
&conduit_user, &conduit_user,
&room_id, &room_id,
&state_lock, &state_lock,
)?; )
.await?;
// 5. Events implied by name and topic // 5. Events implied by name and topic
let room_name = format!("{} Admin Room", services().globals.server_name()); let room_name = format!("{} Admin Room", services().globals.server_name());
services().rooms.timeline.build_and_append_pdu( services()
PduBuilder { .rooms
event_type: TimelineEventType::RoomName, .timeline
content: to_raw_value(&RoomNameEventContent::new(room_name)) .build_and_append_pdu(
.expect("event is valid, we just created it"), PduBuilder {
unsigned: None, event_type: TimelineEventType::RoomName,
state_key: Some("".to_owned()), content: to_raw_value(&RoomNameEventContent::new(room_name))
redacts: None, .expect("event is valid, we just created it"),
}, unsigned: None,
&conduit_user, state_key: Some("".to_owned()),
&room_id, redacts: None,
&state_lock, },
)?; &conduit_user,
&room_id,
&state_lock,
)
.await?;
services().rooms.timeline.build_and_append_pdu( services()
PduBuilder { .rooms
event_type: TimelineEventType::RoomTopic, .timeline
content: to_raw_value(&RoomTopicEventContent { .build_and_append_pdu(
topic: format!("Manage {}", services().globals.server_name()), PduBuilder {
}) event_type: TimelineEventType::RoomTopic,
.expect("event is valid, we just created it"), content: to_raw_value(&RoomTopicEventContent {
unsigned: None, topic: format!("Manage {}", services().globals.server_name()),
state_key: Some("".to_owned()), })
redacts: None, .expect("event is valid, we just created it"),
}, unsigned: None,
&conduit_user, state_key: Some("".to_owned()),
&room_id, redacts: None,
&state_lock, },
)?; &conduit_user,
&room_id,
&state_lock,
)
.await?;
// 6. Room alias // 6. Room alias
let alias: OwnedRoomAliasId = format!("#admins:{}", services().globals.server_name()) let alias: OwnedRoomAliasId = format!("#admins:{}", services().globals.server_name())
.try_into() .try_into()
.expect("#admins:server_name is a valid alias name"); .expect("#admins:server_name is a valid alias name");
services().rooms.timeline.build_and_append_pdu( services()
PduBuilder { .rooms
event_type: TimelineEventType::RoomCanonicalAlias, .timeline
content: to_raw_value(&RoomCanonicalAliasEventContent { .build_and_append_pdu(
alias: Some(alias.clone()), PduBuilder {
alt_aliases: Vec::new(), event_type: TimelineEventType::RoomCanonicalAlias,
}) content: to_raw_value(&RoomCanonicalAliasEventContent {
.expect("event is valid, we just created it"), alias: Some(alias.clone()),
unsigned: None, alt_aliases: Vec::new(),
state_key: Some("".to_owned()), })
redacts: None, .expect("event is valid, we just created it"),
}, unsigned: None,
&conduit_user, state_key: Some("".to_owned()),
&room_id, redacts: None,
&state_lock, },
)?; &conduit_user,
&room_id,
&state_lock,
)
.await?;
services().rooms.alias.set_alias(&alias, &room_id)?; services().rooms.alias.set_alias(&alias, &room_id)?;
@ -1125,7 +1152,7 @@ impl Service {
.globals .globals
.roomid_mutex_state .roomid_mutex_state
.write() .write()
.unwrap() .await
.entry(room_id.clone()) .entry(room_id.clone())
.or_default(), .or_default(),
); );
@ -1137,72 +1164,84 @@ impl Service {
.expect("@conduit:server_name is valid"); .expect("@conduit:server_name is valid");
// Invite and join the real user // Invite and join the real user
services().rooms.timeline.build_and_append_pdu( services()
PduBuilder { .rooms
event_type: TimelineEventType::RoomMember, .timeline
content: to_raw_value(&RoomMemberEventContent { .build_and_append_pdu(
membership: MembershipState::Invite, PduBuilder {
displayname: None, event_type: TimelineEventType::RoomMember,
avatar_url: None, content: to_raw_value(&RoomMemberEventContent {
is_direct: None, membership: MembershipState::Invite,
third_party_invite: None, displayname: None,
blurhash: None, avatar_url: None,
reason: None, is_direct: None,
join_authorized_via_users_server: None, third_party_invite: None,
}) blurhash: None,
.expect("event is valid, we just created it"), reason: None,
unsigned: None, join_authorized_via_users_server: None,
state_key: Some(user_id.to_string()), })
redacts: None, .expect("event is valid, we just created it"),
}, unsigned: None,
&conduit_user, state_key: Some(user_id.to_string()),
&room_id, redacts: None,
&state_lock, },
)?; &conduit_user,
services().rooms.timeline.build_and_append_pdu( &room_id,
PduBuilder { &state_lock,
event_type: TimelineEventType::RoomMember, )
content: to_raw_value(&RoomMemberEventContent { .await?;
membership: MembershipState::Join, services()
displayname: Some(displayname), .rooms
avatar_url: None, .timeline
is_direct: None, .build_and_append_pdu(
third_party_invite: None, PduBuilder {
blurhash: None, event_type: TimelineEventType::RoomMember,
reason: None, content: to_raw_value(&RoomMemberEventContent {
join_authorized_via_users_server: None, membership: MembershipState::Join,
}) displayname: Some(displayname),
.expect("event is valid, we just created it"), avatar_url: None,
unsigned: None, is_direct: None,
state_key: Some(user_id.to_string()), third_party_invite: None,
redacts: None, blurhash: None,
}, reason: None,
user_id, join_authorized_via_users_server: None,
&room_id, })
&state_lock, .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 // Set power level
let mut users = BTreeMap::new(); let mut users = BTreeMap::new();
users.insert(conduit_user.to_owned(), 100.into()); users.insert(conduit_user.to_owned(), 100.into());
users.insert(user_id.to_owned(), 100.into()); users.insert(user_id.to_owned(), 100.into());
services().rooms.timeline.build_and_append_pdu( services()
PduBuilder { .rooms
event_type: TimelineEventType::RoomPowerLevels, .timeline
content: to_raw_value(&RoomPowerLevelsEventContent { .build_and_append_pdu(
users, PduBuilder {
..Default::default() event_type: TimelineEventType::RoomPowerLevels,
}) content: to_raw_value(&RoomPowerLevelsEventContent {
.expect("event is valid, we just created it"), users,
unsigned: None, ..Default::default()
state_key: Some("".to_owned()), })
redacts: None, .expect("event is valid, we just created it"),
}, unsigned: None,
&conduit_user, state_key: Some("".to_owned()),
&room_id, redacts: None,
&state_lock, },
)?; &conduit_user,
&room_id,
&state_lock,
)
.await?;
// Send welcome message // Send welcome message
services().rooms.timeline.build_and_append_pdu( services().rooms.timeline.build_and_append_pdu(
@ -1220,7 +1259,7 @@ impl Service {
&conduit_user, &conduit_user,
&room_id, &room_id,
&state_lock, &state_lock,
)?; ).await?;
} }
Ok(()) Ok(())
} }

View file

@ -31,11 +31,11 @@ use std::{
path::PathBuf, path::PathBuf,
sync::{ sync::{
atomic::{self, AtomicBool}, atomic::{self, AtomicBool},
Arc, Mutex, RwLock, Arc, RwLock as SyncRwLock,
}, },
time::{Duration, Instant}, time::{Duration, Instant},
}; };
use tokio::sync::{broadcast, watch::Receiver, Mutex as TokioMutex, Semaphore}; use tokio::sync::{broadcast, watch::Receiver, Mutex, RwLock, Semaphore};
use tracing::{error, info}; use tracing::{error, info};
use trust_dns_resolver::TokioAsyncResolver; use trust_dns_resolver::TokioAsyncResolver;
@ -53,7 +53,7 @@ pub struct Service {
pub db: &'static dyn Data, pub db: &'static dyn Data,
pub actual_destination_cache: Arc<RwLock<WellKnownMap>>, // actual_destination, host pub actual_destination_cache: Arc<RwLock<WellKnownMap>>, // actual_destination, host
pub tls_name_override: Arc<RwLock<TlsNameMap>>, pub tls_name_override: Arc<SyncRwLock<TlsNameMap>>,
pub config: Config, pub config: Config,
keypair: Arc<ruma::signatures::Ed25519KeyPair>, keypair: Arc<ruma::signatures::Ed25519KeyPair>,
dns_resolver: TokioAsyncResolver, dns_resolver: TokioAsyncResolver,
@ -68,8 +68,8 @@ pub struct Service {
pub servername_ratelimiter: Arc<RwLock<HashMap<OwnedServerName, Arc<Semaphore>>>>, pub servername_ratelimiter: Arc<RwLock<HashMap<OwnedServerName, Arc<Semaphore>>>>,
pub sync_receivers: RwLock<HashMap<(OwnedUserId, OwnedDeviceId), SyncHandle>>, 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<Mutex<()>>>>,
pub roomid_mutex_state: RwLock<HashMap<OwnedRoomId, Arc<TokioMutex<()>>>>, pub roomid_mutex_state: RwLock<HashMap<OwnedRoomId, Arc<Mutex<()>>>>,
pub roomid_mutex_federation: RwLock<HashMap<OwnedRoomId, Arc<TokioMutex<()>>>>, // this lock will be held longer pub roomid_mutex_federation: RwLock<HashMap<OwnedRoomId, Arc<Mutex<()>>>>, // this lock will be held longer
pub roomid_federationhandletime: RwLock<HashMap<OwnedRoomId, (OwnedEventId, Instant)>>, pub roomid_federationhandletime: RwLock<HashMap<OwnedRoomId, (OwnedEventId, Instant)>>,
pub stateres_mutex: Arc<Mutex<()>>, pub stateres_mutex: Arc<Mutex<()>>,
pub rotate: RotationHandler, pub rotate: RotationHandler,
@ -109,11 +109,11 @@ impl Default for RotationHandler {
pub struct Resolver { pub struct Resolver {
inner: GaiResolver, inner: GaiResolver,
overrides: Arc<RwLock<TlsNameMap>>, overrides: Arc<SyncRwLock<TlsNameMap>>,
} }
impl Resolver { impl Resolver {
pub fn new(overrides: Arc<RwLock<TlsNameMap>>) -> Self { pub fn new(overrides: Arc<SyncRwLock<TlsNameMap>>) -> Self {
Resolver { Resolver {
inner: GaiResolver::new(), inner: GaiResolver::new(),
overrides, overrides,
@ -125,7 +125,7 @@ impl Resolve for Resolver {
fn resolve(&self, name: Name) -> Resolving { fn resolve(&self, name: Name) -> Resolving {
self.overrides self.overrides
.read() .read()
.expect("lock should not be poisoned") .unwrap()
.get(name.as_str()) .get(name.as_str())
.and_then(|(override_name, port)| { .and_then(|(override_name, port)| {
override_name.first().map(|first_name| { override_name.first().map(|first_name| {
@ -159,7 +159,7 @@ impl Service {
} }
}; };
let tls_name_override = Arc::new(RwLock::new(TlsNameMap::new())); let tls_name_override = Arc::new(SyncRwLock::new(TlsNameMap::new()));
let jwt_decoding_key = config let jwt_decoding_key = config
.jwt_secret .jwt_secret

View file

@ -1,9 +1,10 @@
use std::{ use std::{
collections::{BTreeMap, HashMap}, collections::{BTreeMap, HashMap},
sync::{Arc, Mutex}, sync::{Arc, Mutex as SyncMutex},
}; };
use lru_cache::LruCache; use lru_cache::LruCache;
use tokio::sync::Mutex;
use crate::{Config, Result}; use crate::{Config, Result};
@ -79,17 +80,17 @@ impl Services {
state: rooms::state::Service { db }, state: rooms::state::Service { db },
state_accessor: rooms::state_accessor::Service { state_accessor: rooms::state_accessor::Service {
db, db,
server_visibility_cache: Mutex::new(LruCache::new( server_visibility_cache: SyncMutex::new(LruCache::new(
(100.0 * config.conduit_cache_capacity_modifier) as usize, (100.0 * config.conduit_cache_capacity_modifier) as usize,
)), )),
user_visibility_cache: Mutex::new(LruCache::new( user_visibility_cache: SyncMutex::new(LruCache::new(
(100.0 * config.conduit_cache_capacity_modifier) as usize, (100.0 * config.conduit_cache_capacity_modifier) as usize,
)), )),
}, },
state_cache: rooms::state_cache::Service { db }, state_cache: rooms::state_cache::Service { db },
state_compressor: rooms::state_compressor::Service { state_compressor: rooms::state_compressor::Service {
db, db,
stateinfo_cache: Mutex::new(LruCache::new( stateinfo_cache: SyncMutex::new(LruCache::new(
(100.0 * config.conduit_cache_capacity_modifier) as usize, (100.0 * config.conduit_cache_capacity_modifier) as usize,
)), )),
}, },
@ -107,7 +108,7 @@ impl Services {
uiaa: uiaa::Service { db }, uiaa: uiaa::Service { db },
users: users::Service { users: users::Service {
db, db,
connections: Mutex::new(BTreeMap::new()), connections: SyncMutex::new(BTreeMap::new()),
}, },
account_data: account_data::Service { db }, account_data: account_data::Service { db },
admin: admin::Service::build(), admin: admin::Service::build(),
@ -118,14 +119,8 @@ impl Services {
globals: globals::Service::load(db, config)?, globals: globals::Service::load(db, config)?,
}) })
} }
fn memory_usage(&self) -> String { async fn memory_usage(&self) -> String {
let lazy_load_waiting = self let lazy_load_waiting = self.rooms.lazy_loading.lazy_load_waiting.lock().await.len();
.rooms
.lazy_loading
.lazy_load_waiting
.lock()
.unwrap()
.len();
let server_visibility_cache = self let server_visibility_cache = self
.rooms .rooms
.state_accessor .state_accessor
@ -152,15 +147,9 @@ impl Services {
.timeline .timeline
.lasttimelinecount_cache .lasttimelinecount_cache
.lock() .lock()
.unwrap() .await
.len();
let roomid_spacechunk_cache = self
.rooms
.spaces
.roomid_spacechunk_cache
.lock()
.unwrap()
.len(); .len();
let roomid_spacechunk_cache = self.rooms.spaces.roomid_spacechunk_cache.lock().await.len();
format!( format!(
"\ "\
@ -173,13 +162,13 @@ roomid_spacechunk_cache: {roomid_spacechunk_cache}\
" "
) )
} }
fn clear_caches(&self, amount: u32) { async fn clear_caches(&self, amount: u32) {
if amount > 0 { if amount > 0 {
self.rooms self.rooms
.lazy_loading .lazy_loading
.lazy_load_waiting .lazy_load_waiting
.lock() .lock()
.unwrap() .await
.clear(); .clear();
} }
if amount > 1 { if amount > 1 {
@ -211,7 +200,7 @@ roomid_spacechunk_cache: {roomid_spacechunk_cache}\
.timeline .timeline
.lasttimelinecount_cache .lasttimelinecount_cache
.lock() .lock()
.unwrap() .await
.clear(); .clear();
} }
if amount > 5 { if amount > 5 {
@ -219,7 +208,7 @@ roomid_spacechunk_cache: {roomid_spacechunk_cache}\
.spaces .spaces
.roomid_spacechunk_cache .roomid_spacechunk_cache
.lock() .lock()
.unwrap() .await
.clear(); .clear();
} }
} }

View file

@ -1,25 +1,24 @@
/// An async function that can recursively call itself. /// An async function that can recursively call itself.
type AsyncRecursiveType<'a, T> = Pin<Box<dyn Future<Output = T> + 'a + Send>>; type AsyncRecursiveType<'a, T> = Pin<Box<dyn Future<Output = T> + 'a + Send>>;
use ruma::{
api::federation::discovery::{get_remote_server_keys, get_server_keys},
CanonicalJsonObject, CanonicalJsonValue, OwnedServerName, OwnedServerSigningKeyId,
RoomVersionId,
};
use std::{ use std::{
collections::{hash_map, BTreeMap, HashMap, HashSet}, collections::{hash_map, BTreeMap, HashMap, HashSet},
pin::Pin, pin::Pin,
sync::{Arc, RwLock, RwLockWriteGuard}, sync::Arc,
time::{Duration, Instant, SystemTime}, time::{Duration, Instant, SystemTime},
}; };
use tokio::sync::Semaphore;
use async_recursion::async_recursion;
use futures_util::{stream::FuturesUnordered, Future, StreamExt}; use futures_util::{stream::FuturesUnordered, Future, StreamExt};
use ruma::{ use ruma::{
api::{ api::{
client::error::ErrorKind, client::error::ErrorKind,
federation::{ federation::{
discovery::get_remote_server_keys_batch::{self, v2::QueryCriteria}, discovery::{
get_remote_server_keys,
get_remote_server_keys_batch::{self, v2::QueryCriteria},
get_server_keys,
},
event::{get_event, get_room_state_ids}, event::{get_event, get_room_state_ids},
membership::create_join_event, membership::create_join_event,
}, },
@ -31,9 +30,11 @@ use ruma::{
int, int,
serde::Base64, serde::Base64,
state_res::{self, RoomVersion, StateMap}, state_res::{self, RoomVersion, StateMap},
uint, EventId, MilliSecondsSinceUnixEpoch, RoomId, ServerName, uint, CanonicalJsonObject, CanonicalJsonValue, EventId, MilliSecondsSinceUnixEpoch,
OwnedServerName, OwnedServerSigningKeyId, RoomId, RoomVersionId, ServerName,
}; };
use serde_json::value::RawValue as RawJsonValue; use serde_json::value::RawValue as RawJsonValue;
use tokio::sync::{RwLock, RwLockWriteGuard, Semaphore};
use tracing::{debug, error, info, trace, warn}; use tracing::{debug, error, info, trace, warn};
use crate::{service::*, services, Error, PduEvent, Result}; use crate::{service::*, services, Error, PduEvent, Result};
@ -168,7 +169,7 @@ impl Service {
.globals .globals
.bad_event_ratelimiter .bad_event_ratelimiter
.read() .read()
.unwrap() .await
.get(&*prev_id) .get(&*prev_id)
{ {
// Exponential backoff // Exponential backoff
@ -189,7 +190,7 @@ impl Service {
.globals .globals
.bad_event_ratelimiter .bad_event_ratelimiter
.write() .write()
.unwrap() .await
.entry((*prev_id).to_owned()) .entry((*prev_id).to_owned())
{ {
hash_map::Entry::Vacant(e) => { hash_map::Entry::Vacant(e) => {
@ -213,7 +214,7 @@ impl Service {
.globals .globals
.roomid_federationhandletime .roomid_federationhandletime
.write() .write()
.unwrap() .await
.insert(room_id.to_owned(), ((*prev_id).to_owned(), start_time)); .insert(room_id.to_owned(), ((*prev_id).to_owned(), start_time));
if let Err(e) = self if let Err(e) = self
@ -233,7 +234,7 @@ impl Service {
.globals .globals
.bad_event_ratelimiter .bad_event_ratelimiter
.write() .write()
.unwrap() .await
.entry((*prev_id).to_owned()) .entry((*prev_id).to_owned())
{ {
hash_map::Entry::Vacant(e) => { hash_map::Entry::Vacant(e) => {
@ -249,7 +250,7 @@ impl Service {
.globals .globals
.roomid_federationhandletime .roomid_federationhandletime
.write() .write()
.unwrap() .await
.remove(&room_id.to_owned()); .remove(&room_id.to_owned());
debug!( debug!(
"Handling prev event {} took {}m{}s", "Handling prev event {} took {}m{}s",
@ -267,7 +268,7 @@ impl Service {
.globals .globals
.roomid_federationhandletime .roomid_federationhandletime
.write() .write()
.unwrap() .await
.insert(room_id.to_owned(), (event_id.to_owned(), start_time)); .insert(room_id.to_owned(), (event_id.to_owned(), start_time));
let r = services() let r = services()
.rooms .rooms
@ -285,7 +286,7 @@ impl Service {
.globals .globals
.roomid_federationhandletime .roomid_federationhandletime
.write() .write()
.unwrap() .await
.remove(&room_id.to_owned()); .remove(&room_id.to_owned());
r r
@ -326,11 +327,8 @@ impl Service {
let room_version = let room_version =
RoomVersion::new(room_version_id).expect("room version is supported"); RoomVersion::new(room_version_id).expect("room version is supported");
let mut val = match ruma::signatures::verify_event( let guard = pub_key_map.read().await;
&pub_key_map.read().expect("RwLock is poisoned."), let mut val = match ruma::signatures::verify_event(&guard, &value, room_version_id) {
&value,
room_version_id,
) {
Err(e) => { Err(e) => {
// Drop // Drop
warn!("Dropping bad event {}: {}", event_id, e,); warn!("Dropping bad event {}: {}", event_id, e,);
@ -365,6 +363,8 @@ impl Service {
Ok(ruma::signatures::Verified::All) => value, Ok(ruma::signatures::Verified::All) => value,
}; };
drop(guard);
// Now that we have checked the signature and hashes we can add the eventID and convert // Now that we have checked the signature and hashes we can add the eventID and convert
// to our PduEvent type // to our PduEvent type
val.insert( val.insert(
@ -692,13 +692,15 @@ impl Service {
{ {
Ok(res) => { Ok(res) => {
debug!("Fetching state events at event."); debug!("Fetching state events at event.");
let collect = res
.pdu_ids
.iter()
.map(|x| Arc::from(&**x))
.collect::<Vec<_>>();
let state_vec = self let state_vec = self
.fetch_and_handle_outliers( .fetch_and_handle_outliers(
origin, origin,
&res.pdu_ids &collect,
.iter()
.map(|x| Arc::from(&**x))
.collect::<Vec<_>>(),
create_event, create_event,
room_id, room_id,
room_version_id, room_version_id,
@ -805,7 +807,7 @@ impl Service {
.globals .globals
.roomid_mutex_state .roomid_mutex_state
.write() .write()
.unwrap() .await
.entry(room_id.to_owned()) .entry(room_id.to_owned())
.or_default(), .or_default(),
); );
@ -884,14 +886,18 @@ impl Service {
debug!("Starting soft fail auth check"); debug!("Starting soft fail auth check");
if soft_fail { if soft_fail {
services().rooms.timeline.append_incoming_pdu( services()
&incoming_pdu, .rooms
val, .timeline
extremities.iter().map(|e| (**e).to_owned()).collect(), .append_incoming_pdu(
state_ids_compressed, &incoming_pdu,
soft_fail, val,
&state_lock, extremities.iter().map(|e| (**e).to_owned()).collect(),
)?; 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 // Soft fail, we keep the event as an outlier but don't add it to the timeline
warn!("Event was soft failed: {:?}", incoming_pdu); warn!("Event was soft failed: {:?}", incoming_pdu);
@ -912,14 +918,18 @@ impl Service {
// We use the `state_at_event` instead of `state_after` so we accurately // We use the `state_at_event` instead of `state_after` so we accurately
// represent the state for this event. // represent the state for this event.
let pdu_id = services().rooms.timeline.append_incoming_pdu( let pdu_id = services()
&incoming_pdu, .rooms
val, .timeline
extremities.iter().map(|e| (**e).to_owned()).collect(), .append_incoming_pdu(
state_ids_compressed, &incoming_pdu,
soft_fail, val,
&state_lock, extremities.iter().map(|e| (**e).to_owned()).collect(),
)?; state_ids_compressed,
soft_fail,
&state_lock,
)
.await?;
debug!("Appended incoming pdu"); debug!("Appended incoming pdu");
@ -1034,7 +1044,8 @@ impl Service {
/// d. TODO: Ask other servers over federation? /// d. TODO: Ask other servers over federation?
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
#[tracing::instrument(skip_all)] #[tracing::instrument(skip_all)]
pub(crate) fn fetch_and_handle_outliers<'a>( #[async_recursion]
pub(crate) async fn fetch_and_handle_outliers<'a>(
&'a self, &'a self,
origin: &'a ServerName, origin: &'a ServerName,
events: &'a [Arc<EventId>], events: &'a [Arc<EventId>],
@ -1042,176 +1053,175 @@ impl Service {
room_id: &'a RoomId, room_id: &'a RoomId,
room_version_id: &'a RoomVersionId, room_version_id: &'a RoomVersionId,
pub_key_map: &'a RwLock<BTreeMap<String, BTreeMap<String, Base64>>>, pub_key_map: &'a RwLock<BTreeMap<String, BTreeMap<String, Base64>>>,
) -> AsyncRecursiveType<'a, Vec<(Arc<PduEvent>, Option<BTreeMap<String, CanonicalJsonValue>>)>> ) -> Vec<(Arc<PduEvent>, Option<BTreeMap<String, CanonicalJsonValue>>)> {
{ let back_off = |id| async move {
Box::pin(async move { match services()
let back_off = |id| match services()
.globals .globals
.bad_event_ratelimiter .bad_event_ratelimiter
.write() .write()
.unwrap() .await
.entry(id) .entry(id)
{ {
hash_map::Entry::Vacant(e) => { hash_map::Entry::Vacant(e) => {
e.insert((Instant::now(), 1)); e.insert((Instant::now(), 1));
} }
hash_map::Entry::Occupied(mut e) => *e.get_mut() = (Instant::now(), e.get().1 + 1), hash_map::Entry::Occupied(mut e) => *e.get_mut() = (Instant::now(), e.get().1 + 1),
}; }
};
let mut pdus = vec![]; let mut pdus = vec![];
for id in events { for id in events {
// a. Look in the main timeline (pduid_pdu tree) // a. Look in the main timeline (pduid_pdu tree)
// b. Look at outlier pdu tree // b. Look at outlier pdu tree
// (get_pdu_json checks both) // (get_pdu_json checks both)
if let Ok(Some(local_pdu)) = services().rooms.timeline.get_pdu(id) { if let Ok(Some(local_pdu)) = services().rooms.timeline.get_pdu(id) {
trace!("Found {} in db", id); trace!("Found {} in db", id);
pdus.push((local_pdu, None)); pdus.push((local_pdu, None));
continue;
}
// c. Ask origin server over federation
// We also handle its auth chain here so we don't get a stack overflow in
// handle_outlier_pdu.
let mut todo_auth_events = vec![Arc::clone(id)];
let mut events_in_reverse_order = Vec::new();
let mut events_all = HashSet::new();
let mut i = 0;
while let Some(next_id) = todo_auth_events.pop() {
if let Some((time, tries)) = services()
.globals
.bad_event_ratelimiter
.read()
.await
.get(&*next_id)
{
// Exponential backoff
let mut min_elapsed_duration =
Duration::from_secs(5 * 60) * (*tries) * (*tries);
if min_elapsed_duration > Duration::from_secs(60 * 60 * 24) {
min_elapsed_duration = Duration::from_secs(60 * 60 * 24);
}
if time.elapsed() < min_elapsed_duration {
info!("Backing off from {}", next_id);
continue;
}
}
if events_all.contains(&next_id) {
continue; continue;
} }
// c. Ask origin server over federation i += 1;
// We also handle its auth chain here so we don't get a stack overflow in if i % 100 == 0 {
// handle_outlier_pdu. tokio::task::yield_now().await;
let mut todo_auth_events = vec![Arc::clone(id)];
let mut events_in_reverse_order = Vec::new();
let mut events_all = HashSet::new();
let mut i = 0;
while let Some(next_id) = todo_auth_events.pop() {
if let Some((time, tries)) = services()
.globals
.bad_event_ratelimiter
.read()
.unwrap()
.get(&*next_id)
{
// Exponential backoff
let mut min_elapsed_duration =
Duration::from_secs(5 * 60) * (*tries) * (*tries);
if min_elapsed_duration > Duration::from_secs(60 * 60 * 24) {
min_elapsed_duration = Duration::from_secs(60 * 60 * 24);
}
if time.elapsed() < min_elapsed_duration {
info!("Backing off from {}", next_id);
continue;
}
}
if events_all.contains(&next_id) {
continue;
}
i += 1;
if i % 100 == 0 {
tokio::task::yield_now().await;
}
if let Ok(Some(_)) = services().rooms.timeline.get_pdu(&next_id) {
trace!("Found {} in db", next_id);
continue;
}
info!("Fetching {} over federation.", next_id);
match services()
.sending
.send_federation_request(
origin,
get_event::v1::Request {
event_id: (*next_id).to_owned(),
},
)
.await
{
Ok(res) => {
info!("Got {} over federation", next_id);
let (calculated_event_id, value) =
match pdu::gen_event_id_canonical_json(&res.pdu, room_version_id) {
Ok(t) => t,
Err(_) => {
back_off((*next_id).to_owned());
continue;
}
};
if calculated_event_id != *next_id {
warn!("Server didn't return event id we requested: requested: {}, we got {}. Event: {:?}",
next_id, calculated_event_id, &res.pdu);
}
if let Some(auth_events) =
value.get("auth_events").and_then(|c| c.as_array())
{
for auth_event in auth_events {
if let Ok(auth_event) =
serde_json::from_value(auth_event.clone().into())
{
let a: Arc<EventId> = auth_event;
todo_auth_events.push(a);
} else {
warn!("Auth event id is not valid");
}
}
} else {
warn!("Auth event list invalid");
}
events_in_reverse_order.push((next_id.clone(), value));
events_all.insert(next_id);
}
Err(_) => {
warn!("Failed to fetch event: {}", next_id);
back_off((*next_id).to_owned());
}
}
} }
for (next_id, value) in events_in_reverse_order.iter().rev() { if let Ok(Some(_)) = services().rooms.timeline.get_pdu(&next_id) {
if let Some((time, tries)) = services() trace!("Found {} in db", next_id);
.globals continue;
.bad_event_ratelimiter }
.read()
.unwrap() info!("Fetching {} over federation.", next_id);
.get(&**next_id) match services()
{ .sending
// Exponential backoff .send_federation_request(
let mut min_elapsed_duration = origin,
Duration::from_secs(5 * 60) * (*tries) * (*tries); get_event::v1::Request {
if min_elapsed_duration > Duration::from_secs(60 * 60 * 24) { event_id: (*next_id).to_owned(),
min_elapsed_duration = Duration::from_secs(60 * 60 * 24); },
)
.await
{
Ok(res) => {
info!("Got {} over federation", next_id);
let (calculated_event_id, value) =
match pdu::gen_event_id_canonical_json(&res.pdu, room_version_id) {
Ok(t) => t,
Err(_) => {
back_off((*next_id).to_owned()).await;
continue;
}
};
if calculated_event_id != *next_id {
warn!("Server didn't return event id we requested: requested: {}, we got {}. Event: {:?}",
next_id, calculated_event_id, &res.pdu);
} }
if time.elapsed() < min_elapsed_duration { if let Some(auth_events) =
info!("Backing off from {}", next_id); value.get("auth_events").and_then(|c| c.as_array())
continue; {
} for auth_event in auth_events {
} if let Ok(auth_event) =
serde_json::from_value(auth_event.clone().into())
match self {
.handle_outlier_pdu( let a: Arc<EventId> = auth_event;
origin, todo_auth_events.push(a);
create_event, } else {
next_id, warn!("Auth event id is not valid");
room_id, }
value.clone(),
true,
pub_key_map,
)
.await
{
Ok((pdu, json)) => {
if next_id == id {
pdus.push((pdu, Some(json)));
} }
} else {
warn!("Auth event list invalid");
} }
Err(e) => {
warn!("Authentication of event {} failed: {:?}", next_id, e); events_in_reverse_order.push((next_id.clone(), value));
back_off((**next_id).to_owned()); events_all.insert(next_id);
} }
Err(_) => {
warn!("Failed to fetch event: {}", next_id);
back_off((*next_id).to_owned()).await;
} }
} }
} }
pdus
}) for (next_id, value) in events_in_reverse_order.iter().rev() {
if let Some((time, tries)) = services()
.globals
.bad_event_ratelimiter
.read()
.await
.get(&**next_id)
{
// Exponential backoff
let mut min_elapsed_duration =
Duration::from_secs(5 * 60) * (*tries) * (*tries);
if min_elapsed_duration > Duration::from_secs(60 * 60 * 24) {
min_elapsed_duration = Duration::from_secs(60 * 60 * 24);
}
if time.elapsed() < min_elapsed_duration {
info!("Backing off from {}", next_id);
continue;
}
}
match self
.handle_outlier_pdu(
origin,
create_event,
next_id,
room_id,
value.clone(),
true,
pub_key_map,
)
.await
{
Ok((pdu, json)) => {
if next_id == id {
pdus.push((pdu, Some(json)));
}
}
Err(e) => {
warn!("Authentication of event {} failed: {:?}", next_id, e);
back_off((**next_id).to_owned()).await;
}
}
}
}
pdus
} }
async fn fetch_unknown_prev_events( async fn fetch_unknown_prev_events(
@ -1360,7 +1370,7 @@ impl Service {
pub_key_map pub_key_map
.write() .write()
.map_err(|_| Error::bad_database("RwLock is poisoned."))? .await
.insert(signature_server.clone(), keys); .insert(signature_server.clone(), keys);
} }
@ -1369,7 +1379,7 @@ impl Service {
// Gets a list of servers for which we don't have the signing key yet. We go over // Gets a list of servers for which we don't have the signing key yet. We go over
// the PDUs and either cache the key or add it to the list that needs to be retrieved. // the PDUs and either cache the key or add it to the list that needs to be retrieved.
fn get_server_keys_from_cache( async fn get_server_keys_from_cache(
&self, &self,
pdu: &RawJsonValue, pdu: &RawJsonValue,
servers: &mut BTreeMap<OwnedServerName, BTreeMap<OwnedServerSigningKeyId, QueryCriteria>>, servers: &mut BTreeMap<OwnedServerName, BTreeMap<OwnedServerSigningKeyId, QueryCriteria>>,
@ -1393,7 +1403,7 @@ impl Service {
.globals .globals
.bad_event_ratelimiter .bad_event_ratelimiter
.read() .read()
.unwrap() .await
.get(event_id) .get(event_id)
{ {
// Exponential backoff // Exponential backoff
@ -1469,17 +1479,19 @@ impl Service {
> = BTreeMap::new(); > = BTreeMap::new();
{ {
let mut pkm = pub_key_map let mut pkm = pub_key_map.write().await;
.write()
.map_err(|_| Error::bad_database("RwLock is poisoned."))?;
// Try to fetch keys, failure is okay // Try to fetch keys, failure is okay
// Servers we couldn't find in the cache will be added to `servers` // Servers we couldn't find in the cache will be added to `servers`
for pdu in &event.room_state.state { for pdu in &event.room_state.state {
let _ = self.get_server_keys_from_cache(pdu, &mut servers, room_version, &mut pkm); let _ = self
.get_server_keys_from_cache(pdu, &mut servers, room_version, &mut pkm)
.await;
} }
for pdu in &event.room_state.auth_chain { for pdu in &event.room_state.auth_chain {
let _ = self.get_server_keys_from_cache(pdu, &mut servers, room_version, &mut pkm); let _ = self
.get_server_keys_from_cache(pdu, &mut servers, room_version, &mut pkm)
.await;
} }
drop(pkm); drop(pkm);
@ -1503,9 +1515,7 @@ impl Service {
.await .await
{ {
trace!("Got signing keys: {:?}", keys); trace!("Got signing keys: {:?}", keys);
let mut pkm = pub_key_map let mut pkm = pub_key_map.write().await;
.write()
.map_err(|_| Error::bad_database("RwLock is poisoned."))?;
for k in keys.server_keys { for k in keys.server_keys {
let k = match k.deserialize() { let k = match k.deserialize() {
Ok(key) => key, Ok(key) => key,
@ -1564,10 +1574,7 @@ impl Service {
.into_iter() .into_iter()
.map(|(k, v)| (k.to_string(), v.key)) .map(|(k, v)| (k.to_string(), v.key))
.collect(); .collect();
pub_key_map pub_key_map.write().await.insert(origin.to_string(), result);
.write()
.map_err(|_| Error::bad_database("RwLock is poisoned."))?
.insert(origin.to_string(), result);
} }
} }
info!("Done handling result"); info!("Done handling result");
@ -1632,14 +1639,14 @@ impl Service {
.globals .globals
.servername_ratelimiter .servername_ratelimiter
.read() .read()
.unwrap() .await
.get(origin) .get(origin)
.map(|s| Arc::clone(s).acquire_owned()); .map(|s| Arc::clone(s).acquire_owned());
let permit = match permit { let permit = match permit {
Some(p) => p, Some(p) => p,
None => { None => {
let mut write = services().globals.servername_ratelimiter.write().unwrap(); let mut write = services().globals.servername_ratelimiter.write().await;
let s = Arc::clone( let s = Arc::clone(
write write
.entry(origin.to_owned()) .entry(origin.to_owned())
@ -1651,24 +1658,26 @@ impl Service {
} }
.await; .await;
let back_off = |id| match services() let back_off = |id| async {
.globals match services()
.bad_signature_ratelimiter .globals
.write() .bad_signature_ratelimiter
.unwrap() .write()
.entry(id) .await
{ .entry(id)
hash_map::Entry::Vacant(e) => { {
e.insert((Instant::now(), 1)); hash_map::Entry::Vacant(e) => {
e.insert((Instant::now(), 1));
}
hash_map::Entry::Occupied(mut e) => *e.get_mut() = (Instant::now(), e.get().1 + 1),
} }
hash_map::Entry::Occupied(mut e) => *e.get_mut() = (Instant::now(), e.get().1 + 1),
}; };
if let Some((time, tries)) = services() if let Some((time, tries)) = services()
.globals .globals
.bad_signature_ratelimiter .bad_signature_ratelimiter
.read() .read()
.unwrap() .await
.get(&signature_ids) .get(&signature_ids)
{ {
// Exponential backoff // Exponential backoff
@ -1775,7 +1784,7 @@ impl Service {
drop(permit); drop(permit);
back_off(signature_ids); back_off(signature_ids).await;
warn!("Failed to find public key for server: {}", origin); warn!("Failed to find public key for server: {}", origin);
Err(Error::BadServerResponse( Err(Error::BadServerResponse(

View file

@ -1,11 +1,9 @@
mod data; mod data;
use std::{ use std::collections::{HashMap, HashSet};
collections::{HashMap, HashSet},
sync::Mutex,
};
pub use data::Data; pub use data::Data;
use ruma::{DeviceId, OwnedDeviceId, OwnedRoomId, OwnedUserId, RoomId, UserId}; use ruma::{DeviceId, OwnedDeviceId, OwnedRoomId, OwnedUserId, RoomId, UserId};
use tokio::sync::Mutex;
use crate::Result; use crate::Result;
@ -33,7 +31,7 @@ impl Service {
} }
#[tracing::instrument(skip(self))] #[tracing::instrument(skip(self))]
pub fn lazy_load_mark_sent( pub async fn lazy_load_mark_sent(
&self, &self,
user_id: &UserId, user_id: &UserId,
device_id: &DeviceId, device_id: &DeviceId,
@ -41,7 +39,7 @@ impl Service {
lazy_load: HashSet<OwnedUserId>, lazy_load: HashSet<OwnedUserId>,
count: PduCount, count: PduCount,
) { ) {
self.lazy_load_waiting.lock().unwrap().insert( self.lazy_load_waiting.lock().await.insert(
( (
user_id.to_owned(), user_id.to_owned(),
device_id.to_owned(), device_id.to_owned(),
@ -53,14 +51,14 @@ impl Service {
} }
#[tracing::instrument(skip(self))] #[tracing::instrument(skip(self))]
pub fn lazy_load_confirm_delivery( pub async fn lazy_load_confirm_delivery(
&self, &self,
user_id: &UserId, user_id: &UserId,
device_id: &DeviceId, device_id: &DeviceId,
room_id: &RoomId, room_id: &RoomId,
since: PduCount, since: PduCount,
) -> Result<()> { ) -> Result<()> {
if let Some(user_ids) = self.lazy_load_waiting.lock().unwrap().remove(&( if let Some(user_ids) = self.lazy_load_waiting.lock().await.remove(&(
user_id.to_owned(), user_id.to_owned(),
device_id.to_owned(), device_id.to_owned(),
room_id.to_owned(), room_id.to_owned(),

View file

@ -1,4 +1,4 @@
use std::sync::{Arc, Mutex}; use std::sync::Arc;
use lru_cache::LruCache; use lru_cache::LruCache;
use ruma::{ use ruma::{
@ -25,6 +25,7 @@ use ruma::{
space::SpaceRoomJoinRule, space::SpaceRoomJoinRule,
OwnedRoomId, RoomId, UserId, OwnedRoomId, RoomId, UserId,
}; };
use tokio::sync::Mutex;
use tracing::{debug, error, warn}; use tracing::{debug, error, warn};
@ -79,7 +80,7 @@ impl Service {
if let Some(cached) = self if let Some(cached) = self
.roomid_spacechunk_cache .roomid_spacechunk_cache
.lock() .lock()
.unwrap() .await
.get_mut(&current_room.to_owned()) .get_mut(&current_room.to_owned())
.as_ref() .as_ref()
{ {
@ -171,7 +172,7 @@ impl Service {
.transpose()? .transpose()?
.unwrap_or(JoinRule::Invite); .unwrap_or(JoinRule::Invite);
self.roomid_spacechunk_cache.lock().unwrap().insert( self.roomid_spacechunk_cache.lock().await.insert(
current_room.clone(), current_room.clone(),
Some(CachedSpaceChunk { Some(CachedSpaceChunk {
chunk, chunk,
@ -265,7 +266,7 @@ impl Service {
} }
} }
self.roomid_spacechunk_cache.lock().unwrap().insert( self.roomid_spacechunk_cache.lock().await.insert(
current_room.clone(), current_room.clone(),
Some(CachedSpaceChunk { Some(CachedSpaceChunk {
chunk, chunk,
@ -289,7 +290,7 @@ impl Service {
} else { } else {
self.roomid_spacechunk_cache self.roomid_spacechunk_cache
.lock() .lock()
.unwrap() .await
.insert(current_room.clone(), None); .insert(current_room.clone(), None);
} }
} }

View file

@ -95,7 +95,7 @@ impl Service {
.spaces .spaces
.roomid_spacechunk_cache .roomid_spacechunk_cache
.lock() .lock()
.unwrap() .await
.remove(&pdu.room_id); .remove(&pdu.room_id);
} }
_ => continue, _ => continue,

View file

@ -2,12 +2,8 @@ mod data;
use std::{ use std::{
cmp::Ordering, cmp::Ordering,
collections::{BTreeMap, HashMap}, collections::{BTreeMap, HashMap, HashSet},
}; sync::Arc,
use std::{
collections::HashSet,
sync::{Arc, Mutex, RwLock},
}; };
pub use data::Data; pub use data::Data;
@ -32,7 +28,7 @@ use ruma::{
}; };
use serde::Deserialize; use serde::Deserialize;
use serde_json::value::{to_raw_value, RawValue as RawJsonValue}; use serde_json::value::{to_raw_value, RawValue as RawJsonValue};
use tokio::sync::MutexGuard; use tokio::sync::{Mutex, MutexGuard, RwLock};
use tracing::{error, info, warn}; use tracing::{error, info, warn};
use crate::{ use crate::{
@ -201,7 +197,7 @@ impl Service {
/// ///
/// Returns pdu id /// Returns pdu id
#[tracing::instrument(skip(self, pdu, pdu_json, leaves))] #[tracing::instrument(skip(self, pdu, pdu_json, leaves))]
pub fn append_pdu<'a>( pub async fn append_pdu<'a>(
&self, &self,
pdu: &PduEvent, pdu: &PduEvent,
mut pdu_json: CanonicalJsonObject, mut pdu_json: CanonicalJsonObject,
@ -263,11 +259,11 @@ impl Service {
.globals .globals
.roomid_mutex_insert .roomid_mutex_insert
.write() .write()
.unwrap() .await
.entry(pdu.room_id.clone()) .entry(pdu.room_id.clone())
.or_default(), .or_default(),
); );
let insert_lock = mutex_insert.lock().unwrap(); let insert_lock = mutex_insert.lock().await;
let count1 = services().globals.next_count()?; let count1 = services().globals.next_count()?;
// Mark as read first so the sending client doesn't get a notification even if appending // Mark as read first so the sending client doesn't get a notification even if appending
@ -395,7 +391,7 @@ impl Service {
.spaces .spaces
.roomid_spacechunk_cache .roomid_spacechunk_cache
.lock() .lock()
.unwrap() .await
.remove(&pdu.room_id); .remove(&pdu.room_id);
} }
} }
@ -806,7 +802,7 @@ impl Service {
/// Creates a new persisted data unit and adds it to a room. This function takes a /// 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. /// roomid_mutex_state, meaning that only this function is able to mutate the room state.
#[tracing::instrument(skip(self, state_lock))] #[tracing::instrument(skip(self, state_lock))]
pub fn build_and_append_pdu( pub async fn build_and_append_pdu(
&self, &self,
pdu_builder: PduBuilder, pdu_builder: PduBuilder,
sender: &UserId, sender: &UserId,
@ -902,14 +898,16 @@ impl Service {
// pdu without it's state. This is okay because append_pdu can't fail. // pdu without it's state. This is okay because append_pdu can't fail.
let statehashid = services().rooms.state.append_to_state(&pdu)?; let statehashid = services().rooms.state.append_to_state(&pdu)?;
let pdu_id = self.append_pdu( let pdu_id = self
&pdu, .append_pdu(
pdu_json, &pdu,
// Since this PDU references all pdu_leaves we can update the leaves pdu_json,
// of the room // Since this PDU references all pdu_leaves we can update the leaves
vec![(*pdu.event_id).to_owned()], // of the room
state_lock, 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 // 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 // where events in the current room state do not exist
@ -947,7 +945,7 @@ impl Service {
/// Append the incoming event setting the state snapshot to the state from the /// Append the incoming event setting the state snapshot to the state from the
/// server that sent the event. /// server that sent the event.
#[tracing::instrument(skip_all)] #[tracing::instrument(skip_all)]
pub fn append_incoming_pdu<'a>( pub async fn append_incoming_pdu<'a>(
&self, &self,
pdu: &PduEvent, pdu: &PduEvent,
pdu_json: CanonicalJsonObject, pdu_json: CanonicalJsonObject,
@ -977,11 +975,11 @@ impl Service {
return Ok(None); return Ok(None);
} }
let pdu_id = let pdu_id = services()
services() .rooms
.rooms .timeline
.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)) Ok(Some(pdu_id))
} }
@ -1118,7 +1116,7 @@ impl Service {
.globals .globals
.roomid_mutex_federation .roomid_mutex_federation
.write() .write()
.unwrap() .await
.entry(room_id.to_owned()) .entry(room_id.to_owned())
.or_default(), .or_default(),
); );
@ -1150,11 +1148,11 @@ impl Service {
.globals .globals
.roomid_mutex_insert .roomid_mutex_insert
.write() .write()
.unwrap() .await
.entry(room_id.clone()) .entry(room_id.clone())
.or_default(), .or_default(),
); );
let insert_lock = mutex_insert.lock().unwrap(); let insert_lock = mutex_insert.lock().await;
let count = services().globals.next_count()?; let count = services().globals.next_count()?;
let mut pdu_id = shortroomid.to_be_bytes().to_vec(); let mut pdu_id = shortroomid.to_be_bytes().to_vec();

View file

@ -45,7 +45,7 @@ impl Service {
self.db.exists(user_id) self.db.exists(user_id)
} }
pub fn forget_sync_request_connection( pub async fn forget_sync_request_connection(
&self, &self,
user_id: OwnedUserId, user_id: OwnedUserId,
device_id: OwnedDeviceId, device_id: OwnedDeviceId,
@ -186,7 +186,7 @@ impl Service {
cached.known_rooms.clone() cached.known_rooms.clone()
} }
pub fn update_sync_subscriptions( pub async fn update_sync_subscriptions(
&self, &self,
user_id: OwnedUserId, user_id: OwnedUserId,
device_id: OwnedDeviceId, device_id: OwnedDeviceId,
@ -212,7 +212,7 @@ impl Service {
cached.subscriptions = subscriptions; cached.subscriptions = subscriptions;
} }
pub fn update_sync_known_rooms( pub async fn update_sync_known_rooms(
&self, &self,
user_id: OwnedUserId, user_id: OwnedUserId,
device_id: OwnedDeviceId, device_id: OwnedDeviceId,