@ -1,26 +1,30 @@
use super ::State ;
use super ::State ;
use crate ::{
use crate ::{
client_server , pdu ::PduBuilder , server_server , utils , ConduitResult , Database , Error , Ruma ,
client_server ,
pdu ::{ PduBuilder , PduEvent } ,
server_server , utils , ConduitResult , Database , Error , Result , Ruma ,
} ;
} ;
use log ::warn ;
use ruma ::{
use ruma ::{
api ::{
api ::{
client ::{
client ::{
error ::ErrorKind ,
error ::ErrorKind ,
r0 ::{
r0 ::membership ::{
alias ,
ban_user , forget_room , get_member_events , invite_user , join_room_by_id ,
membership ::{
join_room_by_id_or_alias , joined_members , joined_rooms , kick_user , leave_room ,
ban_user , forget_room , get_member_events , invite_user , join_room_by_id ,
unban_user , IncomingThirdPartySigned ,
join_room_by_id_or_alias , joined_members , joined_rooms , kick_user , leave_room ,
unban_user ,
} ,
} ,
} ,
} ,
} ,
federation ,
federation ,
} ,
} ,
events ::pdu ::Pdu ,
events ::{ room ::member , EventType } ,
events ::{ room ::member , EventType } ,
EventId , Raw , RoomId , RoomVersionId ,
EventId , Raw , RoomId , RoomVersionId , ServerName , UserId ,
} ;
use state_res ::StateEvent ;
use std ::{
collections ::BTreeMap , collections ::HashMap , collections ::HashSet , convert ::TryFrom , sync ::Arc ,
} ;
} ;
use std ::{ collections ::BTreeMap , convert ::TryFrom } ;
#[ cfg(feature = " conduit_bin " ) ]
#[ cfg(feature = " conduit_bin " ) ]
use rocket ::{ get , post } ;
use rocket ::{ get , post } ;
@ -31,106 +35,16 @@ use rocket::{get, post};
) ]
) ]
pub async fn join_room_by_id_route (
pub async fn join_room_by_id_route (
db : State < ' _ , Database > ,
db : State < ' _ , Database > ,
body : Ruma < join_room_by_id ::Incoming Request> ,
body : Ruma < join_room_by_id :: Request< ' _ > > ,
) -> ConduitResult < join_room_by_id ::Response > {
) -> ConduitResult < join_room_by_id ::Response > {
let sender_id = body . sender_id . as_ref ( ) . expect ( "user is authenticated" ) ;
join_room_by_id_helper (
& db ,
// Ask a remote server if we don't have this room
body . sender_id . as_ref ( ) ,
if ! db . rooms . exists ( & body . room_id ) ? & & body . room_id . server_name ( ) ! = db . globals . server_name ( ) {
& body . room_id ,
let make_join_response = server_server ::send_request (
& [ body . room_id . server_name ( ) . to_owned ( ) ] ,
& db ,
body . third_party_signed . as_ref ( ) ,
body . room_id . server_name ( ) . to_string ( ) ,
)
federation ::membership ::create_join_event_template ::v1 ::Request {
. await
room_id : body . room_id . clone ( ) ,
user_id : sender_id . clone ( ) ,
ver : vec ! [ RoomVersionId ::Version5 , RoomVersionId ::Version6 ] ,
} ,
)
. await ? ;
let mut join_event_stub_value =
serde_json ::from_str ::< serde_json ::Value > ( make_join_response . event . json ( ) . get ( ) )
. map_err ( | _ | {
Error ::BadServerResponse ( "Invalid make_join event json received from server." )
} ) ? ;
let join_event_stub =
join_event_stub_value
. as_object_mut ( )
. ok_or ( Error ::BadServerResponse (
"Invalid make join event object received from server." ,
) ) ? ;
join_event_stub . insert (
"origin" . to_owned ( ) ,
db . globals . server_name ( ) . to_owned ( ) . to_string ( ) . into ( ) ,
) ;
join_event_stub . insert (
"origin_server_ts" . to_owned ( ) ,
utils ::millis_since_unix_epoch ( ) . into ( ) ,
) ;
// Generate event id
let event_id = EventId ::try_from ( & * format! (
"${}" ,
ruma ::signatures ::reference_hash ( & join_event_stub_value )
. expect ( "ruma can calculate reference hashes" )
) )
. expect ( "ruma's reference hashes are valid event ids" ) ;
// We don't leave the event id into the pdu because that's only allowed in v1 or v2 rooms
let join_event_stub = join_event_stub_value . as_object_mut ( ) . unwrap ( ) ;
join_event_stub . remove ( "event_id" ) ;
ruma ::signatures ::hash_and_sign_event (
db . globals . server_name ( ) . as_str ( ) ,
db . globals . keypair ( ) ,
& mut join_event_stub_value ,
)
. expect ( "event is valid, we just created it" ) ;
let send_join_response = server_server ::send_request (
& db ,
body . room_id . server_name ( ) . to_string ( ) ,
federation ::membership ::create_join_event ::v2 ::Request {
room_id : body . room_id . clone ( ) ,
event_id ,
pdu_stub : serde_json ::from_value ::< Raw < _ > > ( join_event_stub_value )
. expect ( "Raw::from_value always works" ) ,
} ,
)
. await ? ;
dbg! ( send_join_response ) ;
todo! ( "Take send_join_response and 'create' the room using that data" ) ;
}
let event = member ::MemberEventContent {
membership : member ::MembershipState ::Join ,
displayname : db . users . displayname ( & sender_id ) ? ,
avatar_url : db . users . avatar_url ( & sender_id ) ? ,
is_direct : None ,
third_party_invite : None ,
} ;
db . rooms . append_pdu (
PduBuilder {
room_id : body . room_id . clone ( ) ,
sender : sender_id . clone ( ) ,
event_type : EventType ::RoomMember ,
content : serde_json ::to_value ( event ) . expect ( "event is valid, we just created it" ) ,
unsigned : None ,
state_key : Some ( sender_id . to_string ( ) ) ,
redacts : None ,
} ,
& db . globals ,
& db . account_data ,
) ? ;
Ok ( join_room_by_id ::Response {
room_id : body . room_id . clone ( ) ,
}
. into ( ) )
}
}
#[ cfg_attr(
#[ cfg_attr(
@ -139,39 +53,28 @@ pub async fn join_room_by_id_route(
) ]
) ]
pub async fn join_room_by_id_or_alias_route (
pub async fn join_room_by_id_or_alias_route (
db : State < ' _ , Database > ,
db : State < ' _ , Database > ,
db2 : State < ' _ , Database > ,
body : Ruma < join_room_by_id_or_alias ::Request < ' _ > > ,
body : Ruma < join_room_by_id_or_alias ::Request > ,
) -> ConduitResult < join_room_by_id_or_alias ::Response > {
) -> ConduitResult < join_room_by_id_or_alias ::Response > {
let room_id = match RoomId ::try_from ( body . room_id_or_alias . clone ( ) ) {
let ( servers , room_id ) = match RoomId ::try_from ( body . room_id_or_alias . clone ( ) ) {
Ok ( room_id ) = > room_id ,
Ok ( room_id ) = > ( vec! [ room_id . server_name ( ) . to_owned ( ) ] , room_id ) ,
Err ( room_alias ) = > {
Err ( room_alias ) = > {
client_server ::get_alias_route (
let response = client_server ::get_alias_helper ( & db , & room_alias ) . await ? ;
db ,
Ruma {
body : alias ::get_alias ::IncomingRequest { room_alias } ,
sender_id : body . sender_id . clone ( ) ,
device_id : body . device_id . clone ( ) ,
json_body : None ,
} ,
)
. await ?
. 0
. room_id
}
} ;
let body = Ruma {
( response . 0. servers , response . 0. room_id )
sender_id : body . sender_id . clone ( ) ,
}
device_id : body . device_id . clone ( ) ,
json_body : None ,
body : join_room_by_id ::IncomingRequest {
room_id ,
third_party_signed : body . third_party_signed . clone ( ) ,
} ,
} ;
} ;
Ok ( join_room_by_id_or_alias ::Response {
Ok ( join_room_by_id_or_alias ::Response {
room_id : join_room_by_id_route ( db2 , body ) . await ? . 0. room_id ,
room_id : join_room_by_id_helper (
& db ,
body . sender_id . as_ref ( ) ,
& room_id ,
& servers ,
body . third_party_signed . as_ref ( ) ,
)
. await ?
. 0
. room_id ,
}
}
. into ( ) )
. into ( ) )
}
}
@ -180,9 +83,9 @@ pub async fn join_room_by_id_or_alias_route(
feature = "conduit_bin" ,
feature = "conduit_bin" ,
post ( "/_matrix/client/r0/rooms/<_>/leave" , data = "<body>" )
post ( "/_matrix/client/r0/rooms/<_>/leave" , data = "<body>" )
) ]
) ]
pub fn leave_room_route (
pub async fn leave_room_route (
db : State < ' _ , Database > ,
db : State < ' _ , Database > ,
body : Ruma < leave_room ::Incoming Request> ,
body : Ruma < leave_room :: Request< ' _ > > ,
) -> ConduitResult < leave_room ::Response > {
) -> ConduitResult < leave_room ::Response > {
let sender_id = body . sender_id . as_ref ( ) . expect ( "user is authenticated" ) ;
let sender_id = body . sender_id . as_ref ( ) . expect ( "user is authenticated" ) ;
@ -205,38 +108,37 @@ pub fn leave_room_route(
event . membership = member ::MembershipState ::Leave ;
event . membership = member ::MembershipState ::Leave ;
db . rooms . append_pdu(
db . rooms . build_and_ append_pdu(
PduBuilder {
PduBuilder {
room_id : body . room_id . clone ( ) ,
sender : sender_id . clone ( ) ,
event_type : EventType ::RoomMember ,
event_type : EventType ::RoomMember ,
content : serde_json ::to_value ( event ) . expect ( "event is valid, we just created it" ) ,
content : serde_json ::to_value ( event ) . expect ( "event is valid, we just created it" ) ,
unsigned : None ,
unsigned : None ,
state_key : Some ( sender_id . to_string ( ) ) ,
state_key : Some ( sender_id . to_string ( ) ) ,
redacts : None ,
redacts : None ,
} ,
} ,
& sender_id ,
& body . room_id ,
& db . globals ,
& db . globals ,
& db . sending ,
& db . account_data ,
& db . account_data ,
) ? ;
) ? ;
Ok ( leave_room ::Response . into ( ) )
Ok ( leave_room ::Response ::new ( ) . into ( ) )
}
}
#[ cfg_attr(
#[ cfg_attr(
feature = "conduit_bin" ,
feature = "conduit_bin" ,
post ( "/_matrix/client/r0/rooms/<_>/invite" , data = "<body>" )
post ( "/_matrix/client/r0/rooms/<_>/invite" , data = "<body>" )
) ]
) ]
pub fn invite_user_route (
pub async fn invite_user_route (
db : State < ' _ , Database > ,
db : State < ' _ , Database > ,
body : Ruma < invite_user ::Request >,
body : Ruma < invite_user ::Request <' _ > >,
) -> ConduitResult < invite_user ::Response > {
) -> ConduitResult < invite_user ::Response > {
let sender_id = body . sender_id . as_ref ( ) . expect ( "user is authenticated" ) ;
let sender_id = body . sender_id . as_ref ( ) . expect ( "user is authenticated" ) ;
if let invite_user ::In vitationRecipient::UserId { user_id } = & body . recipient {
if let invite_user ::In comingIn vitationRecipient::UserId { user_id } = & body . recipient {
db . rooms . append_pdu(
db . rooms . build_and_ append_pdu(
PduBuilder {
PduBuilder {
room_id : body . room_id . clone ( ) ,
sender : sender_id . clone ( ) ,
event_type : EventType ::RoomMember ,
event_type : EventType ::RoomMember ,
content : serde_json ::to_value ( member ::MemberEventContent {
content : serde_json ::to_value ( member ::MemberEventContent {
membership : member ::MembershipState ::Invite ,
membership : member ::MembershipState ::Invite ,
@ -250,7 +152,10 @@ pub fn invite_user_route(
state_key : Some ( user_id . to_string ( ) ) ,
state_key : Some ( user_id . to_string ( ) ) ,
redacts : None ,
redacts : None ,
} ,
} ,
& sender_id ,
& body . room_id ,
& db . globals ,
& db . globals ,
& db . sending ,
& db . account_data ,
& db . account_data ,
) ? ;
) ? ;
@ -264,9 +169,9 @@ pub fn invite_user_route(
feature = "conduit_bin" ,
feature = "conduit_bin" ,
post ( "/_matrix/client/r0/rooms/<_>/kick" , data = "<body>" )
post ( "/_matrix/client/r0/rooms/<_>/kick" , data = "<body>" )
) ]
) ]
pub fn kick_user_route (
pub async fn kick_user_route (
db : State < ' _ , Database > ,
db : State < ' _ , Database > ,
body : Ruma < kick_user ::Request >,
body : Ruma < kick_user ::Request <' _ > >,
) -> ConduitResult < kick_user ::Response > {
) -> ConduitResult < kick_user ::Response > {
let sender_id = body . sender_id . as_ref ( ) . expect ( "user is authenticated" ) ;
let sender_id = body . sender_id . as_ref ( ) . expect ( "user is authenticated" ) ;
@ -290,30 +195,31 @@ pub fn kick_user_route(
event . membership = ruma ::events ::room ::member ::MembershipState ::Leave ;
event . membership = ruma ::events ::room ::member ::MembershipState ::Leave ;
// TODO: reason
// TODO: reason
db . rooms . append_pdu(
db . rooms . build_and_ append_pdu(
PduBuilder {
PduBuilder {
room_id : body . room_id . clone ( ) ,
sender : sender_id . clone ( ) ,
event_type : EventType ::RoomMember ,
event_type : EventType ::RoomMember ,
content : serde_json ::to_value ( event ) . expect ( "event is valid, we just created it" ) ,
content : serde_json ::to_value ( event ) . expect ( "event is valid, we just created it" ) ,
unsigned : None ,
unsigned : None ,
state_key : Some ( body . user_id . to_string ( ) ) ,
state_key : Some ( body . user_id . to_string ( ) ) ,
redacts : None ,
redacts : None ,
} ,
} ,
& sender_id ,
& body . room_id ,
& db . globals ,
& db . globals ,
& db . sending ,
& db . account_data ,
& db . account_data ,
) ? ;
) ? ;
Ok ( kick_user ::Response . into ( ) )
Ok ( kick_user ::Response ::new ( ) . into ( ) )
}
}
#[ cfg_attr(
#[ cfg_attr(
feature = "conduit_bin" ,
feature = "conduit_bin" ,
post ( "/_matrix/client/r0/rooms/<_>/ban" , data = "<body>" )
post ( "/_matrix/client/r0/rooms/<_>/ban" , data = "<body>" )
) ]
) ]
pub fn ban_user_route (
pub async fn ban_user_route (
db : State < ' _ , Database > ,
db : State < ' _ , Database > ,
body : Ruma < ban_user ::Request >,
body : Ruma < ban_user ::Request <' _ > >,
) -> ConduitResult < ban_user ::Response > {
) -> ConduitResult < ban_user ::Response > {
let sender_id = body . sender_id . as_ref ( ) . expect ( "user is authenticated" ) ;
let sender_id = body . sender_id . as_ref ( ) . expect ( "user is authenticated" ) ;
@ -345,30 +251,31 @@ pub fn ban_user_route(
} ,
} ,
) ? ;
) ? ;
db . rooms . append_pdu(
db . rooms . build_and_ append_pdu(
PduBuilder {
PduBuilder {
room_id : body . room_id . clone ( ) ,
sender : sender_id . clone ( ) ,
event_type : EventType ::RoomMember ,
event_type : EventType ::RoomMember ,
content : serde_json ::to_value ( event ) . expect ( "event is valid, we just created it" ) ,
content : serde_json ::to_value ( event ) . expect ( "event is valid, we just created it" ) ,
unsigned : None ,
unsigned : None ,
state_key : Some ( body . user_id . to_string ( ) ) ,
state_key : Some ( body . user_id . to_string ( ) ) ,
redacts : None ,
redacts : None ,
} ,
} ,
& sender_id ,
& body . room_id ,
& db . globals ,
& db . globals ,
& db . sending ,
& db . account_data ,
& db . account_data ,
) ? ;
) ? ;
Ok ( ban_user ::Response . into ( ) )
Ok ( ban_user ::Response ::new ( ) . into ( ) )
}
}
#[ cfg_attr(
#[ cfg_attr(
feature = "conduit_bin" ,
feature = "conduit_bin" ,
post ( "/_matrix/client/r0/rooms/<_>/unban" , data = "<body>" )
post ( "/_matrix/client/r0/rooms/<_>/unban" , data = "<body>" )
) ]
) ]
pub fn unban_user_route (
pub async fn unban_user_route (
db : State < ' _ , Database > ,
db : State < ' _ , Database > ,
body : Ruma < unban_user ::Request >,
body : Ruma < unban_user ::Request <' _ > >,
) -> ConduitResult < unban_user ::Response > {
) -> ConduitResult < unban_user ::Response > {
let sender_id = body . sender_id . as_ref ( ) . expect ( "user is authenticated" ) ;
let sender_id = body . sender_id . as_ref ( ) . expect ( "user is authenticated" ) ;
@ -391,21 +298,22 @@ pub fn unban_user_route(
event . membership = ruma ::events ::room ::member ::MembershipState ::Leave ;
event . membership = ruma ::events ::room ::member ::MembershipState ::Leave ;
db . rooms . append_pdu(
db . rooms . build_and_ append_pdu(
PduBuilder {
PduBuilder {
room_id : body . room_id . clone ( ) ,
sender : sender_id . clone ( ) ,
event_type : EventType ::RoomMember ,
event_type : EventType ::RoomMember ,
content : serde_json ::to_value ( event ) . expect ( "event is valid, we just created it" ) ,
content : serde_json ::to_value ( event ) . expect ( "event is valid, we just created it" ) ,
unsigned : None ,
unsigned : None ,
state_key : Some ( body . user_id . to_string ( ) ) ,
state_key : Some ( body . user_id . to_string ( ) ) ,
redacts : None ,
redacts : None ,
} ,
} ,
& sender_id ,
& body . room_id ,
& db . globals ,
& db . globals ,
& db . sending ,
& db . account_data ,
& db . account_data ,
) ? ;
) ? ;
Ok ( unban_user ::Response . into ( ) )
Ok ( unban_user ::Response ::new ( ) . into ( ) )
}
}
#[ cfg_attr(
#[ cfg_attr(
@ -414,13 +322,13 @@ pub fn unban_user_route(
) ]
) ]
pub fn forget_room_route (
pub fn forget_room_route (
db : State < ' _ , Database > ,
db : State < ' _ , Database > ,
body : Ruma < forget_room ::Request >,
body : Ruma < forget_room ::Request <' _ > >,
) -> ConduitResult < forget_room ::Response > {
) -> ConduitResult < forget_room ::Response > {
let sender_id = body . sender_id . as_ref ( ) . expect ( "user is authenticated" ) ;
let sender_id = body . sender_id . as_ref ( ) . expect ( "user is authenticated" ) ;
db . rooms . forget ( & body . room_id , & sender_id ) ? ;
db . rooms . forget ( & body . room_id , & sender_id ) ? ;
Ok ( forget_room ::Response . into ( ) )
Ok ( forget_room ::Response ::new ( ) . into ( ) )
}
}
#[ cfg_attr(
#[ cfg_attr(
@ -449,7 +357,7 @@ pub fn joined_rooms_route(
) ]
) ]
pub fn get_member_events_route (
pub fn get_member_events_route (
db : State < ' _ , Database > ,
db : State < ' _ , Database > ,
body : Ruma < get_member_events ::Request >,
body : Ruma < get_member_events ::Request <' _ > >,
) -> ConduitResult < get_member_events ::Response > {
) -> ConduitResult < get_member_events ::Response > {
let sender_id = body . sender_id . as_ref ( ) . expect ( "user is authenticated" ) ;
let sender_id = body . sender_id . as_ref ( ) . expect ( "user is authenticated" ) ;
@ -477,7 +385,7 @@ pub fn get_member_events_route(
) ]
) ]
pub fn joined_members_route (
pub fn joined_members_route (
db : State < ' _ , Database > ,
db : State < ' _ , Database > ,
body : Ruma < joined_members ::Request >,
body : Ruma < joined_members ::Request <' _ > >,
) -> ConduitResult < joined_members ::Response > {
) -> ConduitResult < joined_members ::Response > {
let sender_id = body . sender_id . as_ref ( ) . expect ( "user is authenticated" ) ;
let sender_id = body . sender_id . as_ref ( ) . expect ( "user is authenticated" ) ;
@ -508,3 +416,253 @@ pub fn joined_members_route(
Ok ( joined_members ::Response { joined } . into ( ) )
Ok ( joined_members ::Response { joined } . into ( ) )
}
}
async fn join_room_by_id_helper (
db : & Database ,
sender_id : Option < & UserId > ,
room_id : & RoomId ,
servers : & [ Box < ServerName > ] ,
_third_party_signed : Option < & IncomingThirdPartySigned > ,
) -> ConduitResult < join_room_by_id ::Response > {
let sender_id = sender_id . expect ( "user is authenticated" ) ;
// Ask a remote server if we don't have this room
if ! db . rooms . exists ( & room_id ) ? & & room_id . server_name ( ) ! = db . globals . server_name ( ) {
let mut make_join_response_and_server = Err ( Error ::BadServerResponse (
"No server available to assist in joining." ,
) ) ;
for remote_server in servers {
let make_join_response = server_server ::send_request (
& db . globals ,
remote_server . clone ( ) ,
federation ::membership ::create_join_event_template ::v1 ::Request {
room_id ,
user_id : sender_id ,
ver : & [ RoomVersionId ::Version5 , RoomVersionId ::Version6 ] ,
} ,
)
. await ;
make_join_response_and_server = make_join_response . map ( | r | ( r , remote_server ) ) ;
if make_join_response_and_server . is_ok ( ) {
break ;
}
}
let ( make_join_response , remote_server ) = make_join_response_and_server ? ;
let mut join_event_stub_value =
serde_json ::from_str ::< serde_json ::Value > ( make_join_response . event . json ( ) . get ( ) )
. map_err ( | _ | {
Error ::BadServerResponse ( "Invalid make_join event json received from server." )
} ) ? ;
let join_event_stub =
join_event_stub_value
. as_object_mut ( )
. ok_or ( Error ::BadServerResponse (
"Invalid make join event object received from server." ,
) ) ? ;
join_event_stub . insert (
"origin" . to_owned ( ) ,
db . globals . server_name ( ) . to_owned ( ) . to_string ( ) . into ( ) ,
) ;
join_event_stub . insert (
"origin_server_ts" . to_owned ( ) ,
utils ::millis_since_unix_epoch ( ) . into ( ) ,
) ;
// Generate event id
let event_id = EventId ::try_from ( & * format! (
"${}" ,
ruma ::signatures ::reference_hash ( & join_event_stub_value )
. expect ( "ruma can calculate reference hashes" )
) )
. expect ( "ruma's reference hashes are valid event ids" ) ;
// We don't leave the event id into the pdu because that's only allowed in v1 or v2 rooms
let join_event_stub = join_event_stub_value . as_object_mut ( ) . unwrap ( ) ;
join_event_stub . remove ( "event_id" ) ;
ruma ::signatures ::hash_and_sign_event (
db . globals . server_name ( ) . as_str ( ) ,
db . globals . keypair ( ) ,
& mut join_event_stub_value ,
)
. expect ( "event is valid, we just created it" ) ;
let send_join_response = server_server ::send_request (
& db . globals ,
remote_server . clone ( ) ,
federation ::membership ::create_join_event ::v2 ::Request {
room_id ,
event_id : & event_id ,
pdu_stub : serde_json ::from_value ( join_event_stub_value )
. expect ( "we just created this event" ) ,
} ,
)
. await ? ;
let add_event_id = | pdu : & Raw < Pdu > | {
let mut value = serde_json ::from_str ( pdu . json ( ) . get ( ) )
. expect ( "converting raw jsons to values always works" ) ;
let event_id = EventId ::try_from ( & * format! (
"${}" ,
ruma ::signatures ::reference_hash ( & value )
. expect ( "ruma can calculate reference hashes" )
) )
. expect ( "ruma's reference hashes are valid event ids" ) ;
value
. as_object_mut ( )
. ok_or_else ( | | Error ::BadServerResponse ( "PDU is not an object." ) ) ?
. insert ( "event_id" . to_owned ( ) , event_id . to_string ( ) . into ( ) ) ;
Ok ( ( event_id , value ) )
} ;
let room_state = send_join_response . room_state . state . iter ( ) . map ( add_event_id ) ;
let state_events = room_state
. clone ( )
. map ( | pdu : Result < ( EventId , serde_json ::Value ) > | Ok ( pdu ? . 0 ) )
. collect ::< Result < HashSet < EventId > > > ( ) ? ;
let auth_chain = send_join_response
. room_state
. auth_chain
. iter ( )
. map ( add_event_id ) ;
let mut event_map = room_state
. chain ( auth_chain )
. map ( | r | {
let ( event_id , value ) = r ? ;
serde_json ::from_value ::< StateEvent > ( value )
. map ( | ev | ( event_id , Arc ::new ( ev ) ) )
. map_err ( | e | {
warn ! ( "{}" , e ) ;
Error ::BadServerResponse ( "Invalid PDU bytes in send_join response." )
} )
} )
. collect ::< Result < BTreeMap < EventId , Arc < StateEvent > > > > ( ) ? ;
let control_events = event_map
. values ( )
. filter ( | pdu | pdu . is_power_event ( ) )
. map ( | pdu | pdu . event_id ( ) . clone ( ) )
. collect ::< Vec < _ > > ( ) ;
// These events are not guaranteed to be sorted but they are resolved according to spec
// we auth them anyways to weed out faulty/malicious server. The following is basically the
// full state resolution algorithm.
let event_ids = event_map . keys ( ) . cloned ( ) . collect ::< Vec < _ > > ( ) ;
let sorted_control_events = state_res ::StateResolution ::reverse_topological_power_sort (
& room_id ,
& control_events ,
& mut event_map ,
& db . rooms ,
& event_ids ,
) ;
// Auth check each event against the "partial" state created by the preceding events
let resolved_control_events = state_res ::StateResolution ::iterative_auth_check (
room_id ,
& RoomVersionId ::Version6 ,
& sorted_control_events ,
& BTreeMap ::new ( ) , // We have no "clean/resolved" events to add (these extend the `resolved_control_events`)
& mut event_map ,
& db . rooms ,
)
. expect ( "iterative auth check failed on resolved events" ) ;
// This removes the control events that failed auth, leaving the resolved
// to be mainline sorted
let events_to_sort = event_map
. keys ( )
. filter ( | id | {
! sorted_control_events . contains ( id )
| | resolved_control_events . values ( ) . any ( | rid | * id = = rid )
} )
. cloned ( )
. collect ::< Vec < _ > > ( ) ;
let power_level = resolved_control_events . get ( & ( EventType ::RoomPowerLevels , "" . into ( ) ) ) ;
// Sort the remaining non control events
let sorted_event_ids = state_res ::StateResolution ::mainline_sort (
room_id ,
& events_to_sort ,
power_level ,
& mut event_map ,
& db . rooms ,
) ;
let resolved_events = state_res ::StateResolution ::iterative_auth_check (
room_id ,
& RoomVersionId ::Version6 ,
& sorted_event_ids ,
& resolved_control_events ,
& mut event_map ,
& db . rooms ,
)
. expect ( "iterative auth check failed on resolved events" ) ;
let mut state = HashMap ::new ( ) ;
// filter the events that failed the auth check keeping the remaining events
// sorted correctly
for ev_id in sorted_event_ids
. iter ( )
. filter ( | id | resolved_events . values ( ) . any ( | rid | rid = = * id ) )
{
// this is a `state_res::StateEvent` that holds a `ruma::Pdu`
let pdu = event_map
. get ( ev_id )
. expect ( "Found event_id in sorted events that is not in resolved state" ) ;
// We do not rebuild the PDU in this case only insert to DB
let pdu_id = db . rooms . append_pdu (
& PduEvent ::from ( & * * pdu ) ,
& serde_json ::to_value ( & * * pdu ) . expect ( "PDU is valid value" ) ,
& db . globals ,
& db . account_data ,
& db . sending ,
) ? ;
if state_events . contains ( ev_id ) {
state . insert ( ( pdu . kind ( ) , pdu . state_key ( ) ) , pdu_id ) ;
}
}
db . rooms . force_state ( room_id , state ) ? ;
} else {
let event = member ::MemberEventContent {
membership : member ::MembershipState ::Join ,
displayname : db . users . displayname ( & sender_id ) ? ,
avatar_url : db . users . avatar_url ( & sender_id ) ? ,
is_direct : None ,
third_party_invite : None ,
} ;
db . rooms . build_and_append_pdu (
PduBuilder {
event_type : EventType ::RoomMember ,
content : serde_json ::to_value ( event ) . expect ( "event is valid, we just created it" ) ,
unsigned : None ,
state_key : Some ( sender_id . to_string ( ) ) ,
redacts : None ,
} ,
& sender_id ,
& room_id ,
& db . globals ,
& db . sending ,
& db . account_data ,
) ? ;
}
Ok ( join_room_by_id ::Response ::new ( room_id . clone ( ) ) . into ( ) )
}