mirror of
https://forgejo.ellis.link/continuwuation/continuwuity.git
synced 2026-05-26 20:49:55 +00:00
refactor: Ruma upstraming, bake a little more
This commit is contained in:
@@ -25,7 +25,7 @@ pub fn gen_event_id(
|
||||
room_version_id: &RoomVersionId,
|
||||
) -> Result<OwnedEventId> {
|
||||
let Some(rules) = room_version_id.rules() else {
|
||||
return Err!("Cannot generate event ID for unknown room version {room_version_id}")
|
||||
return Err!("Cannot generate event ID for unknown room version {room_version_id}");
|
||||
};
|
||||
let reference_hash = ruma::signatures::reference_hash(value, &rules)?;
|
||||
let event_id: OwnedEventId = format!("${reference_hash}").try_into()?;
|
||||
|
||||
@@ -9,4 +9,4 @@ pub mod versions;
|
||||
pub use event::{Event, TypeExt as EventTypeExt};
|
||||
pub use pdu::{Pdu, PduBuilder, PduCount, PduEvent, PduId, RawPduId, ShortId};
|
||||
pub use state_key::StateKey;
|
||||
pub use state_res::{StateMap, TypeStateKey};
|
||||
pub use state_res::{StateMap, TypeStateKey};
|
||||
|
||||
@@ -6,7 +6,7 @@ use crate::{Err, Error, Result, err, implement};
|
||||
#[implement(super::Pdu)]
|
||||
pub fn redact(&mut self, room_version_id: &RoomVersionId, reason: JsonValue) -> Result {
|
||||
let Some(rules) = room_version_id.rules() else {
|
||||
return Err!("Cannot redact event for unknown room version {room_version_id}")
|
||||
return Err!("Cannot redact event for unknown room version {room_version_id}");
|
||||
};
|
||||
|
||||
self.unsigned = None;
|
||||
@@ -14,8 +14,7 @@ pub fn redact(&mut self, room_version_id: &RoomVersionId, reason: JsonValue) ->
|
||||
let mut content = serde_json::from_str(self.content.get())
|
||||
.map_err(|e| err!(Request(BadJson("Failed to deserialize content into type: {e}"))))?;
|
||||
|
||||
redact_content_in_place(&mut content, &rules.redaction, self.kind.to_string())
|
||||
.map_err(|e| Error::Redaction(self.sender.server_name().to_owned(), e))?;
|
||||
redact_content_in_place(&mut content, &rules.redaction, self.kind.to_string());
|
||||
|
||||
let reason = serde_json::to_value(reason).expect("Failed to preserialize reason");
|
||||
|
||||
|
||||
@@ -5,12 +5,16 @@ use futures::{
|
||||
future::{OptionFuture, join, join3},
|
||||
};
|
||||
use ruma::{
|
||||
Int, OwnedUserId, RoomVersionId, UserId, events::room::{
|
||||
Int, OwnedUserId, RoomVersionId, UserId,
|
||||
events::room::{
|
||||
create::RoomCreateEventContent,
|
||||
join_rules::{JoinRule, RoomJoinRulesEventContent},
|
||||
member::{MembershipState, ThirdPartyInvite},
|
||||
power_levels::RoomPowerLevelsEventContent,
|
||||
}, int, room_version_rules::{RoomIdFormatVersion, RoomVersionRules}, serde::Raw,
|
||||
},
|
||||
int,
|
||||
room_version_rules::{RoomIdFormatVersion, RoomVersionRules},
|
||||
serde::Raw,
|
||||
};
|
||||
use serde::{
|
||||
Deserialize,
|
||||
@@ -117,11 +121,11 @@ pub fn auth_types_for_event(
|
||||
|
||||
// TODO: restore this once 3pid support isn't broken
|
||||
// if membership == MembershipState::Invite {
|
||||
// if let Some(Ok(t_id)) = content.third_party_invite.map(|t| t.deserialize()) {
|
||||
// let key =
|
||||
// (StateEventType::RoomThirdPartyInvite, t_id.signed.token.into());
|
||||
// if !auth_types.contains(&key) {
|
||||
// auth_types.push(key);
|
||||
// if let Some(Ok(t_id)) = content.third_party_invite.map(|t|
|
||||
// t.deserialize()) { let key =
|
||||
// (StateEventType::RoomThirdPartyInvite,
|
||||
// t_id.signed.token.into()); if !auth_types.contains(&
|
||||
// key) { auth_types.push(key);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
@@ -214,13 +218,17 @@ where
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
if room_version.room_id_format == RoomIdFormatVersion::V2 && incoming_event.room_id().is_some() {
|
||||
if room_version.room_id_format == RoomIdFormatVersion::V2
|
||||
&& incoming_event.room_id().is_some()
|
||||
{
|
||||
warn!("room create event incorrectly claims to have a room ID when it should not");
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
if !room_version.authorization.use_room_create_sender
|
||||
&& !room_version.authorization.explicitly_privilege_room_creators
|
||||
&& !room_version
|
||||
.authorization
|
||||
.explicitly_privilege_room_creators
|
||||
{
|
||||
// If content has no creator field, reject
|
||||
if content.creator.is_none() {
|
||||
@@ -343,7 +351,7 @@ where
|
||||
// Only in some room versions 6 and below
|
||||
if room_version.authorization.special_case_room_aliases {
|
||||
// 4. If type is m.room.aliases
|
||||
if *incoming_event.event_type() == TimelineEventType::RoomAliases {
|
||||
if *incoming_event.event_type() == TimelineEventType::from("m.room.aliases") {
|
||||
debug!("starting m.room.aliases check");
|
||||
|
||||
// If sender's domain doesn't matches state_key, reject
|
||||
@@ -493,7 +501,10 @@ where
|
||||
if is_creator { int!(100) } else { int!(0) }
|
||||
},
|
||||
};
|
||||
if room_version.authorization.explicitly_privilege_room_creators {
|
||||
if room_version
|
||||
.authorization
|
||||
.explicitly_privilege_room_creators
|
||||
{
|
||||
// If the user sent the create event, or is listed in additional_creators, just
|
||||
// give them Int::MAX
|
||||
if sender == room_create_event.sender()
|
||||
@@ -555,7 +566,10 @@ where
|
||||
if *incoming_event.event_type() == TimelineEventType::RoomPowerLevels {
|
||||
debug!("starting m.room.power_levels check");
|
||||
let mut creators = BTreeSet::new();
|
||||
if room_version.authorization.explicitly_privilege_room_creators {
|
||||
if room_version
|
||||
.authorization
|
||||
.explicitly_privilege_room_creators
|
||||
{
|
||||
creators.insert(create_event.sender().to_owned());
|
||||
for creator in room_create_content.additional_creators.iter().flatten() {
|
||||
creators.insert(creator.deserialize()?);
|
||||
@@ -710,7 +724,10 @@ where
|
||||
|
||||
let mut creators = BTreeSet::new();
|
||||
creators.insert(create_room.sender().to_owned());
|
||||
if room_version.authorization.explicitly_privilege_room_creators {
|
||||
if room_version
|
||||
.authorization
|
||||
.explicitly_privilege_room_creators
|
||||
{
|
||||
// Explicitly privilege room creators
|
||||
// If the sender sent the create event, or in additional_creators, give them
|
||||
// Int::MAX. Same case for target.
|
||||
@@ -878,7 +895,8 @@ where
|
||||
trace!(sender=%sender, "sender is invited or already joined to room, allowing join");
|
||||
true
|
||||
},
|
||||
| JoinRule::KnockRestricted(_) if !room_version.authorization.knock_restricted_join_rule =>
|
||||
| JoinRule::KnockRestricted(_)
|
||||
if !room_version.authorization.knock_restricted_join_rule =>
|
||||
{
|
||||
warn!(
|
||||
"Join rule is knock_restricted but room version does not support it"
|
||||
@@ -1508,15 +1526,17 @@ fn verify_third_party_invite(
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use ruma::{events::{
|
||||
StateEventType, TimelineEventType,
|
||||
room::{
|
||||
join_rules::{
|
||||
AllowRule, JoinRule, Restricted, RoomJoinRulesEventContent,
|
||||
use ruma::{
|
||||
events::{
|
||||
StateEventType, TimelineEventType,
|
||||
room::{
|
||||
join_rules::{AllowRule, JoinRule, Restricted, RoomJoinRulesEventContent},
|
||||
member::{MembershipState, RoomMemberEventContent},
|
||||
},
|
||||
member::{MembershipState, RoomMemberEventContent},
|
||||
},
|
||||
}, room::RoomMembership, room_version_rules::RoomVersionRules};
|
||||
room::RoomMembership,
|
||||
room_version_rules::RoomVersionRules,
|
||||
};
|
||||
use serde_json::value::to_raw_value as to_raw_json_value;
|
||||
|
||||
use crate::{
|
||||
|
||||
@@ -25,13 +25,14 @@ use ruma::{
|
||||
StateEventType, TimelineEventType,
|
||||
room::member::{MembershipState, RoomMemberEventContent},
|
||||
},
|
||||
int, room_version_rules::{RoomIdFormatVersion, RoomVersionRules, StateResolutionVersion},
|
||||
int,
|
||||
room_version_rules::{RoomIdFormatVersion, RoomVersionRules, StateResolutionVersion},
|
||||
};
|
||||
use serde_json::from_str as from_json_str;
|
||||
|
||||
pub(crate) use self::error::Error;
|
||||
use self::power_levels::PowerLevelsContentFields;
|
||||
pub use self::event_auth::{auth_check, auth_types_for_event};
|
||||
use self::power_levels::PowerLevelsContentFields;
|
||||
use crate::{
|
||||
debug, debug_error, err,
|
||||
matrix::{Event, StateKey},
|
||||
@@ -106,19 +107,21 @@ where
|
||||
|
||||
debug!(count = conflicting.len(), "conflicting events");
|
||||
trace!(map = ?conflicting, "conflicting events");
|
||||
let (conflicted_state_subgraph, initial_state) =
|
||||
if let StateResolutionVersion::V2(v2_rules) = stateres_version && v2_rules.consider_conflicted_state_subgraph {
|
||||
let csg = calculate_conflicted_subgraph(&conflicting, event_fetch)
|
||||
.await
|
||||
.ok_or_else(|| {
|
||||
Error::InvalidPdu("Failed to calculate conflicted subgraph".to_owned())
|
||||
})?;
|
||||
debug!(count = csg.len(), "conflicted subgraph");
|
||||
trace!(set = ?csg, "conflicted subgraph");
|
||||
(csg, HashMap::new())
|
||||
} else {
|
||||
(HashSet::new(), unconflicted.clone())
|
||||
};
|
||||
let (conflicted_state_subgraph, initial_state) = if let StateResolutionVersion::V2(v2_rules) =
|
||||
stateres_version
|
||||
&& v2_rules.consider_conflicted_state_subgraph
|
||||
{
|
||||
let csg = calculate_conflicted_subgraph(&conflicting, event_fetch)
|
||||
.await
|
||||
.ok_or_else(|| {
|
||||
Error::InvalidPdu("Failed to calculate conflicted subgraph".to_owned())
|
||||
})?;
|
||||
debug!(count = csg.len(), "conflicted subgraph");
|
||||
trace!(set = ?csg, "conflicted subgraph");
|
||||
(csg, HashMap::new())
|
||||
} else {
|
||||
(HashSet::new(), unconflicted.clone())
|
||||
};
|
||||
|
||||
// `all_conflicted` contains unique items
|
||||
// synapse says `full_set = {eid for eid in full_conflicted_set if eid in
|
||||
@@ -974,10 +977,14 @@ mod tests {
|
||||
use maplit::{hashmap, hashset};
|
||||
use rand::seq::SliceRandom;
|
||||
use ruma::{
|
||||
MilliSecondsSinceUnixEpoch, OwnedEventId, RoomVersionId, events::{
|
||||
MilliSecondsSinceUnixEpoch, OwnedEventId, RoomVersionId,
|
||||
events::{
|
||||
StateEventType, TimelineEventType,
|
||||
room::join_rules::{JoinRule, RoomJoinRulesEventContent},
|
||||
}, int, room_version_rules::RoomVersionRules, uint
|
||||
},
|
||||
int,
|
||||
room_version_rules::RoomVersionRules,
|
||||
uint,
|
||||
};
|
||||
use serde_json::{json, value::to_raw_value as to_raw_json_value};
|
||||
|
||||
@@ -1423,13 +1430,18 @@ mod tests {
|
||||
})
|
||||
.collect();
|
||||
|
||||
let resolved =
|
||||
match super::resolve(&RoomVersionRules::V2, &state_sets, &auth_chain, &fetcher, &exists)
|
||||
.await
|
||||
{
|
||||
| Ok(state) => state,
|
||||
| Err(e) => panic!("{e}"),
|
||||
};
|
||||
let resolved = match super::resolve(
|
||||
&RoomVersionRules::V2,
|
||||
&state_sets,
|
||||
&auth_chain,
|
||||
&fetcher,
|
||||
&exists,
|
||||
)
|
||||
.await
|
||||
{
|
||||
| Ok(state) => state,
|
||||
| Err(e) => panic!("{e}"),
|
||||
};
|
||||
|
||||
assert_eq!(expected, resolved);
|
||||
}
|
||||
@@ -1536,13 +1548,18 @@ mod tests {
|
||||
|
||||
let fetcher = |id: OwnedEventId| ready(ev_map.get(&id).cloned());
|
||||
let exists = |id: OwnedEventId| ready(ev_map.get(&id).is_some());
|
||||
let resolved =
|
||||
match super::resolve(&RoomVersionRules::V6, &state_sets, &auth_chain, &fetcher, &exists)
|
||||
.await
|
||||
{
|
||||
| Ok(state) => state,
|
||||
| Err(e) => panic!("{e}"),
|
||||
};
|
||||
let resolved = match super::resolve(
|
||||
&RoomVersionRules::V6,
|
||||
&state_sets,
|
||||
&auth_chain,
|
||||
&fetcher,
|
||||
&exists,
|
||||
)
|
||||
.await
|
||||
{
|
||||
| Ok(state) => state,
|
||||
| Err(e) => panic!("{e}"),
|
||||
};
|
||||
|
||||
debug!(
|
||||
resolved = ?resolved
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use ruma::{
|
||||
Int, OwnedUserId, UserId, events::{TimelineEventType, room::power_levels::RoomPowerLevelsEventContent}, power_levels::{NotificationPowerLevels, default_power_level}, room_version_rules::{AuthorizationRules, RoomVersionRules}, serde::deserialize_v1_powerlevel
|
||||
Int, OwnedUserId, UserId,
|
||||
events::{TimelineEventType, room::power_levels::RoomPowerLevelsEventContent},
|
||||
power_levels::{NotificationPowerLevels, default_power_level},
|
||||
room_version_rules::{AuthorizationRules, RoomVersionRules},
|
||||
serde::deserialize_v1_powerlevel,
|
||||
};
|
||||
use super::serde_backports::*;
|
||||
use serde::Deserialize;
|
||||
use serde_json::{Error, from_str as from_json_str};
|
||||
|
||||
use super::Result;
|
||||
use super::{Result, serde_backports::*};
|
||||
use crate::error;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
@@ -44,7 +47,10 @@ struct IntRoomPowerLevelsEventContent {
|
||||
}
|
||||
|
||||
impl IntRoomPowerLevelsEventContent {
|
||||
fn to_room_power_levels_content(self, auth_rules: &AuthorizationRules) -> RoomPowerLevelsEventContent {
|
||||
fn to_room_power_levels_content(
|
||||
self,
|
||||
auth_rules: &AuthorizationRules,
|
||||
) -> RoomPowerLevelsEventContent {
|
||||
let IntRoomPowerLevelsEventContent {
|
||||
ban,
|
||||
events,
|
||||
@@ -105,7 +111,10 @@ pub(crate) fn deserialize_power_levels(
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_integer_power_levels(content: &str, auth_rules: &AuthorizationRules) -> Option<RoomPowerLevelsEventContent> {
|
||||
fn deserialize_integer_power_levels(
|
||||
content: &str,
|
||||
auth_rules: &AuthorizationRules,
|
||||
) -> Option<RoomPowerLevelsEventContent> {
|
||||
match from_json_str::<IntRoomPowerLevelsEventContent>(content) {
|
||||
| Ok(content) => Some(content.to_room_power_levels_content(auth_rules)),
|
||||
| Err(_) => {
|
||||
|
||||
@@ -1,120 +1,120 @@
|
||||
//! These functions are copied from an old version of Ruma. power_levels.rs uses them to lazily deserialize power level events.
|
||||
//! Upstream Ruma uses a much more elegant approach in its state resolution code, which we may want
|
||||
//! These functions are copied from an old version of Ruma. power_levels.rs uses
|
||||
//! them to lazily deserialize power level events. Upstream Ruma uses a much
|
||||
//! more elegant approach in its state resolution code, which we may want
|
||||
//! to look into at some point.
|
||||
|
||||
use std::marker::PhantomData;
|
||||
use std::fmt;
|
||||
use std::{fmt, marker::PhantomData};
|
||||
|
||||
use serde::{Deserialize, Deserializer, de::{MapAccess, Visitor}};
|
||||
use ruma::{Int, serde::deserialize_v1_powerlevel};
|
||||
use serde::{
|
||||
Deserialize, Deserializer,
|
||||
de::{MapAccess, Visitor},
|
||||
};
|
||||
|
||||
/// Take a Map with values of either an integer number or a string and deserialize
|
||||
/// those to integer numbers in a Vec of sorted pairs.
|
||||
/// Take a Map with values of either an integer number or a string and
|
||||
/// deserialize those to integer numbers in a Vec of sorted pairs.
|
||||
///
|
||||
/// To be used like this:
|
||||
/// `#[serde(deserialize_with = "vec_deserialize_v1_powerlevel_values")]`
|
||||
pub fn vec_deserialize_v1_powerlevel_values<'de, D, T>(de: D) -> Result<Vec<(T, Int)>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
T: Deserialize<'de> + Ord,
|
||||
D: Deserializer<'de>,
|
||||
T: Deserialize<'de> + Ord,
|
||||
{
|
||||
#[repr(transparent)]
|
||||
struct IntWrap(Int);
|
||||
#[repr(transparent)]
|
||||
struct IntWrap(Int);
|
||||
|
||||
impl<'de> Deserialize<'de> for IntWrap {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
deserialize_v1_powerlevel(deserializer).map(IntWrap)
|
||||
}
|
||||
}
|
||||
impl<'de> Deserialize<'de> for IntWrap {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
deserialize_v1_powerlevel(deserializer).map(IntWrap)
|
||||
}
|
||||
}
|
||||
|
||||
struct IntMapVisitor<T> {
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
struct IntMapVisitor<T> {
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> IntMapVisitor<T> {
|
||||
fn new() -> Self {
|
||||
Self { _phantom: PhantomData }
|
||||
}
|
||||
}
|
||||
impl<T> IntMapVisitor<T> {
|
||||
fn new() -> Self { Self { _phantom: PhantomData } }
|
||||
}
|
||||
|
||||
impl<'de, T> Visitor<'de> for IntMapVisitor<T>
|
||||
where
|
||||
T: Deserialize<'de> + Ord,
|
||||
{
|
||||
type Value = Vec<(T, Int)>;
|
||||
impl<'de, T> Visitor<'de> for IntMapVisitor<T>
|
||||
where
|
||||
T: Deserialize<'de> + Ord,
|
||||
{
|
||||
type Value = Vec<(T, Int)>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str("a map with integers or strings as values")
|
||||
}
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str("a map with integers or strings as values")
|
||||
}
|
||||
|
||||
fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Self::Value, A::Error> {
|
||||
let mut res = Vec::new();
|
||||
if let Some(hint) = map.size_hint() {
|
||||
res.reserve(hint);
|
||||
}
|
||||
fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Self::Value, A::Error> {
|
||||
let mut res = Vec::new();
|
||||
if let Some(hint) = map.size_hint() {
|
||||
res.reserve(hint);
|
||||
}
|
||||
|
||||
while let Some((k, IntWrap(v))) = map.next_entry()? {
|
||||
res.push((k, v));
|
||||
}
|
||||
while let Some((k, IntWrap(v))) = map.next_entry()? {
|
||||
res.push((k, v));
|
||||
}
|
||||
|
||||
res.sort_unstable();
|
||||
res.dedup_by(|a, b| a.0 == b.0);
|
||||
res.sort_unstable();
|
||||
res.dedup_by(|a, b| a.0 == b.0);
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
de.deserialize_map(IntMapVisitor::new())
|
||||
de.deserialize_map(IntMapVisitor::new())
|
||||
}
|
||||
|
||||
/// Take a Map with integer values and deserialize those to a Vec of sorted pairs
|
||||
/// Take a Map with integer values and deserialize those to a Vec of sorted
|
||||
/// pairs
|
||||
///
|
||||
/// To be used like this:
|
||||
/// `#[serde(deserialize_with = "vec_deserialize_int_powerlevel_values")]`
|
||||
pub fn vec_deserialize_int_powerlevel_values<'de, D, T>(de: D) -> Result<Vec<(T, Int)>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
T: Deserialize<'de> + Ord,
|
||||
D: Deserializer<'de>,
|
||||
T: Deserialize<'de> + Ord,
|
||||
{
|
||||
struct IntMapVisitor<T> {
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
struct IntMapVisitor<T> {
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> IntMapVisitor<T> {
|
||||
fn new() -> Self {
|
||||
Self { _phantom: PhantomData }
|
||||
}
|
||||
}
|
||||
impl<T> IntMapVisitor<T> {
|
||||
fn new() -> Self { Self { _phantom: PhantomData } }
|
||||
}
|
||||
|
||||
impl<'de, T> Visitor<'de> for IntMapVisitor<T>
|
||||
where
|
||||
T: Deserialize<'de> + Ord,
|
||||
{
|
||||
type Value = Vec<(T, Int)>;
|
||||
impl<'de, T> Visitor<'de> for IntMapVisitor<T>
|
||||
where
|
||||
T: Deserialize<'de> + Ord,
|
||||
{
|
||||
type Value = Vec<(T, Int)>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str("a map with integers as values")
|
||||
}
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str("a map with integers as values")
|
||||
}
|
||||
|
||||
fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Self::Value, A::Error> {
|
||||
let mut res = Vec::new();
|
||||
if let Some(hint) = map.size_hint() {
|
||||
res.reserve(hint);
|
||||
}
|
||||
fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Self::Value, A::Error> {
|
||||
let mut res = Vec::new();
|
||||
if let Some(hint) = map.size_hint() {
|
||||
res.reserve(hint);
|
||||
}
|
||||
|
||||
while let Some(item) = map.next_entry()? {
|
||||
res.push(item);
|
||||
}
|
||||
while let Some(item) = map.next_entry()? {
|
||||
res.push(item);
|
||||
}
|
||||
|
||||
res.sort_unstable();
|
||||
res.dedup_by(|a, b| a.0 == b.0);
|
||||
res.sort_unstable();
|
||||
res.dedup_by(|a, b| a.0 == b.0);
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
de.deserialize_map(IntMapVisitor::new())
|
||||
}
|
||||
de.deserialize_map(IntMapVisitor::new())
|
||||
}
|
||||
|
||||
@@ -6,13 +6,18 @@ use std::{
|
||||
|
||||
use futures::future::ready;
|
||||
use ruma::{
|
||||
EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, RoomId, RoomVersionId, ServerSignatures, UserId, event_id, events::{
|
||||
EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, RoomId, RoomVersionId, ServerSignatures,
|
||||
UserId, event_id,
|
||||
events::{
|
||||
TimelineEventType,
|
||||
room::{
|
||||
join_rules::{JoinRule, RoomJoinRulesEventContent},
|
||||
member::{MembershipState, RoomMemberEventContent},
|
||||
},
|
||||
}, int, room_id, room_version_rules::RoomVersionRules, uint, user_id
|
||||
},
|
||||
int, room_id,
|
||||
room_version_rules::RoomVersionRules,
|
||||
uint, user_id,
|
||||
};
|
||||
use serde_json::{
|
||||
json,
|
||||
@@ -130,9 +135,14 @@ pub(crate) async fn do_check(
|
||||
let event_map = &event_map;
|
||||
let fetch = |id: OwnedEventId| ready(event_map.get(&id).cloned());
|
||||
let exists = |id: OwnedEventId| ready(event_map.get(&id).is_some());
|
||||
let resolved =
|
||||
super::resolve(&RoomVersionRules::V6, state_sets, &auth_chain_sets, &fetch, &exists)
|
||||
.await;
|
||||
let resolved = super::resolve(
|
||||
&RoomVersionRules::V6,
|
||||
state_sets,
|
||||
&auth_chain_sets,
|
||||
&fetch,
|
||||
&exists,
|
||||
)
|
||||
.await;
|
||||
|
||||
match resolved {
|
||||
| Ok(state) => state,
|
||||
|
||||
+38
-38
@@ -1,44 +1,44 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
pub fn versions() -> Vec<String> {
|
||||
vec![
|
||||
"r0.0.1".to_owned(),
|
||||
"r0.1.0".to_owned(),
|
||||
"r0.2.0".to_owned(),
|
||||
"r0.3.0".to_owned(),
|
||||
"r0.4.0".to_owned(),
|
||||
"r0.5.0".to_owned(),
|
||||
"r0.6.0".to_owned(),
|
||||
"r0.6.1".to_owned(),
|
||||
"v1.1".to_owned(),
|
||||
"v1.2".to_owned(),
|
||||
"v1.3".to_owned(),
|
||||
"v1.4".to_owned(),
|
||||
"v1.5".to_owned(),
|
||||
"v1.8".to_owned(),
|
||||
"v1.11".to_owned(),
|
||||
"v1.12".to_owned(),
|
||||
"v1.13".to_owned(),
|
||||
"v1.14".to_owned(),
|
||||
]
|
||||
vec![
|
||||
"r0.0.1".to_owned(),
|
||||
"r0.1.0".to_owned(),
|
||||
"r0.2.0".to_owned(),
|
||||
"r0.3.0".to_owned(),
|
||||
"r0.4.0".to_owned(),
|
||||
"r0.5.0".to_owned(),
|
||||
"r0.6.0".to_owned(),
|
||||
"r0.6.1".to_owned(),
|
||||
"v1.1".to_owned(),
|
||||
"v1.2".to_owned(),
|
||||
"v1.3".to_owned(),
|
||||
"v1.4".to_owned(),
|
||||
"v1.5".to_owned(),
|
||||
"v1.8".to_owned(),
|
||||
"v1.11".to_owned(),
|
||||
"v1.12".to_owned(),
|
||||
"v1.13".to_owned(),
|
||||
"v1.14".to_owned(),
|
||||
]
|
||||
}
|
||||
|
||||
pub fn unstable_features() -> BTreeMap<String, bool> {
|
||||
BTreeMap::from_iter([
|
||||
("org.matrix.e2e_cross_signing".to_owned(), true),
|
||||
("org.matrix.msc2285.stable".to_owned(), true), /* private read receipts (https://github.com/matrix-org/matrix-spec-proposals/pull/2285) */
|
||||
("uk.half-shot.msc2666.query_mutual_rooms".to_owned(), true), /* query mutual rooms (https://github.com/matrix-org/matrix-spec-proposals/pull/2666) */
|
||||
("org.matrix.msc2836".to_owned(), true), /* threading/threads (https://github.com/matrix-org/matrix-spec-proposals/pull/2836) */
|
||||
("org.matrix.msc2946".to_owned(), true), /* spaces/hierarchy summaries (https://github.com/matrix-org/matrix-spec-proposals/pull/2946) */
|
||||
("org.matrix.msc3026.busy_presence".to_owned(), true), /* busy presence status (https://github.com/matrix-org/matrix-spec-proposals/pull/3026) */
|
||||
("org.matrix.msc3827".to_owned(), true), /* filtering of /publicRooms by room type (https://github.com/matrix-org/matrix-spec-proposals/pull/3827) */
|
||||
("org.matrix.msc3952_intentional_mentions".to_owned(), true), /* intentional mentions (https://github.com/matrix-org/matrix-spec-proposals/pull/3952) */
|
||||
("org.matrix.msc3916.stable".to_owned(), true), /* authenticated media (https://github.com/matrix-org/matrix-spec-proposals/pull/3916) */
|
||||
("org.matrix.msc4180".to_owned(), true), /* stable flag for 3916 (https://github.com/matrix-org/matrix-spec-proposals/pull/4180) */
|
||||
("uk.tcpip.msc4133".to_owned(), true), /* Extending User Profile API with Key:Value Pairs (https://github.com/matrix-org/matrix-spec-proposals/pull/4133) */
|
||||
("us.cloke.msc4175".to_owned(), true), /* Profile field for user time zone (https://github.com/matrix-org/matrix-spec-proposals/pull/4175) */
|
||||
("org.matrix.simplified_msc3575".to_owned(), true), /* Simplified Sliding sync (https://github.com/matrix-org/matrix-spec-proposals/pull/4186) */
|
||||
("uk.timedout.msc4323".to_owned(), true), /* agnostic suspend (https://github.com/matrix-org/matrix-spec-proposals/pull/4323) */
|
||||
("org.matrix.msc4155".to_owned(), true), /* invite filtering (https://github.com/matrix-org/matrix-spec-proposals/pull/4155) */
|
||||
])
|
||||
}
|
||||
BTreeMap::from_iter([
|
||||
("org.matrix.e2e_cross_signing".to_owned(), true),
|
||||
("org.matrix.msc2285.stable".to_owned(), true), /* private read receipts (https://github.com/matrix-org/matrix-spec-proposals/pull/2285) */
|
||||
("uk.half-shot.msc2666.query_mutual_rooms".to_owned(), true), /* query mutual rooms (https://github.com/matrix-org/matrix-spec-proposals/pull/2666) */
|
||||
("org.matrix.msc2836".to_owned(), true), /* threading/threads (https://github.com/matrix-org/matrix-spec-proposals/pull/2836) */
|
||||
("org.matrix.msc2946".to_owned(), true), /* spaces/hierarchy summaries (https://github.com/matrix-org/matrix-spec-proposals/pull/2946) */
|
||||
("org.matrix.msc3026.busy_presence".to_owned(), true), /* busy presence status (https://github.com/matrix-org/matrix-spec-proposals/pull/3026) */
|
||||
("org.matrix.msc3827".to_owned(), true), /* filtering of /publicRooms by room type (https://github.com/matrix-org/matrix-spec-proposals/pull/3827) */
|
||||
("org.matrix.msc3952_intentional_mentions".to_owned(), true), /* intentional mentions (https://github.com/matrix-org/matrix-spec-proposals/pull/3952) */
|
||||
("org.matrix.msc3916.stable".to_owned(), true), /* authenticated media (https://github.com/matrix-org/matrix-spec-proposals/pull/3916) */
|
||||
("org.matrix.msc4180".to_owned(), true), /* stable flag for 3916 (https://github.com/matrix-org/matrix-spec-proposals/pull/4180) */
|
||||
("uk.tcpip.msc4133".to_owned(), true), /* Extending User Profile API with Key:Value Pairs (https://github.com/matrix-org/matrix-spec-proposals/pull/4133) */
|
||||
("us.cloke.msc4175".to_owned(), true), /* Profile field for user time zone (https://github.com/matrix-org/matrix-spec-proposals/pull/4175) */
|
||||
("org.matrix.simplified_msc3575".to_owned(), true), /* Simplified Sliding sync (https://github.com/matrix-org/matrix-spec-proposals/pull/4186) */
|
||||
("uk.timedout.msc4323".to_owned(), true), /* agnostic suspend (https://github.com/matrix-org/matrix-spec-proposals/pull/4323) */
|
||||
("org.matrix.msc4155".to_owned(), true), /* invite filtering (https://github.com/matrix-org/matrix-spec-proposals/pull/4155) */
|
||||
])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user