#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Routing {
Owned,
Delegated,
OpenBootstrap,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Category {
Status,
Config,
Log,
Cache,
HostedStores,
Sync,
Updater,
Pairing,
Peers,
Subscriptions,
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ControlMethod {
Status,
ConfigGet,
ConfigSetUpstream,
LogSetLevel,
CacheGet,
CacheSetCap,
CacheClear,
HostedStoresList,
HostedStoresPin,
HostedStoresUnpin,
HostedStoresStatus,
SyncStatus,
SyncTrigger,
UpdaterStatus,
UpdaterSetChannel,
UpdaterPause,
UpdaterResume,
UpdaterCheckNow,
PairingList,
PairingApprove,
PairingRevoke,
PeerStatus,
PeersConnect,
PeersDisconnect,
Subscribe,
Unsubscribe,
ListSubscriptions,
PairingRequest,
PairingPoll,
}
impl ControlMethod {
pub const fn name(self) -> &'static str {
match self {
ControlMethod::Status => "control.status",
ControlMethod::ConfigGet => "control.config.get",
ControlMethod::ConfigSetUpstream => "control.config.setUpstream",
ControlMethod::LogSetLevel => "control.log.setLevel",
ControlMethod::CacheGet => "control.cache.get",
ControlMethod::CacheSetCap => "control.cache.setCap",
ControlMethod::CacheClear => "control.cache.clear",
ControlMethod::HostedStoresList => "control.hostedStores.list",
ControlMethod::HostedStoresPin => "control.hostedStores.pin",
ControlMethod::HostedStoresUnpin => "control.hostedStores.unpin",
ControlMethod::HostedStoresStatus => "control.hostedStores.status",
ControlMethod::SyncStatus => "control.sync.status",
ControlMethod::SyncTrigger => "control.sync.trigger",
ControlMethod::UpdaterStatus => "control.updater.status",
ControlMethod::UpdaterSetChannel => "control.updater.setChannel",
ControlMethod::UpdaterPause => "control.updater.pause",
ControlMethod::UpdaterResume => "control.updater.resume",
ControlMethod::UpdaterCheckNow => "control.updater.checkNow",
ControlMethod::PairingList => "control.pairing.list",
ControlMethod::PairingApprove => "control.pairing.approve",
ControlMethod::PairingRevoke => "control.pairing.revoke",
ControlMethod::PeerStatus => "control.peerStatus",
ControlMethod::PeersConnect => "control.peers.connect",
ControlMethod::PeersDisconnect => "control.peers.disconnect",
ControlMethod::Subscribe => "control.subscribe",
ControlMethod::Unsubscribe => "control.unsubscribe",
ControlMethod::ListSubscriptions => "control.listSubscriptions",
ControlMethod::PairingRequest => "pairing.request",
ControlMethod::PairingPoll => "pairing.poll",
}
}
pub fn from_name(name: &str) -> Option<ControlMethod> {
ControlMethod::ALL
.iter()
.copied()
.find(|m| m.name() == name)
}
pub const fn requires_auth(self) -> bool {
!matches!(
self,
ControlMethod::PairingRequest | ControlMethod::PairingPoll
)
}
pub const fn is_pairing_admin(self) -> bool {
matches!(
self,
ControlMethod::PairingList
| ControlMethod::PairingApprove
| ControlMethod::PairingRevoke
)
}
pub const fn routing(self) -> Routing {
match self {
ControlMethod::PeerStatus
| ControlMethod::PeersConnect
| ControlMethod::PeersDisconnect
| ControlMethod::Subscribe
| ControlMethod::Unsubscribe
| ControlMethod::ListSubscriptions => Routing::Delegated,
ControlMethod::PairingRequest | ControlMethod::PairingPoll => Routing::OpenBootstrap,
_ => Routing::Owned,
}
}
pub const fn category(self) -> Category {
match self {
ControlMethod::Status => Category::Status,
ControlMethod::ConfigGet | ControlMethod::ConfigSetUpstream => Category::Config,
ControlMethod::LogSetLevel => Category::Log,
ControlMethod::CacheGet | ControlMethod::CacheSetCap | ControlMethod::CacheClear => {
Category::Cache
}
ControlMethod::HostedStoresList
| ControlMethod::HostedStoresPin
| ControlMethod::HostedStoresUnpin
| ControlMethod::HostedStoresStatus => Category::HostedStores,
ControlMethod::SyncStatus | ControlMethod::SyncTrigger => Category::Sync,
ControlMethod::UpdaterStatus
| ControlMethod::UpdaterSetChannel
| ControlMethod::UpdaterPause
| ControlMethod::UpdaterResume
| ControlMethod::UpdaterCheckNow => Category::Updater,
ControlMethod::PairingList
| ControlMethod::PairingApprove
| ControlMethod::PairingRevoke
| ControlMethod::PairingRequest
| ControlMethod::PairingPoll => Category::Pairing,
ControlMethod::PeerStatus
| ControlMethod::PeersConnect
| ControlMethod::PeersDisconnect => Category::Peers,
ControlMethod::Subscribe
| ControlMethod::Unsubscribe
| ControlMethod::ListSubscriptions => Category::Subscriptions,
}
}
pub const fn summary(self) -> &'static str {
match self {
ControlMethod::Status => "A rich node status snapshot (version, uptime, addr, cache, hosted/pinned counts, sync availability).",
ControlMethod::ConfigGet => "The node's effective configuration (addr/port, upstream + override, cache dir/shared, config path, sync availability).",
ControlMethod::ConfigSetUpstream => "Persist an upstream-RPC override; takes effect on next node start (requires_restart).",
ControlMethod::LogSetLevel => "Live-swap the running node's tracing EnvFilter directive (not persisted).",
ControlMethod::CacheGet => "The on-disk content-cache view: cap_bytes, used_bytes, dir, shared.",
ControlMethod::CacheSetCap => "Set the on-disk cache size cap in bytes (floored at 64 MiB).",
ControlMethod::CacheClear => "Delete all locally cached DIG content.",
ControlMethod::HostedStoresList => "Every held/pinned store, merged, with each store's cached capsules and a pinned flag.",
ControlMethod::HostedStoresPin => "Pin a store (storeId[:rootHash]); pre-fetches the capsule when a root is given and §21 sync is available.",
ControlMethod::HostedStoresUnpin => "Unpin a store and evict its cached capsules.",
ControlMethod::HostedStoresStatus => "Per-store status: pinned flag, cached capsules, total bytes.",
ControlMethod::SyncStatus => "Whether authenticated §21 whole-store sync is available, plus pinned-store cache coverage.",
ControlMethod::SyncTrigger => "Trigger a §21 sync for one capsule (storeId + root).",
ControlMethod::UpdaterStatus => "The DIG auto-update beacon's current status (proxied from dig-updater).",
ControlMethod::UpdaterSetChannel => "Set the beacon's update channel (\"nightly\" | \"stable\").",
ControlMethod::UpdaterPause => "Suspend the beacon's auto-updates (optionally until a unix time).",
ControlMethod::UpdaterResume => "Resume the beacon's auto-updates.",
ControlMethod::UpdaterCheckNow => "Force an immediate beacon update check.",
ControlMethod::PairingList => "List pending pairing requests and issued paired tokens (MASTER token only).",
ControlMethod::PairingApprove => "Approve a pending pairing, minting a scoped token (MASTER token only).",
ControlMethod::PairingRevoke => "Revoke an issued paired token by token_id (MASTER token only).",
ControlMethod::PeerStatus => "Live peer-pool + relay-reservation snapshot, including the per-peer connected array.",
ControlMethod::PeersConnect => "Dial a peer by address, or resolve an already-connected peer_id, via the live gossip pool.",
ControlMethod::PeersDisconnect => "Drop a pooled peer by peer_id, closing its mTLS link (idempotent).",
ControlMethod::Subscribe => "Subscribe the node to a store it actively watches and gap-fills.",
ControlMethod::Unsubscribe => "Stop watching a store.",
ControlMethod::ListSubscriptions => "The node's persisted subscription set + count.",
ControlMethod::PairingRequest => "OPEN: request a control-token pairing; returns a pairing_id + pairing_code to compare.",
ControlMethod::PairingPoll => "OPEN: poll a pairing by id; once the operator approves, returns the scoped token once.",
}
}
pub const ALL: &'static [ControlMethod] = &[
ControlMethod::Status,
ControlMethod::ConfigGet,
ControlMethod::ConfigSetUpstream,
ControlMethod::LogSetLevel,
ControlMethod::CacheGet,
ControlMethod::CacheSetCap,
ControlMethod::CacheClear,
ControlMethod::HostedStoresList,
ControlMethod::HostedStoresPin,
ControlMethod::HostedStoresUnpin,
ControlMethod::HostedStoresStatus,
ControlMethod::SyncStatus,
ControlMethod::SyncTrigger,
ControlMethod::UpdaterStatus,
ControlMethod::UpdaterSetChannel,
ControlMethod::UpdaterPause,
ControlMethod::UpdaterResume,
ControlMethod::UpdaterCheckNow,
ControlMethod::PairingList,
ControlMethod::PairingApprove,
ControlMethod::PairingRevoke,
ControlMethod::PeerStatus,
ControlMethod::PeersConnect,
ControlMethod::PeersDisconnect,
ControlMethod::Subscribe,
ControlMethod::Unsubscribe,
ControlMethod::ListSubscriptions,
ControlMethod::PairingRequest,
ControlMethod::PairingPoll,
];
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::BTreeSet;
#[test]
fn every_method_has_a_unique_wire_name() {
let names: BTreeSet<&str> = ControlMethod::ALL.iter().map(|m| m.name()).collect();
assert_eq!(
names.len(),
ControlMethod::ALL.len(),
"duplicate or missing wire names in the catalog"
);
}
#[test]
fn from_name_round_trips_every_method() {
for &m in ControlMethod::ALL {
assert_eq!(ControlMethod::from_name(m.name()), Some(m));
}
assert_eq!(ControlMethod::from_name("control.nope"), None);
assert_eq!(ControlMethod::from_name(""), None);
}
#[test]
fn only_pairing_bootstrap_is_open() {
for &m in ControlMethod::ALL {
let open = matches!(
m,
ControlMethod::PairingRequest | ControlMethod::PairingPoll
);
assert_eq!(m.requires_auth(), !open, "{} auth mismatch", m.name());
assert_eq!(
m.routing() == Routing::OpenBootstrap,
open,
"{} routing mismatch",
m.name()
);
}
}
#[test]
fn pairing_admin_methods_are_exactly_three() {
let admin: Vec<&str> = ControlMethod::ALL
.iter()
.filter(|m| m.is_pairing_admin())
.map(|m| m.name())
.collect();
assert_eq!(
admin,
vec![
"control.pairing.list",
"control.pairing.approve",
"control.pairing.revoke"
]
);
}
#[test]
fn delegated_set_matches_the_engine_surface() {
let delegated: BTreeSet<&str> = ControlMethod::ALL
.iter()
.filter(|m| m.routing() == Routing::Delegated)
.map(|m| m.name())
.collect();
let expected: BTreeSet<&str> = [
"control.peerStatus",
"control.peers.connect",
"control.peers.disconnect",
"control.subscribe",
"control.unsubscribe",
"control.listSubscriptions",
]
.into_iter()
.collect();
assert_eq!(delegated, expected);
}
#[test]
fn every_method_has_a_nonempty_summary() {
for &m in ControlMethod::ALL {
assert!(!m.summary().is_empty(), "{} has no summary", m.name());
}
}
}