use std::{collections::HashSet, path::PathBuf, time::Duration};
use serde::{Deserialize, Serialize};
use serde_with::serde_as;
pub const NO_PREFERRED_ROUTE_HINT: u32 = 0;
#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
#[serde(default)]
pub struct TransportConfig {
pub peer_to_peer: PeerToPeer,
pub connect: Connect,
pub listen: Listen,
pub global: Global,
}
impl TransportConfig {
pub fn new() -> Self {
Self {
peer_to_peer: PeerToPeer {
bluetooth_le: BluetoothLEConfig::new(),
lan: LanConfig::new(),
awdl: AwdlConfig::new(),
wifi_aware: WifiAwareConfig::new(),
},
connect: Connect {
tcp_servers: HashSet::new(),
websocket_urls: HashSet::new(),
retry_interval: Duration::from_secs(5),
},
listen: Listen {
tcp: TcpListenConfig::new(),
http: HttpListenConfig::new(),
},
global: Global {
sync_group: 0,
routing_hint: NO_PREFERRED_ROUTE_HINT,
},
}
}
pub fn enable_all_peer_to_peer(&mut self) {
self.peer_to_peer.bluetooth_le.enabled = true;
self.peer_to_peer.lan.enabled = true;
self.peer_to_peer.awdl.enabled = true;
self.peer_to_peer.wifi_aware.enabled = true;
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
#[serde(default)]
pub struct PeerToPeer {
pub bluetooth_le: BluetoothLEConfig,
pub lan: LanConfig,
pub awdl: AwdlConfig,
pub wifi_aware: WifiAwareConfig,
}
#[serde_as]
#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
#[serde(default)]
pub struct Connect {
pub tcp_servers: HashSet<String>,
pub websocket_urls: HashSet<String>,
#[serde_as(as = "::serde_with::DurationMilliSeconds<u64>")]
pub retry_interval: Duration,
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
#[serde(default)]
pub struct Listen {
pub tcp: TcpListenConfig,
pub http: HttpListenConfig,
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
#[serde(default)]
pub struct Global {
pub sync_group: u32,
pub routing_hint: u32,
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
#[serde(default)]
pub struct HttpListenConfig {
pub enabled: bool,
pub interface_ip: String,
pub port: u16,
pub websocket_sync: bool,
pub tls_key_path: Option<PathBuf>,
pub tls_certificate_path: Option<PathBuf>,
}
impl HttpListenConfig {
pub fn new() -> Self {
Self {
enabled: false,
interface_ip: "[::]".to_string(),
port: 80,
websocket_sync: true,
tls_key_path: None,
tls_certificate_path: None,
}
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
#[serde(default)]
pub struct TcpListenConfig {
pub enabled: bool,
pub interface_ip: String,
pub port: u16,
}
impl TcpListenConfig {
pub fn new() -> Self {
Self {
enabled: false,
interface_ip: "[::]".to_string(),
port: 4040,
}
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
#[serde(default)]
pub struct BluetoothLEConfig {
pub enabled: bool,
}
impl BluetoothLEConfig {
pub fn new() -> Self {
Self { enabled: false }
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
#[serde(default)]
pub struct LanConfig {
pub enabled: bool,
pub mdns_enabled: bool,
pub multicast_enabled: bool,
}
impl LanConfig {
pub fn new() -> Self {
Self {
enabled: false,
mdns_enabled: true,
multicast_enabled: true,
}
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
#[serde(default)]
pub struct AwdlConfig {
pub enabled: bool,
}
impl AwdlConfig {
pub fn new() -> Self {
Self { enabled: false }
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
#[serde(default)]
pub struct WifiAwareConfig {
pub enabled: bool,
}
impl WifiAwareConfig {
pub fn new() -> Self {
Self { enabled: false }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn awdl_config_default_disabled() {
assert!(!AwdlConfig::default().enabled);
assert!(!AwdlConfig::new().enabled);
}
#[test]
fn wifi_aware_config_default_disabled() {
assert!(!WifiAwareConfig::default().enabled);
assert!(!WifiAwareConfig::new().enabled);
}
#[test]
fn enable_all_peer_to_peer_enables_all_transports() {
let mut config = TransportConfig::new();
config.enable_all_peer_to_peer();
assert!(config.peer_to_peer.bluetooth_le.enabled);
assert!(config.peer_to_peer.lan.enabled);
assert!(config.peer_to_peer.awdl.enabled);
assert!(config.peer_to_peer.wifi_aware.enabled);
}
#[test]
fn awdl_config_serde_roundtrip() {
let original = AwdlConfig { enabled: true };
let json = serde_json::to_string(&original).unwrap();
let decoded: AwdlConfig = serde_json::from_str(&json).unwrap();
assert_eq!(original, decoded);
}
#[test]
fn wifi_aware_config_serde_roundtrip() {
let original = WifiAwareConfig { enabled: true };
let json = serde_json::to_string(&original).unwrap();
let decoded: WifiAwareConfig = serde_json::from_str(&json).unwrap();
assert_eq!(original, decoded);
}
#[test]
fn peer_to_peer_missing_fields_default_to_disabled() {
let json = r#"{"bluetooth_le":{"enabled":true},"lan":{"enabled":true,"mdns_enabled":true,"multicast_enabled":true}}"#;
let peer_to_peer: PeerToPeer = serde_json::from_str(json).unwrap();
assert!(!peer_to_peer.awdl.enabled);
assert!(!peer_to_peer.wifi_aware.enabled);
}
}