Skip to main content

koi_common/
mdns_protocol.rs

1//! mDNS registration/admin **wire-contract** types.
2//!
3//! These are the shapes exchanged between the daemon (which produces them in
4//! `koi-mdns`'s HTTP/NDJSON handlers) and clients that consume them (`koi-client`,
5//! external API consumers). They live in the kernel — alongside [`crate::types`] and
6//! [`crate::pipeline`] — so a client can speak the contract without depending on the
7//! mDNS engine. `koi-mdns` re-exports them from its `protocol` module.
8
9use std::collections::HashMap;
10
11use serde::{Deserialize, Serialize};
12use utoipa::ToSchema;
13
14/// Payload for registering a new service.
15#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, ToSchema)]
16pub struct RegisterPayload {
17    pub name: String,
18    #[serde(rename = "type")]
19    pub service_type: String,
20    pub port: u16,
21    /// Pin the A/AAAA record to a specific IP address.
22    /// When absent, all machine IPs are advertised (auto-detect).
23    #[serde(default)]
24    #[serde(skip_serializing_if = "Option::is_none")]
25    pub ip: Option<String>,
26    #[serde(default)]
27    #[serde(skip_serializing_if = "Option::is_none")]
28    pub lease_secs: Option<u64>,
29    #[serde(default)]
30    pub txt: HashMap<String, String>,
31}
32
33/// Result of a successful registration.
34#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, ToSchema)]
35pub struct RegistrationResult {
36    pub id: String,
37    pub name: String,
38    #[serde(rename = "type")]
39    pub service_type: String,
40    pub port: u16,
41    pub mode: LeaseMode,
42    #[serde(skip_serializing_if = "Option::is_none")]
43    pub lease_secs: Option<u64>,
44}
45
46/// Result of a successful lease renewal (heartbeat).
47#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, ToSchema)]
48pub struct RenewalResult {
49    pub id: String,
50    pub lease_secs: u64,
51}
52
53/// How a registration stays alive (wire representation).
54#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, ToSchema)]
55#[serde(rename_all = "lowercase")]
56pub enum LeaseMode {
57    Session,
58    Heartbeat,
59    Permanent,
60}
61
62/// Wire-level registration state (display-only projection).
63#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, ToSchema)]
64#[serde(rename_all = "lowercase")]
65pub enum LeaseState {
66    Alive,
67    Draining,
68}
69
70/// Full registration state as exposed to admin queries.
71#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
72pub struct AdminRegistration {
73    pub id: String,
74    pub name: String,
75    #[serde(rename = "type")]
76    pub service_type: String,
77    pub port: u16,
78    pub mode: LeaseMode,
79    pub state: LeaseState,
80    #[serde(skip_serializing_if = "Option::is_none")]
81    pub lease_secs: Option<u64>,
82    #[serde(skip_serializing_if = "Option::is_none")]
83    pub remaining_secs: Option<u64>,
84    pub grace_secs: u64,
85    #[serde(skip_serializing_if = "Option::is_none")]
86    pub session_id: Option<String>,
87    pub registered_at: String,
88    pub last_seen: String,
89    #[serde(default)]
90    pub txt: HashMap<String, String>,
91}
92
93/// Daemon status overview for admin queries.
94#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
95pub struct DaemonStatus {
96    pub version: String,
97    pub uptime_secs: u64,
98    pub platform: String,
99    pub registrations: RegistrationCounts,
100}
101
102/// Registration counts by state.
103#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
104pub struct RegistrationCounts {
105    pub alive: usize,
106    pub draining: usize,
107    pub permanent: usize,
108    pub total: usize,
109}