diff --git a/crates/ruma-appservice-api/src/event/push_events/v1.rs b/crates/ruma-appservice-api/src/event/push_events/v1.rs index 9bd8e97b..cedca421 100644 --- a/crates/ruma-appservice-api/src/event/push_events/v1.rs +++ b/crates/ruma-appservice-api/src/event/push_events/v1.rs @@ -2,6 +2,7 @@ use ruma_api::ruma_api; use ruma_events::AnyRoomEvent; +use ruma_identifiers::TransactionId; use ruma_serde::Raw; ruma_api! { @@ -19,7 +20,7 @@ ruma_api! { /// /// Homeservers generate these IDs and they are used to ensure idempotency of results. #[ruma_api(path)] - pub txn_id: &'a str, + pub txn_id: &'a TransactionId, /// A list of events. pub events: &'a [Raw], @@ -31,14 +32,14 @@ ruma_api! { impl<'a> Request<'a> { /// Creates a new `Request` with the given transaction ID and list of events. - pub fn new(txn_id: &'a str, events: &'a [Raw]) -> Self { + pub fn new(txn_id: &'a TransactionId, events: &'a [Raw]) -> Self { Self { txn_id, events } } } impl IncomingRequest { /// Creates an `IncomingRequest` with the given transaction ID and list of events. - pub fn new(txn_id: String, events: Vec>) -> IncomingRequest { + pub fn new(txn_id: Box, events: Vec>) -> IncomingRequest { IncomingRequest { txn_id, events } } @@ -171,7 +172,7 @@ mod tests { let dummy_event = Raw::new(&dummy_event).unwrap(); 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::>( "https://homeserver.tld", SendAccessToken::IfRequired("auth_tok"), diff --git a/crates/ruma-client-api/src/r0/message/send_message_event.rs b/crates/ruma-client-api/src/r0/message/send_message_event.rs index c90bdeb6..f5dfbbf5 100644 --- a/crates/ruma-client-api/src/r0/message/send_message_event.rs +++ b/crates/ruma-client-api/src/r0/message/send_message_event.rs @@ -2,7 +2,7 @@ use ruma_api::ruma_api; use ruma_events::{AnyMessageEventContent, MessageEventContent}; -use ruma_identifiers::{EventId, RoomId}; +use ruma_identifiers::{EventId, RoomId, TransactionId}; use ruma_serde::Raw; 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 /// idempotency of requests. #[ruma_api(path)] - pub txn_id: &'a str, + pub txn_id: &'a TransactionId, /// The event content to send. #[ruma_api(body)] @@ -55,7 +55,7 @@ impl<'a> Request<'a> { /// [`Serialize`][serde::Serialize] implementation can fail. pub fn new( room_id: &'a RoomId, - txn_id: &'a str, + txn_id: &'a TransactionId, content: &'a T, ) -> serde_json::Result { Ok(Self { @@ -70,7 +70,7 @@ impl<'a> Request<'a> { /// content. pub fn new_raw( room_id: &'a RoomId, - txn_id: &'a str, + txn_id: &'a TransactionId, event_type: &'a str, body: Raw, ) -> Self { diff --git a/crates/ruma-client-api/src/r0/redact/redact_event.rs b/crates/ruma-client-api/src/r0/redact/redact_event.rs index a0546793..448829c7 100644 --- a/crates/ruma-client-api/src/r0/redact/redact_event.rs +++ b/crates/ruma-client-api/src/r0/redact/redact_event.rs @@ -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) use ruma_api::ruma_api; -use ruma_identifiers::{EventId, RoomId}; +use ruma_identifiers::{EventId, RoomId, TransactionId}; ruma_api! { metadata: { @@ -27,7 +27,7 @@ ruma_api! { /// Clients should generate a unique ID; it will be used by the server to ensure idempotency /// of requests. #[ruma_api(path)] - pub txn_id: &'a str, + pub txn_id: &'a TransactionId, /// The reason for the redaction. #[serde(skip_serializing_if = "Option::is_none")] @@ -44,7 +44,7 @@ ruma_api! { impl<'a> Request<'a> { /// 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 } } } diff --git a/crates/ruma-client-api/src/r0/to_device/send_event_to_device.rs b/crates/ruma-client-api/src/r0/to_device/send_event_to_device.rs index e8d959e0..aa08e207 100644 --- a/crates/ruma-client-api/src/r0/to_device/send_event_to_device.rs +++ b/crates/ruma-client-api/src/r0/to_device/send_event_to_device.rs @@ -5,7 +5,7 @@ use std::collections::BTreeMap; use ruma_api::ruma_api; use ruma_common::to_device::DeviceIdOrAllDevices; use ruma_events::AnyToDeviceEventContent; -use ruma_identifiers::UserId; +use ruma_identifiers::{TransactionId, UserId}; use ruma_serde::Raw; ruma_api! { @@ -25,7 +25,7 @@ ruma_api! { /// A request identifier unique to the access token used to send the request. #[ruma_api(path)] - pub txn_id: &'a str, + pub txn_id: &'a TransactionId, /// Messages to send. /// @@ -42,7 +42,7 @@ ruma_api! { impl<'a> Request<'a> { /// 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 } } } diff --git a/crates/ruma-client-api/src/r0/uiaa.rs b/crates/ruma-client-api/src/r0/uiaa.rs index 0be71a79..8ec95dd7 100644 --- a/crates/ruma-client-api/src/r0/uiaa.rs +++ b/crates/ruma-client-api/src/r0/uiaa.rs @@ -10,7 +10,7 @@ use ruma_api::{ EndpointError, OutgoingResponse, }; use ruma_common::thirdparty::Medium; -use ruma_identifiers::{ClientSecret, SessionId}; +use ruma_identifiers::{ClientSecret, SessionId, TransactionId}; use ruma_serde::{JsonObject, Outgoing, StringEnum}; use serde::{ de::{self, DeserializeOwned}, @@ -470,7 +470,7 @@ pub struct Token<'a> { pub token: &'a str, /// 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. pub session: Option<&'a str>, @@ -478,7 +478,7 @@ pub struct Token<'a> { impl<'a> Token<'a> { /// 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 } } } diff --git a/crates/ruma-client-api/tests/uiaa.rs b/crates/ruma-client-api/tests/uiaa.rs index c77bb8ee..216d231e 100644 --- a/crates/ruma-client-api/tests/uiaa.rs +++ b/crates/ruma-client-api/tests/uiaa.rs @@ -30,7 +30,7 @@ fn deserialize_user_identifier() { #[test] fn serialize_auth_data_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!( diff --git a/crates/ruma-events/src/key/verification/accept.rs b/crates/ruma-events/src/key/verification/accept.rs index 7082f7f9..48cd4761 100644 --- a/crates/ruma-events/src/key/verification/accept.rs +++ b/crates/ruma-events/src/key/verification/accept.rs @@ -5,6 +5,7 @@ use std::collections::BTreeMap; use ruma_events_macros::EventContent; +use ruma_identifiers::TransactionId; use ruma_serde::Base64; use serde::{Deserialize, Serialize}; use serde_json::Value as JsonValue; @@ -25,7 +26,7 @@ pub struct ToDeviceKeyVerificationAcceptEventContent { /// An opaque identifier for the verification process. /// /// Must be the same as the one used for the `m.key.verification.start` message. - pub transaction_id: String, + pub transaction_id: Box, /// The method specific content. #[serde(flatten)] @@ -35,7 +36,7 @@ pub struct ToDeviceKeyVerificationAcceptEventContent { impl ToDeviceKeyVerificationAcceptEventContent { /// Creates a new `ToDeviceKeyVerificationAcceptEventContent` with the given transaction ID and /// method-specific content. - pub fn new(transaction_id: String, method: AcceptMethod) -> Self { + pub fn new(transaction_id: Box, method: AcceptMethod) -> Self { Self { transaction_id, method } } } diff --git a/crates/ruma-events/src/key/verification/cancel.rs b/crates/ruma-events/src/key/verification/cancel.rs index ecf5ec1b..a828898e 100644 --- a/crates/ruma-events/src/key/verification/cancel.rs +++ b/crates/ruma-events/src/key/verification/cancel.rs @@ -3,6 +3,7 @@ //! [`m.key.verification.cancel`]: https://spec.matrix.org/v1.1/client-server-api/#mkeyverificationcancel use ruma_events_macros::EventContent; +use ruma_identifiers::TransactionId; use ruma_serde::StringEnum; use serde::{Deserialize, Serialize}; @@ -19,7 +20,7 @@ use super::Relation; #[ruma_event(type = "m.key.verification.cancel", kind = ToDevice)] pub struct ToDeviceKeyVerificationCancelEventContent { /// The opaque identifier for the verification process/request. - pub transaction_id: String, + pub transaction_id: Box, /// A human readable description of the `code`. /// @@ -33,7 +34,7 @@ pub struct ToDeviceKeyVerificationCancelEventContent { impl ToDeviceKeyVerificationCancelEventContent { /// Creates a new `ToDeviceKeyVerificationCancelEventContent` with the given transaction ID, /// reason and code. - pub fn new(transaction_id: String, reason: String, code: CancelCode) -> Self { + pub fn new(transaction_id: Box, reason: String, code: CancelCode) -> Self { Self { transaction_id, reason, code } } } diff --git a/crates/ruma-events/src/key/verification/done.rs b/crates/ruma-events/src/key/verification/done.rs index c8e97d21..e188bc46 100644 --- a/crates/ruma-events/src/key/verification/done.rs +++ b/crates/ruma-events/src/key/verification/done.rs @@ -3,6 +3,7 @@ //! [`m.key.verification.done`]: https://spec.matrix.org/v1.1/client-server-api/#mkeyverificationdone use ruma_events_macros::EventContent; +use ruma_identifiers::TransactionId; use serde::{Deserialize, Serialize}; use super::Relation; @@ -17,12 +18,12 @@ pub struct ToDeviceKeyVerificationDoneEventContent { /// An opaque identifier for the verification process. /// /// Must be the same as the one used for the `m.key.verification.start` message. - pub transaction_id: String, + pub transaction_id: Box, } impl ToDeviceKeyVerificationDoneEventContent { /// Creates a new `ToDeviceKeyVerificationDoneEventContent` with the given transaction ID. - pub fn new(transaction_id: String) -> Self { + pub fn new(transaction_id: Box) -> Self { Self { transaction_id } } } diff --git a/crates/ruma-events/src/key/verification/key.rs b/crates/ruma-events/src/key/verification/key.rs index 8d31bd69..3e5cd4b7 100644 --- a/crates/ruma-events/src/key/verification/key.rs +++ b/crates/ruma-events/src/key/verification/key.rs @@ -3,6 +3,7 @@ //! [`m.key.verification.key`]: https://spec.matrix.org/v1.1/client-server-api/#mkeyverificationkey use ruma_events_macros::EventContent; +use ruma_identifiers::TransactionId; use ruma_serde::Base64; use serde::{Deserialize, Serialize}; @@ -19,7 +20,7 @@ pub struct ToDeviceKeyVerificationKeyEventContent { /// An opaque identifier for the verification process. /// /// Must be the same as the one used for the `m.key.verification.start` message. - pub transaction_id: String, + pub transaction_id: Box, /// The device's ephemeral public key, encoded as unpadded base64. pub key: Base64, @@ -28,7 +29,7 @@ pub struct ToDeviceKeyVerificationKeyEventContent { impl ToDeviceKeyVerificationKeyEventContent { /// Creates a new `ToDeviceKeyVerificationKeyEventContent` with the given transaction ID and /// key. - pub fn new(transaction_id: String, key: Base64) -> Self { + pub fn new(transaction_id: Box, key: Base64) -> Self { Self { transaction_id, key } } } diff --git a/crates/ruma-events/src/key/verification/mac.rs b/crates/ruma-events/src/key/verification/mac.rs index 4f57892b..64d449cc 100644 --- a/crates/ruma-events/src/key/verification/mac.rs +++ b/crates/ruma-events/src/key/verification/mac.rs @@ -5,6 +5,7 @@ use std::collections::BTreeMap; use ruma_events_macros::EventContent; +use ruma_identifiers::TransactionId; use ruma_serde::Base64; use serde::{Deserialize, Serialize}; @@ -21,7 +22,7 @@ pub struct ToDeviceKeyVerificationMacEventContent { /// An opaque identifier for the verification process. /// /// Must be the same as the one used for the `m.key.verification.start` message. - pub transaction_id: String, + pub transaction_id: Box, /// 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 { /// Creates a new `ToDeviceKeyVerificationMacEventContent` with the given transaction ID, key ID /// to MAC map and key MAC. - pub fn new(transaction_id: String, mac: BTreeMap, keys: Base64) -> Self { + pub fn new( + transaction_id: Box, + mac: BTreeMap, + keys: Base64, + ) -> Self { Self { transaction_id, mac, keys } } } diff --git a/crates/ruma-events/src/key/verification/ready.rs b/crates/ruma-events/src/key/verification/ready.rs index e34c902a..edf49d3a 100644 --- a/crates/ruma-events/src/key/verification/ready.rs +++ b/crates/ruma-events/src/key/verification/ready.rs @@ -3,7 +3,7 @@ //! [`m.key.verification.ready`]: https://spec.matrix.org/v1.1/client-server-api/#mkeyverificationready use ruma_events_macros::EventContent; -use ruma_identifiers::DeviceId; +use ruma_identifiers::{DeviceId, TransactionId}; use serde::{Deserialize, Serialize}; 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 /// `transaction_id` given in the `m.key.verification.request` from a /// request. - pub transaction_id: String, + pub transaction_id: Box, } impl ToDeviceKeyVerificationReadyEventContent { @@ -35,7 +35,7 @@ impl ToDeviceKeyVerificationReadyEventContent { pub fn new( from_device: Box, methods: Vec, - transaction_id: String, + transaction_id: Box, ) -> Self { Self { from_device, methods, transaction_id } } @@ -111,7 +111,7 @@ mod tests { let content = ToDeviceKeyVerificationReadyEventContent { from_device: device, - transaction_id: "456".to_owned(), + transaction_id: "456".into(), methods: vec![VerificationMethod::SasV1], }; diff --git a/crates/ruma-events/src/key/verification/request.rs b/crates/ruma-events/src/key/verification/request.rs index aa388c50..4ab6742f 100644 --- a/crates/ruma-events/src/key/verification/request.rs +++ b/crates/ruma-events/src/key/verification/request.rs @@ -4,7 +4,7 @@ use ruma_common::MilliSecondsSinceUnixEpoch; use ruma_events_macros::EventContent; -use ruma_identifiers::DeviceId; +use ruma_identifiers::{DeviceId, TransactionId}; use serde::{Deserialize, Serialize}; use super::VerificationMethod; @@ -20,7 +20,7 @@ pub struct ToDeviceKeyVerificationRequestEventContent { /// An opaque identifier for the verification request. /// /// Must be unique with respect to the devices involved. - pub transaction_id: String, + pub transaction_id: Box, /// The verification methods supported by the sender. pub methods: Vec, @@ -37,7 +37,7 @@ impl ToDeviceKeyVerificationRequestEventContent { /// transaction ID, methods and timestamp. pub fn new( from_device: Box, - transaction_id: String, + transaction_id: Box, methods: Vec, timestamp: MilliSecondsSinceUnixEpoch, ) -> Self { diff --git a/crates/ruma-events/src/key/verification/start.rs b/crates/ruma-events/src/key/verification/start.rs index 07c784a4..b54d4712 100644 --- a/crates/ruma-events/src/key/verification/start.rs +++ b/crates/ruma-events/src/key/verification/start.rs @@ -5,7 +5,7 @@ use std::collections::BTreeMap; use ruma_events_macros::EventContent; -use ruma_identifiers::DeviceId; +use ruma_identifiers::{DeviceId, TransactionId}; #[cfg(feature = "unstable-pre-spec")] use ruma_serde::Base64; 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 /// `transaction_id` given in the `m.key.verification.request` if this process is originating /// from a request. - pub transaction_id: String, + pub transaction_id: Box, /// Method specific content. #[serde(flatten)] @@ -42,7 +42,11 @@ pub struct ToDeviceKeyVerificationStartEventContent { impl ToDeviceKeyVerificationStartEventContent { /// Creates a new `ToDeviceKeyVerificationStartEventContent` with the given device ID, /// transaction ID and method specific content. - pub fn new(from_device: Box, transaction_id: String, method: StartMethod) -> Self { + pub fn new( + from_device: Box, + transaction_id: Box, + method: StartMethod, + ) -> Self { Self { from_device, transaction_id, method } } } diff --git a/crates/ruma-events/src/unsigned.rs b/crates/ruma-events/src/unsigned.rs index 4de9872b..4622149d 100644 --- a/crates/ruma-events/src/unsigned.rs +++ b/crates/ruma-events/src/unsigned.rs @@ -1,4 +1,5 @@ use js_int::Int; +use ruma_identifiers::TransactionId; use serde::{Deserialize, Serialize}; #[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 /// which sent it. #[serde(skip_serializing_if = "Option::is_none")] - pub transaction_id: Option, + pub transaction_id: Option>, /// Server-compiled information from other events relating to this event. #[cfg(feature = "unstable-pre-spec")] @@ -82,7 +83,7 @@ pub struct UnsignedWithPrevContent { age: Option, #[serde(skip_serializing_if = "Option::is_none")] - transaction_id: Option, + transaction_id: Option>, #[cfg(feature = "unstable-pre-spec")] #[serde(rename = "m.relations", skip_serializing_if = "Option::is_none")] diff --git a/crates/ruma-federation-api/src/transactions/send_transaction_message/v1.rs b/crates/ruma-federation-api/src/transactions/send_transaction_message/v1.rs index 779126ea..f6876c3a 100644 --- a/crates/ruma-federation-api/src/transactions/send_transaction_message/v1.rs +++ b/crates/ruma-federation-api/src/transactions/send_transaction_message/v1.rs @@ -4,7 +4,7 @@ use std::collections::BTreeMap; use ruma_api::ruma_api; use ruma_common::MilliSecondsSinceUnixEpoch; -use ruma_identifiers::{EventId, ServerName}; +use ruma_identifiers::{EventId, ServerName, TransactionId}; use ruma_serde::Raw; use serde_json::value::RawValue as RawJsonValue; @@ -23,7 +23,7 @@ ruma_api! { request: { /// A transaction ID unique between sending and receiving homeservers. #[ruma_api(path)] - pub transaction_id: &'a str, + pub transaction_id: &'a TransactionId, /// The server_name of the homeserver sending this transaction. pub origin: &'a ServerName, @@ -58,7 +58,7 @@ impl<'a> Request<'a> { /// /// The PDU and EDU lists will start off empty. pub fn new( - transaction_id: &'a str, + transaction_id: &'a TransactionId, origin: &'a ServerName, origin_server_ts: MilliSecondsSinceUnixEpoch, ) -> Self { diff --git a/crates/ruma-identifiers/Cargo.toml b/crates/ruma-identifiers/Cargo.toml index 50fd5877..9b19e28c 100644 --- a/crates/ruma-identifiers/Cargo.toml +++ b/crates/ruma-identifiers/Cargo.toml @@ -21,19 +21,21 @@ rustdoc-args = ["--cfg", "docsrs"] [features] default = ["serde"] compat = ["ruma-identifiers-validation/compat"] +rand = ["rand_crate", "uuid"] serde = ["ruma-serde", "serde1"] unstable-pre-spec = [] [dependencies] either = { version = "1.6.1", optional = true } 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-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-macros = { version = "0.5.0", path = "../ruma-serde-macros" } # Renamed so we can have a serde feature. serde1 = { package = "serde", version = "1.0.126", optional = true, features = ["derive"] } +uuid = { version = "0.8.2", optional = true, features = ["v4"] } [dev-dependencies] matches = "0.1.8" diff --git a/crates/ruma-identifiers/src/lib.rs b/crates/ruma-identifiers/src/lib.rs index 9614de57..1b839a83 100644 --- a/crates/ruma-identifiers/src/lib.rs +++ b/crates/ruma-identifiers/src/lib.rs @@ -8,11 +8,14 @@ #![allow(unused_qualifications)] #![cfg_attr(docsrs, feature(doc_auto_cfg))] -// Renamed in `Cargo.toml` so we can have a serde feature. -// Rename it back here because `serde1` is ugly. +// Renamed in `Cargo.toml` so we can features with the same name as the package. +// Rename them back here because the `Cargo.toml` names are ugly. #[cfg(feature = "serde")] extern crate serde1 as serde; +#[cfg(feature = "rand")] +extern crate rand_crate as rand; + #[cfg(feature = "serde")] use std::convert::TryFrom; @@ -38,6 +41,7 @@ pub use crate::{ server_name::ServerName, session_id::SessionId, signatures::{DeviceSignatures, EntitySignatures, ServerSignatures, Signatures}, + transaction_id::TransactionId, user_id::UserId, }; #[doc(inline)] @@ -65,6 +69,7 @@ mod room_version_id; mod server_name; mod session_id; mod signatures; +mod transaction_id; /// Generates a random identifier localpart. #[cfg(feature = "rand")] diff --git a/crates/ruma-identifiers/src/transaction_id.rs b/crates/ruma-identifiers/src/transaction_id.rs new file mode 100644 index 00000000..2815cd88 --- /dev/null +++ b/crates/ruma-identifiers/src/transaction_id.rs @@ -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 { + let id = uuid::Uuid::new_v4(); + Self::from_owned(id.to_simple().to_string().into_boxed_str()) + } +} + +opaque_identifier!(TransactionId); diff --git a/crates/ruma-serde-macros/src/outgoing.rs b/crates/ruma-serde-macros/src/outgoing.rs index 3b0cccbf..00c2241b 100644 --- a/crates/ruma-serde-macros/src/outgoing.rs +++ b/crates/ruma-serde-macros/src/outgoing.rs @@ -275,6 +275,7 @@ fn strip_lifetimes(field_type: &mut Type) -> bool { || last_seg.ident == "RoomName" || last_seg.ident == "ServerSigningKeyId" || last_seg.ident == "SigningKeyId" + || last_seg.ident == "TransactionId" || last_seg.ident == "UserId" { // The identifiers that need to be boxed `Box` since they are DST's. diff --git a/crates/ruma/Cargo.toml b/crates/ruma/Cargo.toml index 42d26f3d..6301337b 100644 --- a/crates/ruma/Cargo.toml +++ b/crates/ruma/Cargo.toml @@ -149,7 +149,7 @@ tokio-stream = { version = "0.1.1", default-features = false } [[example]] 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]] name = "hello_isahc" diff --git a/crates/ruma/examples/hello_world.rs b/crates/ruma/examples/hello_world.rs index 8960af8a..5ad63d63 100644 --- a/crates/ruma/examples/hello_world.rs +++ b/crates/ruma/examples/hello_world.rs @@ -5,6 +5,7 @@ use ruma::{ events::room::message::RoomMessageEventContent, RoomAliasId, }; +use ruma_identifiers::TransactionId; type MatrixClient = ruma_client::Client; @@ -22,7 +23,7 @@ async fn hello_world( client .send_request(send_message_event::Request::new( &room_id, - "1", + &TransactionId::new(), &RoomMessageEventContent::text_plain("Hello World!"), )?) .await?; diff --git a/examples/joke_bot/src/main.rs b/examples/joke_bot/src/main.rs index 86362d0a..18a2b19a 100644 --- a/examples/joke_bot/src/main.rs +++ b/examples/joke_bot/src/main.rs @@ -1,10 +1,4 @@ -use std::{ - convert::TryInto, - error::Error, - io, - process::exit, - time::{Duration, SystemTime}, -}; +use std::{convert::TryInto, error::Error, io, process::exit, time::Duration}; use ruma::{ api::client::r0::{ @@ -16,6 +10,7 @@ use ruma::{ room::message::{MessageType, RoomMessageEventContent}, AnySyncMessageEvent, AnySyncRoomEvent, }, + identifiers::TransactionId, presence::PresenceState, serde::Raw, RoomId, UserId, @@ -154,7 +149,7 @@ async fn handle_messages( }; 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)?; // Do nothing if we can't send the message. 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 joke = get_joke(http_client).await.unwrap_or_else(|_| "err... never mind.".to_owned()); 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)?; matrix_client.send_request(message).await?; 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> { let uri = "https://v2.jokeapi.dev/joke/Programming,Pun,Misc?safe-mode&type=single" .parse::()?;