diff --git a/shared/tunnelbroker_messages/src/messages/connection_initialization_response.rs b/shared/tunnelbroker_messages/src/messages/connection_initialization_response.rs new file mode 100644 index 000000000..c9ad590cf --- /dev/null +++ b/shared/tunnelbroker_messages/src/messages/connection_initialization_response.rs @@ -0,0 +1,56 @@ +//! Message sent from Tunnelbroker to WebSocket as a response to +//! ConnectionInitializationMessage. + +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, PartialEq, Debug)] +#[serde(tag = "type", content = "data")] +pub enum ConnectionInitializationStatus { + Success, + Error(String), +} + +#[derive(Serialize, Deserialize, PartialEq, Debug)] +#[serde(tag = "type", rename_all = "camelCase")] +pub struct ConnectionInitializationResponse { + pub status: ConnectionInitializationStatus, +} + +#[cfg(test)] +mod connection_init_response_tests { + use super::*; + + #[test] + fn test_connection_init_response_success() { + let example_payload = r#"{ + "type":"ConnectionInitializationResponse", + "status": {"type":"Success"} + }"#; + + let request = + serde_json::from_str::(example_payload) + .unwrap(); + + assert_eq!(request.status, ConnectionInitializationStatus::Success); + } + + #[test] + fn test_connection_init_response_error() { + let example_payload = r#"{ + "type": "ConnectionInitializationResponse", + "status": { + "type":"Error", + "data":"Something went wrong" + } + }"#; + + let request = + serde_json::from_str::(example_payload) + .unwrap(); + + assert_eq!( + request.status, + ConnectionInitializationStatus::Error("Something went wrong".into()) + ); + } +} diff --git a/shared/tunnelbroker_messages/src/messages/mod.rs b/shared/tunnelbroker_messages/src/messages/mod.rs index ee8b7eaa4..3364d4638 100644 --- a/shared/tunnelbroker_messages/src/messages/mod.rs +++ b/shared/tunnelbroker_messages/src/messages/mod.rs @@ -1,31 +1,34 @@ //! Messages sent between Tunnelbroker and a device. +pub mod connection_initialization_response; pub mod keys; pub mod message_receive_confirmation; pub mod message_to_device; pub mod message_to_device_request; pub mod message_to_device_request_status; pub mod session; +pub use connection_initialization_response::*; pub use keys::*; pub use message_receive_confirmation::*; pub use message_to_device::*; pub use message_to_device_request::*; pub use message_to_device_request_status::*; pub use session::*; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug)] #[serde(untagged)] pub enum Messages { RefreshKeysRequest(RefreshKeyRequest), ConnectionInitializationMessage(ConnectionInitializationMessage), + ConnectionInitializationResponse(ConnectionInitializationResponse), // MessageToDeviceRequestStatus must be placed before MessageToDeviceRequest. // This is due to serde's pattern matching behavior where it prioritizes // the first matching pattern it encounters. MessageToDeviceRequestStatus(MessageToDeviceRequestStatus), MessageToDeviceRequest(MessageToDeviceRequest), MessageToDevice(MessageToDevice), MessageReceiveConfirmation(MessageReceiveConfirmation), } diff --git a/shared/tunnelbroker_messages/src/messages/session.rs b/shared/tunnelbroker_messages/src/messages/session.rs index e9e5e9519..4f98961ce 100644 --- a/shared/tunnelbroker_messages/src/messages/session.rs +++ b/shared/tunnelbroker_messages/src/messages/session.rs @@ -1,73 +1,68 @@ //! The first message sent from WebSocket client to Tunnelbroker. use serde::{Deserialize, Serialize}; /// The workflow when establishing a Tunnelbroker connection: /// - Client sends ConnectionInitializationMessage /// - Tunnelbroker validates access_token with identity service /// - Tunnelbroker emits an AMQP message declaring that it has opened a new /// connection with a given device, so that the respective Tunnelbroker /// instance can close the existing connection. /// - Tunnelbroker returns a session_id representing that the connection was /// accepted /// - Tunnelbroker will flush all messages related to device from RabbitMQ. /// This must be done first before flushing DynamoDB to prevent duplicated /// messages. /// - Tunnelbroker flushes all messages in DynamoDB /// - Tunnelbroker orders messages by creation date (oldest first), and sends /// messages to device /// - Tunnelbroker then polls for incoming messages from device #[derive(Serialize, Deserialize, Debug, PartialEq)] #[serde(rename_all = "camelCase")] pub enum DeviceTypes { Mobile, Web, Keyserver, } /// Message sent by a client to Tunnelbroker to initiate a websocket /// session. Tunnelbroker will then validate the access token with identity /// service before continuing with the request. #[derive(Serialize, Deserialize, Debug)] #[serde(tag = "type", rename_all = "camelCase")] pub struct ConnectionInitializationMessage { #[serde(rename = "deviceID")] pub device_id: String, pub access_token: String, #[serde(rename = "userID")] pub user_id: String, pub notify_token: Option, pub device_type: DeviceTypes, pub device_app_version: Option, pub device_os: Option, } -#[derive(Serialize, Deserialize)] -pub struct ConnectionInitializationResponse { - pub session_id: String, -} - #[cfg(test)] mod session_tests { use super::*; #[test] fn test_session_deserialization() { let example_payload = r#"{ "type": "sessionRequest", "accessToken": "xkdeifjsld", "deviceID": "foo", "userID": "alice", "deviceType": "keyserver" }"#; let request = serde_json::from_str::(example_payload) .unwrap(); assert_eq!(request.device_id, "foo"); assert_eq!(request.access_token, "xkdeifjsld"); assert_eq!(request.device_os, None); assert_eq!(request.device_type, DeviceTypes::Keyserver); } }