use serde::{Deserialize, Serialize};
use std::net::{IpAddr, SocketAddr};
use std::path::PathBuf;
use std::time::Duration;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TakTransportConfig {
pub mode: TakTransportMode,
pub identity: Option<TakIdentity>,
pub queue: QueueConfig,
pub reconnect: ReconnectPolicy,
pub protocol: ProtocolConfig,
pub metrics_enabled: bool,
}
impl Default for TakTransportConfig {
fn default() -> Self {
Self {
mode: TakTransportMode::TakServer {
address: "127.0.0.1:8087".parse().expect("valid default address"),
use_tls: false,
},
identity: None,
queue: QueueConfig::default(),
reconnect: ReconnectPolicy::default(),
protocol: ProtocolConfig::default(),
metrics_enabled: true,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum TakTransportMode {
TakServer {
address: SocketAddr,
use_tls: bool,
},
MeshSa {
multicast_group: IpAddr,
port: u16,
interface: Option<String>,
},
Hybrid {
server_address: SocketAddr,
server_use_tls: bool,
mesh_group: IpAddr,
mesh_port: u16,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TakIdentity {
pub client_cert: PathBuf,
pub client_key: PathBuf,
pub ca_cert: Option<PathBuf>,
pub callsign: String,
pub tls_server_name: Option<String>,
pub credentials: Option<TakCredentials>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TakCredentials {
pub username: String,
#[serde(skip_serializing)]
pub password: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProtocolConfig {
pub version: TakProtocolVersion,
pub xml_options: XmlEncodingOptions,
pub max_message_size: usize,
#[serde(with = "humantime_serde")]
pub heartbeat_interval: Duration,
}
impl Default for ProtocolConfig {
fn default() -> Self {
Self {
version: TakProtocolVersion::default(),
xml_options: XmlEncodingOptions::default(),
max_message_size: 64 * 1024, heartbeat_interval: Duration::from_secs(30),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
pub enum TakProtocolVersion {
RawXml,
XmlTcp,
#[default]
ProtobufV1,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct XmlEncodingOptions {
pub xml_declaration: bool,
pub pretty_print: bool,
pub include_peat_extension: bool,
}
impl Default for XmlEncodingOptions {
fn default() -> Self {
Self {
xml_declaration: false,
pretty_print: false,
include_peat_extension: true,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct QueueConfig {
pub max_messages: usize,
pub max_bytes: usize,
pub priority_limits: PriorityQueueLimits,
pub filter_stale: bool,
pub persistent: bool,
pub persistence_path: Option<PathBuf>,
}
impl Default for QueueConfig {
fn default() -> Self {
Self {
max_messages: 1000,
max_bytes: 10 * 1024 * 1024, priority_limits: PriorityQueueLimits::default(),
filter_stale: true,
persistent: false,
persistence_path: None,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PriorityQueueLimits {
pub p1_limit: usize,
pub p2_limit: usize,
pub p3_limit: usize,
pub p4_limit: usize,
pub p5_limit: usize,
}
impl Default for PriorityQueueLimits {
fn default() -> Self {
Self {
p1_limit: 200, p2_limit: 300, p3_limit: 250, p4_limit: 150, p5_limit: 100, }
}
}
impl PriorityQueueLimits {
pub fn limit_for(&self, priority: u8) -> usize {
match priority {
1 => self.p1_limit,
2 => self.p2_limit,
3 => self.p3_limit,
4 => self.p4_limit,
_ => self.p5_limit,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReconnectPolicy {
pub enabled: bool,
#[serde(with = "humantime_serde")]
pub initial_delay: Duration,
#[serde(with = "humantime_serde")]
pub max_delay: Duration,
pub backoff_multiplier: f64,
pub max_attempts: Option<usize>,
pub jitter: f64,
}
impl Default for ReconnectPolicy {
fn default() -> Self {
Self {
enabled: true,
initial_delay: Duration::from_secs(1),
max_delay: Duration::from_secs(60),
backoff_multiplier: 2.0,
max_attempts: None,
jitter: 0.1,
}
}
}
mod humantime_serde {
use serde::{Deserialize, Deserializer, Serializer};
use std::time::Duration;
pub fn serialize<S>(duration: &Duration, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_u64(duration.as_millis() as u64)
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<Duration, D::Error>
where
D: Deserializer<'de>,
{
let millis = u64::deserialize(deserializer)?;
Ok(Duration::from_millis(millis))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_config() {
let config = TakTransportConfig::default();
assert!(config.metrics_enabled);
assert!(config.reconnect.enabled);
assert_eq!(config.queue.max_messages, 1000);
}
#[test]
fn test_priority_limits() {
let limits = PriorityQueueLimits::default();
assert_eq!(limits.limit_for(1), 200);
assert_eq!(limits.limit_for(5), 100);
assert_eq!(limits.limit_for(99), 100); }
#[test]
fn test_protocol_version_default() {
assert_eq!(
TakProtocolVersion::default(),
TakProtocolVersion::ProtobufV1
);
}
}