diff --git a/shared/tunnelbroker_messages/src/lib.rs b/shared/tunnelbroker_messages/src/lib.rs index 8f054889b..14d04d641 100644 --- a/shared/tunnelbroker_messages/src/lib.rs +++ b/shared/tunnelbroker_messages/src/lib.rs @@ -1,3 +1,4 @@ pub mod messages; pub use messages::*; +pub use send_confirmation::*; diff --git a/shared/tunnelbroker_messages/src/messages/mod.rs b/shared/tunnelbroker_messages/src/messages/mod.rs index f793ab2ed..d18ef0963 100644 --- a/shared/tunnelbroker_messages/src/messages/mod.rs +++ b/shared/tunnelbroker_messages/src/messages/mod.rs @@ -1,24 +1,27 @@ // Messages sent between Tunnelbroker and a device pub mod keys; pub mod message_to_device; pub mod message_to_device_request; +pub mod send_confirmation; pub mod session; pub use keys::*; pub use message_to_device::*; pub use message_to_device_request::*; +pub use send_confirmation::*; pub use session::*; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug)] #[serde(untagged)] pub enum Messages { RefreshKeysRequest(RefreshKeyRequest), ConnectionInitializationMessage(ConnectionInitializationMessage), // MessageToDeviceRequest must be placed before MessageToDevice. // This is due to serde's pattern matching behavior where it prioritizes // the first matching pattern it encounters. MessageToDeviceRequest(MessageToDeviceRequest), MessageToDevice(MessageToDevice), + MessageToDeviceRequestStatus(MessageToDeviceRequestStatus), } diff --git a/shared/tunnelbroker_messages/src/messages/send_confirmation.rs b/shared/tunnelbroker_messages/src/messages/send_confirmation.rs new file mode 100644 index 000000000..9e33cd180 --- /dev/null +++ b/shared/tunnelbroker_messages/src/messages/send_confirmation.rs @@ -0,0 +1,86 @@ +// Message sent from Tunnelbroker to WebSocket clients to inform that message +// was processed, saved in DDB and will be delivered. + +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, PartialEq, Debug)] +pub struct Failure { + pub id: String, + pub error: String, +} + +#[derive(Serialize, Deserialize, PartialEq, Debug)] +#[serde(tag = "type", content = "data")] +pub enum MessageSentStatus { + /// The message with the provided ID (String) has been processed + /// by the Tunnelbroker and is queued for delivery. + Success(String), + /// 'Failure' contains information about the message ID + /// along with the specific error message. + Error(Failure), + /// The request was invalid (e.g., Bytes instead of Text). + /// In this case, the ID cannot be retrieved. + InvalidRequest, + /// The JSON could not be serialized, which is why the entire message is + /// returned back. + /// It becomes impossible to retrieve the message ID in such circumstances. + SerializationError(String), +} + +#[derive(Serialize, Deserialize, PartialEq, Debug)] +#[serde(tag = "type", rename_all = "camelCase")] +pub struct MessageToDeviceRequestStatus { + #[serde(rename = "clientMessageIDs")] + pub client_message_ids: Vec, +} + +#[cfg(test)] +mod send_confirmation_tests { + use super::*; + + #[test] + fn test_send_confirmation_deserialization() { + let example_payload = r#"{ + "type": "MessageToDeviceRequestStatus", + "clientMessageIDs": [ + {"type": "Success", "data": "id123"}, + {"type": "Success", "data": "id456"}, + {"type": "Error", "data": {"id": "id789", "error": "Something went wrong"}}, + {"type": "SerializationError", "data": "message"}, + {"type": "InvalidRequest"} + ] + }"#; + + let request = + serde_json::from_str::(example_payload) + .unwrap(); + + let expected_client_message_ids = vec![ + MessageSentStatus::Success("id123".to_string()), + MessageSentStatus::Success("id456".to_string()), + MessageSentStatus::Error(Failure { + id: String::from("id789"), + error: String::from("Something went wrong"), + }), + MessageSentStatus::SerializationError("message".to_string()), + MessageSentStatus::InvalidRequest, + ]; + + assert_eq!(request.client_message_ids, expected_client_message_ids); + } + + #[test] + fn test_send_confirmation_deserialization_empty_vec() { + let example_payload = r#"{ + "type": "MessageToDeviceRequestStatus", + "clientMessageIDs": [] + }"#; + + let request = + serde_json::from_str::(example_payload) + .unwrap(); + let expected_client_message_ids: Vec = Vec::new(); + + assert_eq!(request.client_message_ids, expected_client_message_ids); + } +}