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/// Responses to queries.
722#[derive(Debug)]
723pub enum QueryResponse {
724    /// Python-compatible tri-state result: success, failure, or missing name.
725    InterfaceManagement(Option<bool>),
726    InterfaceStats(InterfaceStatsResponse),
727    PathTable(Vec<PathTableEntry>),
728    RateTable(Vec<RateTableEntry>),
729    LowestInterfaceBitrate(Option<u64>),
730    MediumPathTimeout(f64),
731    FirstHopTimeout(f64),
732    NextHop(Option<NextHopResponse>),
733    NextHopIfName(Option<String>),
734    LinkCount(usize),
735    ActiveLinkCount(usize),
736    DropPath(bool),
737    DropAllVia(usize),
738    DropAnnounceQueues,
739    TransportIdentity(Option<[u8; 16]>),
740    TransportStateSnapshot(rns_core::transport::persistence::TransportStateSnapshot),
741    Blackholed(Vec<BlackholeInfo>),
742    BlackholeResult(bool),
743    UnblackholeResult(bool),
744    HasPath(bool),
745    HopsTo(Option<u8>),
746    RecallIdentity(Option<crate::common::destination::AnnouncedIdentity>),
747    KnownDestinations(Vec<KnownDestinationEntry>),
748    LocalDestinations(Vec<LocalDestinationEntry>),
749    Links(Vec<LinkInfoEntry>),
750    Resources(Vec<ResourceInfoEntry>),
751    InjectPath(bool),
752    InjectIdentity(bool),
753    RestoreKnownDestination(bool),
754    RetainKnownDestination(bool),
755    RetainIdentity(bool),
756    UnretainKnownDestination(bool),
757    MarkKnownDestinationUsed(bool),
758    /// List of discovered interfaces.
759    DiscoveredInterfaces(Vec<crate::common::discovery::DiscoveredInterface>),
760    /// Probe sent: (packet_hash, hops) or None if identity unknown.
761    SendProbe(Option<([u8; 32], u8)>),
762    /// Proof check: RTT if received, None if still pending.
763    CheckProof(Option<f64>),
764    /// Runtime-config entries currently supported by the daemon.
765    RuntimeConfigList(Vec<RuntimeConfigEntry>),
766    /// A specific runtime-config entry, or None if the key is unknown.
767    RuntimeConfigEntry(Option<RuntimeConfigEntry>),
768    /// Result of setting a runtime-config value.
769    RuntimeConfigSet(Result<RuntimeConfigEntry, RuntimeConfigError>),
770    /// Result of resetting a runtime-config value.
771    RuntimeConfigReset(Result<RuntimeConfigEntry, RuntimeConfigError>),
772    /// Live backbone peer state entries.
773    BackbonePeerState(Vec<BackbonePeerStateEntry>),
774    /// Registered backbone server interfaces.
775    BackboneInterfaces(Vec<BackboneInterfaceEntry>),
776    /// Live provider-bridge queue/drop state if enabled.
777    ProviderBridgeStats(Option<ProviderBridgeStats>),
778    /// Current lifecycle/drain status.
779    DrainStatus(DrainStatus),
780    /// Result of clearing one backbone peer state entry.
781    ClearBackbonePeerState(bool),
782    /// Result of blacklisting a backbone peer.
783    BlacklistBackbonePeer(bool),
784}
785
786#[derive(Debug, Clone, Copy, PartialEq, Eq)]
787pub enum InterfaceManagementOperation {
788    Attach,
789    Detach,
790    Reload,
791}
792
793/// Interface statistics response.
794#[derive(Debug, Clone)]
795pub struct InterfaceStatsResponse {
796    pub interfaces: Vec<SingleInterfaceStat>,
797    pub transport_id: Option<[u8; 16]>,
798    pub transport_enabled: bool,
799    pub transport_uptime: f64,
800    /// Total received bytes across all interfaces.
801    pub total_rxb: u64,
802    /// Total transmitted bytes across all interfaces.
803    pub total_txb: u64,
804    /// Aggregate received packets per second, excluding local shared-instance traffic.
805    pub rx_pps: f64,
806    /// Aggregate transmitted packets per second, excluding local shared-instance traffic.
807    pub tx_pps: f64,
808    /// Aggregate byte counters and rates for total, announce and path-request traffic.
809    pub traffic: TrafficDetail,
810    /// Probe responder destination hash (if enabled).
811    pub probe_responder: Option<[u8; 16]>,
812    /// Outbound Backbone peer-pool state, if enabled.
813    pub backbone_peer_pool: Option<BackbonePeerPoolStatus>,
814}
815
816/// Detailed traffic counters and average rates in bits per second.
817#[derive(Debug, Clone, Copy, Default)]
818pub struct TrafficDetail {
819    pub rxs: f64,
820    pub txs: f64,
821    pub arxb: u64,
822    pub atxb: u64,
823    pub arxc: u64,
824    pub atxc: u64,
825    pub arxs: f64,
826    pub atxs: f64,
827    pub prxb: u64,
828    pub ptxb: u64,
829    pub prxc: u64,
830    pub ptxc: u64,
831    pub prxs: f64,
832    pub ptxs: f64,
833    pub arxf: f64,
834    pub atxf: f64,
835    pub prxf: f64,
836    pub ptxf: f64,
837}
838
839/// Runtime status for the outbound Backbone peer pool.
840#[derive(Debug, Clone)]
841pub struct BackbonePeerPoolStatus {
842    pub max_connected: usize,
843    pub active_count: usize,
844    pub standby_count: usize,
845    pub cooldown_count: usize,
846    pub members: Vec<BackbonePeerPoolMemberStatus>,
847}
848
849/// Runtime status for one outbound Backbone peer-pool member.
850#[derive(Debug, Clone)]
851pub struct BackbonePeerPoolMemberStatus {
852    pub name: String,
853    pub remote: String,
854    pub source: String,
855    pub priority: u8,
856    pub state: String,
857    pub interface_id: Option<u64>,
858    pub failure_count: usize,
859    pub last_error: Option<String>,
860    pub cooldown_remaining_seconds: Option<f64>,
861}
862
863/// Statistics for a single interface.
864#[derive(Debug, Clone)]
865pub struct SingleInterfaceStat {
866    pub id: u64,
867    pub name: String,
868    pub status: bool,
869    pub mode: u8,
870    /// Signed interface preference used by path selection.
871    pub gravity: i64,
872    /// Whether boundary ingress announces may propagate to internal interfaces.
873    pub announces_to_internal: Option<bool>,
874    pub rxb: u64,
875    pub txb: u64,
876    pub tx_drops: u64,
877    pub tx_dropped_bytes: u64,
878    pub tx_stalled: bool,
879    pub tx_buffered: usize,
880    /// Byte counters and rates for total, announce and path-request traffic.
881    pub traffic: TrafficDetail,
882    pub protocol_violations: u64,
883    pub ifac_violations: u64,
884    pub packet_filter_hits: u64,
885    pub rx_packets: u64,
886    pub tx_packets: u64,
887    pub cpu_load: Option<f64>,
888    pub mem_load: Option<f64>,
889    pub switch_id: Option<[u8; 4]>,
890    pub endpoint_id: Option<[u8; 8]>,
891    pub via_switch_id: Option<[u8; 4]>,
892    pub peers: Option<usize>,
893    pub bitrate: Option<u64>,
894    /// Hardware MTU advertised for this interface, when known.
895    pub mtu: Option<u32>,
896    pub ifac_size: Option<usize>,
897    pub started: f64,
898    /// Incoming announce frequency (per second).
899    pub ia_freq: f64,
900    /// Outgoing announce frequency (per second).
901    pub oa_freq: f64,
902    /// Incoming path request frequency (per second).
903    pub ip_freq: f64,
904    /// Outgoing path request frequency (per second).
905    pub op_freq: f64,
906    /// Outgoing path request samples currently retained.
907    pub op_samples: usize,
908    /// Whether announce ingress-control burst limiting is currently active.
909    pub burst_active: bool,
910    /// Timestamp when announce ingress-control burst limiting activated.
911    pub burst_activated: f64,
912    /// Whether path-request ingress-control burst limiting is currently active.
913    pub pr_burst_active: bool,
914    /// Timestamp when path-request burst limiting activated.
915    pub pr_burst_activated: f64,
916    /// Connected client count for aggregate server interfaces, if reported.
917    pub clients: Option<u64>,
918    /// Fast-flapping IPs currently blocked by an aggregate server interface.
919    pub blocked_ips: Option<u64>,
920    /// Sorted textual IP addresses currently blocked for fast flapping.
921    pub blocked_ip_list: Option<Vec<String>>,
922    /// Target interval for outgoing announce rate control, in seconds.
923    pub announce_rate_target: Option<f64>,
924    /// Announce-rate control grace count.
925    pub announce_rate_grace: u32,
926    /// Announce-rate control penalty, in seconds.
927    pub announce_rate_penalty: f64,
928    /// Human-readable interface type string (e.g. "TCPClientInterface").
929    pub interface_type: String,
930}
931
932/// A locally registered destination.
933#[derive(Debug, Clone)]
934pub struct LocalDestinationEntry {
935    pub hash: [u8; 16],
936    pub dest_type: u8,
937}
938
939/// Information about an active link.
940#[derive(Debug, Clone)]
941pub struct LinkInfoEntry {
942    pub link_id: [u8; 16],
943    /// Confirmed sends admitted locally but not yet fully written (including the current write).
944    pub pending_send_packets: usize,
945    /// Polled async sends waiting for local admission capacity.
946    pub waiting_send_packets: usize,
947    pub state: String,
948    pub is_initiator: bool,
949    pub dest_hash: [u8; 16],
950    pub remote_identity: Option<[u8; 16]>,
951    pub rtt: Option<f64>,
952    pub expected_hops: u8,
953    /// Maximum plaintext bytes accepted by one direct Link data packet.
954    pub mdu: usize,
955    pub tx_packets: u64,
956    pub rx_packets: u64,
957    pub tx_bytes: u64,
958    pub rx_bytes: u64,
959    pub channel_window: Option<u16>,
960    pub channel_outstanding: Option<usize>,
961    pub pending_channel_packets: usize,
962    pub channel_send_ok: u64,
963    pub channel_send_not_ready: u64,
964    pub channel_send_too_big: u64,
965    pub channel_send_other_error: u64,
966    pub channel_messages_received: u64,
967    pub channel_proofs_sent: u64,
968    pub channel_proofs_received: u64,
969}
970
971/// Information about an active resource transfer.
972#[derive(Debug, Clone)]
973pub struct ResourceInfoEntry {
974    pub link_id: [u8; 16],
975    pub direction: String,
976    pub total_parts: usize,
977    pub transferred_parts: usize,
978    pub complete: bool,
979}
980
981/// A single path table entry for query responses.
982#[derive(Debug, Clone)]
983pub struct PathTableEntry {
984    pub hash: [u8; 16],
985    pub timestamp: f64,
986    pub via: [u8; 16],
987    pub hops: u8,
988    pub expires: f64,
989    pub interface: InterfaceId,
990    pub interface_name: String,
991}
992
993/// A single rate table entry for query responses.
994#[derive(Debug, Clone)]
995pub struct RateTableEntry {
996    pub hash: [u8; 16],
997    pub last: f64,
998    pub rate_violations: u32,
999    pub blocked_until: f64,
1000    pub timestamps: Vec<f64>,
1001}
1002
1003/// A blackholed identity for query responses.
1004#[derive(Debug, Clone)]
1005pub struct BlackholeInfo {
1006    pub identity_hash: [u8; 16],
1007    pub created: f64,
1008    pub expires: f64,
1009    pub reason: Option<String>,
1010}
1011
1012/// Next hop lookup result.
1013#[derive(Debug, Clone)]
1014pub struct NextHopResponse {
1015    pub next_hop: [u8; 16],
1016    pub hops: u8,
1017    pub interface: InterfaceId,
1018}
1019
1020impl<W: Send> Event<W> {
1021    /// A query for the driver, answered on `response`.
1022    pub fn query(request: QueryRequest, response: mpsc::Sender<QueryResponse>) -> Self {
1023        Event::Query(Box::new(request), response)
1024    }
1025
1026    /// The request and response channel of a query, or the event itself.
1027    pub fn into_query(self) -> Result<(QueryRequest, mpsc::Sender<QueryResponse>), Self> {
1028        match self {
1029            Event::Query(request, response) => Ok((*request, response)),
1030            other => Err(other),
1031        }
1032    }
1033}
1034
1035impl<W: Send> fmt::Debug for Event<W> {
1036    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1037        match self {
1038            Event::Frame {
1039                interface_id,
1040                data,
1041                rssi,
1042                snr,
1043            } => f
1044                .debug_struct("Frame")
1045                .field("interface_id", interface_id)
1046                .field("data_len", &data.len())
1047                .field("rssi", rssi)
1048                .field("snr", snr)
1049                .finish(),
1050            Event::AnnounceVerified { key, .. } => f
1051                .debug_struct("AnnounceVerified")
1052                .field("destination_hash", &key.destination_hash)
1053                .field("received_from", &key.received_from)
1054                .finish(),
1055            Event::AnnounceVerifyFailed { key, .. } => f
1056                .debug_struct("AnnounceVerifyFailed")
1057                .field("destination_hash", &key.destination_hash)
1058                .field("received_from", &key.received_from)
1059                .finish(),
1060            Event::InterfaceUp(id, writer, info) => f
1061                .debug_tuple("InterfaceUp")
1062                .field(id)
1063                .field(&writer.is_some())
1064                .field(&info.is_some())
1065                .finish(),
1066            Event::DynamicInterfaceUp {
1067                id, registration, ..
1068            } => f
1069                .debug_struct("DynamicInterfaceUp")
1070                .field("id", id)
1071                .field("type", &registration.interface_type)
1072                .field("parent_id", &registration.parent_id)
1073                .finish(),
1074            Event::InterfaceTelemetry {
1075                interface_id,
1076                telemetry,
1077            } => f
1078                .debug_struct("InterfaceTelemetry")
1079                .field("interface_id", interface_id)
1080                .field("telemetry", telemetry)
1081                .finish(),
1082            Event::InterfaceDown(id) => f.debug_tuple("InterfaceDown").field(id).finish(),
1083            Event::Tick => write!(f, "Tick"),
1084            Event::BeginDrain { timeout } => f
1085                .debug_struct("BeginDrain")
1086                .field("timeout", timeout)
1087                .finish(),
1088            Event::Shutdown => write!(f, "Shutdown"),
1089            Event::SendOutbound { raw, dest_type, .. }
1090            | Event::SendOutboundTracked { raw, dest_type, .. } => f
1091                .debug_struct("SendOutbound")
1092                .field("raw_len", &raw.len())
1093                .field("dest_type", dest_type)
1094                .finish(),
1095            Event::RegisterDestination {
1096                dest_hash,
1097                dest_type,
1098            } => f
1099                .debug_struct("RegisterDestination")
1100                .field("dest_hash", dest_hash)
1101                .field("dest_type", dest_type)
1102                .finish(),
1103            Event::StoreSharedAnnounce {
1104                dest_hash,
1105                name_hash,
1106                app_data,
1107                ..
1108            } => f
1109                .debug_struct("StoreSharedAnnounce")
1110                .field("dest_hash", dest_hash)
1111                .field("name_hash", name_hash)
1112                .field("app_data_len", &app_data.as_ref().map(|d| d.len()))
1113                .finish(),
1114            Event::DeregisterDestination { dest_hash } => f
1115                .debug_struct("DeregisterDestination")
1116                .field("dest_hash", dest_hash)
1117                .finish(),
1118            Event::DeregisterLinkDestination { dest_hash } => f
1119                .debug_struct("DeregisterLinkDestination")
1120                .field("dest_hash", dest_hash)
1121                .finish(),
1122            Event::Query(req, _) => f.debug_tuple("Query").field(req).finish(),
1123            Event::RegisterLinkDestination { dest_hash, .. } => f
1124                .debug_struct("RegisterLinkDestination")
1125                .field("dest_hash", dest_hash)
1126                .finish(),
1127            Event::RegisterRequestHandler { path, .. } => f
1128                .debug_struct("RegisterRequestHandler")
1129                .field("path", path)
1130                .finish(),
1131            Event::RegisterRequestHandlerResponse { path, .. } => f
1132                .debug_struct("RegisterRequestHandlerResponse")
1133                .field("path", path)
1134                .finish(),
1135            Event::RegisterDeferredRequestHandler { path, .. } => f
1136                .debug_struct("RegisterDeferredRequestHandler")
1137                .field("path", path)
1138                .finish(),
1139            Event::CreateLink { dest_hash, .. } => f
1140                .debug_struct("CreateLink")
1141                .field("dest_hash", dest_hash)
1142                .finish(),
1143            Event::SendRequest { link_id, path, .. } => f
1144                .debug_struct("SendRequest")
1145                .field("link_id", link_id)
1146                .field("path", path)
1147                .finish(),
1148            Event::SendDeferredResponse {
1149                link_id,
1150                request_id,
1151                data,
1152            } => f
1153                .debug_struct("SendDeferredResponse")
1154                .field("link_id", link_id)
1155                .field("request_id", request_id)
1156                .field("data_len", &data.len())
1157                .finish(),
1158            Event::IdentifyOnLink { link_id, .. } => f
1159                .debug_struct("IdentifyOnLink")
1160                .field("link_id", link_id)
1161                .finish(),
1162            Event::TeardownLink { link_id } => f
1163                .debug_struct("TeardownLink")
1164                .field("link_id", link_id)
1165                .finish(),
1166            Event::ResourcePreparationReady => f.write_str("ResourcePreparationReady"),
1167            Event::ResourceAssemblyReady => f.write_str("ResourceAssemblyReady"),
1168            Event::SendResource { link_id, data, .. } => f
1169                .debug_struct("SendResource")
1170                .field("link_id", link_id)
1171                .field("data_len", &data.len())
1172                .finish(),
1173            Event::SendResourceStream {
1174                link_id,
1175                transfer_id,
1176                declared_length,
1177                ..
1178            } => f
1179                .debug_struct("SendResourceStream")
1180                .field("link_id", link_id)
1181                .field("transfer_id", transfer_id)
1182                .field("declared_length", declared_length)
1183                .finish(),
1184            Event::SetResourceStrategy { link_id, strategy } => f
1185                .debug_struct("SetResourceStrategy")
1186                .field("link_id", link_id)
1187                .field("strategy", strategy)
1188                .finish(),
1189            Event::SetResourceReceiveMode { link_id, mode } => f
1190                .debug_struct("SetResourceReceiveMode")
1191                .field("link_id", link_id)
1192                .field("mode", mode)
1193                .finish(),
1194            Event::AcceptResource {
1195                link_id, accept, ..
1196            } => f
1197                .debug_struct("AcceptResource")
1198                .field("link_id", link_id)
1199                .field("accept", accept)
1200                .finish(),
1201            Event::SendChannelMessage {
1202                link_id,
1203                msgtype,
1204                payload,
1205                ..
1206            } => f
1207                .debug_struct("SendChannelMessage")
1208                .field("link_id", link_id)
1209                .field("msgtype", msgtype)
1210                .field("payload_len", &payload.len())
1211                .finish(),
1212            Event::LinkWriterReady => f.write_str("LinkWriterReady"),
1213            Event::SendOnLink {
1214                link_id,
1215                data,
1216                context,
1217                ..
1218            }
1219            | Event::SendLinkTracked {
1220                link_id,
1221                data,
1222                context,
1223                ..
1224            } => f
1225                .debug_struct("SendOnLink")
1226                .field("link_id", link_id)
1227                .field("data_len", &data.len())
1228                .field("context", context)
1229                .finish(),
1230            Event::RequestPath { dest_hash } => f
1231                .debug_struct("RequestPath")
1232                .field("dest_hash", dest_hash)
1233                .finish(),
1234            Event::RegisterProofStrategy {
1235                dest_hash,
1236                strategy,
1237                ..
1238            } => f
1239                .debug_struct("RegisterProofStrategy")
1240                .field("dest_hash", dest_hash)
1241                .field("strategy", strategy)
1242                .finish(),
1243            Event::ProposeDirectConnect { link_id } => f
1244                .debug_struct("ProposeDirectConnect")
1245                .field("link_id", link_id)
1246                .finish(),
1247            Event::SetDirectConnectPolicy { .. } => {
1248                write!(f, "SetDirectConnectPolicy")
1249            }
1250            Event::HolePunchProbeResult {
1251                link_id,
1252                session_id,
1253                observed_addr,
1254                probe_server,
1255                ..
1256            } => f
1257                .debug_struct("HolePunchProbeResult")
1258                .field("link_id", link_id)
1259                .field("session_id", session_id)
1260                .field("observed_addr", observed_addr)
1261                .field("probe_server", probe_server)
1262                .finish(),
1263            Event::HolePunchProbeFailed {
1264                link_id,
1265                session_id,
1266            } => f
1267                .debug_struct("HolePunchProbeFailed")
1268                .field("link_id", link_id)
1269                .field("session_id", session_id)
1270                .finish(),
1271            Event::InterfaceConfigChanged(id) => {
1272                f.debug_tuple("InterfaceConfigChanged").field(id).finish()
1273            }
1274            Event::BackbonePeerConnected {
1275                server_interface_id,
1276                peer_interface_id,
1277                peer_ip,
1278                peer_port,
1279            } => f
1280                .debug_struct("BackbonePeerConnected")
1281                .field("server_interface_id", server_interface_id)
1282                .field("peer_interface_id", peer_interface_id)
1283                .field("peer_ip", peer_ip)
1284                .field("peer_port", peer_port)
1285                .finish(),
1286            Event::BackbonePeerDisconnected {
1287                server_interface_id,
1288                peer_interface_id,
1289                peer_ip,
1290                peer_port,
1291                connected_for,
1292                had_received_data,
1293            } => f
1294                .debug_struct("BackbonePeerDisconnected")
1295                .field("server_interface_id", server_interface_id)
1296                .field("peer_interface_id", peer_interface_id)
1297                .field("peer_ip", peer_ip)
1298                .field("peer_port", peer_port)
1299                .field("connected_for", connected_for)
1300                .field("had_received_data", had_received_data)
1301                .finish(),
1302            Event::BackbonePeerIdleTimeout {
1303                server_interface_id,
1304                peer_interface_id,
1305                peer_ip,
1306                peer_port,
1307                connected_for,
1308            } => f
1309                .debug_struct("BackbonePeerIdleTimeout")
1310                .field("server_interface_id", server_interface_id)
1311                .field("peer_interface_id", peer_interface_id)
1312                .field("peer_ip", peer_ip)
1313                .field("peer_port", peer_port)
1314                .field("connected_for", connected_for)
1315                .finish(),
1316            Event::BackbonePeerWriteStall {
1317                server_interface_id,
1318                peer_interface_id,
1319                peer_ip,
1320                peer_port,
1321                connected_for,
1322            } => f
1323                .debug_struct("BackbonePeerWriteStall")
1324                .field("server_interface_id", server_interface_id)
1325                .field("peer_interface_id", peer_interface_id)
1326                .field("peer_ip", peer_ip)
1327                .field("peer_port", peer_port)
1328                .field("connected_for", connected_for)
1329                .finish(),
1330            Event::BackbonePeerPenalty {
1331                server_interface_id,
1332                peer_ip,
1333                penalty_level,
1334                blacklist_for,
1335            } => f
1336                .debug_struct("BackbonePeerPenalty")
1337                .field("server_interface_id", server_interface_id)
1338                .field("peer_ip", peer_ip)
1339                .field("penalty_level", penalty_level)
1340                .field("blacklist_for", blacklist_for)
1341                .finish(),
1342            Event::LoadHook {
1343                name,
1344                attach_point,
1345                priority,
1346                ..
1347            } => f
1348                .debug_struct("LoadHook")
1349                .field("name", name)
1350                .field("attach_point", attach_point)
1351                .field("priority", priority)
1352                .finish(),
1353            Event::LoadHookFile {
1354                name,
1355                path,
1356                hook_type,
1357                attach_point,
1358                priority,
1359                ..
1360            } => f
1361                .debug_struct("LoadHookFile")
1362                .field("name", name)
1363                .field("path", path)
1364                .field("hook_type", hook_type)
1365                .field("attach_point", attach_point)
1366                .field("priority", priority)
1367                .finish(),
1368            Event::LoadBuiltinHook {
1369                name,
1370                builtin_id,
1371                attach_point,
1372                priority,
1373                ..
1374            } => f
1375                .debug_struct("LoadBuiltinHook")
1376                .field("name", name)
1377                .field("builtin_id", builtin_id)
1378                .field("attach_point", attach_point)
1379                .field("priority", priority)
1380                .finish(),
1381            Event::UnloadHook {
1382                name, attach_point, ..
1383            } => f
1384                .debug_struct("UnloadHook")
1385                .field("name", name)
1386                .field("attach_point", attach_point)
1387                .finish(),
1388            Event::ReloadHook {
1389                name, attach_point, ..
1390            } => f
1391                .debug_struct("ReloadHook")
1392                .field("name", name)
1393                .field("attach_point", attach_point)
1394                .finish(),
1395            Event::ReloadHookFile {
1396                name,
1397                attach_point,
1398                path,
1399                hook_type,
1400                ..
1401            } => f
1402                .debug_struct("ReloadHookFile")
1403                .field("name", name)
1404                .field("attach_point", attach_point)
1405                .field("path", path)
1406                .field("hook_type", hook_type)
1407                .finish(),
1408            Event::ReloadBuiltinHook {
1409                name,
1410                attach_point,
1411                builtin_id,
1412                ..
1413            } => f
1414                .debug_struct("ReloadBuiltinHook")
1415                .field("name", name)
1416                .field("attach_point", attach_point)
1417                .field("builtin_id", builtin_id)
1418                .finish(),
1419            Event::SetHookEnabled {
1420                name,
1421                attach_point,
1422                enabled,
1423                ..
1424            } => f
1425                .debug_struct("SetHookEnabled")
1426                .field("name", name)
1427                .field("attach_point", attach_point)
1428                .field("enabled", enabled)
1429                .finish(),
1430            Event::SetHookPriority {
1431                name,
1432                attach_point,
1433                priority,
1434                ..
1435            } => f
1436                .debug_struct("SetHookPriority")
1437                .field("name", name)
1438                .field("attach_point", attach_point)
1439                .field("priority", priority)
1440                .finish(),
1441            Event::ListHooks { .. } => write!(f, "ListHooks"),
1442        }
1443    }
1444}