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> {
32 let backend = StaticDiscovery::new(services)
33 .map_err(|_| crate::config::invalid("invalid static discovery table"))?;
34 Ok(Self {
35 backend: Backend::Static(backend),
36 closed: AtomicBool::new(false),
37 })
38 }
39
40 pub fn dns_services(services: BTreeMap<String, DnsService>) -> Result<Self> {
47 if services.is_empty() {
48 return Err(crate::config::invalid(
49 "DNS service bindings cannot be empty",
50 ));
51 }
52 let backend = DnsDiscovery::new(services)
53 .map_err(|_| crate::config::invalid("invalid DNS discovery table"))?;
54 Ok(Self {
55 backend: Backend::Dns(backend),
56 closed: AtomicBool::new(false),
57 })
58 }
59
60 fn check(&self) -> Result<()> {
66 if self.closed.load(Ordering::Acquire) {
67 Err(crate::closed())
68 } else {
69 Ok(())
70 }
71 }
72}
73
74#[async_trait::async_trait]
75impl ManagedProvider for LocalProvider {
76 fn capabilities(&self) -> Capabilities {
82 Capabilities {
83 registration: false,
84 enumeration: true,
85 evidence: match self.backend {
86 Backend::Static(_) => EvidenceKind::Static,
87 Backend::Dns(_) => EvidenceKind::Address,
88 },
89 }
90 }
91
92 async fn prepare(&self) -> Result<()> {
98 self.check()
99 }
100
101 async fn observe(&self, service: &str) -> Result<ProviderSnapshot> {
108 self.check()?;
109 let instances = match &self.backend {
110 Backend::Static(provider) => provider.discover_all(service).await,
111 Backend::Dns(provider) => provider.discover_all(service).await,
112 }
113 .map_err(|_| {
114 DiscoveryError::new(ErrorCode::Unavailable, "local provider observation failed")
115 })?;
116 self.check()?;
117 Ok(ProviderSnapshot {
118 instances,
119 evidence: self.capabilities().evidence,
120 })
121 }
122
123 async fn services(&self) -> Result<Vec<String>> {
129 self.check()?;
130 match &self.backend {
131 Backend::Static(provider) => provider.list_services().await,
132 Backend::Dns(provider) => provider.list_services().await,
133 }
134 .map_err(|_| {
135 DiscoveryError::new(ErrorCode::Unavailable, "local service enumeration failed")
136 })
137 }
138
139 async fn close(&self) -> Result<()> {
145 self.closed.store(true, Ordering::Release);
146 Ok(())
147 }
148}