1use std::collections::HashMap;
4use std::sync::Arc;
5
6use async_trait::async_trait;
7use parking_lot::RwLock;
8
9#[derive(Debug, Clone)]
10pub struct ResolvedTarget {
11 pub host: String,
12 pub port: Option<u16>,
13}
14
15#[derive(Debug, Clone)]
16pub struct Resolved {
17 pub service_name: String,
18 pub addresses: Vec<ResolvedTarget>,
19}
20
21#[async_trait]
22pub trait ServiceDiscovery: Send + Sync + 'static {
23 async fn lookup(&self, service_name: &str) -> Resolved;
24}
25
26#[derive(Default)]
27pub struct StaticDiscovery {
28 services: RwLock<HashMap<String, Vec<ResolvedTarget>>>,
29}
30
31impl StaticDiscovery {
32 pub fn new() -> Arc<Self> {
33 Arc::new(Self::default())
34 }
35
36 pub fn register(&self, name: impl Into<String>, target: ResolvedTarget) {
37 self.services.write().entry(name.into()).or_default().push(target);
38 }
39}
40
41#[async_trait]
42impl ServiceDiscovery for StaticDiscovery {
43 async fn lookup(&self, service_name: &str) -> Resolved {
44 Resolved {
45 service_name: service_name.into(),
46 addresses: self.services.read().get(service_name).cloned().unwrap_or_default(),
47 }
48 }
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54
55 #[tokio::test]
56 async fn static_discovery_resolves() {
57 let d = StaticDiscovery::new();
58 d.register("svc", ResolvedTarget { host: "1.2.3.4".into(), port: Some(8080) });
59 let r = d.lookup("svc").await;
60 assert_eq!(r.addresses.len(), 1);
61 }
62}