federation-api: Add lots of non_exhaustive attributes, other minor fixes

This commit is contained in:
Jonas Platte 2020-08-19 02:03:26 +02:00
parent fbeae794c1
commit 64c5159f04
No known key found for this signature in database
GPG Key ID: 7D261D771D915378
16 changed files with 167 additions and 56 deletions

View File

@ -2,7 +2,9 @@
use js_int::UInt; use js_int::UInt;
use ruma_api::ruma_api; use ruma_api::ruma_api;
use ruma_common::directory::{Filter, PublicRoomsChunk, RoomNetwork}; use ruma_common::directory::{
Filter, IncomingFilter, IncomingRoomNetwork, PublicRoomsChunk, RoomNetwork,
};
ruma_api! { ruma_api! {
metadata: { metadata: {
@ -14,6 +16,8 @@ ruma_api! {
requires_authentication: true, requires_authentication: true,
} }
#[derive(Default)]
#[non_exhaustive]
request: { request: {
/// The server to fetch the public room lists from. /// The server to fetch the public room lists from.
/// ///
@ -32,26 +36,45 @@ ruma_api! {
/// Filter to apply to the results. /// Filter to apply to the results.
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub filter: Option<Filter>, pub filter: Option<Filter<'a>>,
/// Network to fetch the public room lists from. /// Network to fetch the public room lists from.
#[serde(flatten, skip_serializing_if = "ruma_serde::is_default")] #[serde(flatten, skip_serializing_if = "ruma_serde::is_default")]
pub room_network: RoomNetwork, pub room_network: RoomNetwork<'a>,
} }
#[derive(Default)]
#[non_exhaustive]
response: { response: {
/// A paginated chunk of public rooms. /// A paginated chunk of public rooms.
pub chunk: Vec<PublicRoomsChunk>, pub chunk: Vec<PublicRoomsChunk>,
/// A pagination token for the response. /// A pagination token for the response.
#[serde(skip_serializing_if = "Option::is_none")]
pub next_batch: Option<String>, pub next_batch: Option<String>,
/// A pagination token that allows fetching previous results. /// A pagination token that allows fetching previous results.
#[serde(skip_serializing_if = "Option::is_none")]
pub prev_batch: Option<String>, pub prev_batch: Option<String>,
/// An estimate on the total number of public rooms, if the server has an estimate. /// An estimate on the total number of public rooms, if the server has an estimate.
#[serde(skip_serializing_if = "Option::is_none")]
pub total_room_count_estimate: Option<UInt>, pub total_room_count_estimate: Option<UInt>,
} }
error: crate::Error error: crate::Error
} }
impl<'a> Request<'a> {
/// Creates an empty `Request`.
pub fn new() -> Self {
Default::default()
}
}
impl Response {
/// Creates an empty `Response`.
pub fn new() -> Self {
Default::default()
}
}

View File

@ -12,6 +12,7 @@ edition = "2018"
[dependencies] [dependencies]
js_int = { version = "0.1.9", features = ["serde"] } js_int = { version = "0.1.9", features = ["serde"] }
ruma-api = { version = "=0.17.0-alpha.1", path = "../ruma-api" }
ruma-identifiers = { version = "0.17.4", path = "../ruma-identifiers" } ruma-identifiers = { version = "0.17.4", path = "../ruma-identifiers" }
ruma-serde = { version = "0.2.3", path = "../ruma-serde" } ruma-serde = { version = "0.2.3", path = "../ruma-serde" }
serde = { version = "1.0.114", features = ["derive"] } serde = { version = "1.0.114", features = ["derive"] }

View File

@ -3,6 +3,7 @@
use std::fmt; use std::fmt;
use js_int::UInt; use js_int::UInt;
use ruma_api::Outgoing;
use ruma_identifiers::{RoomAliasId, RoomId}; use ruma_identifiers::{RoomAliasId, RoomId};
use serde::{ use serde::{
de::{Error, MapAccess, Visitor}, de::{Error, MapAccess, Visitor},
@ -95,15 +96,15 @@ impl From<PublicRoomsChunkInit> for PublicRoomsChunk {
} }
/// A filter for public rooms lists /// A filter for public rooms lists
#[derive(Clone, Debug, Default, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Outgoing, Serialize)]
#[non_exhaustive] #[non_exhaustive]
pub struct Filter { pub struct Filter<'a> {
/// A string to search for in the room metadata, e.g. name, topic, canonical alias etc. /// A string to search for in the room metadata, e.g. name, topic, canonical alias etc.
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub generic_search_term: Option<String>, pub generic_search_term: Option<&'a str>,
} }
impl Filter { impl<'a> Filter<'a> {
/// Creates an empty `Filter`. /// Creates an empty `Filter`.
pub fn new() -> Self { pub fn new() -> Self {
Default::default() Default::default()
@ -112,9 +113,10 @@ impl Filter {
/// Information about which networks/protocols from application services on the /// Information about which networks/protocols from application services on the
/// homeserver from which to request rooms. /// homeserver from which to request rooms.
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq, Outgoing)]
#[non_exhaustive] #[non_exhaustive]
pub enum RoomNetwork { #[incoming_derive(Clone, PartialEq, Eq, !Deserialize)]
pub enum RoomNetwork<'a> {
/// Return rooms from the Matrix network. /// Return rooms from the Matrix network.
Matrix, Matrix,
@ -122,16 +124,16 @@ pub enum RoomNetwork {
All, All,
/// Return rooms from a specific third party network/protocol. /// Return rooms from a specific third party network/protocol.
ThirdParty(String), ThirdParty(&'a str),
} }
impl Default for RoomNetwork { impl<'a> Default for RoomNetwork<'a> {
fn default() -> Self { fn default() -> Self {
RoomNetwork::Matrix RoomNetwork::Matrix
} }
} }
impl Serialize for RoomNetwork { impl<'a> Serialize for RoomNetwork<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where where
S: Serializer, S: Serializer,
@ -154,7 +156,7 @@ impl Serialize for RoomNetwork {
} }
} }
impl<'de> Deserialize<'de> for RoomNetwork { impl<'de> Deserialize<'de> for IncomingRoomNetwork {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
@ -165,7 +167,7 @@ impl<'de> Deserialize<'de> for RoomNetwork {
struct RoomNetworkVisitor; struct RoomNetworkVisitor;
impl<'de> Visitor<'de> for RoomNetworkVisitor { impl<'de> Visitor<'de> for RoomNetworkVisitor {
type Value = RoomNetwork; type Value = IncomingRoomNetwork;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("Network selection") formatter.write_str("Network selection")
@ -194,7 +196,7 @@ impl<'de> Visitor<'de> for RoomNetworkVisitor {
if include_all_networks { if include_all_networks {
if third_party_instance_id.is_none() { if third_party_instance_id.is_none() {
Ok(RoomNetwork::All) Ok(IncomingRoomNetwork::All)
} else { } else {
Err(M::Error::custom( Err(M::Error::custom(
"`include_all_networks = true` and `third_party_instance_id` are mutually exclusive.", "`include_all_networks = true` and `third_party_instance_id` are mutually exclusive.",
@ -202,8 +204,8 @@ impl<'de> Visitor<'de> for RoomNetworkVisitor {
} }
} else { } else {
Ok(match third_party_instance_id { Ok(match third_party_instance_id {
Some(network) => RoomNetwork::ThirdParty(network), Some(network) => IncomingRoomNetwork::ThirdParty(network),
None => RoomNetwork::Matrix, None => IncomingRoomNetwork::Matrix,
}) })
} }
} }
@ -213,7 +215,7 @@ impl<'de> Visitor<'de> for RoomNetworkVisitor {
mod tests { mod tests {
use serde_json::{from_value as from_json_value, json, to_value as to_json_value}; use serde_json::{from_value as from_json_value, json, to_value as to_json_value};
use super::RoomNetwork; use super::{IncomingRoomNetwork, RoomNetwork};
#[test] #[test]
fn test_serialize_matrix_network_only() { fn test_serialize_matrix_network_only() {
@ -224,7 +226,10 @@ mod tests {
#[test] #[test]
fn test_deserialize_matrix_network_only() { fn test_deserialize_matrix_network_only() {
let json = json!({ "include_all_networks": false }); let json = json!({ "include_all_networks": false });
assert_eq!(from_json_value::<RoomNetwork>(json).unwrap(), RoomNetwork::Matrix); assert_eq!(
from_json_value::<IncomingRoomNetwork>(json).unwrap(),
IncomingRoomNetwork::Matrix
);
} }
#[test] #[test]
@ -236,7 +241,10 @@ mod tests {
#[test] #[test]
fn test_deserialize_empty_network_is_default() { fn test_deserialize_empty_network_is_default() {
let json = json!({}); let json = json!({});
assert_eq!(from_json_value::<RoomNetwork>(json).unwrap(), RoomNetwork::default()); assert_eq!(
from_json_value::<IncomingRoomNetwork>(json).unwrap(),
IncomingRoomNetwork::Matrix
);
} }
#[test] #[test]
@ -248,21 +256,21 @@ mod tests {
#[test] #[test]
fn test_deserialize_include_all_networks() { fn test_deserialize_include_all_networks() {
let json = json!({ "include_all_networks": true }); let json = json!({ "include_all_networks": true });
assert_eq!(from_json_value::<RoomNetwork>(json).unwrap(), RoomNetwork::All); assert_eq!(from_json_value::<IncomingRoomNetwork>(json).unwrap(), IncomingRoomNetwork::All);
} }
#[test] #[test]
fn test_serialize_third_party_network() { fn test_serialize_third_party_network() {
let json = json!({ "third_party_instance_id": "freenode" }); let json = json!({ "third_party_instance_id": "freenode" });
assert_eq!(to_json_value(RoomNetwork::ThirdParty("freenode".into())).unwrap(), json); assert_eq!(to_json_value(RoomNetwork::ThirdParty("freenode")).unwrap(), json);
} }
#[test] #[test]
fn test_deserialize_third_party_network() { fn test_deserialize_third_party_network() {
let json = json!({ "third_party_instance_id": "freenode" }); let json = json!({ "third_party_instance_id": "freenode" });
assert_eq!( assert_eq!(
from_json_value::<RoomNetwork>(json).unwrap(), from_json_value::<IncomingRoomNetwork>(json).unwrap(),
RoomNetwork::ThirdParty("freenode".into()) IncomingRoomNetwork::ThirdParty("freenode".into())
); );
} }
@ -270,7 +278,7 @@ mod tests {
fn test_deserialize_include_all_networks_and_third_party_exclusivity() { fn test_deserialize_include_all_networks_and_third_party_exclusivity() {
let json = json!({ "include_all_networks": true, "third_party_instance_id": "freenode" }); let json = json!({ "include_all_networks": true, "third_party_instance_id": "freenode" });
assert_eq!( assert_eq!(
from_json_value::<RoomNetwork>(json).unwrap_err().to_string().as_str(), from_json_value::<IncomingRoomNetwork>(json).unwrap_err().to_string().as_str(),
"`include_all_networks = true` and `third_party_instance_id` are mutually exclusive." "`include_all_networks = true` and `third_party_instance_id` are mutually exclusive."
); );
} }

View File

@ -2,7 +2,7 @@
use js_int::UInt; use js_int::UInt;
use ruma_api::ruma_api; use ruma_api::ruma_api;
use ruma_common::directory::{PublicRoomsChunk, RoomNetwork}; use ruma_common::directory::{IncomingRoomNetwork, PublicRoomsChunk, RoomNetwork};
ruma_api! { ruma_api! {
metadata: { metadata: {
@ -14,6 +14,8 @@ ruma_api! {
requires_authentication: true, requires_authentication: true,
} }
#[derive(Default)]
#[non_exhaustive]
request: { request: {
/// Limit for the number of results to return. /// Limit for the number of results to return.
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
@ -28,9 +30,11 @@ ruma_api! {
/// Network to fetch the public room lists from. /// Network to fetch the public room lists from.
#[serde(flatten, skip_serializing_if = "ruma_serde::is_default")] #[serde(flatten, skip_serializing_if = "ruma_serde::is_default")]
#[ruma_api(query)] #[ruma_api(query)]
pub room_network: RoomNetwork, pub room_network: RoomNetwork<'a>,
} }
#[derive(Default)]
#[non_exhaustive]
response: { response: {
/// A paginated chunk of public rooms. /// A paginated chunk of public rooms.
pub chunk: Vec<PublicRoomsChunk>, pub chunk: Vec<PublicRoomsChunk>,
@ -47,3 +51,17 @@ ruma_api! {
pub total_room_count_estimate: Option<UInt>, pub total_room_count_estimate: Option<UInt>,
} }
} }
impl<'a> Request<'a> {
/// Creates an empty `Request`.
pub fn new() -> Self {
Default::default()
}
}
impl Response {
/// Creates an empty `Response`.
pub fn new() -> Self {
Default::default()
}
}

View File

@ -2,7 +2,9 @@
use js_int::UInt; use js_int::UInt;
use ruma_api::ruma_api; use ruma_api::ruma_api;
use ruma_common::directory::{Filter, PublicRoomsChunk, RoomNetwork}; use ruma_common::directory::{
Filter, IncomingFilter, IncomingRoomNetwork, PublicRoomsChunk, RoomNetwork,
};
ruma_api! { ruma_api! {
metadata: { metadata: {
@ -14,6 +16,8 @@ ruma_api! {
requires_authentication: true, requires_authentication: true,
} }
#[derive(Default)]
#[non_exhaustive]
request: { request: {
/// Limit for the number of results to return. /// Limit for the number of results to return.
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
@ -25,13 +29,15 @@ ruma_api! {
/// Filter to apply to the results. /// Filter to apply to the results.
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub filter: Option<Filter>, pub filter: Option<Filter<'a>>,
/// Network to fetch the public room lists from. /// Network to fetch the public room lists from.
#[serde(flatten, skip_serializing_if = "ruma_serde::is_default")] #[serde(flatten, skip_serializing_if = "ruma_serde::is_default")]
pub room_network: RoomNetwork, pub room_network: RoomNetwork<'a>,
} }
#[derive(Default)]
#[non_exhaustive]
response: { response: {
/// A paginated chunk of public rooms. /// A paginated chunk of public rooms.
pub chunk: Vec<PublicRoomsChunk>, pub chunk: Vec<PublicRoomsChunk>,
@ -46,3 +52,17 @@ ruma_api! {
pub total_room_count_estimate: Option<UInt>, pub total_room_count_estimate: Option<UInt>,
} }
} }
impl<'a> Request<'a> {
/// Creates an empty `Request`.
pub fn new() -> Self {
Default::default()
}
}
impl Response {
/// Creates an empty `Response`.
pub fn new() -> Self {
Default::default()
}
}

View File

@ -1,6 +1,7 @@
//! [GET /.well-known/matrix/server](https://matrix.org/docs/spec/server_server/r0.1.3#get-well-known-matrix-server) //! [GET /.well-known/matrix/server](https://matrix.org/docs/spec/server_server/r0.1.3#get-well-known-matrix-server)
use ruma_api::ruma_api; use ruma_api::ruma_api;
use ruma_identifiers::ServerNameBox;
ruma_api! { ruma_api! {
metadata: { metadata: {
@ -12,11 +13,28 @@ ruma_api! {
requires_authentication: false, requires_authentication: false,
} }
#[derive(Default)]
#[non_exhaustive]
request: {} request: {}
#[non_exhaustive]
response: { response: {
/// The server name to delegate server-server communciations to, with optional port. /// The server name to delegate server-server communciations to, with optional port.
#[serde(rename = "m.homeserver")] #[serde(rename = "m.homeserver")]
pub homeserver: String, pub homeserver: ServerNameBox,
}
}
impl Request {
/// Creates an empty `Request`.
pub fn new() -> Self {
Self
}
}
impl Response {
/// Creates a new `Response` with the given homeserver.
pub fn new(homeserver: ServerNameBox) -> Self {
Self { homeserver }
} }
} }

View File

@ -48,7 +48,8 @@ ruma_api! {
} }
/// The query criteria. /// The query criteria.
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[non_exhaustive]
pub struct QueryCriteria { pub struct QueryCriteria {
/// A millisecond POSIX timestamp in milliseconds indicating when the /// A millisecond POSIX timestamp in milliseconds indicating when the
/// returned certificates will need to be valid until to be useful to the /// returned certificates will need to be valid until to be useful to the
@ -63,3 +64,10 @@ pub struct QueryCriteria {
)] )]
pub minimum_valid_until_ts: Option<SystemTime>, pub minimum_valid_until_ts: Option<SystemTime>,
} }
impl QueryCriteria {
/// Creates empty `QueryCriteria`.
pub fn new() -> Self {
Default::default()
}
}

View File

@ -13,8 +13,12 @@ ruma_api! {
requires_authentication: false, requires_authentication: false,
} }
#[derive(Default)]
#[non_exhaustive]
request: {} request: {}
#[derive(Default)]
#[non_exhaustive]
response: { response: {
/// Information about the homeserver implementation /// Information about the homeserver implementation
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]

View File

@ -17,17 +17,33 @@ ruma_api! {
requires_authentication: true, requires_authentication: true,
} }
#[non_exhaustive]
request: { request: {
/// The keys to be claimed. /// The keys to be claimed.
one_time_keys: OneTimeKeyClaims, one_time_keys: OneTimeKeyClaims,
} }
#[non_exhaustive]
response: { response: {
/// One-time keys for the queried devices /// One-time keys for the queried devices
one_time_keys: OneTimeKeys, one_time_keys: OneTimeKeys,
} }
} }
impl Request {
/// Creates a new `Request` with the given one time key claims.
pub fn new(one_time_keys: OneTimeKeyClaims) -> Self {
Self { one_time_keys }
}
}
impl Response {
/// Creates a new `Response` with the given one time keys.
pub fn new(one_time_keys: OneTimeKeys) -> Self {
Self { one_time_keys }
}
}
/// A claim for one time keys /// A claim for one time keys
pub type OneTimeKeyClaims = BTreeMap<UserId, BTreeMap<DeviceIdBox, DeviceKeyAlgorithm>>; pub type OneTimeKeyClaims = BTreeMap<UserId, BTreeMap<DeviceIdBox, DeviceKeyAlgorithm>>;
@ -43,17 +59,3 @@ pub struct KeyObject {
/// Signature of the key object. /// Signature of the key object.
signatures: BTreeMap<UserId, BTreeMap<DeviceKeyId, String>>, signatures: BTreeMap<UserId, BTreeMap<DeviceKeyId, String>>,
} }
impl Request {
/// Creates a new `Request` with the given one time key claims.
pub fn new(one_time_keys: OneTimeKeyClaims) -> Self {
Self { one_time_keys }
}
}
impl Response {
/// Creates a new `Response` with the given one time keys.
pub fn new(one_time_keys: OneTimeKeys) -> Self {
Self { one_time_keys }
}
}

View File

@ -16,12 +16,14 @@ ruma_api! {
requires_authentication: true, requires_authentication: true,
} }
#[non_exhaustive]
request: { request: {
/// The keys to be downloaded. Gives all keys for a given user if the list of device ids is /// The keys to be downloaded. Gives all keys for a given user if the list of device ids is
/// empty. /// empty.
device_keys: BTreeMap<UserId, Vec<DeviceIdBox>>, device_keys: BTreeMap<UserId, Vec<DeviceIdBox>>,
} }
#[non_exhaustive]
response: { response: {
/// Keys from the queried devices. /// Keys from the queried devices.
device_keys: BTreeMap<UserId, BTreeMap<DeviceIdBox, DeviceKeys>>, device_keys: BTreeMap<UserId, BTreeMap<DeviceIdBox, DeviceKeys>>,

View File

@ -20,10 +20,11 @@ ruma_api! {
request: { request: {
/// The room ID that is about to be joined. /// The room ID that is about to be joined.
#[ruma_api(path)] #[ruma_api(path)]
pub room_id: RoomId, pub room_id: &'a RoomId,
/// The user ID the join event will be for. /// The user ID the join event will be for.
#[ruma_api(path)] #[ruma_api(path)]
pub event_id: EventId, pub event_id: &'a EventId,
/// PDU type without event and room IDs. /// PDU type without event and room IDs.
#[ruma_api(body)] #[ruma_api(body)]

View File

@ -21,6 +21,7 @@ ruma_api! {
/// The room ID that is about to be joined. /// The room ID that is about to be joined.
#[ruma_api(path)] #[ruma_api(path)]
pub room_id: RoomId, pub room_id: RoomId,
/// The user ID the join event will be for. /// The user ID the join event will be for.
#[ruma_api(path)] #[ruma_api(path)]
pub event_id: EventId, pub event_id: EventId,

View File

@ -18,19 +18,22 @@ ruma_api! {
request: { request: {
/// The room ID that is about to be joined. /// The room ID that is about to be joined.
#[ruma_api(path)] #[ruma_api(path)]
pub room_id: RoomId, pub room_id: &'a RoomId,
/// The user ID the join event will be for. /// The user ID the join event will be for.
#[ruma_api(path)] #[ruma_api(path)]
pub user_id: UserId, pub user_id: &'a UserId,
#[ruma_api(query)]
/// The room versions the sending server has support for. Defaults to 1. /// The room versions the sending server has support for. Defaults to 1.
#[serde(skip_serializing_if = "Vec::is_empty")] #[ruma_api(query)]
pub ver: Vec<RoomVersionId>, #[serde(skip_serializing_if = "<[_]>::is_empty")]
pub ver: &'a [RoomVersionId],
} }
response: { response: {
/// The version of the room where the server is trying to join. /// The version of the room where the server is trying to join.
pub room_version: Option<RoomVersionId>, pub room_version: Option<RoomVersionId>,
/// An unsigned template event. /// An unsigned template event.
pub event: Raw<Pdu>, pub event: Raw<Pdu>,
} }

View File

@ -16,7 +16,7 @@ ruma_api! {
request: { request: {
/// The OpenID access token to get information about the owner for. /// The OpenID access token to get information about the owner for.
#[ruma_api(query)] #[ruma_api(query)]
pub access_token: String, pub access_token: &'a str,
} }
response: { response: {

View File

@ -1,7 +1,7 @@
//! [GET /_matrix/federation/v1/query/directory](https://matrix.org/docs/spec/server_server/r0.1.3#get-matrix-federation-v1-query-directory) //! [GET /_matrix/federation/v1/query/directory](https://matrix.org/docs/spec/server_server/r0.1.3#get-matrix-federation-v1-query-directory)
use ruma_api::ruma_api; use ruma_api::ruma_api;
use ruma_identifiers::RoomId; use ruma_identifiers::{RoomAliasId, RoomId};
ruma_api! { ruma_api! {
metadata: { metadata: {
@ -16,12 +16,13 @@ ruma_api! {
request: { request: {
/// Room alias to query. /// Room alias to query.
#[ruma_api(query)] #[ruma_api(query)]
pub room_alias: String, pub room_alias: &'a RoomAliasId,
} }
response: { response: {
/// Room ID mapped to queried alias. /// Room ID mapped to queried alias.
pub room_id: RoomId, pub room_id: RoomId,
/// An array of server names that are likely to hold the given room. /// An array of server names that are likely to hold the given room.
pub servers: Vec<String>, pub servers: Vec<String>,
} }

View File

@ -55,6 +55,7 @@ ruma_api! {
pub struct Edu { pub struct Edu {
/// Type of the ephemeral message. /// Type of the ephemeral message.
pub edu_type: String, pub edu_type: String,
/// Content of ephemeral message /// Content of ephemeral message
pub content: JsonValue, pub content: JsonValue,
} }