From 36e015bd90de43fa91a995a2ef6bb6c0c034231b Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Wed, 4 Sep 2024 19:35:36 +0100 Subject: [PATCH] commit uri_parser.rs --- pairing_api/src/uri_parser.rs | 115 ++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 pairing_api/src/uri_parser.rs diff --git a/pairing_api/src/uri_parser.rs b/pairing_api/src/uri_parser.rs new file mode 100644 index 0000000..795e41b --- /dev/null +++ b/pairing_api/src/uri_parser.rs @@ -0,0 +1,115 @@ +use { + serde::{Deserialize, Serialize}, + std::collections::HashMap, + thiserror::Error, + url::Url, +}; + +#[derive(Debug, Error)] +pub enum ParseError { + #[error("Invalid URI")] + InvalidUri, + #[error("Missing topic")] + MissingTopic, + #[error("Invalid version")] + InvalidVersion, + #[error("Missing symmetric key")] + MissingSymKey, + #[error("Invalid symmetric key")] + InvalidSymKey, + #[error("Missing methods")] + MissingMethods, + #[error("Invalid methods format")] + InvalidMethods, + #[error("Missing relay protocol")] + MissingRelayProtocol, + #[error("Invalid expiry timestamp")] + InvalidExpiryTimestamp, + #[error("Unexpected parameter: {0}")] + UnexpectedParameter(String), +} + +#[derive(Debug)] +pub struct ParsedWcUri { + pub topic: String, + pub version: String, + pub sym_key: String, + pub methods: Methods, + pub relay_protocol: String, + pub relay_data: Option, + pub expiry_timestamp: u64, +} + +pub fn parse_wc_uri(uri: &str) -> Result { + let url = Url::parse(uri).map_err(|_| ParseError::InvalidUri)?; + + if url.scheme() != "wc" { + return Err(ParseError::InvalidUri); + } + + let mut parts = url.path().split('@'); + let topic = parts.next().ok_or(ParseError::MissingTopic)?.to_string(); + let version = parts.next().ok_or(ParseError::InvalidVersion)?.to_string(); + + let mut params = HashMap::new(); + for (key, value) in url.query_pairs() { + params.insert(key.to_string(), value.to_string()); + } + + let methods_str = params.remove("methods"); + let methods = parse_methods(methods_str.as_deref())?; + + let sym_key = params.remove("symKey").ok_or(ParseError::MissingSymKey)?; + let relay_protocol = params + .remove("relay-protocol") + .ok_or(ParseError::MissingRelayProtocol)?; + let relay_data = params.remove("relay-data"); + let expiry_timestamp = params + .remove("expiryTimestamp") + .ok_or(ParseError::InvalidExpiryTimestamp)? + .parse::() + .map_err(|_| ParseError::InvalidExpiryTimestamp)?; + + // Check for unexpected parameters + if !params.is_empty() { + return Err(ParseError::UnexpectedParameter( + params.keys().next().unwrap().clone(), + )); + } + + Ok(ParsedWcUri { + topic, + version, + sym_key, + methods, + relay_protocol, + relay_data, + expiry_timestamp, + }) +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Methods(pub Vec>); + +fn parse_methods(methods_str: Option<&str>) -> Result { + if methods_str.is_none() { + return Ok(Methods(vec![])); + } + + let trimmed = methods_str.unwrap().trim_matches('[').trim_matches(']'); + if trimmed.is_empty() { + return Ok(Methods(vec![])); + } + + let method_groups: Vec> = trimmed + .split("],[") + .map(|group| { + group + .split(',') + .map(|s| s.trim().to_string()) + .collect::>() + }) + .collect(); + + Ok(Methods(method_groups)) +}