igc-net 0.3.0

igc-net protocol rust library — publish and add metadata to IGC flight files
Documentation
#![allow(dead_code)]

use std::time::{Duration, Instant};

use tracing_subscriber::EnvFilter;

/// Minimal valid IGC file with three B-records; used across all tests.
pub const SAMPLE_IGC: &[u8] = b"AXXX001 Test Device\r\n\
    HFDTE020714\r\n\
    HFPLTPILOTINCHARGE:Integration Test Pilot\r\n\
    HFGTYGLIDERTYPE:Test Wing EN-A\r\n\
    HFGIDGLIDERID:TEST-001\r\n\
    B1300004730000N00837000EA0030003000\r\n\
    B1305004732000N00838000EA0050005000\r\n\
    B1310004731000N00839000EA0040004000\r\n";

/// Initialize tracing once for the test binary.
pub fn init_tracing() {
    let _ = tracing_subscriber::fmt()
        .with_env_filter(
            EnvFilter::try_from_default_env()
                .unwrap_or_else(|_| EnvFilter::new("igc_net=debug,iroh_gossip=debug,iroh=info")),
        )
        .with_test_writer()
        .try_init();
}

/// Poll artifact registry until a record for `raw_igc_hash` appears, or
/// `timeout` elapses. Returns `true` if found.
pub async fn wait_for_artifact_registry_record(
    store: &igc_net::FlatFileStore,
    raw_igc_hash: &igc_net::Blake3Hex,
    timeout: Duration,
) -> bool {
    let deadline = Instant::now() + timeout;
    loop {
        if store
            .artifact_registry_record(raw_igc_hash)
            .unwrap()
            .is_some()
        {
            return true;
        }
        if Instant::now() >= deadline {
            return false;
        }
        tokio::time::sleep(Duration::from_millis(100)).await;
    }
}

/// Poll governance state until `pilot_id` resolves authoritatively to
/// `expected_record_id`, or `timeout` elapses. Returns `true` if matched.
pub async fn wait_for_pilot_auth_record(
    node: &igc_net::IgcIrohNode,
    pilot_id: &igc_net::PilotId,
    expected_record_id: &igc_net::Blake3Hex,
    timeout: Duration,
) -> bool {
    let deadline = Instant::now() + timeout;
    loop {
        let matched = node
            .resolve_pilot_auth_did_state(pilot_id)
            .ok()
            .and_then(|state| state.authoritative)
            .is_some_and(|record| record.record_id == *expected_record_id);
        if matched {
            return true;
        }
        if Instant::now() >= deadline {
            return false;
        }
        tokio::time::sleep(Duration::from_millis(100)).await;
    }
}