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