Add a TransactionId type

This commit is contained in:
Jonas Platte 2022-01-14 23:46:35 +01:00
parent 9bdde6241e
commit ef6728abde
No known key found for this signature in database
GPG Key ID: 7D261D771D915378
23 changed files with 101 additions and 68 deletions

View File

@ -2,6 +2,7 @@
use ruma_api::ruma_api; use ruma_api::ruma_api;
use ruma_events::AnyRoomEvent; use ruma_events::AnyRoomEvent;
use ruma_identifiers::TransactionId;
use ruma_serde::Raw; use ruma_serde::Raw;
ruma_api! { ruma_api! {
@ -19,7 +20,7 @@ ruma_api! {
/// ///
/// Homeservers generate these IDs and they are used to ensure idempotency of results. /// Homeservers generate these IDs and they are used to ensure idempotency of results.
#[ruma_api(path)] #[ruma_api(path)]
pub txn_id: &'a str, pub txn_id: &'a TransactionId,
/// A list of events. /// A list of events.
pub events: &'a [Raw<AnyRoomEvent>], pub events: &'a [Raw<AnyRoomEvent>],
@ -31,14 +32,14 @@ ruma_api! {
impl<'a> Request<'a> { impl<'a> Request<'a> {
/// Creates a new `Request` with the given transaction ID and list of events. /// Creates a new `Request` with the given transaction ID and list of events.
pub fn new(txn_id: &'a str, events: &'a [Raw<AnyRoomEvent>]) -> Self { pub fn new(txn_id: &'a TransactionId, events: &'a [Raw<AnyRoomEvent>]) -> Self {
Self { txn_id, events } Self { txn_id, events }
} }
} }
impl IncomingRequest { impl IncomingRequest {
/// Creates an `IncomingRequest` with the given transaction ID and list of events. /// Creates an `IncomingRequest` with the given transaction ID and list of events.
pub fn new(txn_id: String, events: Vec<Raw<AnyRoomEvent>>) -> IncomingRequest { pub fn new(txn_id: Box<TransactionId>, events: Vec<Raw<AnyRoomEvent>>) -> IncomingRequest {
IncomingRequest { txn_id, events } IncomingRequest { txn_id, events }
} }
@ -171,7 +172,7 @@ mod tests {
let dummy_event = Raw::new(&dummy_event).unwrap(); let dummy_event = Raw::new(&dummy_event).unwrap();
let events = vec![dummy_event]; let events = vec![dummy_event];
let req = Request { events: &events, txn_id: "any_txn_id" } let req = Request { events: &events, txn_id: "any_txn_id".into() }
.try_into_http_request::<Vec<u8>>( .try_into_http_request::<Vec<u8>>(
"https://homeserver.tld", "https://homeserver.tld",
SendAccessToken::IfRequired("auth_tok"), SendAccessToken::IfRequired("auth_tok"),

View File

@ -2,7 +2,7 @@
use ruma_api::ruma_api; use ruma_api::ruma_api;
use ruma_events::{AnyMessageEventContent, MessageEventContent}; use ruma_events::{AnyMessageEventContent, MessageEventContent};
use ruma_identifiers::{EventId, RoomId}; use ruma_identifiers::{EventId, RoomId, TransactionId};
use ruma_serde::Raw; use ruma_serde::Raw;
use serde_json::value::to_raw_value as to_raw_json_value; use serde_json::value::to_raw_value as to_raw_json_value;
@ -31,7 +31,7 @@ ruma_api! {
/// same access token; it will be used by the server to ensure /// same access token; it will be used by the server to ensure
/// idempotency of requests. /// idempotency of requests.
#[ruma_api(path)] #[ruma_api(path)]
pub txn_id: &'a str, pub txn_id: &'a TransactionId,
/// The event content to send. /// The event content to send.
#[ruma_api(body)] #[ruma_api(body)]
@ -55,7 +55,7 @@ impl<'a> Request<'a> {
/// [`Serialize`][serde::Serialize] implementation can fail. /// [`Serialize`][serde::Serialize] implementation can fail.
pub fn new<T: MessageEventContent>( pub fn new<T: MessageEventContent>(
room_id: &'a RoomId, room_id: &'a RoomId,
txn_id: &'a str, txn_id: &'a TransactionId,
content: &'a T, content: &'a T,
) -> serde_json::Result<Self> { ) -> serde_json::Result<Self> {
Ok(Self { Ok(Self {
@ -70,7 +70,7 @@ impl<'a> Request<'a> {
/// content. /// content.
pub fn new_raw( pub fn new_raw(
room_id: &'a RoomId, room_id: &'a RoomId,
txn_id: &'a str, txn_id: &'a TransactionId,
event_type: &'a str, event_type: &'a str,
body: Raw<AnyMessageEventContent>, body: Raw<AnyMessageEventContent>,
) -> Self { ) -> Self {

View File

@ -1,7 +1,7 @@
//! [PUT /_matrix/client/r0/rooms/{roomId}/redact/{eventId}/{txnId}](https://matrix.org/docs/spec/client_server/r0.6.1#put-matrix-client-r0-rooms-roomid-redact-eventid-txnid) //! [PUT /_matrix/client/r0/rooms/{roomId}/redact/{eventId}/{txnId}](https://matrix.org/docs/spec/client_server/r0.6.1#put-matrix-client-r0-rooms-roomid-redact-eventid-txnid)
use ruma_api::ruma_api; use ruma_api::ruma_api;
use ruma_identifiers::{EventId, RoomId}; use ruma_identifiers::{EventId, RoomId, TransactionId};
ruma_api! { ruma_api! {
metadata: { metadata: {
@ -27,7 +27,7 @@ ruma_api! {
/// Clients should generate a unique ID; it will be used by the server to ensure idempotency /// Clients should generate a unique ID; it will be used by the server to ensure idempotency
/// of requests. /// of requests.
#[ruma_api(path)] #[ruma_api(path)]
pub txn_id: &'a str, pub txn_id: &'a TransactionId,
/// The reason for the redaction. /// The reason for the redaction.
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
@ -44,7 +44,7 @@ ruma_api! {
impl<'a> Request<'a> { impl<'a> Request<'a> {
/// Creates a new `Request` with the given room ID, event ID and transaction ID. /// Creates a new `Request` with the given room ID, event ID and transaction ID.
pub fn new(room_id: &'a RoomId, event_id: &'a EventId, txn_id: &'a str) -> Self { pub fn new(room_id: &'a RoomId, event_id: &'a EventId, txn_id: &'a TransactionId) -> Self {
Self { room_id, event_id, txn_id, reason: None } Self { room_id, event_id, txn_id, reason: None }
} }
} }

View File

@ -5,7 +5,7 @@ use std::collections::BTreeMap;
use ruma_api::ruma_api; use ruma_api::ruma_api;
use ruma_common::to_device::DeviceIdOrAllDevices; use ruma_common::to_device::DeviceIdOrAllDevices;
use ruma_events::AnyToDeviceEventContent; use ruma_events::AnyToDeviceEventContent;
use ruma_identifiers::UserId; use ruma_identifiers::{TransactionId, UserId};
use ruma_serde::Raw; use ruma_serde::Raw;
ruma_api! { ruma_api! {
@ -25,7 +25,7 @@ ruma_api! {
/// A request identifier unique to the access token used to send the request. /// A request identifier unique to the access token used to send the request.
#[ruma_api(path)] #[ruma_api(path)]
pub txn_id: &'a str, pub txn_id: &'a TransactionId,
/// Messages to send. /// Messages to send.
/// ///
@ -42,7 +42,7 @@ ruma_api! {
impl<'a> Request<'a> { impl<'a> Request<'a> {
/// Creates a new `Request` with the given event type, transaction ID and raw messages. /// Creates a new `Request` with the given event type, transaction ID and raw messages.
pub fn new_raw(event_type: &'a str, txn_id: &'a str, messages: Messages) -> Self { pub fn new_raw(event_type: &'a str, txn_id: &'a TransactionId, messages: Messages) -> Self {
Self { event_type, txn_id, messages } Self { event_type, txn_id, messages }
} }
} }

View File

@ -10,7 +10,7 @@ use ruma_api::{
EndpointError, OutgoingResponse, EndpointError, OutgoingResponse,
}; };
use ruma_common::thirdparty::Medium; use ruma_common::thirdparty::Medium;
use ruma_identifiers::{ClientSecret, SessionId}; use ruma_identifiers::{ClientSecret, SessionId, TransactionId};
use ruma_serde::{JsonObject, Outgoing, StringEnum}; use ruma_serde::{JsonObject, Outgoing, StringEnum};
use serde::{ use serde::{
de::{self, DeserializeOwned}, de::{self, DeserializeOwned},
@ -470,7 +470,7 @@ pub struct Token<'a> {
pub token: &'a str, pub token: &'a str,
/// The transaction ID. /// The transaction ID.
pub txn_id: &'a str, pub txn_id: &'a TransactionId,
/// The value of the session key given by the homeserver, if any. /// The value of the session key given by the homeserver, if any.
pub session: Option<&'a str>, pub session: Option<&'a str>,
@ -478,7 +478,7 @@ pub struct Token<'a> {
impl<'a> Token<'a> { impl<'a> Token<'a> {
/// Creates a new `Token` with the given token and transaction ID. /// Creates a new `Token` with the given token and transaction ID.
pub fn new(token: &'a str, txn_id: &'a str) -> Self { pub fn new(token: &'a str, txn_id: &'a TransactionId) -> Self {
Self { token, txn_id, session: None } Self { token, txn_id, session: None }
} }
} }

View File

@ -30,7 +30,7 @@ fn deserialize_user_identifier() {
#[test] #[test]
fn serialize_auth_data_token() { fn serialize_auth_data_token() {
let auth_data = AuthData::Token( let auth_data = AuthData::Token(
assign!(uiaa::Token::new("mytoken", "txn123"), { session: Some("session") }), assign!(uiaa::Token::new("mytoken", "txn123".into()), { session: Some("session") }),
); );
assert_matches!( assert_matches!(

View File

@ -5,6 +5,7 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use ruma_events_macros::EventContent; use ruma_events_macros::EventContent;
use ruma_identifiers::TransactionId;
use ruma_serde::Base64; use ruma_serde::Base64;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::Value as JsonValue; use serde_json::Value as JsonValue;
@ -25,7 +26,7 @@ pub struct ToDeviceKeyVerificationAcceptEventContent {
/// An opaque identifier for the verification process. /// An opaque identifier for the verification process.
/// ///
/// Must be the same as the one used for the `m.key.verification.start` message. /// Must be the same as the one used for the `m.key.verification.start` message.
pub transaction_id: String, pub transaction_id: Box<TransactionId>,
/// The method specific content. /// The method specific content.
#[serde(flatten)] #[serde(flatten)]
@ -35,7 +36,7 @@ pub struct ToDeviceKeyVerificationAcceptEventContent {
impl ToDeviceKeyVerificationAcceptEventContent { impl ToDeviceKeyVerificationAcceptEventContent {
/// Creates a new `ToDeviceKeyVerificationAcceptEventContent` with the given transaction ID and /// Creates a new `ToDeviceKeyVerificationAcceptEventContent` with the given transaction ID and
/// method-specific content. /// method-specific content.
pub fn new(transaction_id: String, method: AcceptMethod) -> Self { pub fn new(transaction_id: Box<TransactionId>, method: AcceptMethod) -> Self {
Self { transaction_id, method } Self { transaction_id, method }
} }
} }

View File

@ -3,6 +3,7 @@
//! [`m.key.verification.cancel`]: https://spec.matrix.org/v1.1/client-server-api/#mkeyverificationcancel //! [`m.key.verification.cancel`]: https://spec.matrix.org/v1.1/client-server-api/#mkeyverificationcancel
use ruma_events_macros::EventContent; use ruma_events_macros::EventContent;
use ruma_identifiers::TransactionId;
use ruma_serde::StringEnum; use ruma_serde::StringEnum;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -19,7 +20,7 @@ use super::Relation;
#[ruma_event(type = "m.key.verification.cancel", kind = ToDevice)] #[ruma_event(type = "m.key.verification.cancel", kind = ToDevice)]
pub struct ToDeviceKeyVerificationCancelEventContent { pub struct ToDeviceKeyVerificationCancelEventContent {
/// The opaque identifier for the verification process/request. /// The opaque identifier for the verification process/request.
pub transaction_id: String, pub transaction_id: Box<TransactionId>,
/// A human readable description of the `code`. /// A human readable description of the `code`.
/// ///
@ -33,7 +34,7 @@ pub struct ToDeviceKeyVerificationCancelEventContent {
impl ToDeviceKeyVerificationCancelEventContent { impl ToDeviceKeyVerificationCancelEventContent {
/// Creates a new `ToDeviceKeyVerificationCancelEventContent` with the given transaction ID, /// Creates a new `ToDeviceKeyVerificationCancelEventContent` with the given transaction ID,
/// reason and code. /// reason and code.
pub fn new(transaction_id: String, reason: String, code: CancelCode) -> Self { pub fn new(transaction_id: Box<TransactionId>, reason: String, code: CancelCode) -> Self {
Self { transaction_id, reason, code } Self { transaction_id, reason, code }
} }
} }

View File

@ -3,6 +3,7 @@
//! [`m.key.verification.done`]: https://spec.matrix.org/v1.1/client-server-api/#mkeyverificationdone //! [`m.key.verification.done`]: https://spec.matrix.org/v1.1/client-server-api/#mkeyverificationdone
use ruma_events_macros::EventContent; use ruma_events_macros::EventContent;
use ruma_identifiers::TransactionId;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::Relation; use super::Relation;
@ -17,12 +18,12 @@ pub struct ToDeviceKeyVerificationDoneEventContent {
/// An opaque identifier for the verification process. /// An opaque identifier for the verification process.
/// ///
/// Must be the same as the one used for the `m.key.verification.start` message. /// Must be the same as the one used for the `m.key.verification.start` message.
pub transaction_id: String, pub transaction_id: Box<TransactionId>,
} }
impl ToDeviceKeyVerificationDoneEventContent { impl ToDeviceKeyVerificationDoneEventContent {
/// Creates a new `ToDeviceKeyVerificationDoneEventContent` with the given transaction ID. /// Creates a new `ToDeviceKeyVerificationDoneEventContent` with the given transaction ID.
pub fn new(transaction_id: String) -> Self { pub fn new(transaction_id: Box<TransactionId>) -> Self {
Self { transaction_id } Self { transaction_id }
} }
} }

View File

@ -3,6 +3,7 @@
//! [`m.key.verification.key`]: https://spec.matrix.org/v1.1/client-server-api/#mkeyverificationkey //! [`m.key.verification.key`]: https://spec.matrix.org/v1.1/client-server-api/#mkeyverificationkey
use ruma_events_macros::EventContent; use ruma_events_macros::EventContent;
use ruma_identifiers::TransactionId;
use ruma_serde::Base64; use ruma_serde::Base64;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -19,7 +20,7 @@ pub struct ToDeviceKeyVerificationKeyEventContent {
/// An opaque identifier for the verification process. /// An opaque identifier for the verification process.
/// ///
/// Must be the same as the one used for the `m.key.verification.start` message. /// Must be the same as the one used for the `m.key.verification.start` message.
pub transaction_id: String, pub transaction_id: Box<TransactionId>,
/// The device's ephemeral public key, encoded as unpadded base64. /// The device's ephemeral public key, encoded as unpadded base64.
pub key: Base64, pub key: Base64,
@ -28,7 +29,7 @@ pub struct ToDeviceKeyVerificationKeyEventContent {
impl ToDeviceKeyVerificationKeyEventContent { impl ToDeviceKeyVerificationKeyEventContent {
/// Creates a new `ToDeviceKeyVerificationKeyEventContent` with the given transaction ID and /// Creates a new `ToDeviceKeyVerificationKeyEventContent` with the given transaction ID and
/// key. /// key.
pub fn new(transaction_id: String, key: Base64) -> Self { pub fn new(transaction_id: Box<TransactionId>, key: Base64) -> Self {
Self { transaction_id, key } Self { transaction_id, key }
} }
} }

View File

@ -5,6 +5,7 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use ruma_events_macros::EventContent; use ruma_events_macros::EventContent;
use ruma_identifiers::TransactionId;
use ruma_serde::Base64; use ruma_serde::Base64;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -21,7 +22,7 @@ pub struct ToDeviceKeyVerificationMacEventContent {
/// An opaque identifier for the verification process. /// An opaque identifier for the verification process.
/// ///
/// Must be the same as the one used for the `m.key.verification.start` message. /// Must be the same as the one used for the `m.key.verification.start` message.
pub transaction_id: String, pub transaction_id: Box<TransactionId>,
/// A map of the key ID to the MAC of the key, using the algorithm in the verification process. /// A map of the key ID to the MAC of the key, using the algorithm in the verification process.
/// ///
@ -36,7 +37,11 @@ pub struct ToDeviceKeyVerificationMacEventContent {
impl ToDeviceKeyVerificationMacEventContent { impl ToDeviceKeyVerificationMacEventContent {
/// Creates a new `ToDeviceKeyVerificationMacEventContent` with the given transaction ID, key ID /// Creates a new `ToDeviceKeyVerificationMacEventContent` with the given transaction ID, key ID
/// to MAC map and key MAC. /// to MAC map and key MAC.
pub fn new(transaction_id: String, mac: BTreeMap<String, Base64>, keys: Base64) -> Self { pub fn new(
transaction_id: Box<TransactionId>,
mac: BTreeMap<String, Base64>,
keys: Base64,
) -> Self {
Self { transaction_id, mac, keys } Self { transaction_id, mac, keys }
} }
} }

View File

@ -3,7 +3,7 @@
//! [`m.key.verification.ready`]: https://spec.matrix.org/v1.1/client-server-api/#mkeyverificationready //! [`m.key.verification.ready`]: https://spec.matrix.org/v1.1/client-server-api/#mkeyverificationready
use ruma_events_macros::EventContent; use ruma_events_macros::EventContent;
use ruma_identifiers::DeviceId; use ruma_identifiers::{DeviceId, TransactionId};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::{Relation, VerificationMethod}; use super::{Relation, VerificationMethod};
@ -26,7 +26,7 @@ pub struct ToDeviceKeyVerificationReadyEventContent {
/// Must be unique with respect to the devices involved. Must be the same as the /// Must be unique with respect to the devices involved. Must be the same as the
/// `transaction_id` given in the `m.key.verification.request` from a /// `transaction_id` given in the `m.key.verification.request` from a
/// request. /// request.
pub transaction_id: String, pub transaction_id: Box<TransactionId>,
} }
impl ToDeviceKeyVerificationReadyEventContent { impl ToDeviceKeyVerificationReadyEventContent {
@ -35,7 +35,7 @@ impl ToDeviceKeyVerificationReadyEventContent {
pub fn new( pub fn new(
from_device: Box<DeviceId>, from_device: Box<DeviceId>,
methods: Vec<VerificationMethod>, methods: Vec<VerificationMethod>,
transaction_id: String, transaction_id: Box<TransactionId>,
) -> Self { ) -> Self {
Self { from_device, methods, transaction_id } Self { from_device, methods, transaction_id }
} }
@ -111,7 +111,7 @@ mod tests {
let content = ToDeviceKeyVerificationReadyEventContent { let content = ToDeviceKeyVerificationReadyEventContent {
from_device: device, from_device: device,
transaction_id: "456".to_owned(), transaction_id: "456".into(),
methods: vec![VerificationMethod::SasV1], methods: vec![VerificationMethod::SasV1],
}; };

View File

@ -4,7 +4,7 @@
use ruma_common::MilliSecondsSinceUnixEpoch; use ruma_common::MilliSecondsSinceUnixEpoch;
use ruma_events_macros::EventContent; use ruma_events_macros::EventContent;
use ruma_identifiers::DeviceId; use ruma_identifiers::{DeviceId, TransactionId};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::VerificationMethod; use super::VerificationMethod;
@ -20,7 +20,7 @@ pub struct ToDeviceKeyVerificationRequestEventContent {
/// An opaque identifier for the verification request. /// An opaque identifier for the verification request.
/// ///
/// Must be unique with respect to the devices involved. /// Must be unique with respect to the devices involved.
pub transaction_id: String, pub transaction_id: Box<TransactionId>,
/// The verification methods supported by the sender. /// The verification methods supported by the sender.
pub methods: Vec<VerificationMethod>, pub methods: Vec<VerificationMethod>,
@ -37,7 +37,7 @@ impl ToDeviceKeyVerificationRequestEventContent {
/// transaction ID, methods and timestamp. /// transaction ID, methods and timestamp.
pub fn new( pub fn new(
from_device: Box<DeviceId>, from_device: Box<DeviceId>,
transaction_id: String, transaction_id: Box<TransactionId>,
methods: Vec<VerificationMethod>, methods: Vec<VerificationMethod>,
timestamp: MilliSecondsSinceUnixEpoch, timestamp: MilliSecondsSinceUnixEpoch,
) -> Self { ) -> Self {

View File

@ -5,7 +5,7 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use ruma_events_macros::EventContent; use ruma_events_macros::EventContent;
use ruma_identifiers::DeviceId; use ruma_identifiers::{DeviceId, TransactionId};
#[cfg(feature = "unstable-pre-spec")] #[cfg(feature = "unstable-pre-spec")]
use ruma_serde::Base64; use ruma_serde::Base64;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -32,7 +32,7 @@ pub struct ToDeviceKeyVerificationStartEventContent {
/// Must be unique with respect to the devices involved. Must be the same as the /// Must be unique with respect to the devices involved. Must be the same as the
/// `transaction_id` given in the `m.key.verification.request` if this process is originating /// `transaction_id` given in the `m.key.verification.request` if this process is originating
/// from a request. /// from a request.
pub transaction_id: String, pub transaction_id: Box<TransactionId>,
/// Method specific content. /// Method specific content.
#[serde(flatten)] #[serde(flatten)]
@ -42,7 +42,11 @@ pub struct ToDeviceKeyVerificationStartEventContent {
impl ToDeviceKeyVerificationStartEventContent { impl ToDeviceKeyVerificationStartEventContent {
/// Creates a new `ToDeviceKeyVerificationStartEventContent` with the given device ID, /// Creates a new `ToDeviceKeyVerificationStartEventContent` with the given device ID,
/// transaction ID and method specific content. /// transaction ID and method specific content.
pub fn new(from_device: Box<DeviceId>, transaction_id: String, method: StartMethod) -> Self { pub fn new(
from_device: Box<DeviceId>,
transaction_id: Box<TransactionId>,
method: StartMethod,
) -> Self {
Self { from_device, transaction_id, method } Self { from_device, transaction_id, method }
} }
} }

View File

@ -1,4 +1,5 @@
use js_int::Int; use js_int::Int;
use ruma_identifiers::TransactionId;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[cfg(feature = "unstable-pre-spec")] #[cfg(feature = "unstable-pre-spec")]
@ -20,7 +21,7 @@ pub struct Unsigned {
/// The client-supplied transaction ID, if the client being given the event is the same one /// The client-supplied transaction ID, if the client being given the event is the same one
/// which sent it. /// which sent it.
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub transaction_id: Option<String>, pub transaction_id: Option<Box<TransactionId>>,
/// Server-compiled information from other events relating to this event. /// Server-compiled information from other events relating to this event.
#[cfg(feature = "unstable-pre-spec")] #[cfg(feature = "unstable-pre-spec")]
@ -82,7 +83,7 @@ pub struct UnsignedWithPrevContent {
age: Option<Int>, age: Option<Int>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
transaction_id: Option<String>, transaction_id: Option<Box<TransactionId>>,
#[cfg(feature = "unstable-pre-spec")] #[cfg(feature = "unstable-pre-spec")]
#[serde(rename = "m.relations", skip_serializing_if = "Option::is_none")] #[serde(rename = "m.relations", skip_serializing_if = "Option::is_none")]

View File

@ -4,7 +4,7 @@ use std::collections::BTreeMap;
use ruma_api::ruma_api; use ruma_api::ruma_api;
use ruma_common::MilliSecondsSinceUnixEpoch; use ruma_common::MilliSecondsSinceUnixEpoch;
use ruma_identifiers::{EventId, ServerName}; use ruma_identifiers::{EventId, ServerName, TransactionId};
use ruma_serde::Raw; use ruma_serde::Raw;
use serde_json::value::RawValue as RawJsonValue; use serde_json::value::RawValue as RawJsonValue;
@ -23,7 +23,7 @@ ruma_api! {
request: { request: {
/// A transaction ID unique between sending and receiving homeservers. /// A transaction ID unique between sending and receiving homeservers.
#[ruma_api(path)] #[ruma_api(path)]
pub transaction_id: &'a str, pub transaction_id: &'a TransactionId,
/// The server_name of the homeserver sending this transaction. /// The server_name of the homeserver sending this transaction.
pub origin: &'a ServerName, pub origin: &'a ServerName,
@ -58,7 +58,7 @@ impl<'a> Request<'a> {
/// ///
/// The PDU and EDU lists will start off empty. /// The PDU and EDU lists will start off empty.
pub fn new( pub fn new(
transaction_id: &'a str, transaction_id: &'a TransactionId,
origin: &'a ServerName, origin: &'a ServerName,
origin_server_ts: MilliSecondsSinceUnixEpoch, origin_server_ts: MilliSecondsSinceUnixEpoch,
) -> Self { ) -> Self {

View File

@ -21,19 +21,21 @@ rustdoc-args = ["--cfg", "docsrs"]
[features] [features]
default = ["serde"] default = ["serde"]
compat = ["ruma-identifiers-validation/compat"] compat = ["ruma-identifiers-validation/compat"]
rand = ["rand_crate", "uuid"]
serde = ["ruma-serde", "serde1"] serde = ["ruma-serde", "serde1"]
unstable-pre-spec = [] unstable-pre-spec = []
[dependencies] [dependencies]
either = { version = "1.6.1", optional = true } either = { version = "1.6.1", optional = true }
percent-encoding = "2.1.0" percent-encoding = "2.1.0"
rand = { version = "0.8.3", optional = true } rand_crate = { package = "rand", version = "0.8.3", optional = true }
ruma-identifiers-macros = { version = "=0.20.0", path = "../ruma-identifiers-macros" } ruma-identifiers-macros = { version = "=0.20.0", path = "../ruma-identifiers-macros" }
ruma-identifiers-validation = { version = "0.5.0", path = "../ruma-identifiers-validation", default-features = false } ruma-identifiers-validation = { version = "0.5.0", path = "../ruma-identifiers-validation", default-features = false }
ruma-serde = { version = "0.5.0", path = "../ruma-serde", optional = true } ruma-serde = { version = "0.5.0", path = "../ruma-serde", optional = true }
ruma-serde-macros = { version = "0.5.0", path = "../ruma-serde-macros" } ruma-serde-macros = { version = "0.5.0", path = "../ruma-serde-macros" }
# Renamed so we can have a serde feature. # Renamed so we can have a serde feature.
serde1 = { package = "serde", version = "1.0.126", optional = true, features = ["derive"] } serde1 = { package = "serde", version = "1.0.126", optional = true, features = ["derive"] }
uuid = { version = "0.8.2", optional = true, features = ["v4"] }
[dev-dependencies] [dev-dependencies]
matches = "0.1.8" matches = "0.1.8"

View File

@ -8,11 +8,14 @@
#![allow(unused_qualifications)] #![allow(unused_qualifications)]
#![cfg_attr(docsrs, feature(doc_auto_cfg))] #![cfg_attr(docsrs, feature(doc_auto_cfg))]
// Renamed in `Cargo.toml` so we can have a serde feature. // Renamed in `Cargo.toml` so we can features with the same name as the package.
// Rename it back here because `serde1` is ugly. // Rename them back here because the `Cargo.toml` names are ugly.
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
extern crate serde1 as serde; extern crate serde1 as serde;
#[cfg(feature = "rand")]
extern crate rand_crate as rand;
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use std::convert::TryFrom; use std::convert::TryFrom;
@ -38,6 +41,7 @@ pub use crate::{
server_name::ServerName, server_name::ServerName,
session_id::SessionId, session_id::SessionId,
signatures::{DeviceSignatures, EntitySignatures, ServerSignatures, Signatures}, signatures::{DeviceSignatures, EntitySignatures, ServerSignatures, Signatures},
transaction_id::TransactionId,
user_id::UserId, user_id::UserId,
}; };
#[doc(inline)] #[doc(inline)]
@ -65,6 +69,7 @@ mod room_version_id;
mod server_name; mod server_name;
mod session_id; mod session_id;
mod signatures; mod signatures;
mod transaction_id;
/// Generates a random identifier localpart. /// Generates a random identifier localpart.
#[cfg(feature = "rand")] #[cfg(feature = "rand")]

View File

@ -0,0 +1,25 @@
/// A Matrix transaction ID.
///
/// Transaction IDs in Matrix are opaque strings. This type is provided simply for its semantic
/// value.
///
/// You can create one from a string (using `.into()`) but the recommended way is to use
/// `TransactionId::new()` to generate a random one. If that function is not available for you, you
/// need to activate this crate's `rand` Cargo feature.
#[repr(transparent)]
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TransactionId(str);
impl TransactionId {
/// Creates a random transaction ID.
///
/// This will currently be a UUID without hyphens, but no guarantees are made about the
/// structure of transaction IDs generated from this function.
#[cfg(feature = "rand")]
pub fn new() -> Box<Self> {
let id = uuid::Uuid::new_v4();
Self::from_owned(id.to_simple().to_string().into_boxed_str())
}
}
opaque_identifier!(TransactionId);

View File

@ -275,6 +275,7 @@ fn strip_lifetimes(field_type: &mut Type) -> bool {
|| last_seg.ident == "RoomName" || last_seg.ident == "RoomName"
|| last_seg.ident == "ServerSigningKeyId" || last_seg.ident == "ServerSigningKeyId"
|| last_seg.ident == "SigningKeyId" || last_seg.ident == "SigningKeyId"
|| last_seg.ident == "TransactionId"
|| last_seg.ident == "UserId" || last_seg.ident == "UserId"
{ {
// The identifiers that need to be boxed `Box<T>` since they are DST's. // The identifiers that need to be boxed `Box<T>` since they are DST's.

View File

@ -149,7 +149,7 @@ tokio-stream = { version = "0.1.1", default-features = false }
[[example]] [[example]]
name = "hello_world" name = "hello_world"
required-features = ["client-api-c", "client-ext-client-api", "client-hyper-native-tls"] required-features = ["client-api-c", "client-ext-client-api", "client-hyper-native-tls", "rand"]
[[example]] [[example]]
name = "hello_isahc" name = "hello_isahc"

View File

@ -5,6 +5,7 @@ use ruma::{
events::room::message::RoomMessageEventContent, events::room::message::RoomMessageEventContent,
RoomAliasId, RoomAliasId,
}; };
use ruma_identifiers::TransactionId;
type MatrixClient = ruma_client::Client<ruma_client::http_client::HyperNativeTls>; type MatrixClient = ruma_client::Client<ruma_client::http_client::HyperNativeTls>;
@ -22,7 +23,7 @@ async fn hello_world(
client client
.send_request(send_message_event::Request::new( .send_request(send_message_event::Request::new(
&room_id, &room_id,
"1", &TransactionId::new(),
&RoomMessageEventContent::text_plain("Hello World!"), &RoomMessageEventContent::text_plain("Hello World!"),
)?) )?)
.await?; .await?;

View File

@ -1,10 +1,4 @@
use std::{ use std::{convert::TryInto, error::Error, io, process::exit, time::Duration};
convert::TryInto,
error::Error,
io,
process::exit,
time::{Duration, SystemTime},
};
use ruma::{ use ruma::{
api::client::r0::{ api::client::r0::{
@ -16,6 +10,7 @@ use ruma::{
room::message::{MessageType, RoomMessageEventContent}, room::message::{MessageType, RoomMessageEventContent},
AnySyncMessageEvent, AnySyncRoomEvent, AnySyncMessageEvent, AnySyncRoomEvent,
}, },
identifiers::TransactionId,
presence::PresenceState, presence::PresenceState,
serde::Raw, serde::Raw,
RoomId, UserId, RoomId, UserId,
@ -154,7 +149,7 @@ async fn handle_messages(
}; };
let joke_content = RoomMessageEventContent::text_plain(joke); let joke_content = RoomMessageEventContent::text_plain(joke);
let txn_id = generate_txn_id(); let txn_id = TransactionId::new();
let req = send_message_event::Request::new(room_id, &txn_id, &joke_content)?; let req = send_message_event::Request::new(room_id, &txn_id, &joke_content)?;
// Do nothing if we can't send the message. // Do nothing if we can't send the message.
let _ = matrix_client.send_request(req).await; let _ = matrix_client.send_request(req).await;
@ -175,23 +170,12 @@ async fn handle_invitations(
let greeting = "Hello! My name is Mr. Bot! I like to tell jokes. Like this one: "; let greeting = "Hello! My name is Mr. Bot! I like to tell jokes. Like this one: ";
let joke = get_joke(http_client).await.unwrap_or_else(|_| "err... never mind.".to_owned()); let joke = get_joke(http_client).await.unwrap_or_else(|_| "err... never mind.".to_owned());
let content = RoomMessageEventContent::text_plain(format!("{}\n{}", greeting, joke)); let content = RoomMessageEventContent::text_plain(format!("{}\n{}", greeting, joke));
let txn_id = generate_txn_id(); let txn_id = TransactionId::new();
let message = send_message_event::Request::new(room_id, &txn_id, &content)?; let message = send_message_event::Request::new(room_id, &txn_id, &content)?;
matrix_client.send_request(message).await?; matrix_client.send_request(message).await?;
Ok(()) Ok(())
} }
// Each message needs a unique transaction ID, otherwise the server thinks that the message is
// being retransmitted. We could use a random value, or a counter, but to avoid having to store
// the state, we'll just use the current time as a transaction ID.
fn generate_txn_id() -> String {
SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.expect("current time is earlier than Unix epoch")
.as_millis()
.to_string()
}
async fn get_joke(client: &HttpClient) -> Result<String, Box<dyn Error>> { async fn get_joke(client: &HttpClient) -> Result<String, Box<dyn Error>> {
let uri = "https://v2.jokeapi.dev/joke/Programming,Pun,Misc?safe-mode&type=single" let uri = "https://v2.jokeapi.dev/joke/Programming,Pun,Misc?safe-mode&type=single"
.parse::<hyper::Uri>()?; .parse::<hyper::Uri>()?;