use serde::Serialize;
use sha2::{Digest, Sha256};
pub const SCHEMA_VERSION: u32 = 1;
pub const MAX_PEERS: usize = 64;
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct DiagnosticSnapshot {
pub schema_version: u32,
pub sdk_version: &'static str,
pub captured_at_ms: u64,
pub target: &'static str,
pub peers: Vec<PeerDiagnostic>,
pub omitted_peers: usize,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PeerDiagnostic {
pub peer_ref: String,
pub connection_ref: Option<String>,
pub settled_ready: bool,
pub readiness_code: &'static str,
pub transport_generation: u64,
pub route_generation: u64,
pub transport_stable_id: Option<u64>,
pub transport: &'static str,
pub scope_kinds: Vec<&'static str>,
pub admission: &'static str,
pub authoritative_device_bound: bool,
pub crypto_required: bool,
pub crypto_key_installed: bool,
pub crypto_confirmation_required: bool,
pub crypto_confirmed: bool,
pub native_directional_admission: Option<DirectionalAdmissionDiagnostic>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct DirectionalAdmissionDiagnostic {
pub inbound_required: bool,
pub inbound_proven: bool,
pub outbound_required: bool,
pub outbound_proven: bool,
}
pub(crate) fn reference(value: &str) -> String {
hex::encode(&Sha256::digest(value.as_bytes())[..8])
}
pub(crate) fn scope_kind(scope: &str) -> &'static str {
match scope.split(':').next().unwrap_or_default() {
"user-device" => "user-device",
"persistent" | "trusted-device" => "trusted-device",
"ticket" => "ticket",
"room" => "room",
"space" => "space",
"share" => "share",
"drive-grant" => "drive-grant",
_ => "custom",
}
}
pub(crate) fn readiness_code(reason: &str) -> &'static str {
match reason {
"transport-healthy" => "transport-healthy",
"missing-active-transport" => "missing-active-transport",
"native-main-route-pending" => "native-main-route-pending",
"session-admission-pending" => "session-admission-pending",
"application-crypto-key-pending" => "application-crypto-key-pending",
"application-crypto-confirmation-pending" => "application-crypto-confirmation-pending",
"bounded-health-confirmation-pending" => "bounded-health-confirmation-pending",
"authoritative-device-binding-pending" => "authoritative-device-binding-pending",
"device-offline" => "device-offline",
"waiting-for-transport" => "waiting-for-transport",
"transport-attached-awaiting-readiness-confirmation" => {
"transport-attached-awaiting-readiness-confirmation"
}
"transport-connected-health-check-pending" => "transport-connected-health-check-pending",
"readiness-confirmation-timed-out" => "readiness-confirmation-timed-out",
"transport-closed" => "transport-closed",
"connection-failed" => "connection-failed",
"manual disconnect" | "manual-disconnect" => "manual-disconnect",
_ => "unclassified",
}
}
pub(crate) fn transport_kind(value: &str) -> &'static str {
match value {
"iroh" => "iroh",
"iroh-quic" => "iroh-quic",
"iroh-lan" => "iroh-lan",
"iroh-relay" => "iroh-relay",
"webrtc" => "webrtc",
"moq" => "moq",
"ble" => "ble",
_ => "unknown",
}
}