#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "typescript-bindings")]
use ts_rs::TS;
#[cfg(feature = "uniffi-bindings")]
uniffi::setup_scaffolding!();
use std::net::SocketAddr;
#[cfg(feature = "uniffi-bindings")]
use std::str::FromStr;
#[cfg(feature = "uniffi-bindings")]
uniffi::custom_type!(SocketAddr, String, {
remote,
try_lift: |val| Ok(SocketAddr::from_str(&val)?),
lower: |val| val.to_string()
});
#[derive(Debug, PartialEq, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "uniffi-bindings", derive(uniffi::Record))]
#[cfg_attr(
feature = "typescript-bindings",
derive(TS),
ts(export),
ts(export_to = "bindings.ts")
)]
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
pub struct PersistedClientConfig {
pub version: String,
pub transports: Vec<ClientConfig>,
}
impl PersistedClientConfig {
pub fn get_addrs(&self) -> Vec<SocketAddr> {
let mut addrs = Vec::new();
for transport in &self.transports {
match transport {
ClientConfig::QuicPlain(params) => addrs.extend(¶ms.addresses),
ClientConfig::TlsPlain(params) => addrs.extend(¶ms.addresses),
}
}
addrs
}
}
#[derive(Debug, PartialEq, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "transport_type", content = "args"))]
#[cfg_attr(feature = "uniffi-bindings", derive(uniffi::Enum))]
#[cfg_attr(
feature = "typescript-bindings",
derive(TS),
ts(export),
ts(export_to = "bindings.ts")
)]
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
pub enum ClientConfig {
QuicPlain(quic::ClientOptions),
TlsPlain(tls::ClientOptions),
}
impl From<quic::ClientOptions> for ClientConfig {
fn from(value: quic::ClientOptions) -> Self {
ClientConfig::QuicPlain(value)
}
}
impl From<tls::ClientOptions> for ClientConfig {
fn from(value: tls::ClientOptions) -> Self {
ClientConfig::TlsPlain(value)
}
}
pub mod quic {
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use std::net::SocketAddr;
#[cfg(feature = "typescript-bindings")]
use ts_rs::TS;
#[derive(Debug, PartialEq, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "uniffi-bindings", derive(uniffi::Record))]
#[cfg_attr(
feature = "typescript-bindings",
derive(TS),
ts(export),
ts(export_to = "bindings.ts")
)]
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
pub struct QuicPlainClientOptions {
pub addresses: Vec<SocketAddr>,
pub host: Option<String>,
pub id_pubkey: String,
}
pub type ClientOptions = QuicPlainClientOptions;
}
pub mod tls {
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use std::net::SocketAddr;
#[cfg(feature = "typescript-bindings")]
use ts_rs::TS;
#[derive(Debug, PartialEq, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "uniffi-bindings", derive(uniffi::Record))]
#[cfg_attr(
feature = "typescript-bindings",
derive(TS),
ts(export),
ts(export_to = "bindings.ts")
)]
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
pub struct TlsPlainClientOptions {
pub addresses: Vec<SocketAddr>,
pub host: Option<String>,
pub id_pubkey: String,
}
pub type ClientOptions = TlsPlainClientOptions;
}
#[cfg(test)]
mod test {
use crate::{ClientConfig, PersistedClientConfig};
const RAW_V0_CLIENT_CONFIG: &str = r#"{"version":"0","transports":[{"transport_type":"quic_plain","args":{"addresses":["139.162.33.226:4443","[2400:8901::2000:faff:fea6:87f2]:4443"],"host":"netdna.bootstrapcdn.com","id_pubkey":"9JC91ZiszhIn3n4FG+MDYE/lYwhGdpHGWQTKUqGl+sE="}}]}"#;
#[test]
fn ensure_bridge_v0_parsing_compatibility() -> Result<(), Box<dyn std::error::Error>> {
let parsed: PersistedClientConfig = serde_json::from_str(RAW_V0_CLIENT_CONFIG)?;
assert_eq!(parsed.version, "0");
let params = match &parsed.transports[0] {
ClientConfig::QuicPlain(p) => p,
ClientConfig::TlsPlain(_) => return Err("expected quic transport args".into()),
};
let addresses = ¶ms.addresses;
let address_strings: Vec<String> = addresses.iter().map(|v| v.to_string()).collect();
assert!(
address_strings
.iter()
.any(|addr| addr.contains("139.162.33.226:4443"))
);
assert!(
address_strings
.iter()
.any(|addr| addr.contains("[2400:8901::2000:faff:fea6:87f2]:4443"))
);
assert_eq!(params.host, Some("netdna.bootstrapcdn.com".to_string()),);
Ok(())
}
}