Broadcast send_join concurrent to other operations; pre-gather state concurrently.
Broadcast send_knock concurrently. Concurrent access check for fed event. Concurrent gather for state responses. Populate room_version for format_pdu to elide repeated queries. Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
@@ -53,6 +53,12 @@ pub(crate) async fn get_backfill_route(
|
|||||||
.ready_fold(PduCount::min(), cmp::max)
|
.ready_fold(PduCount::min(), cmp::max)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
let room_version = services
|
||||||
|
.state
|
||||||
|
.get_room_version(&body.room_id)
|
||||||
|
.await
|
||||||
|
.ok();
|
||||||
|
|
||||||
Ok(get_backfill::v1::Response {
|
Ok(get_backfill::v1::Response {
|
||||||
origin_server_ts: MilliSecondsSinceUnixEpoch::now(),
|
origin_server_ts: MilliSecondsSinceUnixEpoch::now(),
|
||||||
|
|
||||||
@@ -79,7 +85,7 @@ pub(crate) async fn get_backfill_route(
|
|||||||
.and_then(|pdu| {
|
.and_then(|pdu| {
|
||||||
services
|
services
|
||||||
.federation
|
.federation
|
||||||
.format_pdu_into(pdu, None)
|
.format_pdu_into(pdu, room_version.as_ref())
|
||||||
.map(Ok)
|
.map(Ok)
|
||||||
})
|
})
|
||||||
.try_collect()
|
.try_collect()
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use axum::extract::State;
|
use axum::extract::State;
|
||||||
use ruma::{MilliSecondsSinceUnixEpoch, RoomId, api::federation::event::get_event};
|
use futures::{FutureExt, future::try_join};
|
||||||
|
use ruma::{MilliSecondsSinceUnixEpoch, OwnedRoomId, api::federation::event::get_event};
|
||||||
use tuwunel_core::{Result, err};
|
use tuwunel_core::{Result, err};
|
||||||
|
|
||||||
use super::AccessCheck;
|
use super::AccessCheck;
|
||||||
@@ -21,28 +22,30 @@ pub(crate) async fn get_event_route(
|
|||||||
.await
|
.await
|
||||||
.map_err(|_| err!(Request(NotFound("Event not found."))))?;
|
.map_err(|_| err!(Request(NotFound("Event not found."))))?;
|
||||||
|
|
||||||
let room_id: &RoomId = event
|
let room_id: OwnedRoomId = event
|
||||||
.get("room_id")
|
.get("room_id")
|
||||||
.and_then(|val| val.as_str())
|
.and_then(|val| val.as_str())
|
||||||
.ok_or_else(|| err!(Database("Invalid event in database.")))?
|
.ok_or_else(|| err!(Database("Invalid event in database.")))?
|
||||||
.try_into()
|
.try_into()
|
||||||
.map_err(|_| err!(Database("Invalid room_id in event in database.")))?;
|
.map_err(|_| err!(Database("Invalid room_id in event in database.")))?;
|
||||||
|
|
||||||
AccessCheck {
|
let access_check = AccessCheck {
|
||||||
services: &services,
|
services: &services,
|
||||||
origin: body.origin(),
|
origin: body.origin(),
|
||||||
room_id,
|
room_id: &room_id,
|
||||||
event_id: Some(&body.event_id),
|
event_id: Some(&body.event_id),
|
||||||
}
|
};
|
||||||
.check()
|
|
||||||
.await?;
|
let pdu = services
|
||||||
|
.federation
|
||||||
|
.format_pdu_into(event, None)
|
||||||
|
.map(Ok);
|
||||||
|
|
||||||
|
let ((), pdu) = try_join(access_check.check(), pdu).await?;
|
||||||
|
|
||||||
Ok(get_event::v1::Response {
|
Ok(get_event::v1::Response {
|
||||||
origin: services.globals.server_name().to_owned(),
|
origin: services.globals.server_name().to_owned(),
|
||||||
origin_server_ts: MilliSecondsSinceUnixEpoch::now(),
|
origin_server_ts: MilliSecondsSinceUnixEpoch::now(),
|
||||||
pdu: services
|
pdu,
|
||||||
.federation
|
|
||||||
.format_pdu_into(event, None)
|
|
||||||
.await,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,10 @@ use ruma::{
|
|||||||
RoomId,
|
RoomId,
|
||||||
api::{client::error::ErrorKind, federation::authorization::get_event_authorization},
|
api::{client::error::ErrorKind, federation::authorization::get_event_authorization},
|
||||||
};
|
};
|
||||||
use tuwunel_core::{Error, Result, utils::stream::ReadyExt};
|
use tuwunel_core::{
|
||||||
|
Error, Result,
|
||||||
|
utils::stream::{BroadbandExt, ReadyExt},
|
||||||
|
};
|
||||||
|
|
||||||
use super::AccessCheck;
|
use super::AccessCheck;
|
||||||
use crate::Ruma;
|
use crate::Ruma;
|
||||||
@@ -43,12 +46,26 @@ pub(crate) async fn get_event_authorization_route(
|
|||||||
let room_id = <&RoomId>::try_from(room_id_str)
|
let room_id = <&RoomId>::try_from(room_id_str)
|
||||||
.map_err(|_| Error::bad_database("Invalid room_id in event in database."))?;
|
.map_err(|_| Error::bad_database("Invalid room_id in event in database."))?;
|
||||||
|
|
||||||
|
let room_version = services
|
||||||
|
.state
|
||||||
|
.get_room_version(room_id)
|
||||||
|
.await
|
||||||
|
.ok();
|
||||||
|
|
||||||
let auth_chain = services
|
let auth_chain = services
|
||||||
.auth_chain
|
.auth_chain
|
||||||
.event_ids_iter(room_id, once(body.event_id.borrow()))
|
.event_ids_iter(room_id, once(body.event_id.borrow()))
|
||||||
.ready_filter_map(Result::ok)
|
.ready_filter_map(Result::ok)
|
||||||
.filter_map(async |id| services.timeline.get_pdu_json(&id).await.ok())
|
.broad_filter_map(async |id| {
|
||||||
.then(|pdu| services.federation.format_pdu_into(pdu, None))
|
let pdu = services.timeline.get_pdu_json(&id).await.ok()?;
|
||||||
|
|
||||||
|
let pdu = services
|
||||||
|
.federation
|
||||||
|
.format_pdu_into(pdu, room_version.as_ref())
|
||||||
|
.await;
|
||||||
|
|
||||||
|
Some(pdu)
|
||||||
|
})
|
||||||
.collect()
|
.collect()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,12 @@ pub(crate) async fn get_missing_events_route(
|
|||||||
.unwrap_or(LIMIT_DEFAULT)
|
.unwrap_or(LIMIT_DEFAULT)
|
||||||
.min(LIMIT_MAX);
|
.min(LIMIT_MAX);
|
||||||
|
|
||||||
|
let room_version = services
|
||||||
|
.state
|
||||||
|
.get_room_version(&body.room_id)
|
||||||
|
.await
|
||||||
|
.ok();
|
||||||
|
|
||||||
let mut queued_events = body.latest_events.clone();
|
let mut queued_events = body.latest_events.clone();
|
||||||
// the vec will never have more entries the limit
|
// the vec will never have more entries the limit
|
||||||
let mut events = Vec::with_capacity(limit);
|
let mut events = Vec::with_capacity(limit);
|
||||||
@@ -78,7 +84,7 @@ pub(crate) async fn get_missing_events_route(
|
|||||||
|
|
||||||
let event = services
|
let event = services
|
||||||
.federation
|
.federation
|
||||||
.format_pdu_into(event, None)
|
.format_pdu_into(event, room_version.as_ref())
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
queued_events.extend(prev_events);
|
queued_events.extend(prev_events);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
|
|
||||||
use axum::extract::State;
|
use axum::extract::State;
|
||||||
use futures::{FutureExt, StreamExt, TryStreamExt, future::try_join3};
|
use futures::{FutureExt, StreamExt, TryFutureExt, TryStreamExt, future::try_join4};
|
||||||
use ruma::{
|
use ruma::{
|
||||||
OwnedEventId, OwnedRoomId, OwnedServerName, OwnedUserId, RoomId, ServerName,
|
OwnedEventId, OwnedRoomId, OwnedServerName, OwnedUserId, RoomId, ServerName,
|
||||||
api::federation::membership::create_join_event,
|
api::federation::membership::create_join_event,
|
||||||
@@ -189,6 +189,14 @@ async fn create_join_event(
|
|||||||
)
|
)
|
||||||
.map_err(|e| err!(Request(BadJson("Event has an invalid origin server name: {e}"))))?;
|
.map_err(|e| err!(Request(BadJson("Event has an invalid origin server name: {e}"))))?;
|
||||||
|
|
||||||
|
// Prestart state gather here since it doesn't involve the new join event.
|
||||||
|
let state_ids = services
|
||||||
|
.state_accessor
|
||||||
|
.state_full_ids(shortstatehash)
|
||||||
|
.map(at!(1))
|
||||||
|
.collect::<Vec<OwnedEventId>>()
|
||||||
|
.boxed();
|
||||||
|
|
||||||
let mutex_lock = services
|
let mutex_lock = services
|
||||||
.event_handler
|
.event_handler
|
||||||
.mutex_federation
|
.mutex_federation
|
||||||
@@ -204,49 +212,51 @@ async fn create_join_event(
|
|||||||
|
|
||||||
drop(mutex_lock);
|
drop(mutex_lock);
|
||||||
|
|
||||||
let state_ids: Vec<OwnedEventId> = services
|
// Join event for new server.
|
||||||
.state_accessor
|
|
||||||
.state_full_ids(shortstatehash)
|
|
||||||
.map(at!(1))
|
|
||||||
.collect()
|
|
||||||
.await;
|
|
||||||
|
|
||||||
let starting_events = state_ids.iter().map(Borrow::borrow);
|
|
||||||
let auth_chain = services
|
|
||||||
.auth_chain
|
|
||||||
.event_ids_iter(room_id, starting_events)
|
|
||||||
.broad_and_then(async |event_id| services.timeline.get_pdu_json(&event_id).await)
|
|
||||||
.broad_and_then(|pdu| {
|
|
||||||
services
|
|
||||||
.federation
|
|
||||||
.format_pdu_into(pdu, Some(&room_version_id))
|
|
||||||
.map(Ok)
|
|
||||||
})
|
|
||||||
.try_collect();
|
|
||||||
|
|
||||||
let state = state_ids
|
|
||||||
.iter()
|
|
||||||
.try_stream()
|
|
||||||
.broad_and_then(|event_id| services.timeline.get_pdu_json(event_id))
|
|
||||||
.broad_and_then(|pdu| {
|
|
||||||
services
|
|
||||||
.federation
|
|
||||||
.format_pdu_into(pdu, Some(&room_version_id))
|
|
||||||
.map(Ok)
|
|
||||||
})
|
|
||||||
.try_collect();
|
|
||||||
|
|
||||||
let event = services
|
let event = services
|
||||||
.federation
|
.federation
|
||||||
.format_pdu_into(value, Some(&room_version_id))
|
.format_pdu_into(value, Some(&room_version_id))
|
||||||
.map(Some)
|
.map(Some)
|
||||||
.map(Ok);
|
.map(Ok);
|
||||||
|
|
||||||
let (auth_chain, state, event) = try_join3(auth_chain, state, event).await?;
|
// Join event revealed to existing servers.
|
||||||
|
let broadcast = services.sending.send_pdu_room(room_id, &pdu_id);
|
||||||
|
|
||||||
services
|
// Wait for state gather which the remaining operations depend on.
|
||||||
.sending
|
let state_ids = state_ids.await;
|
||||||
.send_pdu_room(room_id, &pdu_id)
|
let auth_heads = state_ids.iter().map(Borrow::borrow);
|
||||||
|
let into_federation_format = |pdu| {
|
||||||
|
services
|
||||||
|
.federation
|
||||||
|
.format_pdu_into(pdu, Some(&room_version_id))
|
||||||
|
.map(Ok)
|
||||||
|
};
|
||||||
|
|
||||||
|
let auth_chain = services
|
||||||
|
.auth_chain
|
||||||
|
.event_ids_iter(room_id, auth_heads)
|
||||||
|
.broad_and_then(async |event_id| {
|
||||||
|
services
|
||||||
|
.timeline
|
||||||
|
.get_pdu_json(&event_id)
|
||||||
|
.and_then(into_federation_format)
|
||||||
|
.await
|
||||||
|
})
|
||||||
|
.try_collect();
|
||||||
|
|
||||||
|
let state = state_ids
|
||||||
|
.iter()
|
||||||
|
.try_stream()
|
||||||
|
.broad_and_then(|event_id| {
|
||||||
|
services
|
||||||
|
.timeline
|
||||||
|
.get_pdu_json(event_id)
|
||||||
|
.and_then(into_federation_format)
|
||||||
|
})
|
||||||
|
.try_collect();
|
||||||
|
|
||||||
|
let (auth_chain, state, event, ()) = try_join4(auth_chain, state, event, broadcast)
|
||||||
|
.boxed()
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(create_join_event::v1::RoomState { auth_chain, state, event })
|
Ok(create_join_event::v1::RoomState { auth_chain, state, event })
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use axum::extract::State;
|
use axum::extract::State;
|
||||||
use futures::FutureExt;
|
use futures::{FutureExt, future::try_join};
|
||||||
use ruma::{
|
use ruma::{
|
||||||
OwnedServerName, OwnedUserId,
|
OwnedServerName, OwnedUserId,
|
||||||
RoomVersionId::*,
|
RoomVersionId::*,
|
||||||
@@ -174,16 +174,16 @@ pub(crate) async fn create_knock_event_v1_route(
|
|||||||
|
|
||||||
drop(mutex_lock);
|
drop(mutex_lock);
|
||||||
|
|
||||||
services
|
let broadcast = services
|
||||||
.sending
|
.sending
|
||||||
.send_pdu_room(&body.room_id, &pdu_id)
|
.send_pdu_room(&body.room_id, &pdu_id);
|
||||||
.await?;
|
|
||||||
|
let knock_room_state = services.state.summary_stripped(&pdu).map(Ok);
|
||||||
|
|
||||||
|
let (knock_room_state, ()) = try_join(knock_room_state, broadcast).await?;
|
||||||
|
|
||||||
Ok(create_knock_event::v1::Response {
|
Ok(create_knock_event::v1::Response {
|
||||||
knock_room_state: services
|
knock_room_state: knock_room_state
|
||||||
.state
|
|
||||||
.summary_stripped(&pdu)
|
|
||||||
.await
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
.collect(),
|
.collect(),
|
||||||
|
|||||||
@@ -1,9 +1,18 @@
|
|||||||
use std::{borrow::Borrow, iter::once};
|
use std::{borrow::Borrow, iter::once};
|
||||||
|
|
||||||
use axum::extract::State;
|
use axum::extract::State;
|
||||||
use futures::{FutureExt, StreamExt, TryStreamExt};
|
use futures::{
|
||||||
|
FutureExt, StreamExt, TryFutureExt, TryStreamExt,
|
||||||
|
future::{join, try_join},
|
||||||
|
};
|
||||||
use ruma::{OwnedEventId, api::federation::event::get_room_state};
|
use ruma::{OwnedEventId, api::federation::event::get_room_state};
|
||||||
use tuwunel_core::{Result, at, err, utils::IterStream};
|
use tuwunel_core::{
|
||||||
|
Result, at, err,
|
||||||
|
utils::{
|
||||||
|
future::TryExtExt,
|
||||||
|
stream::{IterStream, TryBroadbandExt},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
use super::AccessCheck;
|
use super::AccessCheck;
|
||||||
use crate::Ruma;
|
use crate::Ruma;
|
||||||
@@ -30,38 +39,50 @@ pub(crate) async fn get_room_state_route(
|
|||||||
.await
|
.await
|
||||||
.map_err(|_| err!(Request(NotFound("PDU state not found."))))?;
|
.map_err(|_| err!(Request(NotFound("PDU state not found."))))?;
|
||||||
|
|
||||||
let state_ids: Vec<OwnedEventId> = services
|
let state_ids = services
|
||||||
.state_accessor
|
.state_accessor
|
||||||
.state_full_ids(shortstatehash)
|
.state_full_ids(shortstatehash)
|
||||||
.map(at!(1))
|
.map(at!(1))
|
||||||
.collect()
|
.collect::<Vec<OwnedEventId>>();
|
||||||
.await;
|
|
||||||
|
|
||||||
let pdus = state_ids
|
let room_version = services
|
||||||
.iter()
|
.state
|
||||||
.try_stream()
|
.get_room_version(&body.room_id)
|
||||||
.and_then(|id| services.timeline.get_pdu_json(id))
|
.ok();
|
||||||
.and_then(|pdu| {
|
|
||||||
services
|
let (room_version, state_ids) = join(room_version, state_ids).await;
|
||||||
.federation
|
|
||||||
.format_pdu_into(pdu, None)
|
let into_federation_format = |pdu| {
|
||||||
.map(Ok)
|
services
|
||||||
})
|
.federation
|
||||||
.try_collect()
|
.format_pdu_into(pdu, room_version.as_ref())
|
||||||
.await?;
|
.map(Ok)
|
||||||
|
};
|
||||||
|
|
||||||
let auth_chain = services
|
let auth_chain = services
|
||||||
.auth_chain
|
.auth_chain
|
||||||
.event_ids_iter(&body.room_id, once(body.event_id.borrow()))
|
.event_ids_iter(&body.room_id, once(body.event_id.borrow()))
|
||||||
.and_then(async |id| services.timeline.get_pdu_json(&id).await)
|
.broad_and_then(async |id| {
|
||||||
.and_then(|pdu| {
|
|
||||||
services
|
services
|
||||||
.federation
|
.timeline
|
||||||
.format_pdu_into(pdu, None)
|
.get_pdu_json(&id)
|
||||||
.map(Ok)
|
.and_then(into_federation_format)
|
||||||
|
.await
|
||||||
})
|
})
|
||||||
.try_collect()
|
.try_collect();
|
||||||
.await?;
|
|
||||||
|
let pdus = state_ids
|
||||||
|
.iter()
|
||||||
|
.try_stream()
|
||||||
|
.broad_and_then(|id| {
|
||||||
|
services
|
||||||
|
.timeline
|
||||||
|
.get_pdu_json(id)
|
||||||
|
.and_then(into_federation_format)
|
||||||
|
})
|
||||||
|
.try_collect();
|
||||||
|
|
||||||
|
let (auth_chain, pdus) = try_join(auth_chain, pdus).await?;
|
||||||
|
|
||||||
Ok(get_room_state::v1::Response { auth_chain, pdus })
|
Ok(get_room_state::v1::Response { auth_chain, pdus })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::{borrow::Borrow, iter::once};
|
use std::{borrow::Borrow, iter::once};
|
||||||
|
|
||||||
use axum::extract::State;
|
use axum::extract::State;
|
||||||
use futures::{StreamExt, TryStreamExt};
|
use futures::{FutureExt, StreamExt, TryStreamExt, future::try_join};
|
||||||
use ruma::{OwnedEventId, api::federation::event::get_room_state_ids};
|
use ruma::{OwnedEventId, api::federation::event::get_room_state_ids};
|
||||||
use tuwunel_core::{Result, at, err};
|
use tuwunel_core::{Result, at, err};
|
||||||
|
|
||||||
@@ -31,18 +31,19 @@ pub(crate) async fn get_room_state_ids_route(
|
|||||||
.await
|
.await
|
||||||
.map_err(|_| err!(Request(NotFound("Pdu state not found."))))?;
|
.map_err(|_| err!(Request(NotFound("Pdu state not found."))))?;
|
||||||
|
|
||||||
let pdu_ids: Vec<OwnedEventId> = services
|
|
||||||
.state_accessor
|
|
||||||
.state_full_ids(shortstatehash)
|
|
||||||
.map(at!(1))
|
|
||||||
.collect()
|
|
||||||
.await;
|
|
||||||
|
|
||||||
let auth_chain_ids = services
|
let auth_chain_ids = services
|
||||||
.auth_chain
|
.auth_chain
|
||||||
.event_ids_iter(&body.room_id, once(body.event_id.borrow()))
|
.event_ids_iter(&body.room_id, once(body.event_id.borrow()))
|
||||||
.try_collect()
|
.try_collect();
|
||||||
.await?;
|
|
||||||
|
let pdu_ids = services
|
||||||
|
.state_accessor
|
||||||
|
.state_full_ids(shortstatehash)
|
||||||
|
.map(at!(1))
|
||||||
|
.collect::<Vec<OwnedEventId>>()
|
||||||
|
.map(Ok);
|
||||||
|
|
||||||
|
let (auth_chain_ids, pdu_ids) = try_join(auth_chain_ids, pdu_ids).await?;
|
||||||
|
|
||||||
Ok(get_room_state_ids::v1::Response { auth_chain_ids, pdu_ids })
|
Ok(get_room_state_ids::v1::Response { auth_chain_ids, pdu_ids })
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user