1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
6#[serde(rename_all = "lowercase")]
7pub enum BackendSource {
8 Auto,
10 File,
12 Manual,
14 Env,
16}
17
18impl BackendSource {
19 pub fn as_str(&self) -> &str {
20 match self {
21 BackendSource::Auto => "auto",
22 BackendSource::File => "file",
23 BackendSource::Manual => "manual",
24 BackendSource::Env => "env",
25 }
26 }
27
28 pub fn from_str(s: &str) -> Option<Self> {
29 match s {
30 "auto" => Some(BackendSource::Auto),
31 "file" => Some(BackendSource::File),
32 "manual" => Some(BackendSource::Manual),
33 "env" => Some(BackendSource::Env),
34 _ => None,
35 }
36 }
37}
38
39#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
41pub struct BackendInfo {
42 pub id: String,
44 pub name: String,
46 pub host: String,
48 pub port: u16,
50 pub protocol: String,
52 #[serde(skip_serializing_if = "Option::is_none")]
54 pub description: Option<String>,
55 #[serde(skip_serializing_if = "Option::is_none")]
57 pub namespace: Option<String>,
58 #[serde(skip_serializing_if = "Option::is_none")]
60 pub version: Option<String>,
61 #[serde(skip_serializing_if = "Option::is_none")]
63 pub metadata: Option<String>,
64 pub source: BackendSource,
66 pub is_active: bool,
68 pub registered_at: i64,
70 #[serde(skip_serializing_if = "Option::is_none")]
72 pub last_seen: Option<i64>,
73 pub created_at: i64,
75 pub updated_at: i64,
77}
78
79impl BackendInfo {
80 pub fn url(&self) -> String {
82 format!("{}://{}:{}", self.protocol, self.host, self.port)
83 }
84}
85
86#[derive(Debug, Clone, Deserialize)]
88pub struct BackendConfig {
89 pub name: String,
90 pub host: String,
91 pub port: u16,
92 #[serde(default = "default_protocol")]
93 pub protocol: String,
94 #[serde(default)]
95 pub description: Option<String>,
96 #[serde(default)]
97 pub namespace: Option<String>,
98}
99
100fn default_protocol() -> String {
101 "ws".to_string()
102}
103
104#[derive(Debug, Clone, Deserialize)]
106pub struct RegistryConfig {
107 #[serde(default)]
108 pub backend: Vec<BackendConfig>,
109}
110
111#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
113#[serde(tag = "type")]
114pub enum RegistryEvent {
115 #[serde(rename = "backend_registered")]
117 BackendRegistered { backend: BackendInfo },
118
119 #[serde(rename = "backend_updated")]
121 BackendUpdated { backend: BackendInfo },
122
123 #[serde(rename = "backend_deleted")]
125 BackendDeleted { name: String },
126
127 #[serde(rename = "backends")]
129 Backends { backends: Vec<BackendInfo> },
130
131 #[serde(rename = "backend")]
133 Backend { backend: Option<BackendInfo> },
134
135 #[serde(rename = "ping")]
137 Ping {
138 name: String,
139 success: bool,
140 message: String,
141 },
142
143 #[serde(rename = "reloaded")]
145 Reloaded { count: usize },
146
147 #[serde(rename = "error")]
149 Error { message: String },
150}
151
152#[derive(Debug, Clone)]
154pub struct RegistryStorageConfig {
155 pub db_path: std::path::PathBuf,
157 pub config_path: Option<std::path::PathBuf>,
159}
160
161impl Default for RegistryStorageConfig {
162 fn default() -> Self {
163 let config_dir = dirs::config_dir()
164 .unwrap_or_else(|| std::path::PathBuf::from("."))
165 .join("plexus");
166
167 Self {
168 db_path: config_dir.join("registry.db"),
169 config_path: Some(config_dir.join("backends.toml")),
170 }
171 }
172}