Skip to main content

rns_net/common/
event.rs

1//! Event types for the driver loop — generic over the writer type.
2
3use std::fmt;
4use std::io::Read;
5use std::net::IpAddr;
6use std::sync::mpsc;
7use std::time::Duration;
8
9use rns_core::announce::ValidatedAnnounce;
10use rns_core::transport::announce_verify_queue::AnnounceVerifyKey;
11use rns_core::transport::types::{InterfaceId, InterfaceInfo, PacketBytes};
12
13use crate::common::link_manager::RequestResponse;
14
15/// Identity hash and public key supplied to request callbacks.
16pub type RequestRemoteIdentity = ([u8; 16], [u8; 64]);
17/// Callback for an immediate byte response.
18pub type ByteRequestHandler =
19    dyn Fn([u8; 16], &str, &[u8], Option<&RequestRemoteIdentity>) -> Option<Vec<u8>> + Send;
20/// Callback for an immediate packet or resource response.
21pub type ResponseRequestHandler =
22    dyn Fn([u8; 16], &str, &[u8], Option<&RequestRemoteIdentity>) -> Option<RequestResponse> + Send;
23/// Callback for an application-managed deferred response.
24pub type DeferredRequestHandler =
25    dyn Fn([u8; 16], &str, [u8; 16], &[u8], Option<&RequestRemoteIdentity>) + Send;
26
27/// Why a best-effort link datagram could not be admitted by the node.
28#[derive(Debug, Clone, PartialEq, Eq)]
29pub enum LinkDatagramError {
30    DriverQueueFull,
31    DriverStopped,
32    AdmissionTimedOut,
33    LinkNotFound,
34    LinkNotActive,
35    PayloadTooLarge { maximum: usize, actual: usize },
36    EncryptionFailed,
37    PacketEncodingFailed,
38}
39
40impl fmt::Display for LinkDatagramError {
41    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42        match self {
43            Self::DriverQueueFull => write!(f, "driver queue is full"),
44            Self::DriverStopped => write!(f, "driver has stopped"),
45            Self::AdmissionTimedOut => write!(f, "driver admission timed out"),
46            Self::LinkNotFound => write!(f, "link was not found"),
47            Self::LinkNotActive => write!(f, "link is not active"),
48            Self::PayloadTooLarge { maximum, actual } => {
49                write!(
50                    f,
51                    "payload is too large ({actual} bytes, maximum {maximum})"
52                )
53            }
54            Self::EncryptionFailed => write!(f, "link encryption failed"),
55            Self::PacketEncodingFailed => write!(f, "link packet encoding failed"),
56        }
57    }
58}
59
60impl std::error::Error for LinkDatagramError {}
61
62#[derive(Debug, Clone, Default, PartialEq)]
63pub struct InterfaceTelemetry {
64    pub cpu_load: Option<f64>,
65    pub mem_load: Option<f64>,
66    pub switch_id: Option<[u8; 4]>,
67    pub endpoint_id: Option<[u8; 8]>,
68    pub via_switch_id: Option<[u8; 4]>,
69    pub peers: Option<usize>,
70    pub rssi: Option<i16>,
71    pub snr: Option<f32>,
72    pub signal_quality: Option<f64>,
73    pub frequency: Option<u32>,
74    pub bandwidth: Option<u32>,
75    pub txpower: Option<i8>,
76    pub spreading_factor: Option<u8>,
77    pub coding_rate: Option<u8>,
78    pub channel: Option<u32>,
79    pub modulation: Option<String>,
80}
81
82#[derive(Debug, Clone)]
83pub struct DynamicInterfaceRegistration {
84    pub info: InterfaceInfo,
85    pub interface_type: String,
86    pub parent_id: InterfaceId,
87    pub telemetry: InterfaceTelemetry,
88    pub ifac: Option<crate::ifac::IfacState>,
89}
90
91/// Policy for handling incoming direct-connect proposals.
92#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
93pub enum HolePunchPolicy {
94    /// Reject all proposals.
95    Reject,
96    /// Accept all proposals automatically.
97    AcceptAll,
98    /// Accept proposals only after the Reticulum link peer has identified itself.
99    #[default]
100    IdentifiedOnly,
101    /// Ask the application callback.
102    AskApp,
103}
104
105/// Scalar runtime-config value.
106#[derive(Debug, Clone, PartialEq)]
107pub enum RuntimeConfigValue {
108    Int(i64),
109    Float(f64),
110    Bool(bool),
111    String(String),
112    Null,
113}
114
115/// Source of a runtime-config value.
116#[derive(Debug, Clone, Copy, PartialEq, Eq)]
117pub enum RuntimeConfigSource {
118    Startup,
119    RuntimeOverride,
120}
121
122/// How a runtime-config change applies.
123#[derive(Debug, Clone, Copy, PartialEq, Eq)]
124pub enum RuntimeConfigApplyMode {
125    Immediate,
126    NewConnectionsOnly,
127    NextReconnect,
128    RestartRequired,
129}
130
131/// A runtime-config entry exposed by the daemon.
132#[derive(Debug, Clone, PartialEq)]
133pub struct RuntimeConfigEntry {
134    pub key: String,
135    pub value: RuntimeConfigValue,
136    pub default: RuntimeConfigValue,
137    pub source: RuntimeConfigSource,
138    pub apply_mode: RuntimeConfigApplyMode,
139    pub description: Option<String>,
140}
141
142/// Runtime-config mutation error.
143#[derive(Debug, Clone, PartialEq, Eq)]
144pub struct RuntimeConfigError {
145    pub code: RuntimeConfigErrorCode,
146    pub message: String,
147}
148
149/// Category of runtime-config mutation error.
150#[derive(Debug, Clone, Copy, PartialEq, Eq)]
151pub enum RuntimeConfigErrorCode {
152    UnknownKey,
153    InvalidType,
154    InvalidValue,
155    Unsupported,
156    NotFound,
157    ApplyFailed,
158}
159
160#[derive(Debug, Clone, Copy, PartialEq, Eq)]
161pub enum LifecycleState {
162    Active,
163    Draining,
164    Stopping,
165    Stopped,
166}
167
168#[derive(Debug, Clone, PartialEq)]
169pub struct DrainStatus {
170    pub state: LifecycleState,
171    pub drain_age_seconds: Option<f64>,
172    pub deadline_remaining_seconds: Option<f64>,
173    pub drain_complete: bool,
174    pub interface_writer_queued_frames: usize,
175    pub provider_backlog_events: usize,
176    pub provider_consumer_queued_events: usize,
177    pub detail: Option<String>,
178}
179
180/// Replay metadata carried atomically with an explicit announcement.
181#[doc(hidden)]
182pub struct AnnounceReplay {
183    pub dest_hash: [u8; 16],
184    pub name_hash: [u8; 10],
185    pub identity_prv_key: [u8; 64],
186    pub app_data: Option<Vec<u8>>,
187}
188
189/// A single packet queued to be encrypted off the caller's thread.
190pub struct DeferredSend {
191    pub(crate) ticket: u64,
192    pub(crate) destination: [u8; 16],
193    /// The destination identity's 64-byte public key.
194    pub(crate) public_key: [u8; 64],
195    pub(crate) ratchet: Option<[u8; 32]>,
196    /// The plaintext, or the payload when `encrypted`.
197    pub(crate) data: Vec<u8>,
198    /// Encrypted already by the caller: on one CPU, handing encryption to
199    /// another thread only adds a context switch.
200    pub(crate) encrypted: bool,
201}
202
203impl DeferredSend {
204    /// The encrypted payload, or `None` when it cannot be encrypted.
205    pub(crate) fn run(&self) -> Option<Vec<u8>> {
206        if self.encrypted {
207            return Some(self.data.clone());
208        }
209        rns_crypto::identity::Identity::encrypt_for_public_key(
210            &self.public_key,
211            &self.data,
212            self.ratchet.as_ref(),
213            &mut rns_crypto::OsRng,
214        )
215        .ok()
216    }
217}
218
219/// Events sent to the driver thread.
220///
221/// `W` is the writer type (e.g. `Box<dyn Writer>` for sync,
222/// or a channel sender for async).
223// Boxing the large registration variant would change this published event API.
224#[allow(clippy::large_enum_variant)]
225pub enum Event<W: Send> {
226    /// A decoded frame arrived from an interface. Its bytes are shared, so
227    /// the packet decoded from them is delivered without copying them.
228    Frame {
229        interface_id: InterfaceId,
230        data: PacketBytes,
231        rssi: Option<i16>,
232        snr: Option<f32>,
233    },
234    /// (Internal) An announce was verified off-thread and is ready for driver-side processing.
235    AnnounceVerified {
236        key: AnnounceVerifyKey,
237        validated: Box<ValidatedAnnounce>,
238        sig_cache_key: [u8; 32],
239    },
240    /// (Internal) An announce failed off-thread verification.
241    AnnounceVerifyFailed {
242        key: AnnounceVerifyKey,
243        sig_cache_key: [u8; 32],
244    },
245    /// An interface came online after (re)connecting.
246    /// Carries a new writer if the connection was re-established.
247    /// Carries InterfaceInfo if this is a new dynamic interface (e.g. TCP server client).
248    InterfaceUp(InterfaceId, Option<W>, Option<Box<InterfaceInfo>>),
249    /// Register a dynamic interface with an exact type and parent identity.
250    DynamicInterfaceUp {
251        id: InterfaceId,
252        writer: W,
253        registration: Box<DynamicInterfaceRegistration>,
254    },
255    /// Update optional device/interface telemetry without replacing counters.
256    InterfaceTelemetry {
257        interface_id: InterfaceId,
258        telemetry: Box<InterfaceTelemetry>,
259    },
260    /// An interface went offline (socket closed, error).
261    InterfaceDown(InterfaceId),
262    /// Periodic maintenance tick (1s interval).
263    Tick,
264    /// Enter drain mode and stop admitting new work.
265    BeginDrain { timeout: Duration },
266    /// Shut down the driver loop.
267    Shutdown,
268    /// Send an outbound packet.
269    SendOutbound {
270        raw: Vec<u8>,
271        dest_type: u8,
272        attached_interface: Option<InterfaceId>,
273    },
274    /// A single packet to encrypt off the caller's thread and send
275    /// (`RnsNode::send_packet_deferred`).
276    SendDeferred(Box<DeferredSend>),
277    /// Deliver single packets for `dest_hash` decrypted with `identity`
278    /// (`RnsNode::deliver_decrypted`).
279    DeliverDecrypted {
280        dest_hash: [u8; 16],
281        identity: Box<rns_crypto::identity::Identity>,
282    },
283    /// A locally originated packet with transmission completion tracking.
284    SendOutboundTracked {
285        raw: Vec<u8>,
286        dest_type: u8,
287        replay: Option<Box<AnnounceReplay>>,
288        completion: crate::link_send::Completion,
289    },
290    /// Register a local destination.
291    RegisterDestination { dest_hash: [u8; 16], dest_type: u8 },
292    /// Remember the latest explicit SINGLE announce for shared-client replay.
293    StoreSharedAnnounce {
294        dest_hash: [u8; 16],
295        name_hash: [u8; 10],
296        identity_prv_key: [u8; 64],
297        app_data: Option<Vec<u8>>,
298    },
299    /// Deregister a local destination.
300    DeregisterDestination { dest_hash: [u8; 16] },
301    /// Deregister a link destination (stop accepting incoming links).
302    DeregisterLinkDestination { dest_hash: [u8; 16] },
303    /// Query driver state. Response is sent via the provided channel.
304    Query(Box<QueryRequest>, mpsc::Sender<QueryResponse>),
305    /// Register a link destination (accepts incoming LINKREQUEST).
306    RegisterLinkDestination {
307        dest_hash: [u8; 16],
308        sig_prv_bytes: [u8; 32],
309        sig_pub_bytes: [u8; 32],
310        resource_strategy: u8,
311        max_request_size: Option<usize>,
312    },
313    /// Register a request handler for a path on established links.
314    RegisterRequestHandler {
315        path: String,
316        allowed_list: Option<Vec<[u8; 16]>>,
317        handler: Box<ByteRequestHandler>,
318    },
319    /// Register a request handler that may return resource responses with metadata.
320    RegisterRequestHandlerResponse {
321        path: String,
322        allowed_list: Option<Vec<[u8; 16]>>,
323        handler: Box<ResponseRequestHandler>,
324    },
325    /// Register a request handler that sends its response later.
326    RegisterDeferredRequestHandler {
327        path: String,
328        allowed_list: Option<Vec<[u8; 16]>>,
329        handler: Box<DeferredRequestHandler>,
330    },
331    /// Create an outbound link. Response sends (link_id) back.
332    CreateLink {
333        dest_hash: [u8; 16],
334        dest_sig_pub_bytes: [u8; 32],
335        response_tx: mpsc::Sender<[u8; 16]>,
336    },
337    /// Finish a stamped outbound link whose keys were ground on a helper
338    /// thread. Internal to the driver; carries the link request keys and the
339    /// original `CreateLink` responder.
340    CompleteStampedLink(Box<StampedLinkKeys>),
341    /// A path request stamp ground by the stamper worker; the driver builds
342    /// and sends the request.
343    SendStampedPathRequest(Box<crate::stamper::StampedPathRequest>),
344    /// The stamper persisted the stamp of a built-in destination; the
345    /// driver sends that destination's announce.
346    DestinationStampReady { dest_hash: [u8; 16] },
347    /// Send a request on an established link.
348    SendRequest {
349        link_id: [u8; 16],
350        path: String,
351        data: Vec<u8>,
352        max_response_size: Option<usize>,
353    },
354    /// Complete a request previously delivered to a deferred handler.
355    SendDeferredResponse {
356        link_id: [u8; 16],
357        request_id: [u8; 16],
358        data: Vec<u8>,
359    },
360    /// Identify on a link (send identity to remote peer).
361    IdentifyOnLink {
362        link_id: [u8; 16],
363        identity_prv_key: [u8; 64],
364    },
365    /// Tear down a link.
366    TeardownLink { link_id: [u8; 16] },
367    /// Wake the driver to consume its private Resource preparation mailbox.
368    ResourcePreparationReady,
369    /// Internal wakeup for the bounded Resource assembly mailbox.
370    ResourceAssemblyReady,
371    /// Internal wakeup: link proofs were verified off the driver thread.
372    LinkProofsVerified,
373    /// Send a resource on a link.
374    SendResource {
375        link_id: [u8; 16],
376        data: Vec<u8>,
377        metadata: Option<Vec<u8>>,
378        options: crate::resource::ResourceSendOptions,
379    },
380    /// Send a Resource from a sequential reader without buffering the full payload.
381    SendResourceStream {
382        link_id: [u8; 16],
383        transfer_id: crate::resource::ResourceTransferId,
384        reader: Box<dyn Read + Send>,
385        declared_length: u64,
386        metadata: Option<Vec<u8>>,
387        options: crate::resource::ResourceSendOptions,
388    },
389    /// Set the resource acceptance strategy for a link.
390    SetResourceStrategy { link_id: [u8; 16], strategy: u8 },
391    /// Select in-memory or disk-backed delivery for independent Resources.
392    SetResourceReceiveMode {
393        link_id: [u8; 16],
394        mode: crate::resource::ResourceReceiveMode,
395    },
396    /// Accept or reject a pending resource (for AcceptApp strategy).
397    AcceptResource {
398        link_id: [u8; 16],
399        resource_hash: Vec<u8>,
400        accept: bool,
401    },
402    /// Send a channel message on a link.
403    SendChannelMessage {
404        link_id: [u8; 16],
405        msgtype: u16,
406        payload: Vec<u8>,
407        response_tx: mpsc::Sender<Result<(), String>>,
408    },
409    /// Wake the driver after outbound writer capacity changes.
410    LinkWriterReady,
411    /// Send generic data on a link with transmission completion.
412    SendLinkTracked {
413        link_id: [u8; 16],
414        data: Vec<u8>,
415        context: u8,
416        completion: crate::link_send::Completion,
417    },
418    /// Legacy best-effort datagram admission, without transmission completion.
419    SendOnLink {
420        link_id: [u8; 16],
421        data: Vec<u8>,
422        context: u8,
423        /// Present when the caller needs explicit driver-level admission.
424        response_tx: Option<mpsc::Sender<Result<(), LinkDatagramError>>>,
425    },
426    /// Request a path to a destination from the network.
427    RequestPath { dest_hash: [u8; 16] },
428    /// Register a proof strategy for a destination.
429    RegisterProofStrategy {
430        dest_hash: [u8; 16],
431        strategy: rns_core::types::ProofStrategy,
432        /// Full identity private key (64 bytes) for signing proofs.
433        signing_key: Option<[u8; 64]>,
434    },
435    /// Propose a direct connection to a peer via hole punching.
436    ProposeDirectConnect { link_id: [u8; 16] },
437    /// Set the direct-connect policy.
438    SetDirectConnectPolicy { policy: HolePunchPolicy },
439    /// (Internal) Probe result arrived from a worker thread.
440    HolePunchProbeResult {
441        link_id: [u8; 16],
442        session_id: [u8; 16],
443        observed_addr: std::net::SocketAddr,
444        socket: std::net::UdpSocket,
445        /// The probe server that responded successfully.
446        probe_server: std::net::SocketAddr,
447    },
448    /// (Internal) Probe failed.
449    HolePunchProbeFailed {
450        link_id: [u8; 16],
451        session_id: [u8; 16],
452    },
453    /// An interface's configuration changed (placeholder for future use).
454    InterfaceConfigChanged(InterfaceId),
455    /// A backbone server accepted a new inbound peer connection.
456    BackbonePeerConnected {
457        server_interface_id: InterfaceId,
458        peer_interface_id: InterfaceId,
459        peer_ip: IpAddr,
460        peer_port: u16,
461    },
462    /// A backbone peer connection closed for any reason.
463    BackbonePeerDisconnected {
464        server_interface_id: InterfaceId,
465        peer_interface_id: InterfaceId,
466        peer_ip: IpAddr,
467        peer_port: u16,
468        connected_for: Duration,
469        had_received_data: bool,
470    },
471    /// A backbone peer was disconnected for idling without sending data.
472    BackbonePeerIdleTimeout {
473        server_interface_id: InterfaceId,
474        peer_interface_id: InterfaceId,
475        peer_ip: IpAddr,
476        peer_port: u16,
477        connected_for: Duration,
478    },
479    /// A backbone peer was disconnected because its writer stalled.
480    BackbonePeerWriteStall {
481        server_interface_id: InterfaceId,
482        peer_interface_id: InterfaceId,
483        peer_ip: IpAddr,
484        peer_port: u16,
485        connected_for: Duration,
486    },
487    /// A backbone peer IP was penalized due to abusive behavior.
488    BackbonePeerPenalty {
489        server_interface_id: InterfaceId,
490        peer_ip: IpAddr,
491        penalty_level: u8,
492        blacklist_for: Duration,
493    },
494    /// Load an in-memory WASM hook at runtime.
495    LoadHook {
496        name: String,
497        wasm_bytes: Vec<u8>,
498        attach_point: String,
499        priority: i32,
500        response_tx: mpsc::Sender<Result<(), String>>,
501    },
502    /// Load a hook from a server-local filesystem path at runtime.
503    LoadHookFile {
504        name: String,
505        path: String,
506        hook_type: String,
507        attach_point: String,
508        priority: i32,
509        response_tx: mpsc::Sender<Result<(), String>>,
510    },
511    /// Load a registered built-in hook by ID at runtime.
512    LoadBuiltinHook {
513        name: String,
514        builtin_id: String,
515        attach_point: String,
516        priority: i32,
517        response_tx: mpsc::Sender<Result<(), String>>,
518    },
519    /// Unload a hook at runtime.
520    UnloadHook {
521        name: String,
522        attach_point: String,
523        response_tx: mpsc::Sender<Result<(), String>>,
524    },
525    /// Reload an in-memory WASM hook at runtime (detach + recompile + reattach with same priority).
526    ReloadHook {
527        name: String,
528        attach_point: String,
529        wasm_bytes: Vec<u8>,
530        response_tx: mpsc::Sender<Result<(), String>>,
531    },
532    /// Reload a hook from a server-local filesystem path at runtime.
533    ReloadHookFile {
534        name: String,
535        attach_point: String,
536        path: String,
537        hook_type: String,
538        response_tx: mpsc::Sender<Result<(), String>>,
539    },
540    /// Reload a registered built-in hook by ID at runtime.
541    ReloadBuiltinHook {
542        name: String,
543        attach_point: String,
544        builtin_id: String,
545        response_tx: mpsc::Sender<Result<(), String>>,
546    },
547    /// Enable or disable a loaded hook at runtime.
548    SetHookEnabled {
549        name: String,
550        attach_point: String,
551        enabled: bool,
552        response_tx: mpsc::Sender<Result<(), String>>,
553    },
554    /// Update the priority of a loaded hook at runtime.
555    SetHookPriority {
556        name: String,
557        attach_point: String,
558        priority: i32,
559        response_tx: mpsc::Sender<Result<(), String>>,
560    },
561    /// List all loaded hooks.
562    ListHooks {
563        response_tx: mpsc::Sender<Vec<HookInfo>>,
564    },
565}
566
567/// Information about a loaded hook program.
568#[derive(Debug, Clone)]
569pub struct HookInfo {
570    pub name: String,
571    pub hook_type: String,
572    pub attach_point: String,
573    pub priority: i32,
574    pub enabled: bool,
575    pub consecutive_traps: u32,
576}
577
578/// Live behavioral state for a backbone peer IP.
579#[derive(Debug, Clone, PartialEq)]
580pub struct BackbonePeerStateEntry {
581    pub interface_name: String,
582    pub peer_ip: IpAddr,
583    pub connected_count: usize,
584    pub blacklisted_remaining_secs: Option<f64>,
585    pub blacklist_reason: Option<String>,
586    pub reject_count: u64,
587}
588
589/// Hook-visible snapshot of a backbone peer lifecycle event.
590#[derive(Debug, Clone, PartialEq, Eq)]
591pub struct BackbonePeerHookEvent {
592    pub server_interface_id: InterfaceId,
593    pub peer_interface_id: Option<InterfaceId>,
594    pub peer_ip: IpAddr,
595    pub peer_port: u16,
596    pub connected_for: Duration,
597    pub had_received_data: bool,
598    pub penalty_level: u8,
599    pub blacklist_for: Duration,
600}
601
602#[derive(Debug, Clone, PartialEq, Eq)]
603pub struct BackboneInterfaceEntry {
604    pub interface_id: InterfaceId,
605    pub interface_name: String,
606}
607
608#[derive(Debug, Clone, PartialEq)]
609pub struct KnownDestinationEntry {
610    pub dest_hash: [u8; 16],
611    pub identity_hash: [u8; 16],
612    pub public_key: [u8; 64],
613    pub app_data: Option<Vec<u8>>,
614    pub hops: u8,
615    pub received_at: f64,
616    pub receiving_interface: InterfaceId,
617    pub was_used: bool,
618    pub last_used_at: Option<f64>,
619    pub retained: bool,
620    pub stamp: Option<[u8; rns_core::constants::STAMP_LENGTH]>,
621    pub stamp_value: rns_core::stamp::StampValue,
622    pub lr_cost: Option<rns_core::stamp::StampCost>,
623}
624
625#[derive(Debug, Clone, PartialEq, Eq)]
626pub struct ProviderBridgeConsumerStats {
627    pub id: u64,
628    pub connected: bool,
629    pub queue_len: usize,
630    pub queued_bytes: usize,
631    pub dropped_pending: u64,
632    pub dropped_total: u64,
633    pub queue_max_events: usize,
634    pub queue_max_bytes: usize,
635}
636
637#[derive(Debug, Clone, PartialEq, Eq)]
638pub struct ProviderBridgeStats {
639    pub connected: bool,
640    pub consumer_count: usize,
641    pub queue_max_events: usize,
642    pub queue_max_bytes: usize,
643    pub backlog_len: usize,
644    pub backlog_bytes: usize,
645    pub backlog_dropped_pending: u64,
646    pub backlog_dropped_total: u64,
647    pub total_disconnect_count: u64,
648    pub consumers: Vec<ProviderBridgeConsumerStats>,
649}
650
651/// Queries that can be sent to the driver.
652#[derive(Debug)]
653pub enum QueryRequest {
654    ManageInterface {
655        operation: InterfaceManagementOperation,
656        name: String,
657    },
658    /// Get interface statistics and transport info.
659    InterfaceStats,
660    /// Get path table entries, optionally filtered by max hops.
661    PathTable { max_hops: Option<u8> },
662    /// Get rate table entries.
663    RateTable,
664    /// Get the slowest positive bitrate among online interfaces.
665    LowestInterfaceBitrate,
666    /// Estimate an MTU round trip on the slowest interface plus hop grace.
667    MediumPathTimeout,
668    /// Estimate the first-hop timeout for a destination using its outbound bitrate.
669    FirstHopTimeout { dest_hash: [u8; 16] },
670    /// Look up the next hop for a destination.
671    NextHop { dest_hash: [u8; 16] },
672    /// Look up the next hop interface name for a destination.
673    NextHopIfName { dest_hash: [u8; 16] },
674    /// Get link table entry count.
675    LinkCount,
676    /// Get validated or established link count.
677    ActiveLinkCount,
678    /// Get per-destination link totals and active counts.
679    LinkDistribution,
680    /// Drop a specific path.
681    DropPath { dest_hash: [u8; 16] },
682    /// Drop all paths that route via a given transport hash.
683    DropAllVia { transport_hash: [u8; 16] },
684    /// Drop all announce queues.
685    DropAnnounceQueues,
686    /// Get the transport identity hash.
687    TransportIdentity,
688    /// Snapshot restart-relevant transport routing state.
689    TransportStateSnapshot,
690    /// Get all blackholed identities.
691    GetBlackholed,
692    /// Add an identity to the blackhole list.
693    BlackholeIdentity {
694        identity_hash: [u8; 16],
695        duration_hours: Option<f64>,
696        reason: Option<String>,
697    },
698    /// Remove an identity from the blackhole list.
699    UnblackholeIdentity { identity_hash: [u8; 16] },
700    /// `wants_destination_type`: a local application needs announces of
701    /// this destination type (upstream 825c2e19).
702    WantsDestinationType {
703        full_name: String,
704        requester: Vec<u8>,
705    },
706    /// `unwants_destination_type`: withdraw one such need.
707    UnwantsDestinationType {
708        full_name: String,
709        requester: Vec<u8>,
710    },
711    /// `unwants_all_destination_types`: withdraw every need of a requester.
712    UnwantsAllDestinationTypes { requester: Vec<u8> },
713    /// `Reticulum.required_announces_only`: let only required destination
714    /// types through.
715    SetRequiredDestinationsOnly { enabled: bool },
716    /// Check if a path exists to a destination.
717    HasPath { dest_hash: [u8; 16] },
718    /// Get hop count to a destination.
719    HopsTo { dest_hash: [u8; 16] },
720    /// Recall identity info for a destination.
721    RecallIdentity { dest_hash: [u8; 16] },
722    /// Stamp value and announced link request cost recorded for a known
723    /// destination.
724    RecallDestinationStamp { dest_hash: [u8; 16] },
725    /// List known-destination lifecycle state.
726    KnownDestinations,
727    /// Get locally registered destinations.
728    LocalDestinations,
729    /// Get active links.
730    Links,
731    /// Get active resource transfers.
732    Resources,
733    /// Inject a path entry into the path table.
734    InjectPath {
735        dest_hash: [u8; 16],
736        next_hop: [u8; 16],
737        hops: u8,
738        expires: f64,
739        interface_name: String,
740        packet_hash: [u8; 32],
741    },
742    /// Inject an identity into the known destinations cache.
743    InjectIdentity {
744        dest_hash: [u8; 16],
745        identity_hash: [u8; 16],
746        public_key: [u8; 64],
747        app_data: Option<Vec<u8>>,
748        hops: u8,
749        received_at: f64,
750    },
751    /// Restore a known destination with full lifecycle state.
752    RestoreKnownDestination(KnownDestinationEntry),
753    /// Mark a known destination as explicitly retained.
754    RetainKnownDestination { dest_hash: [u8; 16] },
755    /// Mark all known destinations announced by an identity as retained.
756    RetainIdentity { identity_hash: [u8; 16] },
757    /// Clear the retained flag on a known destination.
758    UnretainKnownDestination { dest_hash: [u8; 16] },
759    /// Mark a known destination as used.
760    MarkKnownDestinationUsed { dest_hash: [u8; 16] },
761    /// Get discovered interfaces.
762    DiscoveredInterfaces {
763        only_available: bool,
764        only_transport: bool,
765    },
766    /// Send a probe packet to a destination and return (packet_hash, hops).
767    SendProbe {
768        dest_hash: [u8; 16],
769        payload_size: usize,
770    },
771    /// Check if a proof was received for a probe packet.
772    CheckProof { packet_hash: [u8; 32] },
773    /// List runtime-config entries currently supported by the daemon.
774    ListRuntimeConfig,
775    /// Get a single runtime-config entry by key.
776    GetRuntimeConfig { key: String },
777    /// Set a runtime-config value by key.
778    SetRuntimeConfig {
779        key: String,
780        value: RuntimeConfigValue,
781    },
782    /// Reset a runtime-config value to its startup/default value.
783    ResetRuntimeConfig { key: String },
784    /// List live backbone peer state, optionally filtered to one interface.
785    BackbonePeerState { interface_name: Option<String> },
786    /// List registered backbone server interfaces.
787    BackboneInterfaces,
788    /// Report live provider-bridge queue/drop state.
789    ProviderBridgeStats,
790    /// Report current lifecycle/drain status.
791    DrainStatus,
792    /// Clear live backbone peer state for one interface/IP pair.
793    ClearBackbonePeerState {
794        interface_name: String,
795        peer_ip: IpAddr,
796    },
797    /// Blacklist a backbone peer IP for a duration.
798    BlacklistBackbonePeer {
799        interface_name: String,
800        peer_ip: IpAddr,
801        duration: Duration,
802        reason: String,
803        penalty_level: u8,
804    },
805}
806
807/// Largest random payload a probe can carry in a single HEADER_1 DATA packet
808/// to a SINGLE destination without exceeding [`rns_core::constants::MTU`].
809///
810/// The payload is encrypted as `ephemeral pubkey (KEYSIZE/16) || IV || AES-CBC
811/// ciphertext (PKCS7-padded, so always at least one byte of padding) || HMAC`,
812/// then prefixed with the HEADER_1 packet header. With MTU 500 this is 399
813/// bytes, matching what Python's `rnprobe` can send before `Packet.pack()`
814/// raises for exceeding the MTU.
815pub const MAX_PROBE_PAYLOAD_SIZE: usize = {
816    use rns_core::constants::{AES128_BLOCKSIZE, HEADER_MINSIZE, KEYSIZE, MTU, TOKEN_OVERHEAD};
817    let numerator = MTU - HEADER_MINSIZE - TOKEN_OVERHEAD - KEYSIZE / 16;
818    (numerator / AES128_BLOCKSIZE) * AES128_BLOCKSIZE - 1
819};
820
821/// Why a [`QueryRequest::SendProbe`] could not be sent.
822#[derive(Debug, Clone, Copy, PartialEq, Eq)]
823pub enum SendProbeError {
824    /// No announced identity is known for the destination.
825    UnknownIdentity,
826    /// The requested payload does not fit in a single packet.
827    PayloadTooLarge { max: usize },
828    /// Encrypting the payload to the remote identity failed.
829    EncryptFailed,
830    /// Packing the probe packet failed.
831    PackFailed,
832}
833
834/// Responses to queries.
835#[derive(Debug)]
836#[allow(clippy::large_enum_variant)]
837pub enum QueryResponse {
838    /// Python-compatible tri-state result: success, failure, or missing name.
839    InterfaceManagement(Option<bool>),
840    InterfaceStats(InterfaceStatsResponse),
841    PathTable(Vec<PathTableEntry>),
842    RateTable(Vec<RateTableEntry>),
843    LowestInterfaceBitrate(Option<u64>),
844    MediumPathTimeout(f64),
845    FirstHopTimeout(f64),
846    NextHop(Option<NextHopResponse>),
847    NextHopIfName(Option<String>),
848    LinkCount(usize),
849    ActiveLinkCount(usize),
850    LinkDistribution(Vec<LinkDistributionEntry>),
851    DropPath(bool),
852    DropAllVia(usize),
853    DropAnnounceQueues,
854    TransportIdentity(Option<[u8; 16]>),
855    TransportStateSnapshot(rns_core::transport::persistence::TransportStateSnapshot),
856    Blackholed(Vec<BlackholeInfo>),
857    BlackholeResult(bool),
858    UnblackholeResult(bool),
859    DestinationTypeRegistration(bool),
860    HasPath(bool),
861    HopsTo(Option<u8>),
862    RecallIdentity(Option<crate::common::destination::AnnouncedIdentity>),
863    RecallDestinationStamp(Option<DestinationStampInfo>),
864    KnownDestinations(Vec<KnownDestinationEntry>),
865    LocalDestinations(Vec<LocalDestinationEntry>),
866    Links(Vec<LinkInfoEntry>),
867    Resources(Vec<ResourceInfoEntry>),
868    InjectPath(bool),
869    InjectIdentity(bool),
870    RestoreKnownDestination(bool),
871    RetainKnownDestination(bool),
872    RetainIdentity(bool),
873    UnretainKnownDestination(bool),
874    MarkKnownDestinationUsed(bool),
875    /// List of discovered interfaces.
876    DiscoveredInterfaces(Vec<crate::common::discovery::DiscoveredInterface>),
877    /// Probe sent: (packet_hash, hops), or why it could not be sent.
878    SendProbe(Result<([u8; 32], u8), SendProbeError>),
879    /// Proof check: RTT if received, None if still pending.
880    CheckProof(Option<f64>),
881    /// Runtime-config entries currently supported by the daemon.
882    RuntimeConfigList(Vec<RuntimeConfigEntry>),
883    /// A specific runtime-config entry, or None if the key is unknown.
884    RuntimeConfigEntry(Option<RuntimeConfigEntry>),
885    /// Result of setting a runtime-config value.
886    RuntimeConfigSet(Result<RuntimeConfigEntry, RuntimeConfigError>),
887    /// Result of resetting a runtime-config value.
888    RuntimeConfigReset(Result<RuntimeConfigEntry, RuntimeConfigError>),
889    /// Live backbone peer state entries.
890    BackbonePeerState(Vec<BackbonePeerStateEntry>),
891    /// Registered backbone server interfaces.
892    BackboneInterfaces(Vec<BackboneInterfaceEntry>),
893    /// Live provider-bridge queue/drop state if enabled.
894    ProviderBridgeStats(Option<ProviderBridgeStats>),
895    /// Current lifecycle/drain status.
896    DrainStatus(DrainStatus),
897    /// Result of clearing one backbone peer state entry.
898    ClearBackbonePeerState(bool),
899    /// Result of blacklisting a backbone peer.
900    BlacklistBackbonePeer(bool),
901}
902
903#[derive(Debug, Clone, Copy, PartialEq, Eq)]
904pub enum InterfaceManagementOperation {
905    Attach,
906    Detach,
907    Reload,
908}
909
910/// Per-destination link totals for status reporting.
911#[derive(Debug, Clone, Copy, PartialEq, Eq)]
912pub struct LinkDistributionEntry {
913    pub destination_hash: [u8; 16],
914    pub total: usize,
915    pub active: usize,
916}
917
918/// Interface statistics response.
919#[derive(Debug, Clone, Default)]
920pub struct InterfaceStatsResponse {
921    pub interfaces: Vec<SingleInterfaceStat>,
922    pub transport_id: Option<[u8; 16]>,
923    pub transport_enabled: bool,
924    pub transport_uptime: f64,
925    /// Total received bytes across all interfaces.
926    pub total_rxb: u64,
927    /// Total transmitted bytes across all interfaces.
928    pub total_txb: u64,
929    /// Total received packets across all interfaces.
930    pub total_rx_packets: u64,
931    /// Total transmitted packets across all interfaces.
932    pub total_tx_packets: u64,
933    /// Total received announce packets.
934    pub total_announce_rx: u64,
935    /// Total transmitted announce packets.
936    pub total_announce_tx: u64,
937    /// Total received path-request packets.
938    pub total_path_request_rx: u64,
939    /// Total transmitted path-request packets.
940    pub total_path_request_tx: u64,
941    /// Total links (validated and pending).
942    pub total_links: usize,
943    /// Active (validated) links.
944    pub active_links: usize,
945    /// Pending links.
946    pub pending_links: usize,
947    /// Total path pool destinations.
948    pub path_pool_total: usize,
949    /// Never-used path pool destinations.
950    pub path_pool_unused: usize,
951    /// Path pool destinations with at least one use.
952    pub path_pool_active: usize,
953    /// Aggregate received packets per second, excluding local shared-instance traffic.
954    pub rx_pps: f64,
955    /// Aggregate transmitted packets per second, excluding local shared-instance traffic.
956    pub tx_pps: f64,
957    /// Aggregate byte counters and rates for total, announce and path-request traffic.
958    pub traffic: TrafficDetail,
959    /// Probe responder destination hash (if enabled).
960    pub probe_responder: Option<[u8; 16]>,
961    /// Outbound Backbone peer-pool state, if enabled.
962    pub backbone_peer_pool: Option<BackbonePeerPoolStatus>,
963}
964
965/// Detailed traffic counters and average rates in bits per second.
966#[derive(Debug, Clone, Copy, Default)]
967pub struct TrafficDetail {
968    pub rxs: f64,
969    pub txs: f64,
970    pub arxb: u64,
971    pub atxb: u64,
972    pub arxc: u64,
973    pub atxc: u64,
974    pub arxs: f64,
975    pub atxs: f64,
976    pub prxb: u64,
977    pub ptxb: u64,
978    pub prxc: u64,
979    pub ptxc: u64,
980    pub prxs: f64,
981    pub ptxs: f64,
982    pub arxf: f64,
983    pub atxf: f64,
984    pub prxf: f64,
985    pub ptxf: f64,
986}
987
988/// Runtime status for the outbound Backbone peer pool.
989#[derive(Debug, Clone)]
990pub struct BackbonePeerPoolStatus {
991    pub max_connected: usize,
992    pub active_count: usize,
993    pub standby_count: usize,
994    pub cooldown_count: usize,
995    pub members: Vec<BackbonePeerPoolMemberStatus>,
996}
997
998/// Runtime status for one outbound Backbone peer-pool member.
999#[derive(Debug, Clone)]
1000pub struct BackbonePeerPoolMemberStatus {
1001    pub name: String,
1002    pub remote: String,
1003    pub source: String,
1004    pub priority: u8,
1005    pub state: String,
1006    pub interface_id: Option<u64>,
1007    pub failure_count: usize,
1008    pub last_error: Option<String>,
1009    pub cooldown_remaining_seconds: Option<f64>,
1010}
1011
1012/// Statistics for a single interface.
1013#[derive(Debug, Clone)]
1014pub struct SingleInterfaceStat {
1015    pub id: u64,
1016    pub name: String,
1017    pub status: bool,
1018    pub mode: u8,
1019    /// Signed interface preference used by path selection.
1020    pub gravity: i64,
1021    /// Whether boundary ingress announces may propagate to internal interfaces.
1022    pub announces_to_internal: Option<bool>,
1023    pub rxb: u64,
1024    pub txb: u64,
1025    pub tx_drops: u64,
1026    pub tx_dropped_bytes: u64,
1027    pub tx_stalled: bool,
1028    pub tx_buffered: usize,
1029    /// Byte counters and rates for total, announce and path-request traffic.
1030    pub traffic: TrafficDetail,
1031    pub protocol_violations: u64,
1032    pub ifac_violations: u64,
1033    pub packet_filter_hits: u64,
1034    pub hop_limiter_hits: u64,
1035    /// Inbound path requests whose stamp met the required cost.
1036    pub stamped_path_requests: u64,
1037    pub rx_packets: u64,
1038    pub tx_packets: u64,
1039    pub cpu_load: Option<f64>,
1040    pub mem_load: Option<f64>,
1041    pub switch_id: Option<[u8; 4]>,
1042    pub endpoint_id: Option<[u8; 8]>,
1043    pub via_switch_id: Option<[u8; 4]>,
1044    pub peers: Option<usize>,
1045    pub rssi: Option<i16>,
1046    pub snr: Option<f32>,
1047    pub signal_quality: Option<f64>,
1048    pub frequency: Option<u32>,
1049    pub bandwidth: Option<u32>,
1050    pub txpower: Option<i8>,
1051    pub spreading_factor: Option<u8>,
1052    pub coding_rate: Option<u8>,
1053    pub channel: Option<u32>,
1054    pub modulation: Option<String>,
1055    pub bitrate: Option<u64>,
1056    /// Hardware MTU advertised for this interface, when known.
1057    pub mtu: Option<u32>,
1058    pub ifac_size: Option<usize>,
1059    pub started: f64,
1060    /// Incoming announce frequency (per second).
1061    pub ia_freq: f64,
1062    /// Outgoing announce frequency (per second).
1063    pub oa_freq: f64,
1064    /// Incoming path request frequency (per second).
1065    pub ip_freq: f64,
1066    /// Outgoing path request frequency (per second).
1067    pub op_freq: f64,
1068    /// Outgoing path request samples currently retained.
1069    pub op_samples: usize,
1070    /// Whether announce ingress-control burst limiting is currently active.
1071    pub burst_active: bool,
1072    /// Timestamp when announce ingress-control burst limiting activated.
1073    pub burst_activated: f64,
1074    /// Whether path-request ingress-control burst limiting is currently active.
1075    pub pr_burst_active: bool,
1076    /// Timestamp when path-request burst limiting activated.
1077    pub pr_burst_activated: f64,
1078    /// Connected client count for aggregate server interfaces, if reported.
1079    pub clients: Option<u64>,
1080    /// Fast-flapping IPs currently blocked by an aggregate server interface.
1081    pub blocked_ips: Option<u64>,
1082    /// Sorted textual IP addresses currently blocked for fast flapping.
1083    pub blocked_ip_list: Option<Vec<String>>,
1084    /// Target interval for outgoing announce rate control, in seconds.
1085    pub announce_rate_target: Option<f64>,
1086    /// Announce-rate control grace count.
1087    pub announce_rate_grace: u32,
1088    /// Announce-rate control penalty, in seconds.
1089    pub announce_rate_penalty: f64,
1090    /// Human-readable interface type string (e.g. "TCPClientInterface").
1091    pub interface_type: String,
1092}
1093
1094/// A locally registered destination.
1095#[derive(Debug, Clone)]
1096pub struct LocalDestinationEntry {
1097    pub hash: [u8; 16],
1098    pub dest_type: u8,
1099}
1100
1101/// Information about an active link.
1102#[derive(Debug, Clone)]
1103pub struct LinkInfoEntry {
1104    pub link_id: [u8; 16],
1105    /// Confirmed sends admitted locally but not yet fully written (including the current write).
1106    pub pending_send_packets: usize,
1107    /// Polled async sends waiting for local admission capacity.
1108    pub waiting_send_packets: usize,
1109    pub state: String,
1110    pub is_initiator: bool,
1111    pub dest_hash: [u8; 16],
1112    pub remote_identity: Option<[u8; 16]>,
1113    pub rtt: Option<f64>,
1114    pub expected_hops: u8,
1115    /// Maximum plaintext bytes accepted by one direct Link data packet.
1116    pub mdu: usize,
1117    pub tx_packets: u64,
1118    pub rx_packets: u64,
1119    pub tx_bytes: u64,
1120    pub rx_bytes: u64,
1121    pub channel_window: Option<u16>,
1122    pub channel_outstanding: Option<usize>,
1123    pub pending_channel_packets: usize,
1124    pub channel_send_ok: u64,
1125    pub channel_send_not_ready: u64,
1126    pub channel_send_too_big: u64,
1127    pub channel_send_other_error: u64,
1128    pub channel_messages_received: u64,
1129    pub channel_proofs_sent: u64,
1130    pub channel_proofs_received: u64,
1131}
1132
1133/// Information about an active resource transfer.
1134#[derive(Debug, Clone)]
1135pub struct ResourceInfoEntry {
1136    pub link_id: [u8; 16],
1137    pub direction: String,
1138    pub total_parts: usize,
1139    pub transferred_parts: usize,
1140    pub complete: bool,
1141}
1142
1143/// A single path table entry for query responses.
1144#[derive(Debug, Clone)]
1145pub struct PathTableEntry {
1146    pub hash: [u8; 16],
1147    pub timestamp: f64,
1148    pub via: [u8; 16],
1149    pub hops: u8,
1150    pub expires: f64,
1151    pub used: f64,
1152    pub interface: InterfaceId,
1153    pub interface_name: String,
1154    /// Stamp value of the destination's announce, when it is a known
1155    /// destination (upstream `21170877` path table `value`).
1156    pub stamp_value: Option<rns_core::stamp::StampValue>,
1157    /// Link request cost the destination announced, when known (`lr_cost`).
1158    pub lr_cost: Option<rns_core::stamp::StampCost>,
1159}
1160
1161/// A single rate table entry for query responses.
1162#[derive(Debug, Clone)]
1163pub struct RateTableEntry {
1164    pub hash: [u8; 16],
1165    pub last: f64,
1166    pub rate_violations: u32,
1167    pub blocked_until: f64,
1168    pub timestamps: Vec<f64>,
1169}
1170
1171/// A blackholed identity for query responses.
1172#[derive(Debug, Clone)]
1173pub struct BlackholeInfo {
1174    pub identity_hash: [u8; 16],
1175    pub created: f64,
1176    pub expires: f64,
1177    pub reason: Option<String>,
1178}
1179
1180/// Keys for a stamped link request, ground off the driver thread, with the
1181/// responder of the `CreateLink` that asked for them.
1182pub struct StampedLinkKeys {
1183    pub dest_hash: [u8; 16],
1184    pub dest_sig_pub_bytes: [u8; 32],
1185    pub prv_bytes: [u8; 32],
1186    pub sig_prv_bytes: [u8; 32],
1187    pub stamp_value: rns_core::stamp::StampValue,
1188    pub response_tx: mpsc::Sender<[u8; 16]>,
1189}
1190
1191/// Stamp information recorded from a destination's last announce.
1192#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1193pub struct DestinationStampInfo {
1194    /// Value of the announce stamp, zero when the announce carried none.
1195    pub stamp_value: rns_core::stamp::StampValue,
1196    /// Link request cost the destination announced, if any.
1197    pub lr_cost: Option<rns_core::stamp::StampCost>,
1198}
1199
1200/// Next hop lookup result.
1201#[derive(Debug, Clone)]
1202pub struct NextHopResponse {
1203    pub next_hop: [u8; 16],
1204    pub hops: u8,
1205    pub interface: InterfaceId,
1206}
1207
1208impl<W: Send> Event<W> {
1209    /// A query for the driver, answered on `response`.
1210    pub fn query(request: QueryRequest, response: mpsc::Sender<QueryResponse>) -> Self {
1211        Event::Query(Box::new(request), response)
1212    }
1213
1214    /// The request and response channel of a query, or the event itself.
1215    pub fn into_query(self) -> Result<(QueryRequest, mpsc::Sender<QueryResponse>), Self> {
1216        match self {
1217            Event::Query(request, response) => Ok((*request, response)),
1218            other => Err(other),
1219        }
1220    }
1221}
1222
1223impl<W: Send> fmt::Debug for Event<W> {
1224    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1225        match self {
1226            Event::Frame {
1227                interface_id,
1228                data,
1229                rssi,
1230                snr,
1231            } => f
1232                .debug_struct("Frame")
1233                .field("interface_id", interface_id)
1234                .field("data_len", &data.len())
1235                .field("rssi", rssi)
1236                .field("snr", snr)
1237                .finish(),
1238            Event::AnnounceVerified { key, .. } => f
1239                .debug_struct("AnnounceVerified")
1240                .field("destination_hash", &key.destination_hash)
1241                .field("received_from", &key.received_from)
1242                .finish(),
1243            Event::AnnounceVerifyFailed { key, .. } => f
1244                .debug_struct("AnnounceVerifyFailed")
1245                .field("destination_hash", &key.destination_hash)
1246                .field("received_from", &key.received_from)
1247                .finish(),
1248            Event::InterfaceUp(id, writer, info) => f
1249                .debug_tuple("InterfaceUp")
1250                .field(id)
1251                .field(&writer.is_some())
1252                .field(&info.is_some())
1253                .finish(),
1254            Event::DynamicInterfaceUp {
1255                id, registration, ..
1256            } => f
1257                .debug_struct("DynamicInterfaceUp")
1258                .field("id", id)
1259                .field("type", &registration.interface_type)
1260                .field("parent_id", &registration.parent_id)
1261                .finish(),
1262            Event::InterfaceTelemetry {
1263                interface_id,
1264                telemetry,
1265            } => f
1266                .debug_struct("InterfaceTelemetry")
1267                .field("interface_id", interface_id)
1268                .field("telemetry", telemetry)
1269                .finish(),
1270            Event::InterfaceDown(id) => f.debug_tuple("InterfaceDown").field(id).finish(),
1271            Event::Tick => write!(f, "Tick"),
1272            Event::BeginDrain { timeout } => f
1273                .debug_struct("BeginDrain")
1274                .field("timeout", timeout)
1275                .finish(),
1276            Event::Shutdown => write!(f, "Shutdown"),
1277            Event::DeliverDecrypted { dest_hash, .. } => f
1278                .debug_struct("DeliverDecrypted")
1279                .field("dest_hash", dest_hash)
1280                .finish(),
1281            Event::SendDeferred(encryption) => f
1282                .debug_struct("SendDeferred")
1283                .field("ticket", &encryption.ticket)
1284                .field("data_len", &encryption.data.len())
1285                .finish(),
1286            Event::SendOutbound { raw, dest_type, .. }
1287            | Event::SendOutboundTracked { raw, dest_type, .. } => f
1288                .debug_struct("SendOutbound")
1289                .field("raw_len", &raw.len())
1290                .field("dest_type", dest_type)
1291                .finish(),
1292            Event::RegisterDestination {
1293                dest_hash,
1294                dest_type,
1295            } => f
1296                .debug_struct("RegisterDestination")
1297                .field("dest_hash", dest_hash)
1298                .field("dest_type", dest_type)
1299                .finish(),
1300            Event::StoreSharedAnnounce {
1301                dest_hash,
1302                name_hash,
1303                app_data,
1304                ..
1305            } => f
1306                .debug_struct("StoreSharedAnnounce")
1307                .field("dest_hash", dest_hash)
1308                .field("name_hash", name_hash)
1309                .field("app_data_len", &app_data.as_ref().map(|d| d.len()))
1310                .finish(),
1311            Event::DeregisterDestination { dest_hash } => f
1312                .debug_struct("DeregisterDestination")
1313                .field("dest_hash", dest_hash)
1314                .finish(),
1315            Event::DeregisterLinkDestination { dest_hash } => f
1316                .debug_struct("DeregisterLinkDestination")
1317                .field("dest_hash", dest_hash)
1318                .finish(),
1319            Event::Query(req, _) => f.debug_tuple("Query").field(req).finish(),
1320            Event::RegisterLinkDestination { dest_hash, .. } => f
1321                .debug_struct("RegisterLinkDestination")
1322                .field("dest_hash", dest_hash)
1323                .finish(),
1324            Event::RegisterRequestHandler { path, .. } => f
1325                .debug_struct("RegisterRequestHandler")
1326                .field("path", path)
1327                .finish(),
1328            Event::RegisterRequestHandlerResponse { path, .. } => f
1329                .debug_struct("RegisterRequestHandlerResponse")
1330                .field("path", path)
1331                .finish(),
1332            Event::RegisterDeferredRequestHandler { path, .. } => f
1333                .debug_struct("RegisterDeferredRequestHandler")
1334                .field("path", path)
1335                .finish(),
1336            Event::CreateLink { dest_hash, .. } => f
1337                .debug_struct("CreateLink")
1338                .field("dest_hash", dest_hash)
1339                .finish(),
1340            Event::CompleteStampedLink(keys) => f
1341                .debug_struct("CompleteStampedLink")
1342                .field("dest_hash", &keys.dest_hash)
1343                .field("stamp_value", &keys.stamp_value)
1344                .finish(),
1345            Event::SendRequest { link_id, path, .. } => f
1346                .debug_struct("SendRequest")
1347                .field("link_id", link_id)
1348                .field("path", path)
1349                .finish(),
1350            Event::SendDeferredResponse {
1351                link_id,
1352                request_id,
1353                data,
1354            } => f
1355                .debug_struct("SendDeferredResponse")
1356                .field("link_id", link_id)
1357                .field("request_id", request_id)
1358                .field("data_len", &data.len())
1359                .finish(),
1360            Event::IdentifyOnLink { link_id, .. } => f
1361                .debug_struct("IdentifyOnLink")
1362                .field("link_id", link_id)
1363                .finish(),
1364            Event::TeardownLink { link_id } => f
1365                .debug_struct("TeardownLink")
1366                .field("link_id", link_id)
1367                .finish(),
1368            Event::ResourcePreparationReady => f.write_str("ResourcePreparationReady"),
1369            Event::ResourceAssemblyReady => f.write_str("ResourceAssemblyReady"),
1370            Event::LinkProofsVerified => f.write_str("LinkProofsVerified"),
1371            Event::SendResource { link_id, data, .. } => f
1372                .debug_struct("SendResource")
1373                .field("link_id", link_id)
1374                .field("data_len", &data.len())
1375                .finish(),
1376            Event::SendResourceStream {
1377                link_id,
1378                transfer_id,
1379                declared_length,
1380                ..
1381            } => f
1382                .debug_struct("SendResourceStream")
1383                .field("link_id", link_id)
1384                .field("transfer_id", transfer_id)
1385                .field("declared_length", declared_length)
1386                .finish(),
1387            Event::SetResourceStrategy { link_id, strategy } => f
1388                .debug_struct("SetResourceStrategy")
1389                .field("link_id", link_id)
1390                .field("strategy", strategy)
1391                .finish(),
1392            Event::SetResourceReceiveMode { link_id, mode } => f
1393                .debug_struct("SetResourceReceiveMode")
1394                .field("link_id", link_id)
1395                .field("mode", mode)
1396                .finish(),
1397            Event::AcceptResource {
1398                link_id, accept, ..
1399            } => f
1400                .debug_struct("AcceptResource")
1401                .field("link_id", link_id)
1402                .field("accept", accept)
1403                .finish(),
1404            Event::SendChannelMessage {
1405                link_id,
1406                msgtype,
1407                payload,
1408                ..
1409            } => f
1410                .debug_struct("SendChannelMessage")
1411                .field("link_id", link_id)
1412                .field("msgtype", msgtype)
1413                .field("payload_len", &payload.len())
1414                .finish(),
1415            Event::LinkWriterReady => f.write_str("LinkWriterReady"),
1416            Event::SendOnLink {
1417                link_id,
1418                data,
1419                context,
1420                ..
1421            }
1422            | Event::SendLinkTracked {
1423                link_id,
1424                data,
1425                context,
1426                ..
1427            } => f
1428                .debug_struct("SendOnLink")
1429                .field("link_id", link_id)
1430                .field("data_len", &data.len())
1431                .field("context", context)
1432                .finish(),
1433            Event::RequestPath { dest_hash } => f
1434                .debug_struct("RequestPath")
1435                .field("dest_hash", dest_hash)
1436                .finish(),
1437            Event::SendStampedPathRequest(request) => f
1438                .debug_struct("SendStampedPathRequest")
1439                .field("dest_hash", &request.destination_hash)
1440                .field("target", &request.target)
1441                .finish(),
1442            Event::DestinationStampReady { dest_hash } => f
1443                .debug_struct("DestinationStampReady")
1444                .field("dest_hash", dest_hash)
1445                .finish(),
1446            Event::RegisterProofStrategy {
1447                dest_hash,
1448                strategy,
1449                ..
1450            } => f
1451                .debug_struct("RegisterProofStrategy")
1452                .field("dest_hash", dest_hash)
1453                .field("strategy", strategy)
1454                .finish(),
1455            Event::ProposeDirectConnect { link_id } => f
1456                .debug_struct("ProposeDirectConnect")
1457                .field("link_id", link_id)
1458                .finish(),
1459            Event::SetDirectConnectPolicy { .. } => {
1460                write!(f, "SetDirectConnectPolicy")
1461            }
1462            Event::HolePunchProbeResult {
1463                link_id,
1464                session_id,
1465                observed_addr,
1466                probe_server,
1467                ..
1468            } => f
1469                .debug_struct("HolePunchProbeResult")
1470                .field("link_id", link_id)
1471                .field("session_id", session_id)
1472                .field("observed_addr", observed_addr)
1473                .field("probe_server", probe_server)
1474                .finish(),
1475            Event::HolePunchProbeFailed {
1476                link_id,
1477                session_id,
1478            } => f
1479                .debug_struct("HolePunchProbeFailed")
1480                .field("link_id", link_id)
1481                .field("session_id", session_id)
1482                .finish(),
1483            Event::InterfaceConfigChanged(id) => {
1484                f.debug_tuple("InterfaceConfigChanged").field(id).finish()
1485            }
1486            Event::BackbonePeerConnected {
1487                server_interface_id,
1488                peer_interface_id,
1489                peer_ip,
1490                peer_port,
1491            } => f
1492                .debug_struct("BackbonePeerConnected")
1493                .field("server_interface_id", server_interface_id)
1494                .field("peer_interface_id", peer_interface_id)
1495                .field("peer_ip", peer_ip)
1496                .field("peer_port", peer_port)
1497                .finish(),
1498            Event::BackbonePeerDisconnected {
1499                server_interface_id,
1500                peer_interface_id,
1501                peer_ip,
1502                peer_port,
1503                connected_for,
1504                had_received_data,
1505            } => f
1506                .debug_struct("BackbonePeerDisconnected")
1507                .field("server_interface_id", server_interface_id)
1508                .field("peer_interface_id", peer_interface_id)
1509                .field("peer_ip", peer_ip)
1510                .field("peer_port", peer_port)
1511                .field("connected_for", connected_for)
1512                .field("had_received_data", had_received_data)
1513                .finish(),
1514            Event::BackbonePeerIdleTimeout {
1515                server_interface_id,
1516                peer_interface_id,
1517                peer_ip,
1518                peer_port,
1519                connected_for,
1520            } => f
1521                .debug_struct("BackbonePeerIdleTimeout")
1522                .field("server_interface_id", server_interface_id)
1523                .field("peer_interface_id", peer_interface_id)
1524                .field("peer_ip", peer_ip)
1525                .field("peer_port", peer_port)
1526                .field("connected_for", connected_for)
1527                .finish(),
1528            Event::BackbonePeerWriteStall {
1529                server_interface_id,
1530                peer_interface_id,
1531                peer_ip,
1532                peer_port,
1533                connected_for,
1534            } => f
1535                .debug_struct("BackbonePeerWriteStall")
1536                .field("server_interface_id", server_interface_id)
1537                .field("peer_interface_id", peer_interface_id)
1538                .field("peer_ip", peer_ip)
1539                .field("peer_port", peer_port)
1540                .field("connected_for", connected_for)
1541                .finish(),
1542            Event::BackbonePeerPenalty {
1543                server_interface_id,
1544                peer_ip,
1545                penalty_level,
1546                blacklist_for,
1547            } => f
1548                .debug_struct("BackbonePeerPenalty")
1549                .field("server_interface_id", server_interface_id)
1550                .field("peer_ip", peer_ip)
1551                .field("penalty_level", penalty_level)
1552                .field("blacklist_for", blacklist_for)
1553                .finish(),
1554            Event::LoadHook {
1555                name,
1556                attach_point,
1557                priority,
1558                ..
1559            } => f
1560                .debug_struct("LoadHook")
1561                .field("name", name)
1562                .field("attach_point", attach_point)
1563                .field("priority", priority)
1564                .finish(),
1565            Event::LoadHookFile {
1566                name,
1567                path,
1568                hook_type,
1569                attach_point,
1570                priority,
1571                ..
1572            } => f
1573                .debug_struct("LoadHookFile")
1574                .field("name", name)
1575                .field("path", path)
1576                .field("hook_type", hook_type)
1577                .field("attach_point", attach_point)
1578                .field("priority", priority)
1579                .finish(),
1580            Event::LoadBuiltinHook {
1581                name,
1582                builtin_id,
1583                attach_point,
1584                priority,
1585                ..
1586            } => f
1587                .debug_struct("LoadBuiltinHook")
1588                .field("name", name)
1589                .field("builtin_id", builtin_id)
1590                .field("attach_point", attach_point)
1591                .field("priority", priority)
1592                .finish(),
1593            Event::UnloadHook {
1594                name, attach_point, ..
1595            } => f
1596                .debug_struct("UnloadHook")
1597                .field("name", name)
1598                .field("attach_point", attach_point)
1599                .finish(),
1600            Event::ReloadHook {
1601                name, attach_point, ..
1602            } => f
1603                .debug_struct("ReloadHook")
1604                .field("name", name)
1605                .field("attach_point", attach_point)
1606                .finish(),
1607            Event::ReloadHookFile {
1608                name,
1609                attach_point,
1610                path,
1611                hook_type,
1612                ..
1613            } => f
1614                .debug_struct("ReloadHookFile")
1615                .field("name", name)
1616                .field("attach_point", attach_point)
1617                .field("path", path)
1618                .field("hook_type", hook_type)
1619                .finish(),
1620            Event::ReloadBuiltinHook {
1621                name,
1622                attach_point,
1623                builtin_id,
1624                ..
1625            } => f
1626                .debug_struct("ReloadBuiltinHook")
1627                .field("name", name)
1628                .field("attach_point", attach_point)
1629                .field("builtin_id", builtin_id)
1630                .finish(),
1631            Event::SetHookEnabled {
1632                name,
1633                attach_point,
1634                enabled,
1635                ..
1636            } => f
1637                .debug_struct("SetHookEnabled")
1638                .field("name", name)
1639                .field("attach_point", attach_point)
1640                .field("enabled", enabled)
1641                .finish(),
1642            Event::SetHookPriority {
1643                name,
1644                attach_point,
1645                priority,
1646                ..
1647            } => f
1648                .debug_struct("SetHookPriority")
1649                .field("name", name)
1650                .field("attach_point", attach_point)
1651                .field("priority", priority)
1652                .finish(),
1653            Event::ListHooks { .. } => write!(f, "ListHooks"),
1654        }
1655    }
1656}