common: Add support for extensible location events
According to MSC3488
This commit is contained in:
parent
5af2e38506
commit
195ddf8112
@ -34,6 +34,7 @@ unstable-msc2675 = []
|
|||||||
unstable-msc2676 = []
|
unstable-msc2676 = []
|
||||||
unstable-msc2677 = []
|
unstable-msc2677 = []
|
||||||
unstable-msc3246 = ["unstable-msc3551", "thiserror"]
|
unstable-msc3246 = ["unstable-msc3551", "thiserror"]
|
||||||
|
unstable-msc3488 = ["unstable-msc1767"]
|
||||||
unstable-msc3551 = ["unstable-msc1767"]
|
unstable-msc3551 = ["unstable-msc1767"]
|
||||||
unstable-msc3552 = ["unstable-msc1767", "unstable-msc3551"]
|
unstable-msc3552 = ["unstable-msc1767", "unstable-msc3551"]
|
||||||
unstable-msc3553 = ["unstable-msc3552"]
|
unstable-msc3553 = ["unstable-msc3552"]
|
||||||
|
@ -159,6 +159,8 @@ pub mod ignored_user_list;
|
|||||||
#[cfg(feature = "unstable-msc3552")]
|
#[cfg(feature = "unstable-msc3552")]
|
||||||
pub mod image;
|
pub mod image;
|
||||||
pub mod key;
|
pub mod key;
|
||||||
|
#[cfg(feature = "unstable-msc3488")]
|
||||||
|
pub mod location;
|
||||||
#[cfg(feature = "unstable-msc1767")]
|
#[cfg(feature = "unstable-msc1767")]
|
||||||
pub mod message;
|
pub mod message;
|
||||||
#[cfg(feature = "unstable-msc1767")]
|
#[cfg(feature = "unstable-msc1767")]
|
||||||
|
@ -52,6 +52,8 @@ event_enum! {
|
|||||||
"m.key.verification.key",
|
"m.key.verification.key",
|
||||||
"m.key.verification.mac",
|
"m.key.verification.mac",
|
||||||
"m.key.verification.done",
|
"m.key.verification.done",
|
||||||
|
#[cfg(feature = "unstable-msc3488")]
|
||||||
|
"m.location",
|
||||||
#[cfg(feature = "unstable-msc1767")]
|
#[cfg(feature = "unstable-msc1767")]
|
||||||
"m.message",
|
"m.message",
|
||||||
#[cfg(feature = "unstable-msc1767")]
|
#[cfg(feature = "unstable-msc1767")]
|
||||||
@ -374,6 +376,8 @@ impl AnyMessageLikeEventContent {
|
|||||||
Self::Emote(ev) => ev.relates_to.clone().map(Into::into),
|
Self::Emote(ev) => ev.relates_to.clone().map(Into::into),
|
||||||
#[cfg(feature = "unstable-msc3246")]
|
#[cfg(feature = "unstable-msc3246")]
|
||||||
Self::Audio(ev) => ev.relates_to.clone().map(Into::into),
|
Self::Audio(ev) => ev.relates_to.clone().map(Into::into),
|
||||||
|
#[cfg(feature = "unstable-msc3488")]
|
||||||
|
Self::Location(ev) => ev.relates_to.clone().map(Into::into),
|
||||||
#[cfg(feature = "unstable-msc3551")]
|
#[cfg(feature = "unstable-msc3551")]
|
||||||
Self::File(ev) => ev.relates_to.clone().map(Into::into),
|
Self::File(ev) => ev.relates_to.clone().map(Into::into),
|
||||||
#[cfg(feature = "unstable-msc3552")]
|
#[cfg(feature = "unstable-msc3552")]
|
||||||
|
173
crates/ruma-common/src/events/location.rs
Normal file
173
crates/ruma-common/src/events/location.rs
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
//! Types for extensible location message events ([MSC3488]).
|
||||||
|
//!
|
||||||
|
//! [MSC3488]: https://github.com/matrix-org/matrix-spec-proposals/pull/3488
|
||||||
|
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
|
use js_int::UInt;
|
||||||
|
use ruma_macros::{EventContent, StringEnum};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
mod zoomlevel_serde;
|
||||||
|
|
||||||
|
use super::{message::MessageContent, room::message::Relation};
|
||||||
|
use crate::{MilliSecondsSinceUnixEpoch, PrivOwnedStr};
|
||||||
|
|
||||||
|
/// The payload for an extensible location message.
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, EventContent)]
|
||||||
|
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
||||||
|
#[ruma_event(type = "m.location", kind = MessageLike)]
|
||||||
|
pub struct LocationEventContent {
|
||||||
|
/// The text representation of the message.
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub message: MessageContent,
|
||||||
|
|
||||||
|
/// The location info of the message.
|
||||||
|
#[serde(rename = "org.matrix.msc3488.location")]
|
||||||
|
pub location: LocationContent,
|
||||||
|
|
||||||
|
/// The asset this message refers to.
|
||||||
|
#[serde(
|
||||||
|
default,
|
||||||
|
rename = "org.matrix.msc3488.asset",
|
||||||
|
skip_serializing_if = "ruma_common::serde::is_default"
|
||||||
|
)]
|
||||||
|
pub asset: AssetContent,
|
||||||
|
|
||||||
|
/// The timestamp this message refers to.
|
||||||
|
#[serde(rename = "org.matrix.msc3488.ts", skip_serializing_if = "Option::is_none")]
|
||||||
|
pub ts: Option<MilliSecondsSinceUnixEpoch>,
|
||||||
|
|
||||||
|
/// Information about related messages.
|
||||||
|
#[serde(flatten, skip_serializing_if = "Option::is_none")]
|
||||||
|
pub relates_to: Option<Relation>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LocationEventContent {
|
||||||
|
/// Creates a new `LocationEventContent` with the given plain text representation and location.
|
||||||
|
pub fn plain(message: impl Into<String>, location: LocationContent) -> Self {
|
||||||
|
Self {
|
||||||
|
message: MessageContent::plain(message),
|
||||||
|
location,
|
||||||
|
asset: Default::default(),
|
||||||
|
ts: None,
|
||||||
|
relates_to: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new `LocationEventContent` with the given text representation and location.
|
||||||
|
pub fn with_message(message: MessageContent, location: LocationContent) -> Self {
|
||||||
|
Self { message, location, asset: Default::default(), ts: None, relates_to: None }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Location content.
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
||||||
|
pub struct LocationContent {
|
||||||
|
/// A `geo:` URI representing the location.
|
||||||
|
///
|
||||||
|
/// See [RFC 5870](https://datatracker.ietf.org/doc/html/rfc5870) for more details.
|
||||||
|
pub uri: String,
|
||||||
|
|
||||||
|
/// The description of the location.
|
||||||
|
///
|
||||||
|
/// It should be used to label the location on a map.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub description: Option<String>,
|
||||||
|
|
||||||
|
/// A zoom level to specify the displayed area size.
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub zoom_level: Option<ZoomLevel>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LocationContent {
|
||||||
|
/// Creates a new `LocationContent` with the given geo URI.
|
||||||
|
pub fn new(uri: String) -> Self {
|
||||||
|
Self { uri, description: None, zoom_level: None }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An error encountered when trying to convert to a `ZoomLevel`.
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, thiserror::Error)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum ZoomLevelError {
|
||||||
|
/// The value is higher than [`ZoomLevel::MAX`].
|
||||||
|
#[error("value too high")]
|
||||||
|
TooHigh,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A zoom level.
|
||||||
|
///
|
||||||
|
/// This is an integer between 0 and 20 as defined in the [OpenStreetMap Wiki].
|
||||||
|
///
|
||||||
|
/// [OpenStreetMap Wiki]: https://wiki.openstreetmap.org/wiki/Zoom_levels
|
||||||
|
#[derive(Clone, Debug, Serialize)]
|
||||||
|
pub struct ZoomLevel(UInt);
|
||||||
|
|
||||||
|
impl ZoomLevel {
|
||||||
|
/// The smallest value of a `ZoomLevel`, 0.
|
||||||
|
pub const MIN: u8 = 0;
|
||||||
|
|
||||||
|
/// The largest value of a `ZoomLevel`, 20.
|
||||||
|
pub const MAX: u8 = 20;
|
||||||
|
|
||||||
|
/// Creates a new `ZoomLevel` with the given value.
|
||||||
|
pub fn new(value: u8) -> Option<Self> {
|
||||||
|
if value > Self::MAX {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(Self(value.into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The value of this `ZoomLevel`.
|
||||||
|
pub fn value(&self) -> UInt {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u8> for ZoomLevel {
|
||||||
|
type Error = ZoomLevelError;
|
||||||
|
|
||||||
|
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||||
|
Self::new(value).ok_or(ZoomLevelError::TooHigh)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Asset content.
|
||||||
|
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
||||||
|
pub struct AssetContent {
|
||||||
|
/// The type of asset being referred to.
|
||||||
|
#[serde(rename = "type")]
|
||||||
|
pub type_: AssetType,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AssetContent {
|
||||||
|
/// Creates a new default `AssetContent`.
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The type of an asset.
|
||||||
|
///
|
||||||
|
/// This type can hold an arbitrary string. To check for formats that are not available as a
|
||||||
|
/// documented variant here, use its string representation, obtained through `.as_str()`.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, StringEnum)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum AssetType {
|
||||||
|
/// The asset is the sender of the event.
|
||||||
|
#[ruma_enum(rename = "m.self")]
|
||||||
|
Self_,
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
_Custom(PrivOwnedStr),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for AssetType {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Self_
|
||||||
|
}
|
||||||
|
}
|
20
crates/ruma-common/src/events/location/zoomlevel_serde.rs
Normal file
20
crates/ruma-common/src/events/location/zoomlevel_serde.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
//! `Serialize` and `Deserialize` implementations for extensible events (MSC1767).
|
||||||
|
|
||||||
|
use js_int::UInt;
|
||||||
|
use serde::{de, Deserialize};
|
||||||
|
|
||||||
|
use super::{ZoomLevel, ZoomLevelError};
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for ZoomLevel {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let uint = UInt::deserialize(deserializer)?;
|
||||||
|
if uint > Self::MAX.into() {
|
||||||
|
Err(de::Error::custom(ZoomLevelError::TooHigh))
|
||||||
|
} else {
|
||||||
|
Ok(Self(uint))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
230
crates/ruma-common/tests/events/location.rs
Normal file
230
crates/ruma-common/tests/events/location.rs
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
#![cfg(feature = "unstable-msc3488")]
|
||||||
|
|
||||||
|
use assign::assign;
|
||||||
|
use js_int::uint;
|
||||||
|
use matches::assert_matches;
|
||||||
|
use ruma_common::{
|
||||||
|
event_id,
|
||||||
|
events::{
|
||||||
|
location::{
|
||||||
|
AssetContent, AssetType, LocationContent, LocationEventContent, ZoomLevel,
|
||||||
|
ZoomLevelError,
|
||||||
|
},
|
||||||
|
message::MessageContent,
|
||||||
|
room::message::{InReplyTo, Relation},
|
||||||
|
AnyMessageLikeEvent, MessageLikeEvent, Unsigned,
|
||||||
|
},
|
||||||
|
room_id, user_id, MilliSecondsSinceUnixEpoch,
|
||||||
|
};
|
||||||
|
use serde_json::{from_value as from_json_value, json, to_value as to_json_value};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn plain_content_serialization() {
|
||||||
|
let event_content = LocationEventContent::plain(
|
||||||
|
"Alice was at geo:51.5008,0.1247;u=35",
|
||||||
|
LocationContent::new("geo:51.5008,0.1247;u=35".to_owned()),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
to_json_value(&event_content).unwrap(),
|
||||||
|
json!({
|
||||||
|
"org.matrix.msc1767.text": "Alice was at geo:51.5008,0.1247;u=35",
|
||||||
|
"org.matrix.msc3488.location": {
|
||||||
|
"uri": "geo:51.5008,0.1247;u=35",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn event_serialization() {
|
||||||
|
let event = MessageLikeEvent {
|
||||||
|
content: assign!(
|
||||||
|
LocationEventContent::with_message(
|
||||||
|
MessageContent::html(
|
||||||
|
"Alice was at geo:51.5008,0.1247;u=35 as of Sat Nov 13 18:50:58 2021",
|
||||||
|
"Alice was at <strong>geo:51.5008,0.1247;u=35</strong> as of <em>Sat Nov 13 18:50:58 2021</em>",
|
||||||
|
),
|
||||||
|
assign!(
|
||||||
|
LocationContent::new("geo:51.5008,0.1247;u=35".to_owned()),
|
||||||
|
{
|
||||||
|
description: Some("Alice's whereabouts".into()),
|
||||||
|
zoom_level: Some(ZoomLevel::new(4).unwrap())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
),
|
||||||
|
{
|
||||||
|
ts: Some(MilliSecondsSinceUnixEpoch(uint!(1_636_829_458))),
|
||||||
|
relates_to: Some(Relation::Reply {
|
||||||
|
in_reply_to: InReplyTo::new(event_id!("$replyevent:example.com").to_owned()),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
event_id: event_id!("$event:notareal.hs").to_owned(),
|
||||||
|
sender: user_id!("@user:notareal.hs").to_owned(),
|
||||||
|
origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(134_829_848)),
|
||||||
|
room_id: room_id!("!roomid:notareal.hs").to_owned(),
|
||||||
|
unsigned: Unsigned::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
to_json_value(&event).unwrap(),
|
||||||
|
json!({
|
||||||
|
"content": {
|
||||||
|
"org.matrix.msc1767.message": [
|
||||||
|
{
|
||||||
|
"body": "Alice was at <strong>geo:51.5008,0.1247;u=35</strong> as of <em>Sat Nov 13 18:50:58 2021</em>",
|
||||||
|
"mimetype": "text/html",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"body": "Alice was at geo:51.5008,0.1247;u=35 as of Sat Nov 13 18:50:58 2021",
|
||||||
|
"mimetype": "text/plain",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"org.matrix.msc3488.location": {
|
||||||
|
"uri": "geo:51.5008,0.1247;u=35",
|
||||||
|
"description": "Alice's whereabouts",
|
||||||
|
"zoom_level": 4,
|
||||||
|
},
|
||||||
|
"org.matrix.msc3488.ts": 1_636_829_458,
|
||||||
|
"m.relates_to": {
|
||||||
|
"m.in_reply_to": {
|
||||||
|
"event_id": "$replyevent:example.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"event_id": "$event:notareal.hs",
|
||||||
|
"origin_server_ts": 134_829_848,
|
||||||
|
"room_id": "!roomid:notareal.hs",
|
||||||
|
"sender": "@user:notareal.hs",
|
||||||
|
"type": "m.location",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn plain_content_deserialization() {
|
||||||
|
let json_data = json!({
|
||||||
|
"org.matrix.msc1767.text": "Alice was at geo:51.5008,0.1247;u=35",
|
||||||
|
"org.matrix.msc3488.location": {
|
||||||
|
"uri": "geo:51.5008,0.1247;u=35",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_matches!(
|
||||||
|
from_json_value::<LocationEventContent>(json_data)
|
||||||
|
.unwrap(),
|
||||||
|
LocationEventContent {
|
||||||
|
message,
|
||||||
|
location: LocationContent {
|
||||||
|
uri,
|
||||||
|
description: None,
|
||||||
|
zoom_level: None,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
asset: AssetContent {
|
||||||
|
type_: AssetType::Self_,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
ts: None,
|
||||||
|
..
|
||||||
|
}
|
||||||
|
if message.find_plain() == Some("Alice was at geo:51.5008,0.1247;u=35")
|
||||||
|
&& message.find_html().is_none()
|
||||||
|
&& uri == "geo:51.5008,0.1247;u=35"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn zoomlevel_deserialization_pass() {
|
||||||
|
let json_data = json!({
|
||||||
|
"uri": "geo:51.5008,0.1247;u=35",
|
||||||
|
"zoom_level": 16,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_matches!(
|
||||||
|
from_json_value::<LocationContent>(json_data).unwrap(),
|
||||||
|
LocationContent {
|
||||||
|
zoom_level: Some(zoom_level),
|
||||||
|
..
|
||||||
|
} if zoom_level.value() == uint!(16)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn zoomlevel_deserialization_too_high() {
|
||||||
|
let json_data = json!({
|
||||||
|
"uri": "geo:51.5008,0.1247;u=35",
|
||||||
|
"zoom_level": 30,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_matches!(
|
||||||
|
from_json_value::<LocationContent>(json_data),
|
||||||
|
Err(err)
|
||||||
|
if err.is_data()
|
||||||
|
&& format!("{}", err) == format!("{}", ZoomLevelError::TooHigh)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn message_event_deserialization() {
|
||||||
|
let json_data = json!({
|
||||||
|
"content": {
|
||||||
|
"org.matrix.msc1767.message": [
|
||||||
|
{ "body": "Alice was at geo:51.5008,0.1247;u=35 as of Sat Nov 13 18:50:58 2021" },
|
||||||
|
],
|
||||||
|
"org.matrix.msc3488.location": {
|
||||||
|
"uri": "geo:51.5008,0.1247;u=35",
|
||||||
|
"description": "Alice's whereabouts",
|
||||||
|
"zoom_level": 4,
|
||||||
|
},
|
||||||
|
"org.matrix.msc3488.ts": 1_636_829_458,
|
||||||
|
"m.relates_to": {
|
||||||
|
"m.in_reply_to": {
|
||||||
|
"event_id": "$replyevent:example.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"event_id": "$event:notareal.hs",
|
||||||
|
"origin_server_ts": 134_829_848,
|
||||||
|
"room_id": "!roomid:notareal.hs",
|
||||||
|
"sender": "@user:notareal.hs",
|
||||||
|
"type": "m.location",
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_matches!(
|
||||||
|
from_json_value::<AnyMessageLikeEvent>(json_data).unwrap(),
|
||||||
|
AnyMessageLikeEvent::Location(MessageLikeEvent {
|
||||||
|
content: LocationEventContent {
|
||||||
|
message,
|
||||||
|
location: LocationContent {
|
||||||
|
uri,
|
||||||
|
description: Some(description),
|
||||||
|
zoom_level: Some(zoom_level),
|
||||||
|
..
|
||||||
|
},
|
||||||
|
asset: AssetContent {
|
||||||
|
type_: AssetType::Self_,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
ts: Some(ts),
|
||||||
|
..
|
||||||
|
},
|
||||||
|
event_id,
|
||||||
|
origin_server_ts,
|
||||||
|
room_id,
|
||||||
|
sender,
|
||||||
|
unsigned
|
||||||
|
}) if event_id == event_id!("$event:notareal.hs")
|
||||||
|
&& message.find_plain() == Some("Alice was at geo:51.5008,0.1247;u=35 as of Sat Nov 13 18:50:58 2021")
|
||||||
|
&& message.find_html().is_none()
|
||||||
|
&& uri == "geo:51.5008,0.1247;u=35"
|
||||||
|
&& description == "Alice's whereabouts"
|
||||||
|
&& zoom_level.value() == uint!(4)
|
||||||
|
&& ts == MilliSecondsSinceUnixEpoch(uint!(1_636_829_458))
|
||||||
|
&& origin_server_ts == MilliSecondsSinceUnixEpoch(uint!(134_829_848))
|
||||||
|
&& room_id == room_id!("!roomid:notareal.hs")
|
||||||
|
&& sender == user_id!("@user:notareal.hs")
|
||||||
|
&& unsigned.is_empty()
|
||||||
|
);
|
||||||
|
}
|
@ -11,6 +11,7 @@ mod event_enums;
|
|||||||
mod file;
|
mod file;
|
||||||
mod image;
|
mod image;
|
||||||
mod initial_state;
|
mod initial_state;
|
||||||
|
mod location;
|
||||||
mod message;
|
mod message;
|
||||||
mod message_event;
|
mod message_event;
|
||||||
mod pdu;
|
mod pdu;
|
||||||
|
@ -118,6 +118,7 @@ unstable-msc2675 = ["ruma-common/unstable-msc2675"]
|
|||||||
unstable-msc2676 = ["ruma-common/unstable-msc2676"]
|
unstable-msc2676 = ["ruma-common/unstable-msc2676"]
|
||||||
unstable-msc2677 = ["ruma-common/unstable-msc2677"]
|
unstable-msc2677 = ["ruma-common/unstable-msc2677"]
|
||||||
unstable-msc3246 = ["ruma-common/unstable-msc3246"]
|
unstable-msc3246 = ["ruma-common/unstable-msc3246"]
|
||||||
|
unstable-msc3488 = ["ruma-common/unstable-msc3488"]
|
||||||
unstable-msc3551 = ["ruma-common/unstable-msc3551"]
|
unstable-msc3551 = ["ruma-common/unstable-msc3551"]
|
||||||
unstable-msc3552 = ["ruma-common/unstable-msc3552"]
|
unstable-msc3552 = ["ruma-common/unstable-msc3552"]
|
||||||
unstable-msc3553 = ["ruma-common/unstable-msc3553"]
|
unstable-msc3553 = ["ruma-common/unstable-msc3553"]
|
||||||
@ -134,6 +135,7 @@ __ci = [
|
|||||||
"unstable-msc2676",
|
"unstable-msc2676",
|
||||||
"unstable-msc2677",
|
"unstable-msc2677",
|
||||||
"unstable-msc3246",
|
"unstable-msc3246",
|
||||||
|
"unstable-msc3488",
|
||||||
"unstable-msc3551",
|
"unstable-msc3551",
|
||||||
"unstable-msc3552",
|
"unstable-msc3552",
|
||||||
"unstable-msc3553",
|
"unstable-msc3553",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user