switchgear_service_api/
discovery.rs

1use crate::service::HasServiceErrorSource;
2use async_trait::async_trait;
3use secp256k1::PublicKey;
4use serde::{Deserialize, Serialize};
5use std::collections::BTreeSet;
6use std::error::Error;
7use std::io;
8
9#[async_trait]
10pub trait DiscoveryBackendStore {
11    type Error: Error + Send + Sync + 'static + HasServiceErrorSource;
12
13    async fn get(&self, public_key: &PublicKey) -> Result<Option<DiscoveryBackend>, Self::Error>;
14
15    async fn get_all(&self, etag: Option<u64>) -> Result<DiscoveryBackends, Self::Error>;
16
17    async fn post(&self, backend: DiscoveryBackend) -> Result<Option<PublicKey>, Self::Error>;
18
19    async fn put(&self, backend: DiscoveryBackend) -> Result<bool, Self::Error>;
20
21    async fn patch(&self, backend: DiscoveryBackendPatch) -> Result<bool, Self::Error>;
22
23    async fn delete(&self, public_key: &PublicKey) -> Result<bool, Self::Error>;
24}
25
26#[async_trait]
27pub trait HttpDiscoveryBackendClient: DiscoveryBackendStore {
28    async fn health(&self) -> Result<(), Self::Error>;
29}
30
31#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
32#[serde(rename_all = "camelCase")]
33pub struct DiscoveryBackends {
34    pub etag: u64,
35    pub backends: Option<Vec<DiscoveryBackend>>,
36}
37
38impl DiscoveryBackends {
39    pub fn etag_from_str(etag: &str) -> io::Result<u64> {
40        let etag = hex::decode(etag).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
41        let etag: [u8; 8] = etag.try_into().map_err(|etag: Vec<u8>| {
42            io::Error::new(
43                io::ErrorKind::InvalidData,
44                format!("invalid etag size: {} bytes", etag.len()),
45            )
46        })?;
47        Ok(u64::from_be_bytes(etag))
48    }
49
50    pub fn etag_string(&self) -> String {
51        hex::encode(self.etag.to_be_bytes())
52    }
53}
54
55#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
56#[serde(rename_all = "camelCase")]
57pub struct DiscoveryBackend {
58    pub public_key: PublicKey,
59    #[serde(flatten)]
60    pub backend: DiscoveryBackendSparse,
61}
62
63#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
64#[serde(rename_all = "camelCase")]
65pub struct DiscoveryBackendSparse {
66    #[serde(skip_serializing_if = "Option::is_none")]
67    pub name: Option<String>,
68    pub partitions: BTreeSet<String>,
69    pub weight: usize,
70    pub enabled: bool,
71    #[serde(with = "json_bytes")]
72    pub implementation: Vec<u8>,
73}
74
75mod json_bytes {
76    use serde::{Deserialize, Deserializer, Serialize, Serializer};
77    use serde_json::Value;
78
79    pub fn serialize<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
80    where
81        S: Serializer,
82    {
83        let value: Value = serde_json::from_slice(bytes).map_err(serde::ser::Error::custom)?;
84        value.serialize(serializer)
85    }
86
87    pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
88    where
89        D: Deserializer<'de>,
90    {
91        let value = Value::deserialize(deserializer)?;
92        serde_json::to_vec(&value).map_err(serde::de::Error::custom)
93    }
94}
95
96#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
97#[serde(rename_all = "camelCase")]
98pub struct DiscoveryBackendPatch {
99    pub public_key: PublicKey,
100    #[serde(flatten)]
101    pub backend: DiscoveryBackendPatchSparse,
102}
103
104#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
105#[serde(rename_all = "camelCase")]
106pub struct DiscoveryBackendPatchSparse {
107    #[serde(skip_serializing_if = "Option::is_none")]
108    pub name: Option<Option<String>>,
109    #[serde(skip_serializing_if = "Option::is_none")]
110    pub partitions: Option<BTreeSet<String>>,
111    #[serde(skip_serializing_if = "Option::is_none")]
112    pub weight: Option<usize>,
113    #[serde(skip_serializing_if = "Option::is_none")]
114    pub enabled: Option<bool>,
115}