mirror of
https://forgejo.ellis.link/continuwuation/continuwuity.git
synced 2025-07-04 23:36:02 +02:00
Toward abstracting Pdu into trait Event.
Co-authored-by: Jade Ellis <jade@ellis.link> Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
parent
3d0360bcd6
commit
116f85360f
41 changed files with 842 additions and 886 deletions
|
@ -7,7 +7,10 @@ use std::{
|
||||||
|
|
||||||
use conduwuit::{
|
use conduwuit::{
|
||||||
Err, Result, debug_error, err, info,
|
Err, Result, debug_error, err, info,
|
||||||
matrix::pdu::{PduEvent, PduId, RawPduId},
|
matrix::{
|
||||||
|
Event,
|
||||||
|
pdu::{PduEvent, PduId, RawPduId},
|
||||||
|
},
|
||||||
trace, utils,
|
trace, utils,
|
||||||
utils::{
|
utils::{
|
||||||
stream::{IterStream, ReadyExt},
|
stream::{IterStream, ReadyExt},
|
||||||
|
@ -19,7 +22,7 @@ use futures::{FutureExt, StreamExt, TryStreamExt};
|
||||||
use ruma::{
|
use ruma::{
|
||||||
CanonicalJsonObject, CanonicalJsonValue, EventId, OwnedEventId, OwnedRoomId,
|
CanonicalJsonObject, CanonicalJsonValue, EventId, OwnedEventId, OwnedRoomId,
|
||||||
OwnedRoomOrAliasId, OwnedServerName, RoomId, RoomVersionId,
|
OwnedRoomOrAliasId, OwnedServerName, RoomId, RoomVersionId,
|
||||||
api::federation::event::get_room_state,
|
api::federation::event::get_room_state, events::AnyStateEvent, serde::Raw,
|
||||||
};
|
};
|
||||||
use service::rooms::{
|
use service::rooms::{
|
||||||
short::{ShortEventId, ShortRoomId},
|
short::{ShortEventId, ShortRoomId},
|
||||||
|
@ -296,12 +299,12 @@ pub(super) async fn get_remote_pdu(
|
||||||
#[admin_command]
|
#[admin_command]
|
||||||
pub(super) async fn get_room_state(&self, room: OwnedRoomOrAliasId) -> Result {
|
pub(super) async fn get_room_state(&self, room: OwnedRoomOrAliasId) -> Result {
|
||||||
let room_id = self.services.rooms.alias.resolve(&room).await?;
|
let room_id = self.services.rooms.alias.resolve(&room).await?;
|
||||||
let room_state: Vec<_> = self
|
let room_state: Vec<Raw<AnyStateEvent>> = self
|
||||||
.services
|
.services
|
||||||
.rooms
|
.rooms
|
||||||
.state_accessor
|
.state_accessor
|
||||||
.room_state_full_pdus(&room_id)
|
.room_state_full_pdus(&room_id)
|
||||||
.map_ok(PduEvent::into_state_event)
|
.map_ok(Event::into_format)
|
||||||
.try_collect()
|
.try_collect()
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
use std::{collections::BTreeMap, fmt::Write as _};
|
use std::{collections::BTreeMap, fmt::Write as _};
|
||||||
|
|
||||||
use api::client::{full_user_deactivate, join_room_by_id_helper, leave_room};
|
use api::client::{
|
||||||
|
full_user_deactivate, join_room_by_id_helper, leave_all_rooms, leave_room, update_avatar_url,
|
||||||
|
update_displayname,
|
||||||
|
};
|
||||||
use conduwuit::{
|
use conduwuit::{
|
||||||
Err, Result, debug, debug_warn, error, info, is_equal_to,
|
Err, Result, debug, debug_warn, error, info, is_equal_to,
|
||||||
matrix::pdu::PduBuilder,
|
matrix::{Event, pdu::PduBuilder},
|
||||||
utils::{self, ReadyExt},
|
utils::{self, ReadyExt},
|
||||||
warn,
|
warn,
|
||||||
};
|
};
|
||||||
use conduwuit_api::client::{leave_all_rooms, update_avatar_url, update_displayname};
|
|
||||||
use futures::{FutureExt, StreamExt};
|
use futures::{FutureExt, StreamExt};
|
||||||
use ruma::{
|
use ruma::{
|
||||||
OwnedEventId, OwnedRoomId, OwnedRoomOrAliasId, OwnedUserId, UserId,
|
OwnedEventId, OwnedRoomId, OwnedRoomOrAliasId, OwnedUserId, UserId,
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
use axum::extract::State;
|
use axum::extract::State;
|
||||||
use conduwuit::{
|
use conduwuit::{
|
||||||
Err, Result, at, debug_warn, err,
|
Err, Event, Result, at, debug_warn, err, ref_at,
|
||||||
matrix::pdu::PduEvent,
|
|
||||||
ref_at,
|
|
||||||
utils::{
|
utils::{
|
||||||
IterStream,
|
IterStream,
|
||||||
future::TryExtExt,
|
future::TryExtExt,
|
||||||
|
@ -179,12 +177,12 @@ pub(crate) async fn get_context_route(
|
||||||
.broad_filter_map(|event_id: &OwnedEventId| {
|
.broad_filter_map(|event_id: &OwnedEventId| {
|
||||||
services.rooms.timeline.get_pdu(event_id.as_ref()).ok()
|
services.rooms.timeline.get_pdu(event_id.as_ref()).ok()
|
||||||
})
|
})
|
||||||
.map(PduEvent::into_state_event)
|
.map(Event::into_format)
|
||||||
.collect()
|
.collect()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
Ok(get_context::v3::Response {
|
Ok(get_context::v3::Response {
|
||||||
event: base_event.map(at!(1)).map(PduEvent::into_room_event),
|
event: base_event.map(at!(1)).map(Event::into_format),
|
||||||
|
|
||||||
start: events_before
|
start: events_before
|
||||||
.last()
|
.last()
|
||||||
|
@ -203,13 +201,13 @@ pub(crate) async fn get_context_route(
|
||||||
events_before: events_before
|
events_before: events_before
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(at!(1))
|
.map(at!(1))
|
||||||
.map(PduEvent::into_room_event)
|
.map(Event::into_format)
|
||||||
.collect(),
|
.collect(),
|
||||||
|
|
||||||
events_after: events_after
|
events_after: events_after
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(at!(1))
|
.map(at!(1))
|
||||||
.map(PduEvent::into_room_event)
|
.map(Event::into_format)
|
||||||
.collect(),
|
.collect(),
|
||||||
|
|
||||||
state,
|
state,
|
||||||
|
|
|
@ -9,7 +9,8 @@ use std::{
|
||||||
use axum::extract::State;
|
use axum::extract::State;
|
||||||
use axum_client_ip::InsecureClientIp;
|
use axum_client_ip::InsecureClientIp;
|
||||||
use conduwuit::{
|
use conduwuit::{
|
||||||
Err, Result, at, debug, debug_error, debug_info, debug_warn, err, error, info, is_matching,
|
Err, Event, Result, at, debug, debug_error, debug_info, debug_warn, err, error, info,
|
||||||
|
is_matching,
|
||||||
matrix::{
|
matrix::{
|
||||||
StateKey,
|
StateKey,
|
||||||
pdu::{PduBuilder, PduEvent, gen_event_id, gen_event_id_canonical_json},
|
pdu::{PduBuilder, PduEvent, gen_event_id, gen_event_id_canonical_json},
|
||||||
|
@ -880,7 +881,7 @@ pub(crate) async fn get_member_events_route(
|
||||||
.ready_filter(|((ty, _), _)| *ty == StateEventType::RoomMember)
|
.ready_filter(|((ty, _), _)| *ty == StateEventType::RoomMember)
|
||||||
.map(at!(1))
|
.map(at!(1))
|
||||||
.ready_filter_map(|pdu| membership_filter(pdu, membership, not_membership))
|
.ready_filter_map(|pdu| membership_filter(pdu, membership, not_membership))
|
||||||
.map(PduEvent::into_member_event)
|
.map(Event::into_format)
|
||||||
.collect()
|
.collect()
|
||||||
.await,
|
.await,
|
||||||
})
|
})
|
||||||
|
|
|
@ -175,7 +175,7 @@ pub(crate) async fn get_message_events_route(
|
||||||
let chunk = events
|
let chunk = events
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(at!(1))
|
.map(at!(1))
|
||||||
.map(PduEvent::into_room_event)
|
.map(Event::into_format)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Ok(get_message_events::v3::Response {
|
Ok(get_message_events::v3::Response {
|
||||||
|
@ -241,7 +241,7 @@ async fn get_member_event(
|
||||||
.rooms
|
.rooms
|
||||||
.state_accessor
|
.state_accessor
|
||||||
.room_state_get(room_id, &StateEventType::RoomMember, user_id.as_str())
|
.room_state_get(room_id, &StateEventType::RoomMember, user_id.as_str())
|
||||||
.map_ok(PduEvent::into_state_event)
|
.map_ok(Event::into_format)
|
||||||
.await
|
.await
|
||||||
.ok()
|
.ok()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use axum::extract::State;
|
use axum::extract::State;
|
||||||
use conduwuit::{
|
use conduwuit::{
|
||||||
Result, at,
|
Result, at,
|
||||||
matrix::pdu::PduCount,
|
matrix::{Event, pdu::PduCount},
|
||||||
utils::{IterStream, ReadyExt, result::FlatOk, stream::WidebandExt},
|
utils::{IterStream, ReadyExt, result::FlatOk, stream::WidebandExt},
|
||||||
};
|
};
|
||||||
use conduwuit_service::{Services, rooms::timeline::PdusIterItem};
|
use conduwuit_service::{Services, rooms::timeline::PdusIterItem};
|
||||||
|
@ -167,7 +167,7 @@ async fn paginate_relations_with_filter(
|
||||||
chunk: events
|
chunk: events
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(at!(1))
|
.map(at!(1))
|
||||||
.map(|pdu| pdu.to_message_like_event())
|
.map(Event::into_format)
|
||||||
.collect(),
|
.collect(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,5 +40,5 @@ pub(crate) async fn get_room_event_route(
|
||||||
|
|
||||||
event.add_age().ok();
|
event.add_age().ok();
|
||||||
|
|
||||||
Ok(get_room_event::v3::Response { event: event.into_room_event() })
|
Ok(get_room_event::v3::Response { event: event.into_format() })
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use axum::extract::State;
|
use axum::extract::State;
|
||||||
use conduwuit::{
|
use conduwuit::{
|
||||||
Err, PduEvent, Result, at,
|
Err, Event, Result, at,
|
||||||
utils::{BoolExt, stream::TryTools},
|
utils::{BoolExt, stream::TryTools},
|
||||||
};
|
};
|
||||||
use futures::TryStreamExt;
|
use futures::TryStreamExt;
|
||||||
|
@ -38,7 +38,7 @@ pub(crate) async fn room_initial_sync_route(
|
||||||
.rooms
|
.rooms
|
||||||
.state_accessor
|
.state_accessor
|
||||||
.room_state_full_pdus(room_id)
|
.room_state_full_pdus(room_id)
|
||||||
.map_ok(PduEvent::into_state_event)
|
.map_ok(Event::into_format)
|
||||||
.try_collect()
|
.try_collect()
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ pub(crate) async fn room_initial_sync_route(
|
||||||
chunk: events
|
chunk: events
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(at!(1))
|
.map(at!(1))
|
||||||
.map(PduEvent::into_room_event)
|
.map(Event::into_format)
|
||||||
.collect(),
|
.collect(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::collections::BTreeMap;
|
||||||
use axum::extract::State;
|
use axum::extract::State;
|
||||||
use conduwuit::{
|
use conduwuit::{
|
||||||
Err, Result, at, is_true,
|
Err, Result, at, is_true,
|
||||||
matrix::pdu::PduEvent,
|
matrix::Event,
|
||||||
result::FlatOk,
|
result::FlatOk,
|
||||||
utils::{IterStream, stream::ReadyExt},
|
utils::{IterStream, stream::ReadyExt},
|
||||||
};
|
};
|
||||||
|
@ -144,7 +144,7 @@ async fn category_room_events(
|
||||||
.map(at!(2))
|
.map(at!(2))
|
||||||
.flatten()
|
.flatten()
|
||||||
.stream()
|
.stream()
|
||||||
.map(PduEvent::into_room_event)
|
.map(Event::into_format)
|
||||||
.map(|result| SearchResult {
|
.map(|result| SearchResult {
|
||||||
rank: None,
|
rank: None,
|
||||||
result: Some(result),
|
result: Some(result),
|
||||||
|
@ -185,7 +185,7 @@ async fn procure_room_state(services: &Services, room_id: &RoomId) -> Result<Roo
|
||||||
.rooms
|
.rooms
|
||||||
.state_accessor
|
.state_accessor
|
||||||
.room_state_full_pdus(room_id)
|
.room_state_full_pdus(room_id)
|
||||||
.map_ok(PduEvent::into_state_event)
|
.map_ok(Event::into_format)
|
||||||
.try_collect()
|
.try_collect()
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use axum::extract::State;
|
use axum::extract::State;
|
||||||
use conduwuit::{
|
use conduwuit::{
|
||||||
Err, Result, err,
|
Err, Result, err,
|
||||||
matrix::pdu::{PduBuilder, PduEvent},
|
matrix::{Event, pdu::PduBuilder},
|
||||||
utils::BoolExt,
|
utils::BoolExt,
|
||||||
};
|
};
|
||||||
use conduwuit_service::Services;
|
use conduwuit_service::Services;
|
||||||
|
@ -21,6 +21,7 @@ use ruma::{
|
||||||
},
|
},
|
||||||
serde::Raw,
|
serde::Raw,
|
||||||
};
|
};
|
||||||
|
use serde_json::json;
|
||||||
|
|
||||||
use crate::{Ruma, RumaResponse};
|
use crate::{Ruma, RumaResponse};
|
||||||
|
|
||||||
|
@ -94,7 +95,7 @@ pub(crate) async fn get_state_events_route(
|
||||||
.rooms
|
.rooms
|
||||||
.state_accessor
|
.state_accessor
|
||||||
.room_state_full_pdus(&body.room_id)
|
.room_state_full_pdus(&body.room_id)
|
||||||
.map_ok(PduEvent::into_state_event)
|
.map_ok(Event::into_format)
|
||||||
.try_collect()
|
.try_collect()
|
||||||
.await?,
|
.await?,
|
||||||
})
|
})
|
||||||
|
@ -145,7 +146,18 @@ pub(crate) async fn get_state_events_for_key_route(
|
||||||
|
|
||||||
Ok(get_state_events_for_key::v3::Response {
|
Ok(get_state_events_for_key::v3::Response {
|
||||||
content: event_format.or(|| event.get_content_as_value()),
|
content: event_format.or(|| event.get_content_as_value()),
|
||||||
event: event_format.then(|| event.into_state_event_value()),
|
event: event_format.then(|| {
|
||||||
|
json!({
|
||||||
|
"content": event.content(),
|
||||||
|
"event_id": event.event_id(),
|
||||||
|
"origin_server_ts": event.origin_server_ts(),
|
||||||
|
"room_id": event.room_id(),
|
||||||
|
"sender": event.sender(),
|
||||||
|
"state_key": event.state_key(),
|
||||||
|
"type": event.kind(),
|
||||||
|
"unsigned": event.unsigned(),
|
||||||
|
})
|
||||||
|
}),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -473,9 +473,7 @@ async fn handle_left_room(
|
||||||
prev_batch: Some(next_batch.to_string()),
|
prev_batch: Some(next_batch.to_string()),
|
||||||
events: Vec::new(),
|
events: Vec::new(),
|
||||||
},
|
},
|
||||||
state: RoomState {
|
state: RoomState { events: vec![event.into_format()] },
|
||||||
events: vec![event.into_sync_state_event()],
|
|
||||||
},
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -559,7 +557,7 @@ async fn handle_left_room(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
left_state_events.push(pdu.into_sync_state_event());
|
left_state_events.push(pdu.into_format());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -755,7 +753,7 @@ async fn load_joined_room(
|
||||||
.wide_filter_map(|item| ignored_filter(services, item, sender_user))
|
.wide_filter_map(|item| ignored_filter(services, item, sender_user))
|
||||||
.map(at!(1))
|
.map(at!(1))
|
||||||
.chain(joined_sender_member.into_iter().stream())
|
.chain(joined_sender_member.into_iter().stream())
|
||||||
.map(|pdu| pdu.to_sync_room_event())
|
.map(Event::into_format)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let account_data_events = services
|
let account_data_events = services
|
||||||
|
@ -877,10 +875,7 @@ async fn load_joined_room(
|
||||||
events: room_events,
|
events: room_events,
|
||||||
},
|
},
|
||||||
state: RoomState {
|
state: RoomState {
|
||||||
events: state_events
|
events: state_events.into_iter().map(Event::into_format).collect(),
|
||||||
.into_iter()
|
|
||||||
.map(PduEvent::into_sync_state_event)
|
|
||||||
.collect(),
|
|
||||||
},
|
},
|
||||||
ephemeral: Ephemeral { events: edus },
|
ephemeral: Ephemeral { events: edus },
|
||||||
unread_thread_notifications: BTreeMap::new(),
|
unread_thread_notifications: BTreeMap::new(),
|
||||||
|
|
|
@ -6,7 +6,7 @@ use std::{
|
||||||
|
|
||||||
use axum::extract::State;
|
use axum::extract::State;
|
||||||
use conduwuit::{
|
use conduwuit::{
|
||||||
Err, Error, PduCount, PduEvent, Result, debug, error, extract_variant,
|
Err, Error, Event, PduCount, PduEvent, Result, at, debug, error, extract_variant,
|
||||||
matrix::TypeStateKey,
|
matrix::TypeStateKey,
|
||||||
utils::{
|
utils::{
|
||||||
BoolExt, IterStream, ReadyExt, TryFutureExtExt,
|
BoolExt, IterStream, ReadyExt, TryFutureExtExt,
|
||||||
|
@ -604,7 +604,8 @@ pub(crate) async fn sync_events_v4_route(
|
||||||
.iter()
|
.iter()
|
||||||
.stream()
|
.stream()
|
||||||
.filter_map(|item| ignored_filter(&services, item.clone(), sender_user))
|
.filter_map(|item| ignored_filter(&services, item.clone(), sender_user))
|
||||||
.map(|(_, pdu)| pdu.to_sync_room_event())
|
.map(at!(1))
|
||||||
|
.map(Event::into_format)
|
||||||
.collect()
|
.collect()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
@ -626,7 +627,7 @@ pub(crate) async fn sync_events_v4_route(
|
||||||
.state_accessor
|
.state_accessor
|
||||||
.room_state_get(room_id, &state.0, &state.1)
|
.room_state_get(room_id, &state.0, &state.1)
|
||||||
.await
|
.await
|
||||||
.map(PduEvent::into_sync_state_event)
|
.map(PduEvent::into_format)
|
||||||
.ok()
|
.ok()
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
|
|
@ -7,11 +7,8 @@ use std::{
|
||||||
|
|
||||||
use axum::extract::State;
|
use axum::extract::State;
|
||||||
use conduwuit::{
|
use conduwuit::{
|
||||||
Err, Error, Result, error, extract_variant, is_equal_to,
|
Err, Error, Result, at, error, extract_variant, is_equal_to,
|
||||||
matrix::{
|
matrix::{Event, TypeStateKey, pdu::PduCount},
|
||||||
TypeStateKey,
|
|
||||||
pdu::{PduCount, PduEvent},
|
|
||||||
},
|
|
||||||
trace,
|
trace,
|
||||||
utils::{
|
utils::{
|
||||||
BoolExt, FutureBoolExt, IterStream, ReadyExt, TryFutureExtExt,
|
BoolExt, FutureBoolExt, IterStream, ReadyExt, TryFutureExtExt,
|
||||||
|
@ -515,7 +512,8 @@ where
|
||||||
.iter()
|
.iter()
|
||||||
.stream()
|
.stream()
|
||||||
.filter_map(|item| ignored_filter(services, item.clone(), sender_user))
|
.filter_map(|item| ignored_filter(services, item.clone(), sender_user))
|
||||||
.map(|(_, pdu)| pdu.to_sync_room_event())
|
.map(at!(1))
|
||||||
|
.map(Event::into_format)
|
||||||
.collect()
|
.collect()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
@ -537,7 +535,7 @@ where
|
||||||
.state_accessor
|
.state_accessor
|
||||||
.room_state_get(room_id, &state.0, &state.1)
|
.room_state_get(room_id, &state.0, &state.1)
|
||||||
.await
|
.await
|
||||||
.map(PduEvent::into_sync_state_event)
|
.map(Event::into_format)
|
||||||
.ok()
|
.ok()
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
use axum::extract::State;
|
use axum::extract::State;
|
||||||
use conduwuit::{
|
use conduwuit::{
|
||||||
Result, at,
|
Result, at,
|
||||||
matrix::pdu::{PduCount, PduEvent},
|
matrix::{
|
||||||
|
Event,
|
||||||
|
pdu::{PduCount, PduEvent},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use ruma::{api::client::threads::get_threads, uint};
|
use ruma::{api::client::threads::get_threads, uint};
|
||||||
|
@ -56,7 +59,7 @@ pub(crate) async fn get_threads_route(
|
||||||
chunk: threads
|
chunk: threads
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(at!(1))
|
.map(at!(1))
|
||||||
.map(PduEvent::into_room_event)
|
.map(Event::into_format)
|
||||||
.collect(),
|
.collect(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,8 @@ use axum::extract::State;
|
||||||
use axum_client_ip::InsecureClientIp;
|
use axum_client_ip::InsecureClientIp;
|
||||||
use base64::{Engine as _, engine::general_purpose};
|
use base64::{Engine as _, engine::general_purpose};
|
||||||
use conduwuit::{
|
use conduwuit::{
|
||||||
Err, Error, PduEvent, Result, err, pdu::gen_event_id, utils, utils::hash::sha256, warn,
|
Err, Error, PduEvent, Result, err, matrix::Event, pdu::gen_event_id, utils,
|
||||||
|
utils::hash::sha256, warn,
|
||||||
};
|
};
|
||||||
use ruma::{
|
use ruma::{
|
||||||
CanonicalJsonValue, OwnedUserId, UserId,
|
CanonicalJsonValue, OwnedUserId, UserId,
|
||||||
|
@ -111,7 +112,7 @@ pub(crate) async fn create_invite_route(
|
||||||
let pdu: PduEvent = serde_json::from_value(event.into())
|
let pdu: PduEvent = serde_json::from_value(event.into())
|
||||||
.map_err(|e| err!(Request(BadJson("Invalid invite event PDU: {e}"))))?;
|
.map_err(|e| err!(Request(BadJson("Invalid invite event PDU: {e}"))))?;
|
||||||
|
|
||||||
invite_state.push(pdu.to_stripped_state_event());
|
invite_state.push(pdu.to_format());
|
||||||
|
|
||||||
// If we are active in the room, the remote server will notify us about the
|
// If we are active in the room, the remote server will notify us about the
|
||||||
// join/invite through /send. If we are not in the room, we need to manually
|
// join/invite through /send. If we are not in the room, we need to manually
|
||||||
|
@ -144,7 +145,7 @@ pub(crate) async fn create_invite_route(
|
||||||
.send_appservice_request(
|
.send_appservice_request(
|
||||||
appservice.registration.clone(),
|
appservice.registration.clone(),
|
||||||
ruma::api::appservice::event::push_events::v1::Request {
|
ruma::api::appservice::event::push_events::v1::Request {
|
||||||
events: vec![pdu.to_room_event()],
|
events: vec![pdu.to_format()],
|
||||||
txn_id: general_purpose::URL_SAFE_NO_PAD
|
txn_id: general_purpose::URL_SAFE_NO_PAD
|
||||||
.encode(sha256::hash(pdu.event_id.as_bytes()))
|
.encode(sha256::hash(pdu.event_id.as_bytes()))
|
||||||
.into(),
|
.into(),
|
||||||
|
|
|
@ -1,63 +1,114 @@
|
||||||
use ruma::{EventId, MilliSecondsSinceUnixEpoch, RoomId, UserId, events::TimelineEventType};
|
mod content;
|
||||||
use serde_json::value::RawValue as RawJsonValue;
|
mod format;
|
||||||
|
mod redact;
|
||||||
|
mod type_ext;
|
||||||
|
|
||||||
|
use ruma::{
|
||||||
|
EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, RoomId, RoomVersionId, UserId,
|
||||||
|
events::TimelineEventType,
|
||||||
|
};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use serde_json::{Value as JsonValue, value::RawValue as RawJsonValue};
|
||||||
|
|
||||||
|
pub use self::type_ext::TypeExt;
|
||||||
|
use super::state_key::StateKey;
|
||||||
|
use crate::Result;
|
||||||
|
|
||||||
/// Abstraction of a PDU so users can have their own PDU types.
|
/// Abstraction of a PDU so users can have their own PDU types.
|
||||||
pub trait Event {
|
pub trait Event {
|
||||||
|
/// Serialize into a Ruma JSON format, consuming.
|
||||||
|
#[inline]
|
||||||
|
fn into_format<T>(self) -> T
|
||||||
|
where
|
||||||
|
T: From<format::Owned<Self>>,
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
format::Owned(self).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Serialize into a Ruma JSON format
|
||||||
|
#[inline]
|
||||||
|
fn to_format<'a, T>(&'a self) -> T
|
||||||
|
where
|
||||||
|
T: From<format::Ref<'a, Self>>,
|
||||||
|
Self: Sized + 'a,
|
||||||
|
{
|
||||||
|
format::Ref(self).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_content_as_value(&self) -> JsonValue
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
content::as_value(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_content<T>(&self) -> Result<T>
|
||||||
|
where
|
||||||
|
for<'de> T: Deserialize<'de>,
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
content::get::<T, _>(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn redacts_id(&self, room_version: &RoomVersionId) -> Option<OwnedEventId>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
redact::redacts_id(self, room_version)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn is_redacted(&self) -> bool
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
redact::is_redacted(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_owned(&self) -> bool;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Canonical properties
|
||||||
|
//
|
||||||
|
|
||||||
|
/// All the authenticating events for this event.
|
||||||
|
fn auth_events(&self) -> impl DoubleEndedIterator<Item = &EventId> + Send + '_;
|
||||||
|
|
||||||
|
/// The event's content.
|
||||||
|
fn content(&self) -> &RawJsonValue;
|
||||||
|
|
||||||
/// The `EventId` of this event.
|
/// The `EventId` of this event.
|
||||||
fn event_id(&self) -> &EventId;
|
fn event_id(&self) -> &EventId;
|
||||||
|
|
||||||
|
/// The time of creation on the originating server.
|
||||||
|
fn origin_server_ts(&self) -> MilliSecondsSinceUnixEpoch;
|
||||||
|
|
||||||
|
/// The events before this event.
|
||||||
|
fn prev_events(&self) -> impl DoubleEndedIterator<Item = &EventId> + Send + '_;
|
||||||
|
|
||||||
|
/// If this event is a redaction event this is the event it redacts.
|
||||||
|
fn redacts(&self) -> Option<&EventId>;
|
||||||
|
|
||||||
/// The `RoomId` of this event.
|
/// The `RoomId` of this event.
|
||||||
fn room_id(&self) -> &RoomId;
|
fn room_id(&self) -> &RoomId;
|
||||||
|
|
||||||
/// The `UserId` of this event.
|
/// The `UserId` of this event.
|
||||||
fn sender(&self) -> &UserId;
|
fn sender(&self) -> &UserId;
|
||||||
|
|
||||||
/// The time of creation on the originating server.
|
|
||||||
fn origin_server_ts(&self) -> MilliSecondsSinceUnixEpoch;
|
|
||||||
|
|
||||||
/// The event type.
|
|
||||||
fn event_type(&self) -> &TimelineEventType;
|
|
||||||
|
|
||||||
/// The event's content.
|
|
||||||
fn content(&self) -> &RawJsonValue;
|
|
||||||
|
|
||||||
/// The state key for this event.
|
/// The state key for this event.
|
||||||
fn state_key(&self) -> Option<&str>;
|
fn state_key(&self) -> Option<&str>;
|
||||||
|
|
||||||
/// The events before this event.
|
/// The event type.
|
||||||
// Requires GATs to avoid boxing (and TAIT for making it convenient).
|
fn kind(&self) -> &TimelineEventType;
|
||||||
fn prev_events(&self) -> impl DoubleEndedIterator<Item = &EventId> + Send + '_;
|
|
||||||
|
|
||||||
/// All the authenticating events for this event.
|
/// Metadata container; peer-trusted only.
|
||||||
// Requires GATs to avoid boxing (and TAIT for making it convenient).
|
fn unsigned(&self) -> Option<&RawJsonValue>;
|
||||||
fn auth_events(&self) -> impl DoubleEndedIterator<Item = &EventId> + Send + '_;
|
|
||||||
|
|
||||||
/// If this event is a redaction event this is the event it redacts.
|
//#[deprecated]
|
||||||
fn redacts(&self) -> Option<&EventId>;
|
#[inline]
|
||||||
}
|
fn event_type(&self) -> &TimelineEventType { self.kind() }
|
||||||
|
|
||||||
impl<T: Event> Event for &T {
|
|
||||||
fn event_id(&self) -> &EventId { (*self).event_id() }
|
|
||||||
|
|
||||||
fn room_id(&self) -> &RoomId { (*self).room_id() }
|
|
||||||
|
|
||||||
fn sender(&self) -> &UserId { (*self).sender() }
|
|
||||||
|
|
||||||
fn origin_server_ts(&self) -> MilliSecondsSinceUnixEpoch { (*self).origin_server_ts() }
|
|
||||||
|
|
||||||
fn event_type(&self) -> &TimelineEventType { (*self).event_type() }
|
|
||||||
|
|
||||||
fn content(&self) -> &RawJsonValue { (*self).content() }
|
|
||||||
|
|
||||||
fn state_key(&self) -> Option<&str> { (*self).state_key() }
|
|
||||||
|
|
||||||
fn prev_events(&self) -> impl DoubleEndedIterator<Item = &EventId> + Send + '_ {
|
|
||||||
(*self).prev_events()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn auth_events(&self) -> impl DoubleEndedIterator<Item = &EventId> + Send + '_ {
|
|
||||||
(*self).auth_events()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn redacts(&self) -> Option<&EventId> { (*self).redacts() }
|
|
||||||
}
|
}
|
||||||
|
|
21
src/core/matrix/event/content.rs
Normal file
21
src/core/matrix/event/content.rs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
use serde::Deserialize;
|
||||||
|
use serde_json::value::Value as JsonValue;
|
||||||
|
|
||||||
|
use super::Event;
|
||||||
|
use crate::{Result, err};
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub(super) fn as_value<E: Event>(event: &E) -> JsonValue {
|
||||||
|
get(event).expect("Failed to represent Event content as JsonValue")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(super) fn get<T, E>(event: &E) -> Result<T>
|
||||||
|
where
|
||||||
|
T: for<'de> Deserialize<'de>,
|
||||||
|
E: Event,
|
||||||
|
{
|
||||||
|
serde_json::from_str(event.content().get())
|
||||||
|
.map_err(|e| err!(Request(BadJson("Failed to deserialize content into type: {e}"))))
|
||||||
|
}
|
219
src/core/matrix/event/format.rs
Normal file
219
src/core/matrix/event/format.rs
Normal file
|
@ -0,0 +1,219 @@
|
||||||
|
use ruma::{
|
||||||
|
events::{
|
||||||
|
AnyMessageLikeEvent, AnyStateEvent, AnyStrippedStateEvent, AnySyncStateEvent,
|
||||||
|
AnySyncTimelineEvent, AnyTimelineEvent, StateEvent, room::member::RoomMemberEventContent,
|
||||||
|
space::child::HierarchySpaceChildEvent,
|
||||||
|
},
|
||||||
|
serde::Raw,
|
||||||
|
};
|
||||||
|
use serde_json::json;
|
||||||
|
|
||||||
|
use super::{Event, redact};
|
||||||
|
|
||||||
|
pub struct Owned<E: Event>(pub(super) E);
|
||||||
|
|
||||||
|
pub struct Ref<'a, E: Event>(pub(super) &'a E);
|
||||||
|
|
||||||
|
impl<E: Event> From<Owned<E>> for Raw<AnySyncTimelineEvent> {
|
||||||
|
fn from(event: Owned<E>) -> Self { Ref(&event.0).into() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, E: Event> From<Ref<'a, E>> for Raw<AnySyncTimelineEvent> {
|
||||||
|
fn from(event: Ref<'a, E>) -> Self {
|
||||||
|
let event = event.0;
|
||||||
|
let (redacts, content) = redact::copy(event);
|
||||||
|
let mut json = json!({
|
||||||
|
"content": content,
|
||||||
|
"event_id": event.event_id(),
|
||||||
|
"origin_server_ts": event.origin_server_ts(),
|
||||||
|
"sender": event.sender(),
|
||||||
|
"type": event.event_type(),
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(redacts) = redacts {
|
||||||
|
json["redacts"] = json!(redacts);
|
||||||
|
}
|
||||||
|
if let Some(state_key) = event.state_key() {
|
||||||
|
json["state_key"] = json!(state_key);
|
||||||
|
}
|
||||||
|
if let Some(unsigned) = event.unsigned() {
|
||||||
|
json["unsigned"] = json!(unsigned);
|
||||||
|
}
|
||||||
|
|
||||||
|
serde_json::from_value(json).expect("Failed to serialize Event value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Event> From<Owned<E>> for Raw<AnyTimelineEvent> {
|
||||||
|
fn from(event: Owned<E>) -> Self { Ref(&event.0).into() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, E: Event> From<Ref<'a, E>> for Raw<AnyTimelineEvent> {
|
||||||
|
fn from(event: Ref<'a, E>) -> Self {
|
||||||
|
let event = event.0;
|
||||||
|
let (redacts, content) = redact::copy(event);
|
||||||
|
let mut json = json!({
|
||||||
|
"content": content,
|
||||||
|
"event_id": event.event_id(),
|
||||||
|
"origin_server_ts": event.origin_server_ts(),
|
||||||
|
"room_id": event.room_id(),
|
||||||
|
"sender": event.sender(),
|
||||||
|
"type": event.kind(),
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(redacts) = redacts {
|
||||||
|
json["redacts"] = json!(redacts);
|
||||||
|
}
|
||||||
|
if let Some(state_key) = event.state_key() {
|
||||||
|
json["state_key"] = json!(state_key);
|
||||||
|
}
|
||||||
|
if let Some(unsigned) = event.unsigned() {
|
||||||
|
json["unsigned"] = json!(unsigned);
|
||||||
|
}
|
||||||
|
|
||||||
|
serde_json::from_value(json).expect("Failed to serialize Event value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Event> From<Owned<E>> for Raw<AnyMessageLikeEvent> {
|
||||||
|
fn from(event: Owned<E>) -> Self { Ref(&event.0).into() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, E: Event> From<Ref<'a, E>> for Raw<AnyMessageLikeEvent> {
|
||||||
|
fn from(event: Ref<'a, E>) -> Self {
|
||||||
|
let event = event.0;
|
||||||
|
let (redacts, content) = redact::copy(event);
|
||||||
|
let mut json = json!({
|
||||||
|
"content": content,
|
||||||
|
"event_id": event.event_id(),
|
||||||
|
"origin_server_ts": event.origin_server_ts(),
|
||||||
|
"room_id": event.room_id(),
|
||||||
|
"sender": event.sender(),
|
||||||
|
"type": event.kind(),
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(redacts) = &redacts {
|
||||||
|
json["redacts"] = json!(redacts);
|
||||||
|
}
|
||||||
|
if let Some(state_key) = event.state_key() {
|
||||||
|
json["state_key"] = json!(state_key);
|
||||||
|
}
|
||||||
|
if let Some(unsigned) = event.unsigned() {
|
||||||
|
json["unsigned"] = json!(unsigned);
|
||||||
|
}
|
||||||
|
|
||||||
|
serde_json::from_value(json).expect("Failed to serialize Event value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Event> From<Owned<E>> for Raw<AnyStateEvent> {
|
||||||
|
fn from(event: Owned<E>) -> Self { Ref(&event.0).into() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, E: Event> From<Ref<'a, E>> for Raw<AnyStateEvent> {
|
||||||
|
fn from(event: Ref<'a, E>) -> Self {
|
||||||
|
let event = event.0;
|
||||||
|
let mut json = json!({
|
||||||
|
"content": event.content(),
|
||||||
|
"event_id": event.event_id(),
|
||||||
|
"origin_server_ts": event.origin_server_ts(),
|
||||||
|
"room_id": event.room_id(),
|
||||||
|
"sender": event.sender(),
|
||||||
|
"state_key": event.state_key(),
|
||||||
|
"type": event.kind(),
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(unsigned) = event.unsigned() {
|
||||||
|
json["unsigned"] = json!(unsigned);
|
||||||
|
}
|
||||||
|
|
||||||
|
serde_json::from_value(json).expect("Failed to serialize Event value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Event> From<Owned<E>> for Raw<AnySyncStateEvent> {
|
||||||
|
fn from(event: Owned<E>) -> Self { Ref(&event.0).into() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, E: Event> From<Ref<'a, E>> for Raw<AnySyncStateEvent> {
|
||||||
|
fn from(event: Ref<'a, E>) -> Self {
|
||||||
|
let event = event.0;
|
||||||
|
let mut json = json!({
|
||||||
|
"content": event.content(),
|
||||||
|
"event_id": event.event_id(),
|
||||||
|
"origin_server_ts": event.origin_server_ts(),
|
||||||
|
"sender": event.sender(),
|
||||||
|
"state_key": event.state_key(),
|
||||||
|
"type": event.kind(),
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(unsigned) = event.unsigned() {
|
||||||
|
json["unsigned"] = json!(unsigned);
|
||||||
|
}
|
||||||
|
|
||||||
|
serde_json::from_value(json).expect("Failed to serialize Event value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Event> From<Owned<E>> for Raw<AnyStrippedStateEvent> {
|
||||||
|
fn from(event: Owned<E>) -> Self { Ref(&event.0).into() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, E: Event> From<Ref<'a, E>> for Raw<AnyStrippedStateEvent> {
|
||||||
|
fn from(event: Ref<'a, E>) -> Self {
|
||||||
|
let event = event.0;
|
||||||
|
let json = json!({
|
||||||
|
"content": event.content(),
|
||||||
|
"sender": event.sender(),
|
||||||
|
"state_key": event.state_key(),
|
||||||
|
"type": event.kind(),
|
||||||
|
});
|
||||||
|
|
||||||
|
serde_json::from_value(json).expect("Failed to serialize Event value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Event> From<Owned<E>> for Raw<HierarchySpaceChildEvent> {
|
||||||
|
fn from(event: Owned<E>) -> Self { Ref(&event.0).into() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, E: Event> From<Ref<'a, E>> for Raw<HierarchySpaceChildEvent> {
|
||||||
|
fn from(event: Ref<'a, E>) -> Self {
|
||||||
|
let event = event.0;
|
||||||
|
let json = json!({
|
||||||
|
"content": event.content(),
|
||||||
|
"origin_server_ts": event.origin_server_ts(),
|
||||||
|
"sender": event.sender(),
|
||||||
|
"state_key": event.state_key(),
|
||||||
|
"type": event.kind(),
|
||||||
|
});
|
||||||
|
|
||||||
|
serde_json::from_value(json).expect("Failed to serialize Event value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Event> From<Owned<E>> for Raw<StateEvent<RoomMemberEventContent>> {
|
||||||
|
fn from(event: Owned<E>) -> Self { Ref(&event.0).into() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, E: Event> From<Ref<'a, E>> for Raw<StateEvent<RoomMemberEventContent>> {
|
||||||
|
fn from(event: Ref<'a, E>) -> Self {
|
||||||
|
let event = event.0;
|
||||||
|
let mut json = json!({
|
||||||
|
"content": event.content(),
|
||||||
|
"event_id": event.event_id(),
|
||||||
|
"origin_server_ts": event.origin_server_ts(),
|
||||||
|
"redacts": event.redacts(),
|
||||||
|
"room_id": event.room_id(),
|
||||||
|
"sender": event.sender(),
|
||||||
|
"state_key": event.state_key(),
|
||||||
|
"type": event.kind(),
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(unsigned) = event.unsigned() {
|
||||||
|
json["unsigned"] = json!(unsigned);
|
||||||
|
}
|
||||||
|
|
||||||
|
serde_json::from_value(json).expect("Failed to serialize Event value")
|
||||||
|
}
|
||||||
|
}
|
86
src/core/matrix/event/redact.rs
Normal file
86
src/core/matrix/event/redact.rs
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
use ruma::{
|
||||||
|
OwnedEventId, RoomVersionId,
|
||||||
|
events::{TimelineEventType, room::redaction::RoomRedactionEventContent},
|
||||||
|
};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use serde_json::value::{RawValue as RawJsonValue, to_raw_value};
|
||||||
|
|
||||||
|
use super::Event;
|
||||||
|
|
||||||
|
/// Copies the `redacts` property of the event to the `content` dict and
|
||||||
|
/// vice-versa.
|
||||||
|
///
|
||||||
|
/// This follows the specification's
|
||||||
|
/// [recommendation](https://spec.matrix.org/v1.10/rooms/v11/#moving-the-redacts-property-of-mroomredaction-events-to-a-content-property):
|
||||||
|
///
|
||||||
|
/// > For backwards-compatibility with older clients, servers should add a
|
||||||
|
/// > redacts property to the top level of m.room.redaction events in when
|
||||||
|
/// > serving such events over the Client-Server API.
|
||||||
|
///
|
||||||
|
/// > For improved compatibility with newer clients, servers should add a
|
||||||
|
/// > redacts property to the content of m.room.redaction events in older
|
||||||
|
/// > room versions when serving such events over the Client-Server API.
|
||||||
|
#[must_use]
|
||||||
|
pub(super) fn copy<E: Event>(event: &E) -> (Option<OwnedEventId>, Box<RawJsonValue>) {
|
||||||
|
if *event.event_type() != TimelineEventType::RoomRedaction {
|
||||||
|
return (event.redacts().map(ToOwned::to_owned), event.content().to_owned());
|
||||||
|
}
|
||||||
|
|
||||||
|
let Ok(mut content) = event.get_content::<RoomRedactionEventContent>() else {
|
||||||
|
return (event.redacts().map(ToOwned::to_owned), event.content().to_owned());
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(redacts) = content.redacts {
|
||||||
|
return (Some(redacts), event.content().to_owned());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(redacts) = event.redacts().map(ToOwned::to_owned) {
|
||||||
|
content.redacts = Some(redacts);
|
||||||
|
return (
|
||||||
|
event.redacts().map(ToOwned::to_owned),
|
||||||
|
to_raw_value(&content).expect("Must be valid, we only added redacts field"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
(event.redacts().map(ToOwned::to_owned), event.content().to_owned())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub(super) fn is_redacted<E: Event>(event: &E) -> bool {
|
||||||
|
let Some(unsigned) = event.unsigned() else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
let Ok(unsigned) = ExtractRedactedBecause::deserialize(unsigned) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned.redacted_because.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub(super) fn redacts_id<E: Event>(
|
||||||
|
event: &E,
|
||||||
|
room_version: &RoomVersionId,
|
||||||
|
) -> Option<OwnedEventId> {
|
||||||
|
use RoomVersionId::*;
|
||||||
|
|
||||||
|
if *event.kind() != TimelineEventType::RoomRedaction {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
match *room_version {
|
||||||
|
| V1 | V2 | V3 | V4 | V5 | V6 | V7 | V8 | V9 | V10 =>
|
||||||
|
event.redacts().map(ToOwned::to_owned),
|
||||||
|
| _ =>
|
||||||
|
event
|
||||||
|
.get_content::<RoomRedactionEventContent>()
|
||||||
|
.ok()?
|
||||||
|
.redacts,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct ExtractRedactedBecause {
|
||||||
|
redacted_because: Option<serde::de::IgnoredAny>,
|
||||||
|
}
|
32
src/core/matrix/event/type_ext.rs
Normal file
32
src/core/matrix/event/type_ext.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
use ruma::events::{StateEventType, TimelineEventType};
|
||||||
|
|
||||||
|
use super::StateKey;
|
||||||
|
|
||||||
|
/// Convenience trait for adding event type plus state key to state maps.
|
||||||
|
pub trait TypeExt {
|
||||||
|
fn with_state_key(self, state_key: impl Into<StateKey>) -> (StateEventType, StateKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypeExt for StateEventType {
|
||||||
|
fn with_state_key(self, state_key: impl Into<StateKey>) -> (StateEventType, StateKey) {
|
||||||
|
(self, state_key.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypeExt for &StateEventType {
|
||||||
|
fn with_state_key(self, state_key: impl Into<StateKey>) -> (StateEventType, StateKey) {
|
||||||
|
(self.clone(), state_key.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypeExt for TimelineEventType {
|
||||||
|
fn with_state_key(self, state_key: impl Into<StateKey>) -> (StateEventType, StateKey) {
|
||||||
|
(self.into(), state_key.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypeExt for &TimelineEventType {
|
||||||
|
fn with_state_key(self, state_key: impl Into<StateKey>) -> (StateEventType, StateKey) {
|
||||||
|
(self.clone().into(), state_key.into())
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,8 +2,10 @@
|
||||||
|
|
||||||
pub mod event;
|
pub mod event;
|
||||||
pub mod pdu;
|
pub mod pdu;
|
||||||
|
pub mod state_key;
|
||||||
pub mod state_res;
|
pub mod state_res;
|
||||||
|
|
||||||
pub use event::Event;
|
pub use event::{Event, TypeExt as EventTypeExt};
|
||||||
pub use pdu::{PduBuilder, PduCount, PduEvent, PduId, RawPduId, StateKey};
|
pub use pdu::{Pdu, PduBuilder, PduCount, PduEvent, PduId, RawPduId, ShortId};
|
||||||
pub use state_res::{EventTypeExt, RoomVersion, StateMap, TypeStateKey};
|
pub use state_key::StateKey;
|
||||||
|
pub use state_res::{RoomVersion, StateMap, TypeStateKey};
|
||||||
|
|
|
@ -7,8 +7,6 @@ mod id;
|
||||||
mod raw_id;
|
mod raw_id;
|
||||||
mod redact;
|
mod redact;
|
||||||
mod relation;
|
mod relation;
|
||||||
mod state_key;
|
|
||||||
mod strip;
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
mod unsigned;
|
mod unsigned;
|
||||||
|
@ -27,37 +25,50 @@ pub use self::{
|
||||||
builder::{Builder, Builder as PduBuilder},
|
builder::{Builder, Builder as PduBuilder},
|
||||||
count::Count,
|
count::Count,
|
||||||
event_id::*,
|
event_id::*,
|
||||||
id::*,
|
id::{ShortId, *},
|
||||||
raw_id::*,
|
raw_id::*,
|
||||||
state_key::{ShortStateKey, StateKey},
|
|
||||||
};
|
};
|
||||||
use super::Event;
|
use super::{Event, StateKey};
|
||||||
use crate::Result;
|
use crate::Result;
|
||||||
|
|
||||||
/// Persistent Data Unit (Event)
|
/// Persistent Data Unit (Event)
|
||||||
#[derive(Clone, Deserialize, Serialize, Debug)]
|
#[derive(Clone, Deserialize, Serialize, Debug)]
|
||||||
pub struct Pdu {
|
pub struct Pdu {
|
||||||
pub event_id: OwnedEventId,
|
pub event_id: OwnedEventId,
|
||||||
|
|
||||||
pub room_id: OwnedRoomId,
|
pub room_id: OwnedRoomId,
|
||||||
|
|
||||||
pub sender: OwnedUserId,
|
pub sender: OwnedUserId,
|
||||||
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub origin: Option<OwnedServerName>,
|
pub origin: Option<OwnedServerName>,
|
||||||
|
|
||||||
pub origin_server_ts: UInt,
|
pub origin_server_ts: UInt,
|
||||||
|
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
pub kind: TimelineEventType,
|
pub kind: TimelineEventType,
|
||||||
|
|
||||||
pub content: Box<RawJsonValue>,
|
pub content: Box<RawJsonValue>,
|
||||||
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub state_key: Option<StateKey>,
|
pub state_key: Option<StateKey>,
|
||||||
|
|
||||||
pub prev_events: Vec<OwnedEventId>,
|
pub prev_events: Vec<OwnedEventId>,
|
||||||
|
|
||||||
pub depth: UInt,
|
pub depth: UInt,
|
||||||
|
|
||||||
pub auth_events: Vec<OwnedEventId>,
|
pub auth_events: Vec<OwnedEventId>,
|
||||||
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub redacts: Option<OwnedEventId>,
|
pub redacts: Option<OwnedEventId>,
|
||||||
|
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub unsigned: Option<Box<RawJsonValue>>,
|
pub unsigned: Option<Box<RawJsonValue>>,
|
||||||
|
|
||||||
pub hashes: EventHash,
|
pub hashes: EventHash,
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
||||||
// BTreeMap<Box<ServerName>, BTreeMap<ServerSigningKeyId, String>>
|
// BTreeMap<Box<ServerName>, BTreeMap<ServerSigningKeyId, String>>
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub signatures: Option<Box<RawJsonValue>>,
|
pub signatures: Option<Box<RawJsonValue>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,31 +90,91 @@ impl Pdu {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Event for Pdu {
|
impl Event for Pdu {
|
||||||
fn event_id(&self) -> &EventId { &self.event_id }
|
#[inline]
|
||||||
|
|
||||||
fn room_id(&self) -> &RoomId { &self.room_id }
|
|
||||||
|
|
||||||
fn sender(&self) -> &UserId { &self.sender }
|
|
||||||
|
|
||||||
fn event_type(&self) -> &TimelineEventType { &self.kind }
|
|
||||||
|
|
||||||
fn content(&self) -> &RawJsonValue { &self.content }
|
|
||||||
|
|
||||||
fn origin_server_ts(&self) -> MilliSecondsSinceUnixEpoch {
|
|
||||||
MilliSecondsSinceUnixEpoch(self.origin_server_ts)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn state_key(&self) -> Option<&str> { self.state_key.as_deref() }
|
|
||||||
|
|
||||||
fn prev_events(&self) -> impl DoubleEndedIterator<Item = &EventId> + Send + '_ {
|
|
||||||
self.prev_events.iter().map(AsRef::as_ref)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn auth_events(&self) -> impl DoubleEndedIterator<Item = &EventId> + Send + '_ {
|
fn auth_events(&self) -> impl DoubleEndedIterator<Item = &EventId> + Send + '_ {
|
||||||
self.auth_events.iter().map(AsRef::as_ref)
|
self.auth_events.iter().map(AsRef::as_ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn content(&self) -> &RawJsonValue { &self.content }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn event_id(&self) -> &EventId { &self.event_id }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn origin_server_ts(&self) -> MilliSecondsSinceUnixEpoch {
|
||||||
|
MilliSecondsSinceUnixEpoch(self.origin_server_ts)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn prev_events(&self) -> impl DoubleEndedIterator<Item = &EventId> + Send + '_ {
|
||||||
|
self.prev_events.iter().map(AsRef::as_ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn redacts(&self) -> Option<&EventId> { self.redacts.as_deref() }
|
fn redacts(&self) -> Option<&EventId> { self.redacts.as_deref() }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn room_id(&self) -> &RoomId { &self.room_id }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn sender(&self) -> &UserId { &self.sender }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn state_key(&self) -> Option<&str> { self.state_key.as_deref() }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn kind(&self) -> &TimelineEventType { &self.kind }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn unsigned(&self) -> Option<&RawJsonValue> { self.unsigned.as_deref() }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn is_owned(&self) -> bool { true }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Event for &Pdu {
|
||||||
|
#[inline]
|
||||||
|
fn auth_events(&self) -> impl DoubleEndedIterator<Item = &EventId> + Send + '_ {
|
||||||
|
self.auth_events.iter().map(AsRef::as_ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn content(&self) -> &RawJsonValue { &self.content }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn event_id(&self) -> &EventId { &self.event_id }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn origin_server_ts(&self) -> MilliSecondsSinceUnixEpoch {
|
||||||
|
MilliSecondsSinceUnixEpoch(self.origin_server_ts)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn prev_events(&self) -> impl DoubleEndedIterator<Item = &EventId> + Send + '_ {
|
||||||
|
self.prev_events.iter().map(AsRef::as_ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn redacts(&self) -> Option<&EventId> { self.redacts.as_deref() }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn room_id(&self) -> &RoomId { &self.room_id }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn sender(&self) -> &UserId { &self.sender }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn state_key(&self) -> Option<&str> { self.state_key.as_deref() }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn kind(&self) -> &TimelineEventType { &self.kind }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn unsigned(&self) -> Option<&RawJsonValue> { self.unsigned.as_deref() }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn is_owned(&self) -> bool { false }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prevent derived equality which wouldn't limit itself to event_id
|
/// Prevent derived equality which wouldn't limit itself to event_id
|
||||||
|
|
|
@ -3,6 +3,7 @@ use crate::utils::u64_from_u8x8;
|
||||||
|
|
||||||
pub type ShortRoomId = ShortId;
|
pub type ShortRoomId = ShortId;
|
||||||
pub type ShortEventId = ShortId;
|
pub type ShortEventId = ShortId;
|
||||||
|
pub type ShortStateKey = ShortId;
|
||||||
pub type ShortId = u64;
|
pub type ShortId = u64;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
|
|
@ -1,117 +1,29 @@
|
||||||
use ruma::{
|
use ruma::{RoomVersionId, canonical_json::redact_content_in_place};
|
||||||
OwnedEventId, RoomVersionId,
|
use serde_json::{json, value::to_raw_value};
|
||||||
canonical_json::redact_content_in_place,
|
|
||||||
events::{TimelineEventType, room::redaction::RoomRedactionEventContent},
|
|
||||||
};
|
|
||||||
use serde::Deserialize;
|
|
||||||
use serde_json::{
|
|
||||||
json,
|
|
||||||
value::{RawValue as RawJsonValue, to_raw_value},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{Error, Result, implement};
|
use crate::{Error, Result, err, implement};
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct ExtractRedactedBecause {
|
|
||||||
redacted_because: Option<serde::de::IgnoredAny>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[implement(super::Pdu)]
|
#[implement(super::Pdu)]
|
||||||
pub fn redact(&mut self, room_version_id: &RoomVersionId, reason: &Self) -> Result {
|
pub fn redact(&mut self, room_version_id: &RoomVersionId, reason: &Self) -> Result {
|
||||||
self.unsigned = None;
|
self.unsigned = None;
|
||||||
|
|
||||||
let mut content = serde_json::from_str(self.content.get())
|
let mut content = serde_json::from_str(self.content.get())
|
||||||
.map_err(|_| Error::bad_database("PDU in db has invalid content."))?;
|
.map_err(|e| err!(Request(BadJson("Failed to deserialize content into type: {e}"))))?;
|
||||||
|
|
||||||
redact_content_in_place(&mut content, room_version_id, self.kind.to_string())
|
redact_content_in_place(&mut content, room_version_id, self.kind.to_string())
|
||||||
.map_err(|e| Error::Redaction(self.sender.server_name().to_owned(), e))?;
|
.map_err(|e| Error::Redaction(self.sender.server_name().to_owned(), e))?;
|
||||||
|
|
||||||
self.unsigned = Some(
|
let reason = serde_json::to_value(reason).expect("Failed to preserialize reason");
|
||||||
to_raw_value(&json!({
|
|
||||||
"redacted_because": serde_json::to_value(reason).expect("to_value(Pdu) always works")
|
|
||||||
}))
|
|
||||||
.expect("to string always works"),
|
|
||||||
);
|
|
||||||
|
|
||||||
self.content = to_raw_value(&content).expect("to string always works");
|
let redacted_because = json!({
|
||||||
|
"redacted_because": reason,
|
||||||
|
});
|
||||||
|
|
||||||
|
self.unsigned = to_raw_value(&redacted_because)
|
||||||
|
.expect("Failed to serialize unsigned")
|
||||||
|
.into();
|
||||||
|
|
||||||
|
self.content = to_raw_value(&content).expect("Failed to serialize content");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[implement(super::Pdu)]
|
|
||||||
#[must_use]
|
|
||||||
pub fn is_redacted(&self) -> bool {
|
|
||||||
let Some(unsigned) = &self.unsigned else {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
let Ok(unsigned) = ExtractRedactedBecause::deserialize(&**unsigned) else {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
unsigned.redacted_because.is_some()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Copies the `redacts` property of the event to the `content` dict and
|
|
||||||
/// vice-versa.
|
|
||||||
///
|
|
||||||
/// This follows the specification's
|
|
||||||
/// [recommendation](https://spec.matrix.org/v1.10/rooms/v11/#moving-the-redacts-property-of-mroomredaction-events-to-a-content-property):
|
|
||||||
///
|
|
||||||
/// > For backwards-compatibility with older clients, servers should add a
|
|
||||||
/// > redacts
|
|
||||||
/// > property to the top level of m.room.redaction events in when serving
|
|
||||||
/// > such events
|
|
||||||
/// > over the Client-Server API.
|
|
||||||
///
|
|
||||||
/// > For improved compatibility with newer clients, servers should add a
|
|
||||||
/// > redacts property
|
|
||||||
/// > to the content of m.room.redaction events in older room versions when
|
|
||||||
/// > serving
|
|
||||||
/// > such events over the Client-Server API.
|
|
||||||
#[implement(super::Pdu)]
|
|
||||||
#[must_use]
|
|
||||||
pub fn copy_redacts(&self) -> (Option<OwnedEventId>, Box<RawJsonValue>) {
|
|
||||||
if self.kind == TimelineEventType::RoomRedaction {
|
|
||||||
if let Ok(mut content) =
|
|
||||||
serde_json::from_str::<RoomRedactionEventContent>(self.content.get())
|
|
||||||
{
|
|
||||||
match content.redacts {
|
|
||||||
| Some(redacts) => {
|
|
||||||
return (Some(redacts), self.content.clone());
|
|
||||||
},
|
|
||||||
| _ => match self.redacts.clone() {
|
|
||||||
| Some(redacts) => {
|
|
||||||
content.redacts = Some(redacts);
|
|
||||||
return (
|
|
||||||
self.redacts.clone(),
|
|
||||||
to_raw_value(&content)
|
|
||||||
.expect("Must be valid, we only added redacts field"),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
| _ => {},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(self.redacts.clone(), self.content.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[implement(super::Pdu)]
|
|
||||||
#[must_use]
|
|
||||||
pub fn redacts_id(&self, room_version: &RoomVersionId) -> Option<OwnedEventId> {
|
|
||||||
use RoomVersionId::*;
|
|
||||||
|
|
||||||
if self.kind != TimelineEventType::RoomRedaction {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
match *room_version {
|
|
||||||
| V1 | V2 | V3 | V4 | V5 | V6 | V7 | V8 | V9 | V10 => self.redacts.clone(),
|
|
||||||
| _ =>
|
|
||||||
self.get_content::<RoomRedactionEventContent>()
|
|
||||||
.ok()?
|
|
||||||
.redacts,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,257 +0,0 @@
|
||||||
use ruma::{
|
|
||||||
events::{
|
|
||||||
AnyMessageLikeEvent, AnyStateEvent, AnyStrippedStateEvent, AnySyncStateEvent,
|
|
||||||
AnySyncTimelineEvent, AnyTimelineEvent, StateEvent, room::member::RoomMemberEventContent,
|
|
||||||
space::child::HierarchySpaceChildEvent,
|
|
||||||
},
|
|
||||||
serde::Raw,
|
|
||||||
};
|
|
||||||
use serde_json::{json, value::Value as JsonValue};
|
|
||||||
|
|
||||||
use crate::implement;
|
|
||||||
|
|
||||||
#[implement(super::Pdu)]
|
|
||||||
#[must_use]
|
|
||||||
#[inline]
|
|
||||||
pub fn into_room_event(self) -> Raw<AnyTimelineEvent> { self.to_room_event() }
|
|
||||||
|
|
||||||
#[implement(super::Pdu)]
|
|
||||||
#[must_use]
|
|
||||||
pub fn to_room_event(&self) -> Raw<AnyTimelineEvent> {
|
|
||||||
let value = self.to_room_event_value();
|
|
||||||
serde_json::from_value(value).expect("Failed to serialize Event value")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[implement(super::Pdu)]
|
|
||||||
#[must_use]
|
|
||||||
#[inline]
|
|
||||||
pub fn to_room_event_value(&self) -> JsonValue {
|
|
||||||
let (redacts, content) = self.copy_redacts();
|
|
||||||
let mut json = json!({
|
|
||||||
"content": content,
|
|
||||||
"type": self.kind,
|
|
||||||
"event_id": self.event_id,
|
|
||||||
"sender": self.sender,
|
|
||||||
"origin_server_ts": self.origin_server_ts,
|
|
||||||
"room_id": self.room_id,
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Some(unsigned) = &self.unsigned {
|
|
||||||
json["unsigned"] = json!(unsigned);
|
|
||||||
}
|
|
||||||
if let Some(state_key) = &self.state_key {
|
|
||||||
json["state_key"] = json!(state_key);
|
|
||||||
}
|
|
||||||
if let Some(redacts) = &redacts {
|
|
||||||
json["redacts"] = json!(redacts);
|
|
||||||
}
|
|
||||||
|
|
||||||
json
|
|
||||||
}
|
|
||||||
|
|
||||||
#[implement(super::Pdu)]
|
|
||||||
#[must_use]
|
|
||||||
#[inline]
|
|
||||||
pub fn into_message_like_event(self) -> Raw<AnyMessageLikeEvent> { self.to_message_like_event() }
|
|
||||||
|
|
||||||
#[implement(super::Pdu)]
|
|
||||||
#[must_use]
|
|
||||||
pub fn to_message_like_event(&self) -> Raw<AnyMessageLikeEvent> {
|
|
||||||
let value = self.to_message_like_event_value();
|
|
||||||
serde_json::from_value(value).expect("Failed to serialize Event value")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[implement(super::Pdu)]
|
|
||||||
#[must_use]
|
|
||||||
#[inline]
|
|
||||||
pub fn to_message_like_event_value(&self) -> JsonValue {
|
|
||||||
let (redacts, content) = self.copy_redacts();
|
|
||||||
let mut json = json!({
|
|
||||||
"content": content,
|
|
||||||
"type": self.kind,
|
|
||||||
"event_id": self.event_id,
|
|
||||||
"sender": self.sender,
|
|
||||||
"origin_server_ts": self.origin_server_ts,
|
|
||||||
"room_id": self.room_id,
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Some(unsigned) = &self.unsigned {
|
|
||||||
json["unsigned"] = json!(unsigned);
|
|
||||||
}
|
|
||||||
if let Some(state_key) = &self.state_key {
|
|
||||||
json["state_key"] = json!(state_key);
|
|
||||||
}
|
|
||||||
if let Some(redacts) = &redacts {
|
|
||||||
json["redacts"] = json!(redacts);
|
|
||||||
}
|
|
||||||
|
|
||||||
json
|
|
||||||
}
|
|
||||||
|
|
||||||
#[implement(super::Pdu)]
|
|
||||||
#[must_use]
|
|
||||||
#[inline]
|
|
||||||
pub fn into_sync_room_event(self) -> Raw<AnySyncTimelineEvent> { self.to_sync_room_event() }
|
|
||||||
|
|
||||||
#[implement(super::Pdu)]
|
|
||||||
#[must_use]
|
|
||||||
pub fn to_sync_room_event(&self) -> Raw<AnySyncTimelineEvent> {
|
|
||||||
let value = self.to_sync_room_event_value();
|
|
||||||
serde_json::from_value(value).expect("Failed to serialize Event value")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[implement(super::Pdu)]
|
|
||||||
#[must_use]
|
|
||||||
#[inline]
|
|
||||||
pub fn to_sync_room_event_value(&self) -> JsonValue {
|
|
||||||
let (redacts, content) = self.copy_redacts();
|
|
||||||
let mut json = json!({
|
|
||||||
"content": content,
|
|
||||||
"type": self.kind,
|
|
||||||
"event_id": self.event_id,
|
|
||||||
"sender": self.sender,
|
|
||||||
"origin_server_ts": self.origin_server_ts,
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Some(unsigned) = &self.unsigned {
|
|
||||||
json["unsigned"] = json!(unsigned);
|
|
||||||
}
|
|
||||||
if let Some(state_key) = &self.state_key {
|
|
||||||
json["state_key"] = json!(state_key);
|
|
||||||
}
|
|
||||||
if let Some(redacts) = &redacts {
|
|
||||||
json["redacts"] = json!(redacts);
|
|
||||||
}
|
|
||||||
|
|
||||||
json
|
|
||||||
}
|
|
||||||
|
|
||||||
#[implement(super::Pdu)]
|
|
||||||
#[must_use]
|
|
||||||
pub fn into_state_event(self) -> Raw<AnyStateEvent> {
|
|
||||||
let value = self.into_state_event_value();
|
|
||||||
serde_json::from_value(value).expect("Failed to serialize Event value")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[implement(super::Pdu)]
|
|
||||||
#[must_use]
|
|
||||||
#[inline]
|
|
||||||
pub fn into_state_event_value(self) -> JsonValue {
|
|
||||||
let mut json = json!({
|
|
||||||
"content": self.content,
|
|
||||||
"type": self.kind,
|
|
||||||
"event_id": self.event_id,
|
|
||||||
"sender": self.sender,
|
|
||||||
"origin_server_ts": self.origin_server_ts,
|
|
||||||
"room_id": self.room_id,
|
|
||||||
"state_key": self.state_key,
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Some(unsigned) = self.unsigned {
|
|
||||||
json["unsigned"] = json!(unsigned);
|
|
||||||
}
|
|
||||||
|
|
||||||
json
|
|
||||||
}
|
|
||||||
|
|
||||||
#[implement(super::Pdu)]
|
|
||||||
#[must_use]
|
|
||||||
pub fn into_sync_state_event(self) -> Raw<AnySyncStateEvent> {
|
|
||||||
let value = self.into_sync_state_event_value();
|
|
||||||
serde_json::from_value(value).expect("Failed to serialize Event value")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[implement(super::Pdu)]
|
|
||||||
#[must_use]
|
|
||||||
#[inline]
|
|
||||||
pub fn into_sync_state_event_value(self) -> JsonValue {
|
|
||||||
let mut json = json!({
|
|
||||||
"content": self.content,
|
|
||||||
"type": self.kind,
|
|
||||||
"event_id": self.event_id,
|
|
||||||
"sender": self.sender,
|
|
||||||
"origin_server_ts": self.origin_server_ts,
|
|
||||||
"state_key": self.state_key,
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Some(unsigned) = &self.unsigned {
|
|
||||||
json["unsigned"] = json!(unsigned);
|
|
||||||
}
|
|
||||||
|
|
||||||
json
|
|
||||||
}
|
|
||||||
|
|
||||||
#[implement(super::Pdu)]
|
|
||||||
#[must_use]
|
|
||||||
#[inline]
|
|
||||||
pub fn into_stripped_state_event(self) -> Raw<AnyStrippedStateEvent> {
|
|
||||||
self.to_stripped_state_event()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[implement(super::Pdu)]
|
|
||||||
#[must_use]
|
|
||||||
pub fn to_stripped_state_event(&self) -> Raw<AnyStrippedStateEvent> {
|
|
||||||
let value = self.to_stripped_state_event_value();
|
|
||||||
serde_json::from_value(value).expect("Failed to serialize Event value")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[implement(super::Pdu)]
|
|
||||||
#[must_use]
|
|
||||||
#[inline]
|
|
||||||
pub fn to_stripped_state_event_value(&self) -> JsonValue {
|
|
||||||
json!({
|
|
||||||
"content": self.content,
|
|
||||||
"type": self.kind,
|
|
||||||
"sender": self.sender,
|
|
||||||
"state_key": self.state_key,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[implement(super::Pdu)]
|
|
||||||
#[must_use]
|
|
||||||
pub fn into_stripped_spacechild_state_event(self) -> Raw<HierarchySpaceChildEvent> {
|
|
||||||
let value = self.into_stripped_spacechild_state_event_value();
|
|
||||||
serde_json::from_value(value).expect("Failed to serialize Event value")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[implement(super::Pdu)]
|
|
||||||
#[must_use]
|
|
||||||
#[inline]
|
|
||||||
pub fn into_stripped_spacechild_state_event_value(self) -> JsonValue {
|
|
||||||
json!({
|
|
||||||
"content": self.content,
|
|
||||||
"type": self.kind,
|
|
||||||
"sender": self.sender,
|
|
||||||
"state_key": self.state_key,
|
|
||||||
"origin_server_ts": self.origin_server_ts,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[implement(super::Pdu)]
|
|
||||||
#[must_use]
|
|
||||||
pub fn into_member_event(self) -> Raw<StateEvent<RoomMemberEventContent>> {
|
|
||||||
let value = self.into_member_event_value();
|
|
||||||
serde_json::from_value(value).expect("Failed to serialize Event value")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[implement(super::Pdu)]
|
|
||||||
#[must_use]
|
|
||||||
#[inline]
|
|
||||||
pub fn into_member_event_value(self) -> JsonValue {
|
|
||||||
let mut json = json!({
|
|
||||||
"content": self.content,
|
|
||||||
"type": self.kind,
|
|
||||||
"event_id": self.event_id,
|
|
||||||
"sender": self.sender,
|
|
||||||
"origin_server_ts": self.origin_server_ts,
|
|
||||||
"redacts": self.redacts,
|
|
||||||
"room_id": self.room_id,
|
|
||||||
"state_key": self.state_key,
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Some(unsigned) = self.unsigned {
|
|
||||||
json["unsigned"] = json!(unsigned);
|
|
||||||
}
|
|
||||||
|
|
||||||
json
|
|
||||||
}
|
|
|
@ -1,8 +1,5 @@
|
||||||
use smallstr::SmallString;
|
use smallstr::SmallString;
|
||||||
|
|
||||||
use super::ShortId;
|
|
||||||
|
|
||||||
pub type StateKey = SmallString<[u8; INLINE_SIZE]>;
|
pub type StateKey = SmallString<[u8; INLINE_SIZE]>;
|
||||||
pub type ShortStateKey = ShortId;
|
|
||||||
|
|
||||||
const INLINE_SIZE: usize = 48;
|
const INLINE_SIZE: usize = 48;
|
|
@ -13,7 +13,6 @@ use ruma::{
|
||||||
EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, RoomId, RoomVersionId, Signatures, UserId,
|
EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, RoomId, RoomVersionId, Signatures, UserId,
|
||||||
events::{
|
events::{
|
||||||
StateEventType, TimelineEventType,
|
StateEventType, TimelineEventType,
|
||||||
pdu::{EventHash, Pdu, RoomV3Pdu},
|
|
||||||
room::{
|
room::{
|
||||||
join_rules::{JoinRule, RoomJoinRulesEventContent},
|
join_rules::{JoinRule, RoomJoinRulesEventContent},
|
||||||
member::{MembershipState, RoomMemberEventContent},
|
member::{MembershipState, RoomMemberEventContent},
|
||||||
|
@ -26,8 +25,10 @@ use serde_json::{
|
||||||
value::{RawValue as RawJsonValue, to_raw_value as to_raw_json_value},
|
value::{RawValue as RawJsonValue, to_raw_value as to_raw_json_value},
|
||||||
};
|
};
|
||||||
|
|
||||||
use self::event::PduEvent;
|
use crate::{
|
||||||
use crate::state_res::{self as state_res, Error, Event, Result, StateMap};
|
matrix::{Event, Pdu, pdu::EventHash},
|
||||||
|
state_res::{self as state_res, Error, Result, StateMap},
|
||||||
|
};
|
||||||
|
|
||||||
static SERVER_TIMESTAMP: AtomicU64 = AtomicU64::new(0);
|
static SERVER_TIMESTAMP: AtomicU64 = AtomicU64::new(0);
|
||||||
|
|
||||||
|
@ -60,7 +61,7 @@ fn resolution_shallow_auth_chain(c: &mut test::Bencher) {
|
||||||
c.iter(|| async {
|
c.iter(|| async {
|
||||||
let ev_map = store.0.clone();
|
let ev_map = store.0.clone();
|
||||||
let state_sets = [&state_at_bob, &state_at_charlie];
|
let state_sets = [&state_at_bob, &state_at_charlie];
|
||||||
let fetch = |id: OwnedEventId| ready(ev_map.get(&id).clone());
|
let fetch = |id: OwnedEventId| ready(ev_map.get(&id).map(ToOwned::to_owned));
|
||||||
let exists = |id: OwnedEventId| ready(ev_map.get(&id).is_some());
|
let exists = |id: OwnedEventId| ready(ev_map.get(&id).is_some());
|
||||||
let auth_chain_sets: Vec<HashSet<_>> = state_sets
|
let auth_chain_sets: Vec<HashSet<_>> = state_sets
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -142,7 +143,7 @@ fn resolve_deeper_event_set(c: &mut test::Bencher) {
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let fetch = |id: OwnedEventId| ready(inner.get(&id).clone());
|
let fetch = |id: OwnedEventId| ready(inner.get(&id).map(ToOwned::to_owned));
|
||||||
let exists = |id: OwnedEventId| ready(inner.get(&id).is_some());
|
let exists = |id: OwnedEventId| ready(inner.get(&id).is_some());
|
||||||
let _ = match state_res::resolve(
|
let _ = match state_res::resolve(
|
||||||
&RoomVersionId::V6,
|
&RoomVersionId::V6,
|
||||||
|
@ -246,7 +247,7 @@ impl<E: Event + Clone> TestStore<E> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestStore<PduEvent> {
|
impl TestStore<Pdu> {
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
fn set_up(
|
fn set_up(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -380,7 +381,7 @@ fn to_pdu_event<S>(
|
||||||
content: Box<RawJsonValue>,
|
content: Box<RawJsonValue>,
|
||||||
auth_events: &[S],
|
auth_events: &[S],
|
||||||
prev_events: &[S],
|
prev_events: &[S],
|
||||||
) -> PduEvent
|
) -> Pdu
|
||||||
where
|
where
|
||||||
S: AsRef<str>,
|
S: AsRef<str>,
|
||||||
{
|
{
|
||||||
|
@ -403,30 +404,28 @@ where
|
||||||
.map(event_id)
|
.map(event_id)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let state_key = state_key.map(ToOwned::to_owned);
|
Pdu {
|
||||||
PduEvent {
|
|
||||||
event_id: id.try_into().unwrap(),
|
event_id: id.try_into().unwrap(),
|
||||||
rest: Pdu::RoomV3Pdu(RoomV3Pdu {
|
room_id: room_id().to_owned(),
|
||||||
room_id: room_id().to_owned(),
|
sender: sender.to_owned(),
|
||||||
sender: sender.to_owned(),
|
origin_server_ts: ts.try_into().unwrap(),
|
||||||
origin_server_ts: MilliSecondsSinceUnixEpoch(ts.try_into().unwrap()),
|
state_key: state_key.map(Into::into),
|
||||||
state_key,
|
kind: ev_type,
|
||||||
kind: ev_type,
|
content,
|
||||||
content,
|
origin: None,
|
||||||
redacts: None,
|
redacts: None,
|
||||||
unsigned: btreemap! {},
|
unsigned: None,
|
||||||
auth_events,
|
auth_events,
|
||||||
prev_events,
|
prev_events,
|
||||||
depth: uint!(0),
|
depth: uint!(0),
|
||||||
hashes: EventHash::new(String::new()),
|
hashes: EventHash { sha256: String::new() },
|
||||||
signatures: Signatures::new(),
|
signatures: None,
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// all graphs start with these input events
|
// all graphs start with these input events
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn INITIAL_EVENTS() -> HashMap<OwnedEventId, PduEvent> {
|
fn INITIAL_EVENTS() -> HashMap<OwnedEventId, Pdu> {
|
||||||
vec![
|
vec![
|
||||||
to_pdu_event::<&EventId>(
|
to_pdu_event::<&EventId>(
|
||||||
"CREATE",
|
"CREATE",
|
||||||
|
@ -508,7 +507,7 @@ fn INITIAL_EVENTS() -> HashMap<OwnedEventId, PduEvent> {
|
||||||
|
|
||||||
// all graphs start with these input events
|
// all graphs start with these input events
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn BAN_STATE_SET() -> HashMap<OwnedEventId, PduEvent> {
|
fn BAN_STATE_SET() -> HashMap<OwnedEventId, Pdu> {
|
||||||
vec![
|
vec![
|
||||||
to_pdu_event(
|
to_pdu_event(
|
||||||
"PA",
|
"PA",
|
||||||
|
@ -551,119 +550,3 @@ fn BAN_STATE_SET() -> HashMap<OwnedEventId, PduEvent> {
|
||||||
.map(|ev| (ev.event_id().to_owned(), ev))
|
.map(|ev| (ev.event_id().to_owned(), ev))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convenience trait for adding event type plus state key to state maps.
|
|
||||||
trait EventTypeExt {
|
|
||||||
fn with_state_key(self, state_key: impl Into<String>) -> (StateEventType, String);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EventTypeExt for &TimelineEventType {
|
|
||||||
fn with_state_key(self, state_key: impl Into<String>) -> (StateEventType, String) {
|
|
||||||
(self.to_string().into(), state_key.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod event {
|
|
||||||
use ruma::{
|
|
||||||
EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, RoomId, UserId,
|
|
||||||
events::{TimelineEventType, pdu::Pdu},
|
|
||||||
};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use serde_json::value::RawValue as RawJsonValue;
|
|
||||||
|
|
||||||
use super::Event;
|
|
||||||
|
|
||||||
impl Event for PduEvent {
|
|
||||||
fn event_id(&self) -> &EventId { &self.event_id }
|
|
||||||
|
|
||||||
fn room_id(&self) -> &RoomId {
|
|
||||||
match &self.rest {
|
|
||||||
| Pdu::RoomV1Pdu(ev) => &ev.room_id,
|
|
||||||
| Pdu::RoomV3Pdu(ev) => &ev.room_id,
|
|
||||||
#[cfg(not(feature = "unstable-exhaustive-types"))]
|
|
||||||
| _ => unreachable!("new PDU version"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sender(&self) -> &UserId {
|
|
||||||
match &self.rest {
|
|
||||||
| Pdu::RoomV1Pdu(ev) => &ev.sender,
|
|
||||||
| Pdu::RoomV3Pdu(ev) => &ev.sender,
|
|
||||||
#[cfg(not(feature = "unstable-exhaustive-types"))]
|
|
||||||
| _ => unreachable!("new PDU version"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn event_type(&self) -> &TimelineEventType {
|
|
||||||
match &self.rest {
|
|
||||||
| Pdu::RoomV1Pdu(ev) => &ev.kind,
|
|
||||||
| Pdu::RoomV3Pdu(ev) => &ev.kind,
|
|
||||||
#[cfg(not(feature = "unstable-exhaustive-types"))]
|
|
||||||
| _ => unreachable!("new PDU version"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn content(&self) -> &RawJsonValue {
|
|
||||||
match &self.rest {
|
|
||||||
| Pdu::RoomV1Pdu(ev) => &ev.content,
|
|
||||||
| Pdu::RoomV3Pdu(ev) => &ev.content,
|
|
||||||
#[cfg(not(feature = "unstable-exhaustive-types"))]
|
|
||||||
| _ => unreachable!("new PDU version"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn origin_server_ts(&self) -> MilliSecondsSinceUnixEpoch {
|
|
||||||
match &self.rest {
|
|
||||||
| Pdu::RoomV1Pdu(ev) => ev.origin_server_ts,
|
|
||||||
| Pdu::RoomV3Pdu(ev) => ev.origin_server_ts,
|
|
||||||
#[cfg(not(feature = "unstable-exhaustive-types"))]
|
|
||||||
| _ => unreachable!("new PDU version"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn state_key(&self) -> Option<&str> {
|
|
||||||
match &self.rest {
|
|
||||||
| Pdu::RoomV1Pdu(ev) => ev.state_key.as_deref(),
|
|
||||||
| Pdu::RoomV3Pdu(ev) => ev.state_key.as_deref(),
|
|
||||||
#[cfg(not(feature = "unstable-exhaustive-types"))]
|
|
||||||
| _ => unreachable!("new PDU version"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn prev_events(&self) -> Box<dyn DoubleEndedIterator<Item = &EventId> + Send + '_> {
|
|
||||||
match &self.rest {
|
|
||||||
| Pdu::RoomV1Pdu(ev) =>
|
|
||||||
Box::new(ev.prev_events.iter().map(|(id, _)| id.as_ref())),
|
|
||||||
| Pdu::RoomV3Pdu(ev) => Box::new(ev.prev_events.iter().map(AsRef::as_ref)),
|
|
||||||
#[cfg(not(feature = "unstable-exhaustive-types"))]
|
|
||||||
| _ => unreachable!("new PDU version"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn auth_events(&self) -> Box<dyn DoubleEndedIterator<Item = &EventId> + Send + '_> {
|
|
||||||
match &self.rest {
|
|
||||||
| Pdu::RoomV1Pdu(ev) =>
|
|
||||||
Box::new(ev.auth_events.iter().map(|(id, _)| id.as_ref())),
|
|
||||||
| Pdu::RoomV3Pdu(ev) => Box::new(ev.auth_events.iter().map(AsRef::as_ref)),
|
|
||||||
#[cfg(not(feature = "unstable-exhaustive-types"))]
|
|
||||||
| _ => unreachable!("new PDU version"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn redacts(&self) -> Option<&EventId> {
|
|
||||||
match &self.rest {
|
|
||||||
| Pdu::RoomV1Pdu(ev) => ev.redacts.as_deref(),
|
|
||||||
| Pdu::RoomV3Pdu(ev) => ev.redacts.as_deref(),
|
|
||||||
#[cfg(not(feature = "unstable-exhaustive-types"))]
|
|
||||||
| _ => unreachable!("new PDU version"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
|
||||||
pub(crate) struct PduEvent {
|
|
||||||
pub(crate) event_id: OwnedEventId,
|
|
||||||
#[serde(flatten)]
|
|
||||||
pub(crate) rest: Pdu,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -136,17 +136,17 @@ pub fn auth_types_for_event(
|
||||||
event_id = incoming_event.event_id().as_str(),
|
event_id = incoming_event.event_id().as_str(),
|
||||||
)
|
)
|
||||||
)]
|
)]
|
||||||
pub async fn auth_check<F, Fut, Fetched, Incoming>(
|
pub async fn auth_check<E, F, Fut>(
|
||||||
room_version: &RoomVersion,
|
room_version: &RoomVersion,
|
||||||
incoming_event: &Incoming,
|
incoming_event: &E,
|
||||||
current_third_party_invite: Option<&Incoming>,
|
current_third_party_invite: Option<&E>,
|
||||||
fetch_state: F,
|
fetch_state: F,
|
||||||
) -> Result<bool, Error>
|
) -> Result<bool, Error>
|
||||||
where
|
where
|
||||||
F: Fn(&StateEventType, &str) -> Fut + Send,
|
F: Fn(&StateEventType, &str) -> Fut + Send,
|
||||||
Fut: Future<Output = Option<Fetched>> + Send,
|
Fut: Future<Output = Option<E>> + Send,
|
||||||
Fetched: Event + Send,
|
E: Event + Send + Sync,
|
||||||
Incoming: Event + Send + Sync,
|
for<'a> &'a E: Event + Send,
|
||||||
{
|
{
|
||||||
debug!(
|
debug!(
|
||||||
event_id = format!("{}", incoming_event.event_id()),
|
event_id = format!("{}", incoming_event.event_id()),
|
||||||
|
@ -514,20 +514,24 @@ where
|
||||||
/// event and the current State.
|
/// event and the current State.
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
#[allow(clippy::cognitive_complexity)]
|
#[allow(clippy::cognitive_complexity)]
|
||||||
fn valid_membership_change(
|
fn valid_membership_change<E>(
|
||||||
room_version: &RoomVersion,
|
room_version: &RoomVersion,
|
||||||
target_user: &UserId,
|
target_user: &UserId,
|
||||||
target_user_membership_event: Option<&impl Event>,
|
target_user_membership_event: Option<&E>,
|
||||||
sender: &UserId,
|
sender: &UserId,
|
||||||
sender_membership_event: Option<&impl Event>,
|
sender_membership_event: Option<&E>,
|
||||||
current_event: impl Event,
|
current_event: &E,
|
||||||
current_third_party_invite: Option<&impl Event>,
|
current_third_party_invite: Option<&E>,
|
||||||
power_levels_event: Option<&impl Event>,
|
power_levels_event: Option<&E>,
|
||||||
join_rules_event: Option<&impl Event>,
|
join_rules_event: Option<&E>,
|
||||||
user_for_join_auth: Option<&UserId>,
|
user_for_join_auth: Option<&UserId>,
|
||||||
user_for_join_auth_membership: &MembershipState,
|
user_for_join_auth_membership: &MembershipState,
|
||||||
create_room: &impl Event,
|
create_room: &E,
|
||||||
) -> Result<bool> {
|
) -> Result<bool>
|
||||||
|
where
|
||||||
|
E: Event + Send + Sync,
|
||||||
|
for<'a> &'a E: Event + Send,
|
||||||
|
{
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct GetThirdPartyInvite {
|
struct GetThirdPartyInvite {
|
||||||
third_party_invite: Option<Raw<ThirdPartyInvite>>,
|
third_party_invite: Option<Raw<ThirdPartyInvite>>,
|
||||||
|
@ -820,7 +824,7 @@ fn valid_membership_change(
|
||||||
///
|
///
|
||||||
/// Does the event have the correct userId as its state_key if it's not the ""
|
/// Does the event have the correct userId as its state_key if it's not the ""
|
||||||
/// state_key.
|
/// state_key.
|
||||||
fn can_send_event(event: impl Event, ple: Option<impl Event>, user_level: Int) -> bool {
|
fn can_send_event(event: &impl Event, ple: Option<&impl Event>, user_level: Int) -> bool {
|
||||||
let event_type_power_level = get_send_level(event.event_type(), event.state_key(), ple);
|
let event_type_power_level = get_send_level(event.event_type(), event.state_key(), ple);
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
|
@ -846,8 +850,8 @@ fn can_send_event(event: impl Event, ple: Option<impl Event>, user_level: Int) -
|
||||||
/// Confirm that the event sender has the required power levels.
|
/// Confirm that the event sender has the required power levels.
|
||||||
fn check_power_levels(
|
fn check_power_levels(
|
||||||
room_version: &RoomVersion,
|
room_version: &RoomVersion,
|
||||||
power_event: impl Event,
|
power_event: &impl Event,
|
||||||
previous_power_event: Option<impl Event>,
|
previous_power_event: Option<&impl Event>,
|
||||||
user_level: Int,
|
user_level: Int,
|
||||||
) -> Option<bool> {
|
) -> Option<bool> {
|
||||||
match power_event.state_key() {
|
match power_event.state_key() {
|
||||||
|
@ -1010,7 +1014,7 @@ fn get_deserialize_levels(
|
||||||
/// given event.
|
/// given event.
|
||||||
fn check_redaction(
|
fn check_redaction(
|
||||||
_room_version: &RoomVersion,
|
_room_version: &RoomVersion,
|
||||||
redaction_event: impl Event,
|
redaction_event: &impl Event,
|
||||||
user_level: Int,
|
user_level: Int,
|
||||||
redact_level: Int,
|
redact_level: Int,
|
||||||
) -> Result<bool> {
|
) -> Result<bool> {
|
||||||
|
@ -1039,7 +1043,7 @@ fn check_redaction(
|
||||||
fn get_send_level(
|
fn get_send_level(
|
||||||
e_type: &TimelineEventType,
|
e_type: &TimelineEventType,
|
||||||
state_key: Option<&str>,
|
state_key: Option<&str>,
|
||||||
power_lvl: Option<impl Event>,
|
power_lvl: Option<&impl Event>,
|
||||||
) -> Int {
|
) -> Int {
|
||||||
power_lvl
|
power_lvl
|
||||||
.and_then(|ple| {
|
.and_then(|ple| {
|
||||||
|
@ -1062,7 +1066,7 @@ fn verify_third_party_invite(
|
||||||
target_user: Option<&UserId>,
|
target_user: Option<&UserId>,
|
||||||
sender: &UserId,
|
sender: &UserId,
|
||||||
tp_id: &ThirdPartyInvite,
|
tp_id: &ThirdPartyInvite,
|
||||||
current_third_party_invite: Option<impl Event>,
|
current_third_party_invite: Option<&impl Event>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// 1. Check for user being banned happens before this is called
|
// 1. Check for user being banned happens before this is called
|
||||||
// checking for mxid and token keys is done by ruma when deserializing
|
// checking for mxid and token keys is done by ruma when deserializing
|
||||||
|
@ -1128,12 +1132,15 @@ mod tests {
|
||||||
};
|
};
|
||||||
use serde_json::value::to_raw_value as to_raw_json_value;
|
use serde_json::value::to_raw_value as to_raw_json_value;
|
||||||
|
|
||||||
use crate::state_res::{
|
use crate::{
|
||||||
Event, EventTypeExt, RoomVersion, StateMap,
|
matrix::{Event, EventTypeExt, Pdu as PduEvent},
|
||||||
event_auth::valid_membership_change,
|
state_res::{
|
||||||
test_utils::{
|
RoomVersion, StateMap,
|
||||||
INITIAL_EVENTS, INITIAL_EVENTS_CREATE_ROOM, PduEvent, alice, charlie, ella, event_id,
|
event_auth::valid_membership_change,
|
||||||
member_content_ban, member_content_join, room_id, to_pdu_event,
|
test_utils::{
|
||||||
|
INITIAL_EVENTS, INITIAL_EVENTS_CREATE_ROOM, alice, charlie, ella, event_id,
|
||||||
|
member_content_ban, member_content_join, room_id, to_pdu_event,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ pub use self::{
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
debug, debug_error,
|
debug, debug_error,
|
||||||
matrix::{event::Event, pdu::StateKey},
|
matrix::{Event, StateKey},
|
||||||
trace,
|
trace,
|
||||||
utils::stream::{BroadbandExt, IterStream, ReadyExt, TryBroadbandExt, WidebandExt},
|
utils::stream::{BroadbandExt, IterStream, ReadyExt, TryBroadbandExt, WidebandExt},
|
||||||
warn,
|
warn,
|
||||||
|
@ -90,7 +90,7 @@ where
|
||||||
SetIter: Iterator<Item = &'a StateMap<OwnedEventId>> + Clone + Send,
|
SetIter: Iterator<Item = &'a StateMap<OwnedEventId>> + Clone + Send,
|
||||||
Hasher: BuildHasher + Send + Sync,
|
Hasher: BuildHasher + Send + Sync,
|
||||||
E: Event + Clone + Send + Sync,
|
E: Event + Clone + Send + Sync,
|
||||||
for<'b> &'b E: Send,
|
for<'b> &'b E: Event + Send,
|
||||||
{
|
{
|
||||||
debug!("State resolution starting");
|
debug!("State resolution starting");
|
||||||
|
|
||||||
|
@ -522,6 +522,7 @@ where
|
||||||
Fut: Future<Output = Option<E>> + Send,
|
Fut: Future<Output = Option<E>> + Send,
|
||||||
S: Stream<Item = &'a EventId> + Send + 'a,
|
S: Stream<Item = &'a EventId> + Send + 'a,
|
||||||
E: Event + Clone + Send + Sync,
|
E: Event + Clone + Send + Sync,
|
||||||
|
for<'b> &'b E: Event + Send,
|
||||||
{
|
{
|
||||||
debug!("starting iterative auth check");
|
debug!("starting iterative auth check");
|
||||||
|
|
||||||
|
@ -552,7 +553,7 @@ where
|
||||||
|
|
||||||
let auth_events = &auth_events;
|
let auth_events = &auth_events;
|
||||||
let mut resolved_state = unconflicted_state;
|
let mut resolved_state = unconflicted_state;
|
||||||
for event in &events_to_check {
|
for event in events_to_check {
|
||||||
let state_key = event
|
let state_key = event
|
||||||
.state_key()
|
.state_key()
|
||||||
.ok_or_else(|| Error::InvalidPdu("State event had no state key".to_owned()))?;
|
.ok_or_else(|| Error::InvalidPdu("State event had no state key".to_owned()))?;
|
||||||
|
@ -607,11 +608,15 @@ where
|
||||||
});
|
});
|
||||||
|
|
||||||
let fetch_state = |ty: &StateEventType, key: &str| {
|
let fetch_state = |ty: &StateEventType, key: &str| {
|
||||||
future::ready(auth_state.get(&ty.with_state_key(key)))
|
future::ready(
|
||||||
|
auth_state
|
||||||
|
.get(&ty.with_state_key(key))
|
||||||
|
.map(ToOwned::to_owned),
|
||||||
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let auth_result =
|
let auth_result =
|
||||||
auth_check(room_version, &event, current_third_party.as_ref(), fetch_state).await;
|
auth_check(room_version, &event, current_third_party, fetch_state).await;
|
||||||
|
|
||||||
match auth_result {
|
match auth_result {
|
||||||
| Ok(true) => {
|
| Ok(true) => {
|
||||||
|
@ -794,11 +799,11 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_type_and_key(ev: impl Event, ev_type: &TimelineEventType, state_key: &str) -> bool {
|
fn is_type_and_key(ev: &impl Event, ev_type: &TimelineEventType, state_key: &str) -> bool {
|
||||||
ev.event_type() == ev_type && ev.state_key() == Some(state_key)
|
ev.event_type() == ev_type && ev.state_key() == Some(state_key)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_power_event(event: impl Event) -> bool {
|
fn is_power_event(event: &impl Event) -> bool {
|
||||||
match event.event_type() {
|
match event.event_type() {
|
||||||
| TimelineEventType::RoomPowerLevels
|
| TimelineEventType::RoomPowerLevels
|
||||||
| TimelineEventType::RoomJoinRules
|
| TimelineEventType::RoomJoinRules
|
||||||
|
@ -859,15 +864,19 @@ mod tests {
|
||||||
use serde_json::{json, value::to_raw_value as to_raw_json_value};
|
use serde_json::{json, value::to_raw_value as to_raw_json_value};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
Event, EventTypeExt, StateMap, is_power_event,
|
StateMap, is_power_event,
|
||||||
room_version::RoomVersion,
|
room_version::RoomVersion,
|
||||||
test_utils::{
|
test_utils::{
|
||||||
INITIAL_EVENTS, PduEvent, TestStore, alice, bob, charlie, do_check, ella, event_id,
|
INITIAL_EVENTS, TestStore, alice, bob, charlie, do_check, ella, event_id,
|
||||||
member_content_ban, member_content_join, room_id, to_init_pdu_event, to_pdu_event,
|
member_content_ban, member_content_join, room_id, to_init_pdu_event, to_pdu_event,
|
||||||
zara,
|
zara,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use crate::{debug, utils::stream::IterStream};
|
use crate::{
|
||||||
|
debug,
|
||||||
|
matrix::{Event, EventTypeExt, Pdu as PduEvent},
|
||||||
|
utils::stream::IterStream,
|
||||||
|
};
|
||||||
|
|
||||||
async fn test_event_sort() {
|
async fn test_event_sort() {
|
||||||
use futures::future::ready;
|
use futures::future::ready;
|
||||||
|
|
|
@ -10,7 +10,6 @@ use ruma::{
|
||||||
UserId, event_id,
|
UserId, event_id,
|
||||||
events::{
|
events::{
|
||||||
TimelineEventType,
|
TimelineEventType,
|
||||||
pdu::{EventHash, Pdu, RoomV3Pdu},
|
|
||||||
room::{
|
room::{
|
||||||
join_rules::{JoinRule, RoomJoinRulesEventContent},
|
join_rules::{JoinRule, RoomJoinRulesEventContent},
|
||||||
member::{MembershipState, RoomMemberEventContent},
|
member::{MembershipState, RoomMemberEventContent},
|
||||||
|
@ -23,17 +22,16 @@ use serde_json::{
|
||||||
value::{RawValue as RawJsonValue, to_raw_value as to_raw_json_value},
|
value::{RawValue as RawJsonValue, to_raw_value as to_raw_json_value},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) use self::event::PduEvent;
|
|
||||||
use super::auth_types_for_event;
|
use super::auth_types_for_event;
|
||||||
use crate::{
|
use crate::{
|
||||||
Result, info,
|
Result, info,
|
||||||
matrix::{Event, EventTypeExt, StateMap},
|
matrix::{Event, EventTypeExt, Pdu, StateMap, pdu::EventHash},
|
||||||
};
|
};
|
||||||
|
|
||||||
static SERVER_TIMESTAMP: AtomicU64 = AtomicU64::new(0);
|
static SERVER_TIMESTAMP: AtomicU64 = AtomicU64::new(0);
|
||||||
|
|
||||||
pub(crate) async fn do_check(
|
pub(crate) async fn do_check(
|
||||||
events: &[PduEvent],
|
events: &[Pdu],
|
||||||
edges: Vec<Vec<OwnedEventId>>,
|
edges: Vec<Vec<OwnedEventId>>,
|
||||||
expected_state_ids: Vec<OwnedEventId>,
|
expected_state_ids: Vec<OwnedEventId>,
|
||||||
) {
|
) {
|
||||||
|
@ -81,8 +79,8 @@ pub(crate) async fn do_check(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// event_id -> PduEvent
|
// event_id -> Pdu
|
||||||
let mut event_map: HashMap<OwnedEventId, PduEvent> = HashMap::new();
|
let mut event_map: HashMap<OwnedEventId, Pdu> = HashMap::new();
|
||||||
// event_id -> StateMap<OwnedEventId>
|
// event_id -> StateMap<OwnedEventId>
|
||||||
let mut state_at_event: HashMap<OwnedEventId, StateMap<OwnedEventId>> = HashMap::new();
|
let mut state_at_event: HashMap<OwnedEventId, StateMap<OwnedEventId>> = HashMap::new();
|
||||||
|
|
||||||
|
@ -265,7 +263,7 @@ impl<E: Event + Clone> TestStore<E> {
|
||||||
|
|
||||||
// A StateStore implementation for testing
|
// A StateStore implementation for testing
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
impl TestStore<PduEvent> {
|
impl TestStore<Pdu> {
|
||||||
pub(crate) fn set_up(
|
pub(crate) fn set_up(
|
||||||
&mut self,
|
&mut self,
|
||||||
) -> (StateMap<OwnedEventId>, StateMap<OwnedEventId>, StateMap<OwnedEventId>) {
|
) -> (StateMap<OwnedEventId>, StateMap<OwnedEventId>, StateMap<OwnedEventId>) {
|
||||||
|
@ -390,7 +388,7 @@ pub(crate) fn to_init_pdu_event(
|
||||||
ev_type: TimelineEventType,
|
ev_type: TimelineEventType,
|
||||||
state_key: Option<&str>,
|
state_key: Option<&str>,
|
||||||
content: Box<RawJsonValue>,
|
content: Box<RawJsonValue>,
|
||||||
) -> PduEvent {
|
) -> Pdu {
|
||||||
let ts = SERVER_TIMESTAMP.fetch_add(1, SeqCst);
|
let ts = SERVER_TIMESTAMP.fetch_add(1, SeqCst);
|
||||||
let id = if id.contains('$') {
|
let id = if id.contains('$') {
|
||||||
id.to_owned()
|
id.to_owned()
|
||||||
|
@ -398,24 +396,22 @@ pub(crate) fn to_init_pdu_event(
|
||||||
format!("${id}:foo")
|
format!("${id}:foo")
|
||||||
};
|
};
|
||||||
|
|
||||||
let state_key = state_key.map(ToOwned::to_owned);
|
Pdu {
|
||||||
PduEvent {
|
|
||||||
event_id: id.try_into().unwrap(),
|
event_id: id.try_into().unwrap(),
|
||||||
rest: Pdu::RoomV3Pdu(RoomV3Pdu {
|
room_id: room_id().to_owned(),
|
||||||
room_id: room_id().to_owned(),
|
sender: sender.to_owned(),
|
||||||
sender: sender.to_owned(),
|
origin_server_ts: ts.try_into().unwrap(),
|
||||||
origin_server_ts: MilliSecondsSinceUnixEpoch(ts.try_into().unwrap()),
|
state_key: state_key.map(Into::into),
|
||||||
state_key,
|
kind: ev_type,
|
||||||
kind: ev_type,
|
content,
|
||||||
content,
|
origin: None,
|
||||||
redacts: None,
|
redacts: None,
|
||||||
unsigned: BTreeMap::new(),
|
unsigned: None,
|
||||||
auth_events: vec![],
|
auth_events: vec![],
|
||||||
prev_events: vec![],
|
prev_events: vec![],
|
||||||
depth: uint!(0),
|
depth: uint!(0),
|
||||||
hashes: EventHash::new("".to_owned()),
|
hashes: EventHash { sha256: "".to_owned() },
|
||||||
signatures: ServerSignatures::default(),
|
signatures: None,
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -427,7 +423,7 @@ pub(crate) fn to_pdu_event<S>(
|
||||||
content: Box<RawJsonValue>,
|
content: Box<RawJsonValue>,
|
||||||
auth_events: &[S],
|
auth_events: &[S],
|
||||||
prev_events: &[S],
|
prev_events: &[S],
|
||||||
) -> PduEvent
|
) -> Pdu
|
||||||
where
|
where
|
||||||
S: AsRef<str>,
|
S: AsRef<str>,
|
||||||
{
|
{
|
||||||
|
@ -448,30 +444,28 @@ where
|
||||||
.map(event_id)
|
.map(event_id)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let state_key = state_key.map(ToOwned::to_owned);
|
Pdu {
|
||||||
PduEvent {
|
|
||||||
event_id: id.try_into().unwrap(),
|
event_id: id.try_into().unwrap(),
|
||||||
rest: Pdu::RoomV3Pdu(RoomV3Pdu {
|
room_id: room_id().to_owned(),
|
||||||
room_id: room_id().to_owned(),
|
sender: sender.to_owned(),
|
||||||
sender: sender.to_owned(),
|
origin_server_ts: ts.try_into().unwrap(),
|
||||||
origin_server_ts: MilliSecondsSinceUnixEpoch(ts.try_into().unwrap()),
|
state_key: state_key.map(Into::into),
|
||||||
state_key,
|
kind: ev_type,
|
||||||
kind: ev_type,
|
content,
|
||||||
content,
|
origin: None,
|
||||||
redacts: None,
|
redacts: None,
|
||||||
unsigned: BTreeMap::new(),
|
unsigned: None,
|
||||||
auth_events,
|
auth_events,
|
||||||
prev_events,
|
prev_events,
|
||||||
depth: uint!(0),
|
depth: uint!(0),
|
||||||
hashes: EventHash::new("".to_owned()),
|
hashes: EventHash { sha256: "".to_owned() },
|
||||||
signatures: ServerSignatures::default(),
|
signatures: None,
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// all graphs start with these input events
|
// all graphs start with these input events
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub(crate) fn INITIAL_EVENTS() -> HashMap<OwnedEventId, PduEvent> {
|
pub(crate) fn INITIAL_EVENTS() -> HashMap<OwnedEventId, Pdu> {
|
||||||
vec![
|
vec![
|
||||||
to_pdu_event::<&EventId>(
|
to_pdu_event::<&EventId>(
|
||||||
"CREATE",
|
"CREATE",
|
||||||
|
@ -553,7 +547,7 @@ pub(crate) fn INITIAL_EVENTS() -> HashMap<OwnedEventId, PduEvent> {
|
||||||
|
|
||||||
// all graphs start with these input events
|
// all graphs start with these input events
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub(crate) fn INITIAL_EVENTS_CREATE_ROOM() -> HashMap<OwnedEventId, PduEvent> {
|
pub(crate) fn INITIAL_EVENTS_CREATE_ROOM() -> HashMap<OwnedEventId, Pdu> {
|
||||||
vec![to_pdu_event::<&EventId>(
|
vec![to_pdu_event::<&EventId>(
|
||||||
"CREATE",
|
"CREATE",
|
||||||
alice(),
|
alice(),
|
||||||
|
@ -575,111 +569,3 @@ pub(crate) fn INITIAL_EDGES() -> Vec<OwnedEventId> {
|
||||||
.map(event_id)
|
.map(event_id)
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) mod event {
|
|
||||||
use ruma::{
|
|
||||||
EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, RoomId, UserId,
|
|
||||||
events::{TimelineEventType, pdu::Pdu},
|
|
||||||
};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use serde_json::value::RawValue as RawJsonValue;
|
|
||||||
|
|
||||||
use crate::Event;
|
|
||||||
|
|
||||||
impl Event for PduEvent {
|
|
||||||
fn event_id(&self) -> &EventId { &self.event_id }
|
|
||||||
|
|
||||||
fn room_id(&self) -> &RoomId {
|
|
||||||
match &self.rest {
|
|
||||||
| Pdu::RoomV1Pdu(ev) => &ev.room_id,
|
|
||||||
| Pdu::RoomV3Pdu(ev) => &ev.room_id,
|
|
||||||
#[allow(unreachable_patterns)]
|
|
||||||
| _ => unreachable!("new PDU version"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sender(&self) -> &UserId {
|
|
||||||
match &self.rest {
|
|
||||||
| Pdu::RoomV1Pdu(ev) => &ev.sender,
|
|
||||||
| Pdu::RoomV3Pdu(ev) => &ev.sender,
|
|
||||||
#[allow(unreachable_patterns)]
|
|
||||||
| _ => unreachable!("new PDU version"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn event_type(&self) -> &TimelineEventType {
|
|
||||||
match &self.rest {
|
|
||||||
| Pdu::RoomV1Pdu(ev) => &ev.kind,
|
|
||||||
| Pdu::RoomV3Pdu(ev) => &ev.kind,
|
|
||||||
#[allow(unreachable_patterns)]
|
|
||||||
| _ => unreachable!("new PDU version"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn content(&self) -> &RawJsonValue {
|
|
||||||
match &self.rest {
|
|
||||||
| Pdu::RoomV1Pdu(ev) => &ev.content,
|
|
||||||
| Pdu::RoomV3Pdu(ev) => &ev.content,
|
|
||||||
#[allow(unreachable_patterns)]
|
|
||||||
| _ => unreachable!("new PDU version"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn origin_server_ts(&self) -> MilliSecondsSinceUnixEpoch {
|
|
||||||
match &self.rest {
|
|
||||||
| Pdu::RoomV1Pdu(ev) => ev.origin_server_ts,
|
|
||||||
| Pdu::RoomV3Pdu(ev) => ev.origin_server_ts,
|
|
||||||
#[allow(unreachable_patterns)]
|
|
||||||
| _ => unreachable!("new PDU version"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn state_key(&self) -> Option<&str> {
|
|
||||||
match &self.rest {
|
|
||||||
| Pdu::RoomV1Pdu(ev) => ev.state_key.as_deref(),
|
|
||||||
| Pdu::RoomV3Pdu(ev) => ev.state_key.as_deref(),
|
|
||||||
#[allow(unreachable_patterns)]
|
|
||||||
| _ => unreachable!("new PDU version"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(refining_impl_trait)]
|
|
||||||
fn prev_events(&self) -> Box<dyn DoubleEndedIterator<Item = &EventId> + Send + '_> {
|
|
||||||
match &self.rest {
|
|
||||||
| Pdu::RoomV1Pdu(ev) =>
|
|
||||||
Box::new(ev.prev_events.iter().map(|(id, _)| id.as_ref())),
|
|
||||||
| Pdu::RoomV3Pdu(ev) => Box::new(ev.prev_events.iter().map(AsRef::as_ref)),
|
|
||||||
#[allow(unreachable_patterns)]
|
|
||||||
| _ => unreachable!("new PDU version"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(refining_impl_trait)]
|
|
||||||
fn auth_events(&self) -> Box<dyn DoubleEndedIterator<Item = &EventId> + Send + '_> {
|
|
||||||
match &self.rest {
|
|
||||||
| Pdu::RoomV1Pdu(ev) =>
|
|
||||||
Box::new(ev.auth_events.iter().map(|(id, _)| id.as_ref())),
|
|
||||||
| Pdu::RoomV3Pdu(ev) => Box::new(ev.auth_events.iter().map(AsRef::as_ref)),
|
|
||||||
#[allow(unreachable_patterns)]
|
|
||||||
| _ => unreachable!("new PDU version"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn redacts(&self) -> Option<&EventId> {
|
|
||||||
match &self.rest {
|
|
||||||
| Pdu::RoomV1Pdu(ev) => ev.redacts.as_deref(),
|
|
||||||
| Pdu::RoomV3Pdu(ev) => ev.redacts.as_deref(),
|
|
||||||
#[allow(unreachable_patterns)]
|
|
||||||
| _ => unreachable!("new PDU version"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
|
||||||
#[allow(clippy::exhaustive_structs)]
|
|
||||||
pub(crate) struct PduEvent {
|
|
||||||
pub(crate) event_id: OwnedEventId,
|
|
||||||
#[serde(flatten)]
|
|
||||||
pub(crate) rest: Pdu,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -25,7 +25,9 @@ pub use info::{
|
||||||
rustc_flags_capture, version,
|
rustc_flags_capture, version,
|
||||||
version::{name, version},
|
version::{name, version},
|
||||||
};
|
};
|
||||||
pub use matrix::{Event, EventTypeExt, PduCount, PduEvent, PduId, RoomVersion, pdu, state_res};
|
pub use matrix::{
|
||||||
|
Event, EventTypeExt, Pdu, PduCount, PduEvent, PduId, RoomVersion, pdu, state_res,
|
||||||
|
};
|
||||||
pub use server::Server;
|
pub use server::Server;
|
||||||
pub use utils::{ctor, dtor, implement, result, result::Result};
|
pub use utils::{ctor, dtor, implement, result, result::Result};
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,8 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use conduwuit::{
|
use conduwuit_core::{
|
||||||
Error, PduEvent, Result, Server, debug, err, error, error::default_log, pdu::PduBuilder,
|
Error, Event, Result, Server, debug, err, error, error::default_log, pdu::PduBuilder,
|
||||||
};
|
};
|
||||||
pub use create::create_admin_room;
|
pub use create::create_admin_room;
|
||||||
use futures::{Future, FutureExt, TryFutureExt};
|
use futures::{Future, FutureExt, TryFutureExt};
|
||||||
|
@ -361,7 +361,10 @@ impl Service {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn is_admin_command(&self, pdu: &PduEvent, body: &str) -> bool {
|
pub async fn is_admin_command<E>(&self, event: &E, body: &str) -> bool
|
||||||
|
where
|
||||||
|
E: Event + Send + Sync,
|
||||||
|
{
|
||||||
// Server-side command-escape with public echo
|
// Server-side command-escape with public echo
|
||||||
let is_escape = body.starts_with('\\');
|
let is_escape = body.starts_with('\\');
|
||||||
let is_public_escape = is_escape && body.trim_start_matches('\\').starts_with("!admin");
|
let is_public_escape = is_escape && body.trim_start_matches('\\').starts_with("!admin");
|
||||||
|
@ -376,8 +379,10 @@ impl Service {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let user_is_local = self.services.globals.user_is_local(event.sender());
|
||||||
|
|
||||||
// only allow public escaped commands by local admins
|
// only allow public escaped commands by local admins
|
||||||
if is_public_escape && !self.services.globals.user_is_local(&pdu.sender) {
|
if is_public_escape && !user_is_local {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -387,20 +392,20 @@ impl Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prevent unescaped !admin from being used outside of the admin room
|
// Prevent unescaped !admin from being used outside of the admin room
|
||||||
if is_public_prefix && !self.is_admin_room(&pdu.room_id).await {
|
if is_public_prefix && !self.is_admin_room(event.room_id()).await {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only senders who are admin can proceed
|
// Only senders who are admin can proceed
|
||||||
if !self.user_is_admin(&pdu.sender).await {
|
if !self.user_is_admin(event.sender()).await {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This will evaluate to false if the emergency password is set up so that
|
// This will evaluate to false if the emergency password is set up so that
|
||||||
// the administrator can execute commands as the server user
|
// the administrator can execute commands as the server user
|
||||||
let emergency_password_set = self.services.server.config.emergency_password.is_some();
|
let emergency_password_set = self.services.server.config.emergency_password.is_some();
|
||||||
let from_server = pdu.sender == *server_user && !emergency_password_set;
|
let from_server = event.sender() == server_user && !emergency_password_set;
|
||||||
if from_server && self.is_admin_room(&pdu.room_id).await {
|
if from_server && self.is_admin_room(event.room_id()).await {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use std::{fmt::Debug, mem, sync::Arc};
|
use std::{fmt::Debug, mem, sync::Arc};
|
||||||
|
|
||||||
use bytes::BytesMut;
|
use bytes::BytesMut;
|
||||||
use conduwuit::{
|
use conduwuit_core::{
|
||||||
Err, PduEvent, Result, debug_warn, err, trace,
|
Err, Event, Result, debug_warn, err, trace,
|
||||||
utils::{stream::TryIgnore, string_from_bytes},
|
utils::{stream::TryIgnore, string_from_bytes},
|
||||||
warn,
|
warn,
|
||||||
};
|
};
|
||||||
use database::{Deserialized, Ignore, Interfix, Json, Map};
|
use conduwuit_database::{Deserialized, Ignore, Interfix, Json, Map};
|
||||||
use futures::{Stream, StreamExt};
|
use futures::{Stream, StreamExt};
|
||||||
use ipaddress::IPAddress;
|
use ipaddress::IPAddress;
|
||||||
use ruma::{
|
use ruma::{
|
||||||
|
@ -272,22 +272,26 @@ impl Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self, user, unread, pusher, ruleset, pdu))]
|
#[tracing::instrument(skip(self, user, unread, pusher, ruleset, event))]
|
||||||
pub async fn send_push_notice(
|
pub async fn send_push_notice<E>(
|
||||||
&self,
|
&self,
|
||||||
user: &UserId,
|
user: &UserId,
|
||||||
unread: UInt,
|
unread: UInt,
|
||||||
pusher: &Pusher,
|
pusher: &Pusher,
|
||||||
ruleset: Ruleset,
|
ruleset: Ruleset,
|
||||||
pdu: &PduEvent,
|
event: &E,
|
||||||
) -> Result<()> {
|
) -> Result
|
||||||
|
where
|
||||||
|
E: Event + Send + Sync,
|
||||||
|
for<'a> &'a E: Event + Send,
|
||||||
|
{
|
||||||
let mut notify = None;
|
let mut notify = None;
|
||||||
let mut tweaks = Vec::new();
|
let mut tweaks = Vec::new();
|
||||||
|
|
||||||
let power_levels: RoomPowerLevelsEventContent = self
|
let power_levels: RoomPowerLevelsEventContent = self
|
||||||
.services
|
.services
|
||||||
.state_accessor
|
.state_accessor
|
||||||
.room_state_get(&pdu.room_id, &StateEventType::RoomPowerLevels, "")
|
.room_state_get(event.room_id(), &StateEventType::RoomPowerLevels, "")
|
||||||
.await
|
.await
|
||||||
.and_then(|ev| {
|
.and_then(|ev| {
|
||||||
serde_json::from_str(ev.content.get()).map_err(|e| {
|
serde_json::from_str(ev.content.get()).map_err(|e| {
|
||||||
|
@ -296,8 +300,9 @@ impl Service {
|
||||||
})
|
})
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
let serialized = event.to_format();
|
||||||
for action in self
|
for action in self
|
||||||
.get_actions(user, &ruleset, &power_levels, &pdu.to_sync_room_event(), &pdu.room_id)
|
.get_actions(user, &ruleset, &power_levels, &serialized, event.room_id())
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
let n = match action {
|
let n = match action {
|
||||||
|
@ -319,7 +324,7 @@ impl Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
if notify == Some(true) {
|
if notify == Some(true) {
|
||||||
self.send_notice(unread, pusher, tweaks, pdu).await?;
|
self.send_notice(unread, pusher, tweaks, event).await?;
|
||||||
}
|
}
|
||||||
// Else the event triggered no actions
|
// Else the event triggered no actions
|
||||||
|
|
||||||
|
@ -369,13 +374,16 @@ impl Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self, unread, pusher, tweaks, event))]
|
#[tracing::instrument(skip(self, unread, pusher, tweaks, event))]
|
||||||
async fn send_notice(
|
async fn send_notice<E>(
|
||||||
&self,
|
&self,
|
||||||
unread: UInt,
|
unread: UInt,
|
||||||
pusher: &Pusher,
|
pusher: &Pusher,
|
||||||
tweaks: Vec<Tweak>,
|
tweaks: Vec<Tweak>,
|
||||||
event: &PduEvent,
|
event: &E,
|
||||||
) -> Result {
|
) -> Result
|
||||||
|
where
|
||||||
|
E: Event + Send + Sync,
|
||||||
|
{
|
||||||
// TODO: email
|
// TODO: email
|
||||||
match &pusher.kind {
|
match &pusher.kind {
|
||||||
| PusherKind::Http(http) => {
|
| PusherKind::Http(http) => {
|
||||||
|
@ -421,8 +429,8 @@ impl Service {
|
||||||
let d = vec![device];
|
let d = vec![device];
|
||||||
let mut notifi = Notification::new(d);
|
let mut notifi = Notification::new(d);
|
||||||
|
|
||||||
notifi.event_id = Some((*event.event_id).to_owned());
|
notifi.event_id = Some(event.event_id().to_owned());
|
||||||
notifi.room_id = Some((*event.room_id).to_owned());
|
notifi.room_id = Some(event.room_id().to_owned());
|
||||||
if http
|
if http
|
||||||
.data
|
.data
|
||||||
.get("org.matrix.msc4076.disable_badge_count")
|
.get("org.matrix.msc4076.disable_badge_count")
|
||||||
|
@ -442,7 +450,7 @@ impl Service {
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
} else {
|
} else {
|
||||||
if event.kind == TimelineEventType::RoomEncrypted
|
if *event.kind() == TimelineEventType::RoomEncrypted
|
||||||
|| tweaks
|
|| tweaks
|
||||||
.iter()
|
.iter()
|
||||||
.any(|t| matches!(t, Tweak::Highlight(true) | Tweak::Sound(_)))
|
.any(|t| matches!(t, Tweak::Highlight(true) | Tweak::Sound(_)))
|
||||||
|
@ -451,29 +459,29 @@ impl Service {
|
||||||
} else {
|
} else {
|
||||||
notifi.prio = NotificationPriority::Low;
|
notifi.prio = NotificationPriority::Low;
|
||||||
}
|
}
|
||||||
notifi.sender = Some(event.sender.clone());
|
notifi.sender = Some(event.sender().to_owned());
|
||||||
notifi.event_type = Some(event.kind.clone());
|
notifi.event_type = Some(event.kind().to_owned());
|
||||||
notifi.content = serde_json::value::to_raw_value(&event.content).ok();
|
notifi.content = serde_json::value::to_raw_value(event.content()).ok();
|
||||||
|
|
||||||
if event.kind == TimelineEventType::RoomMember {
|
if *event.kind() == TimelineEventType::RoomMember {
|
||||||
notifi.user_is_target =
|
notifi.user_is_target =
|
||||||
event.state_key.as_deref() == Some(event.sender.as_str());
|
event.state_key() == Some(event.sender().as_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
notifi.sender_display_name =
|
notifi.sender_display_name =
|
||||||
self.services.users.displayname(&event.sender).await.ok();
|
self.services.users.displayname(event.sender()).await.ok();
|
||||||
|
|
||||||
notifi.room_name = self
|
notifi.room_name = self
|
||||||
.services
|
.services
|
||||||
.state_accessor
|
.state_accessor
|
||||||
.get_name(&event.room_id)
|
.get_name(event.room_id())
|
||||||
.await
|
.await
|
||||||
.ok();
|
.ok();
|
||||||
|
|
||||||
notifi.room_alias = self
|
notifi.room_alias = self
|
||||||
.services
|
.services
|
||||||
.state_accessor
|
.state_accessor
|
||||||
.get_canonical_alias(&event.room_id)
|
.get_canonical_alias(event.room_id())
|
||||||
.await
|
.await
|
||||||
.ok();
|
.ok();
|
||||||
|
|
||||||
|
|
|
@ -126,7 +126,7 @@ pub(super) async fn handle_outlier_pdu<'a>(
|
||||||
|
|
||||||
let state_fetch = |ty: &StateEventType, sk: &str| {
|
let state_fetch = |ty: &StateEventType, sk: &str| {
|
||||||
let key = (ty.to_owned(), sk.into());
|
let key = (ty.to_owned(), sk.into());
|
||||||
ready(auth_events.get(&key))
|
ready(auth_events.get(&key).map(ToOwned::to_owned))
|
||||||
};
|
};
|
||||||
|
|
||||||
let auth_check = state_res::event_auth::auth_check(
|
let auth_check = state_res::event_auth::auth_check(
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::{borrow::Borrow, collections::BTreeMap, iter::once, sync::Arc, time::In
|
||||||
|
|
||||||
use conduwuit::{
|
use conduwuit::{
|
||||||
Err, Result, debug, debug_info, err, implement,
|
Err, Result, debug, debug_info, err, implement,
|
||||||
matrix::{EventTypeExt, PduEvent, StateKey, state_res},
|
matrix::{Event, EventTypeExt, PduEvent, StateKey, state_res},
|
||||||
trace,
|
trace,
|
||||||
utils::stream::{BroadbandExt, ReadyExt},
|
utils::stream::{BroadbandExt, ReadyExt},
|
||||||
warn,
|
warn,
|
||||||
|
@ -108,7 +108,7 @@ pub(super) async fn upgrade_outlier_to_timeline_pdu(
|
||||||
|
|
||||||
let state_fetch = |k: &StateEventType, s: &str| {
|
let state_fetch = |k: &StateEventType, s: &str| {
|
||||||
let key = k.with_state_key(s);
|
let key = k.with_state_key(s);
|
||||||
ready(auth_events.get(&key).cloned())
|
ready(auth_events.get(&key).map(ToOwned::to_owned))
|
||||||
};
|
};
|
||||||
|
|
||||||
let auth_check = state_res::event_auth::auth_check(
|
let auth_check = state_res::event_auth::auth_check(
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use conduwuit::{
|
use conduwuit_core::{
|
||||||
PduCount, PduEvent, Result,
|
Event, PduCount, PduEvent, Result,
|
||||||
arrayvec::ArrayVec,
|
arrayvec::ArrayVec,
|
||||||
implement,
|
implement,
|
||||||
utils::{
|
utils::{
|
||||||
|
|
|
@ -5,8 +5,8 @@ mod tests;
|
||||||
use std::{fmt::Write, sync::Arc};
|
use std::{fmt::Write, sync::Arc};
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use conduwuit::{
|
use conduwuit_core::{
|
||||||
Err, Error, PduEvent, Result, implement,
|
Err, Error, Event, PduEvent, Result, implement,
|
||||||
utils::{
|
utils::{
|
||||||
IterStream,
|
IterStream,
|
||||||
future::{BoolExt, TryExtExt},
|
future::{BoolExt, TryExtExt},
|
||||||
|
@ -142,7 +142,7 @@ pub async fn get_summary_and_children_local(
|
||||||
|
|
||||||
let children_pdus: Vec<_> = self
|
let children_pdus: Vec<_> = self
|
||||||
.get_space_child_events(current_room)
|
.get_space_child_events(current_room)
|
||||||
.map(PduEvent::into_stripped_spacechild_state_event)
|
.map(Event::into_format)
|
||||||
.collect()
|
.collect()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
@ -511,7 +511,7 @@ async fn cache_insert(
|
||||||
room_id: room_id.clone(),
|
room_id: room_id.clone(),
|
||||||
children_state: self
|
children_state: self
|
||||||
.get_space_child_events(&room_id)
|
.get_space_child_events(&room_id)
|
||||||
.map(PduEvent::into_stripped_spacechild_state_event)
|
.map(Event::into_format)
|
||||||
.collect()
|
.collect()
|
||||||
.await,
|
.await,
|
||||||
encryption,
|
encryption,
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use std::{collections::HashMap, fmt::Write, iter::once, sync::Arc};
|
use std::{collections::HashMap, fmt::Write, iter::once, sync::Arc};
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use conduwuit::{
|
use conduwuit_core::{
|
||||||
PduEvent, Result, err,
|
Event, PduEvent, Result, err,
|
||||||
result::FlatOk,
|
result::FlatOk,
|
||||||
state_res::{self, StateMap},
|
state_res::{self, StateMap},
|
||||||
utils::{
|
utils::{
|
||||||
|
@ -11,7 +11,7 @@ use conduwuit::{
|
||||||
},
|
},
|
||||||
warn,
|
warn,
|
||||||
};
|
};
|
||||||
use database::{Deserialized, Ignore, Interfix, Map};
|
use conduwuit_database::{Deserialized, Ignore, Interfix, Map};
|
||||||
use futures::{
|
use futures::{
|
||||||
FutureExt, Stream, StreamExt, TryFutureExt, TryStreamExt, future::join_all, pin_mut,
|
FutureExt, Stream, StreamExt, TryFutureExt, TryStreamExt, future::join_all, pin_mut,
|
||||||
};
|
};
|
||||||
|
@ -319,30 +319,34 @@ impl Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all, level = "debug")]
|
#[tracing::instrument(skip_all, level = "debug")]
|
||||||
pub async fn summary_stripped(&self, event: &PduEvent) -> Vec<Raw<AnyStrippedStateEvent>> {
|
pub async fn summary_stripped<'a, E>(&self, event: &'a E) -> Vec<Raw<AnyStrippedStateEvent>>
|
||||||
|
where
|
||||||
|
E: Event + Send + Sync,
|
||||||
|
&'a E: Event + Send,
|
||||||
|
{
|
||||||
let cells = [
|
let cells = [
|
||||||
(&StateEventType::RoomCreate, ""),
|
(&StateEventType::RoomCreate, ""),
|
||||||
(&StateEventType::RoomJoinRules, ""),
|
(&StateEventType::RoomJoinRules, ""),
|
||||||
(&StateEventType::RoomCanonicalAlias, ""),
|
(&StateEventType::RoomCanonicalAlias, ""),
|
||||||
(&StateEventType::RoomName, ""),
|
(&StateEventType::RoomName, ""),
|
||||||
(&StateEventType::RoomAvatar, ""),
|
(&StateEventType::RoomAvatar, ""),
|
||||||
(&StateEventType::RoomMember, event.sender.as_str()), // Add recommended events
|
(&StateEventType::RoomMember, event.sender().as_str()), // Add recommended events
|
||||||
(&StateEventType::RoomEncryption, ""),
|
(&StateEventType::RoomEncryption, ""),
|
||||||
(&StateEventType::RoomTopic, ""),
|
(&StateEventType::RoomTopic, ""),
|
||||||
];
|
];
|
||||||
|
|
||||||
let fetches = cells.iter().map(|(event_type, state_key)| {
|
let fetches = cells.into_iter().map(|(event_type, state_key)| {
|
||||||
self.services
|
self.services
|
||||||
.state_accessor
|
.state_accessor
|
||||||
.room_state_get(&event.room_id, event_type, state_key)
|
.room_state_get(event.room_id(), event_type, state_key)
|
||||||
});
|
});
|
||||||
|
|
||||||
join_all(fetches)
|
join_all(fetches)
|
||||||
.await
|
.await
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(Result::ok)
|
.filter_map(Result::ok)
|
||||||
.map(PduEvent::into_stripped_state_event)
|
.map(Event::into_format)
|
||||||
.chain(once(event.to_stripped_state_event()))
|
.chain(once(event.to_format()))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::{collections::BTreeMap, sync::Arc};
|
use std::{collections::BTreeMap, sync::Arc};
|
||||||
|
|
||||||
use conduwuit::{
|
use conduwuit_core::{
|
||||||
Result, err,
|
Event, Result, err,
|
||||||
matrix::pdu::{PduCount, PduEvent, PduId, RawPduId},
|
matrix::pdu::{PduCount, PduEvent, PduId, RawPduId},
|
||||||
utils::{
|
utils::{
|
||||||
ReadyExt,
|
ReadyExt,
|
||||||
|
@ -49,7 +49,11 @@ impl crate::Service for Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Service {
|
impl Service {
|
||||||
pub async fn add_to_thread(&self, root_event_id: &EventId, pdu: &PduEvent) -> Result<()> {
|
pub async fn add_to_thread<'a, E>(&self, root_event_id: &EventId, event: &'a E) -> Result
|
||||||
|
where
|
||||||
|
E: Event + Send + Sync,
|
||||||
|
&'a E: Event + Send,
|
||||||
|
{
|
||||||
let root_id = self
|
let root_id = self
|
||||||
.services
|
.services
|
||||||
.timeline
|
.timeline
|
||||||
|
@ -86,7 +90,7 @@ impl Service {
|
||||||
}) {
|
}) {
|
||||||
// Thread already existed
|
// Thread already existed
|
||||||
relations.count = relations.count.saturating_add(uint!(1));
|
relations.count = relations.count.saturating_add(uint!(1));
|
||||||
relations.latest_event = pdu.to_message_like_event();
|
relations.latest_event = event.to_format();
|
||||||
|
|
||||||
let content = serde_json::to_value(relations).expect("to_value always works");
|
let content = serde_json::to_value(relations).expect("to_value always works");
|
||||||
|
|
||||||
|
@ -99,7 +103,7 @@ impl Service {
|
||||||
} else {
|
} else {
|
||||||
// New thread
|
// New thread
|
||||||
let relations = BundledThread {
|
let relations = BundledThread {
|
||||||
latest_event: pdu.to_message_like_event(),
|
latest_event: event.to_format(),
|
||||||
count: uint!(1),
|
count: uint!(1),
|
||||||
current_user_participated: true,
|
current_user_participated: true,
|
||||||
};
|
};
|
||||||
|
@ -129,7 +133,7 @@ impl Service {
|
||||||
users.push(root_pdu.sender);
|
users.push(root_pdu.sender);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
users.push(pdu.sender.clone());
|
users.push(event.sender().to_owned());
|
||||||
|
|
||||||
self.update_participants(&root_id, &users)
|
self.update_participants(&root_id, &users)
|
||||||
}
|
}
|
||||||
|
|
|
@ -375,8 +375,6 @@ impl Service {
|
||||||
.await
|
.await
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
let sync_pdu = pdu.to_sync_room_event();
|
|
||||||
|
|
||||||
let mut push_target: HashSet<_> = self
|
let mut push_target: HashSet<_> = self
|
||||||
.services
|
.services
|
||||||
.state_cache
|
.state_cache
|
||||||
|
@ -401,6 +399,7 @@ impl Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let serialized = pdu.to_format();
|
||||||
for user in &push_target {
|
for user in &push_target {
|
||||||
let rules_for_user = self
|
let rules_for_user = self
|
||||||
.services
|
.services
|
||||||
|
@ -418,7 +417,7 @@ impl Service {
|
||||||
for action in self
|
for action in self
|
||||||
.services
|
.services
|
||||||
.pusher
|
.pusher
|
||||||
.get_actions(user, &rules_for_user, &power_levels, &sync_pdu, &pdu.room_id)
|
.get_actions(user, &rules_for_user, &power_levels, &serialized, &pdu.room_id)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
match action {
|
match action {
|
||||||
|
@ -768,7 +767,7 @@ impl Service {
|
||||||
|
|
||||||
let auth_fetch = |k: &StateEventType, s: &str| {
|
let auth_fetch = |k: &StateEventType, s: &str| {
|
||||||
let key = (k.clone(), s.into());
|
let key = (k.clone(), s.into());
|
||||||
ready(auth_events.get(&key))
|
ready(auth_events.get(&key).map(ToOwned::to_owned))
|
||||||
};
|
};
|
||||||
|
|
||||||
let auth_check = state_res::auth_check(
|
let auth_check = state_res::auth_check(
|
||||||
|
|
|
@ -9,8 +9,8 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use base64::{Engine as _, engine::general_purpose::URL_SAFE_NO_PAD};
|
use base64::{Engine as _, engine::general_purpose::URL_SAFE_NO_PAD};
|
||||||
use conduwuit::{
|
use conduwuit_core::{
|
||||||
Error, Result, debug, err, error,
|
Error, Event, Result, debug, err, error,
|
||||||
result::LogErr,
|
result::LogErr,
|
||||||
trace,
|
trace,
|
||||||
utils::{
|
utils::{
|
||||||
|
@ -697,7 +697,7 @@ impl Service {
|
||||||
match event {
|
match event {
|
||||||
| SendingEvent::Pdu(pdu_id) => {
|
| SendingEvent::Pdu(pdu_id) => {
|
||||||
if let Ok(pdu) = self.services.timeline.get_pdu_from_id(pdu_id).await {
|
if let Ok(pdu) = self.services.timeline.get_pdu_from_id(pdu_id).await {
|
||||||
pdu_jsons.push(pdu.into_room_event());
|
pdu_jsons.push(pdu.to_format());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
| SendingEvent::Edu(edu) =>
|
| SendingEvent::Edu(edu) =>
|
||||||
|
|
Loading…
Add table
Reference in a new issue