takproto 0.4.2

Rust library for TAK (Team Awareness Kit) Protocol - send CoT messages to TAK servers with mTLS support
Documentation
use std::env;
use std::time::{SystemTime, UNIX_EPOCH};
use takproto::proto::{CotEvent, Detail};
use takproto::{TakClient, TlsConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Parse command line arguments
    let args: Vec<String> = env::args().collect();

    if args.len() < 5 {
        eprintln!(
            "Usage: {} <server_addr> <server_name> <ca_cert> <client_cert> <client_key>",
            args[0]
        );
        eprintln!();
        eprintln!("Example:");
        eprintln!("  {} takserver.example.com:8089 takserver.example.com ca.pem client.pem client-key.pem", args[0]);
        eprintln!();
        eprintln!("Arguments:");
        eprintln!(
            "  server_addr   - TAK server address with port (e.g., takserver.example.com:8089)"
        );
        eprintln!("  server_name   - Server hostname for SNI and cert validation");
        eprintln!("  ca_cert       - Path to CA certificate file (PEM format)");
        eprintln!("  client_cert   - Path to client certificate file (PEM format)");
        eprintln!("  client_key    - Path to client private key file (PEM format)");
        std::process::exit(1);
    }

    let server_addr = &args[1];
    let server_name = &args[2];
    let ca_cert_path = &args[3];
    let client_cert_path = &args[4];
    let client_key_path = &args[5];

    println!("Loading TLS certificates...");
    println!("  CA cert: {}", ca_cert_path);
    println!("  Client cert: {}", client_cert_path);
    println!("  Client key: {}", client_key_path);

    // Configure TLS with client certificate (mTLS)
    let tls_config =
        TlsConfig::new_with_client_cert(ca_cert_path, client_cert_path, client_key_path)?;

    println!();
    println!("Connecting to TAK server at {}...", server_addr);
    println!("  Server name (SNI): {}", server_name);

    // Connect to the TAK server with mTLS
    let mut client = TakClient::connect_tls(server_addr, server_name, tls_config).await?;

    println!("Connected successfully with mTLS!");
    println!();

    // Negotiate protocol version (required for protobuf messages)
    println!("Negotiating TAK Protocol Version 1...");
    match client.negotiate_protocol(1, 60).await {
        Ok(()) => println!("Protocol negotiation successful!"),
        Err(e) => {
            eprintln!("Protocol negotiation failed: {}", e);
            eprintln!("Falling back to XML mode...");
        }
    }
    println!();

    // Get current time in milliseconds since Unix epoch
    let now_ms = SystemTime::now().duration_since(UNIX_EPOCH)?.as_millis() as u64;

    // Create a position report CoT event
    let event = CotEvent {
        r#type: "a-f-G-U-C".to_string(), // Friendly ground unit
        uid: "RUST-TAK-TLS-CLIENT-001".to_string(),
        send_time: now_ms,
        start_time: now_ms,
        stale_time: now_ms + 60_000, // Valid for 60 seconds
        how: "m-g".to_string(),

        // Position (San Francisco coordinates as example)
        lat: 39.377445,
        lon:  -76.83216000,
        hae: 10.0,
        ce: 9.9,
        le: 9.9,

        // Optional detail information with clickable links
        detail: Some(Detail {
            xml_detail: r#"<contact callsign="RustClientTLS" endpoint="*:-1:stcp"/>
<link uid="RUST-TAK-TLS-CLIENT-001" type="a-f-G-U-C" relation="p-p" url="https://github.com/rust-lang/rust" mime="text/html"/>
<link uid="RUST-TAK-TLS-CLIENT-001" type="a-f-G-U-C" relation="p-p" url="https://www.rust-lang.org/learn" mime="text/html" remarks="Rust Documentation"/>
<remarks>Position report from Rust TAK client with embedded links</remarks>"#.to_string(),
            ..Default::default()
        }),

        ..Default::default()
    };

    println!("Sending CoT event...");
    println!("  UID: {}", event.uid);
    println!("  Type: {}", event.r#type);
    println!("  Position: {}, {}", event.lat, event.lon);

    // Send the event
    client.send_cot_event(event).await?;

    println!();
    println!("Event sent successfully over mTLS!");

    // Close the connection
    client.close().await?;

    Ok(())
}