use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet};
#[derive(Default)]
pub(super) struct ConnectionStore {
pub by_id: HashMap<String, ConnectionRecord>,
pub by_node_id: HashMap<String, HashSet<String>>,
pub by_device_id: HashMap<String, HashSet<String>>,
pub by_device_hint_id: HashMap<String, HashSet<String>>,
pub by_endpoint_id: HashMap<String, HashSet<String>>,
pub history_by_connection_id: HashMap<String, ConnectionHistory>,
pub health_by_peer: HashMap<String, ConnectionHealth>,
pub scopes_by_peer: HashMap<String, HashSet<String>>,
pub transport_health_by_peer: HashMap<String, HashMap<String, ConnectionHealth>>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub enum ConnectionState {
Pending,
Connecting,
Connected,
Closing,
Closed,
Failed,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub enum ConnectionHealth {
Unknown,
Healthy,
Suspect,
Stale,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ConnectionRecord {
pub connection_id: String,
pub node_id: Option<String>,
pub device_id: Option<String>,
pub device_id_hint: Option<String>,
pub endpoint_id: Option<String>,
pub transport_generation: u64,
pub route_generation: u64,
pub transport_stable_id: Option<u64>,
pub transport_source: Option<String>,
pub active_transport: String,
pub parallel_transport: Option<String>,
pub last_state_change_at_ms: i64,
pub last_transport_change_at_ms: i64,
pub last_route_change_at_ms: i64,
pub state: ConnectionState,
pub status_reason: Option<String>,
pub transition_count: u64,
pub connecting_transition_count: u64,
pub replacement_count: u64,
pub retire_count: u64,
pub last_disconnect_reason: Option<String>,
pub last_reconnect_reason: Option<String>,
pub created_at_ms: i64,
pub updated_at_ms: i64,
}
#[derive(Debug, Clone, Default)]
pub(super) struct ConnectionHistory {
pub transport_generation: u64,
pub route_generation: u64,
pub transition_count: u64,
pub connecting_transition_count: u64,
pub replacement_count: u64,
pub retire_count: u64,
pub last_disconnect_reason: Option<String>,
pub last_reconnect_reason: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PeerSnapshot {
pub peer_id: String,
pub device_id: Option<String>,
pub device_id_hint: Option<String>,
pub node_id: Option<String>,
pub connection_ids: Vec<String>,
pub active_transport_stable_id: Option<u64>,
pub active_transport_generation: u64,
pub active_route_generation: u64,
pub active_transport: String,
pub parallel_transport: Option<String>,
pub last_route_change_at_ms: i64,
pub last_lifecycle_transition_at_ms: i64,
pub status: ConnectionState,
pub health: ConnectionHealth,
pub transition_count: u64,
pub connecting_transition_count: u64,
pub replacement_count: u64,
pub retire_count: u64,
pub last_disconnect_reason: Option<String>,
pub last_reconnect_reason: Option<String>,
pub scopes: Vec<String>,
pub last_seen_at_ms: i64,
pub error: Option<String>,
}
impl ConnectionRecord {
pub(super) fn new(
connection_id: String,
node_id: Option<String>,
device_id_hint: Option<String>,
endpoint_id: Option<String>,
) -> Self {
let now = super::store::unix_ms_now();
Self {
connection_id,
node_id,
device_id: None,
device_id_hint,
endpoint_id,
transport_generation: 0,
route_generation: 0,
transport_stable_id: None,
transport_source: None,
active_transport: "iroh".to_string(),
parallel_transport: None,
last_state_change_at_ms: now,
last_transport_change_at_ms: now,
last_route_change_at_ms: now,
state: ConnectionState::Pending,
status_reason: None,
transition_count: 0,
connecting_transition_count: 0,
replacement_count: 0,
retire_count: 0,
last_disconnect_reason: None,
last_reconnect_reason: None,
created_at_ms: now,
updated_at_ms: now,
}
}
}
impl From<&ConnectionRecord> for ConnectionHistory {
fn from(record: &ConnectionRecord) -> Self {
Self {
transport_generation: record.transport_generation,
route_generation: record.route_generation,
transition_count: record.transition_count,
connecting_transition_count: record.connecting_transition_count,
replacement_count: record.replacement_count,
retire_count: record.retire_count,
last_disconnect_reason: record.last_disconnect_reason.clone(),
last_reconnect_reason: record.last_reconnect_reason.clone(),
}
}
}