nadisc_runtime/
providers.rs1use nadisc::managed::{
4 Capabilities, DiscoveryError, ErrorCode, EvidenceKind, ManagedProvider, ProviderSnapshot,
5 Result,
6};
7use nadisc::{DiscoveryClient, DnsDiscovery, DnsService, Instance, StaticDiscovery};
8use std::{
9 collections::BTreeMap,
10 sync::atomic::{AtomicBool, Ordering},
11};
12
13enum Backend {
14 Static(StaticDiscovery),
15 Dns(DnsDiscovery),
16}
17
18pub struct LocalProvider {
20 backend: Backend,
21 closed: AtomicBool,
22}
23
24impl LocalProvider {
25 pub fn static_services(services: BTreeMap<String, Vec<Instance>>) -> Result<Self> {
29 let backend = StaticDiscovery::new(services)
30 .map_err(|_| crate::config::invalid("invalid static discovery table"))?;
31 Ok(Self {
32 backend: Backend::Static(backend),
33 closed: AtomicBool::new(false),
34 })
35 }
36
37 pub fn dns_services(services: BTreeMap<String, DnsService>) -> Result<Self> {
41 if services.is_empty() {
42 return Err(crate::config::invalid(
43 "DNS service bindings cannot be empty",
44 ));
45 }
46 let backend = DnsDiscovery::new(services)
47 .map_err(|_| crate::config::invalid("invalid DNS discovery table"))?;
48 Ok(Self {
49 backend: Backend::Dns(backend),
50 closed: AtomicBool::new(false),
51 })
52 }
53
54 fn check(&self) -> Result<()> {
58 if self.closed.load(Ordering::Acquire) {
59 Err(crate::closed())
60 } else {
61 Ok(())
62 }
63 }
64}
65
66#[async_trait::async_trait]
67impl ManagedProvider for LocalProvider {
68 fn capabilities(&self) -> Capabilities {
72 Capabilities {
73 registration: false,
74 enumeration: true,
75 evidence: match self.backend {
76 Backend::Static(_) => EvidenceKind::Static,
77 Backend::Dns(_) => EvidenceKind::Address,
78 },
79 }
80 }
81
82 async fn prepare(&self) -> Result<()> {
86 self.check()
87 }
88
89 async fn observe(&self, service: &str) -> Result<ProviderSnapshot> {
93 self.check()?;
94 let instances = match &self.backend {
95 Backend::Static(provider) => provider.discover_all(service).await,
96 Backend::Dns(provider) => provider.discover_all(service).await,
97 }
98 .map_err(|_| {
99 DiscoveryError::new(ErrorCode::Unavailable, "local provider observation failed")
100 })?;
101 self.check()?;
102 Ok(ProviderSnapshot {
103 instances,
104 evidence: self.capabilities().evidence,
105 })
106 }
107
108 async fn services(&self) -> Result<Vec<String>> {
112 self.check()?;
113 match &self.backend {
114 Backend::Static(provider) => provider.list_services().await,
115 Backend::Dns(provider) => provider.list_services().await,
116 }
117 .map_err(|_| {
118 DiscoveryError::new(ErrorCode::Unavailable, "local service enumeration failed")
119 })
120 }
121
122 async fn close(&self) -> Result<()> {
126 self.closed.store(true, Ordering::Release);
127 Ok(())
128 }
129}