Skip to main content

plexus_registry/
types.rs

1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3
4/// Source of a backend registration
5#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
6#[serde(rename_all = "lowercase")]
7pub enum BackendSource {
8    /// Automatically registered (self-registration at startup)
9    Auto,
10    /// Loaded from config file
11    File,
12    /// Manually registered via RPC
13    Manual,
14    /// Loaded from environment variable
15    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/// Backend connection information
40#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
41pub struct BackendInfo {
42    /// Unique identifier (UUID)
43    pub id: String,
44    /// Human-readable name (unique)
45    pub name: String,
46    /// Host address
47    pub host: String,
48    /// Port number
49    pub port: u16,
50    /// Protocol (ws or wss)
51    pub protocol: String,
52    /// Optional description
53    #[serde(skip_serializing_if = "Option::is_none")]
54    pub description: Option<String>,
55    /// Optional routing namespace
56    #[serde(skip_serializing_if = "Option::is_none")]
57    pub namespace: Option<String>,
58    /// Plexus version (from hash)
59    #[serde(skip_serializing_if = "Option::is_none")]
60    pub version: Option<String>,
61    /// JSON metadata (extensibility)
62    #[serde(skip_serializing_if = "Option::is_none")]
63    pub metadata: Option<String>,
64    /// Source of registration
65    pub source: BackendSource,
66    /// Whether this backend is active
67    pub is_active: bool,
68    /// Timestamp when registered (Unix seconds)
69    pub registered_at: i64,
70    /// Timestamp when last seen (Unix seconds, for health checks)
71    #[serde(skip_serializing_if = "Option::is_none")]
72    pub last_seen: Option<i64>,
73    /// Timestamp when created (Unix seconds)
74    pub created_at: i64,
75    /// Timestamp when last updated (Unix seconds)
76    pub updated_at: i64,
77}
78
79impl BackendInfo {
80    /// Build WebSocket URL from backend info
81    pub fn url(&self) -> String {
82        format!("{}://{}:{}", self.protocol, self.host, self.port)
83    }
84}
85
86/// Configuration for a backend from TOML file
87#[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/// Registry configuration from TOML file
105#[derive(Debug, Clone, Deserialize)]
106pub struct RegistryConfig {
107    #[serde(default)]
108    pub backend: Vec<BackendConfig>,
109}
110
111/// Events emitted by registry methods
112#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
113#[serde(tag = "type")]
114pub enum RegistryEvent {
115    /// Backend was registered
116    #[serde(rename = "backend_registered")]
117    BackendRegistered { backend: BackendInfo },
118
119    /// Backend was updated
120    #[serde(rename = "backend_updated")]
121    BackendUpdated { backend: BackendInfo },
122
123    /// Backend was deleted
124    #[serde(rename = "backend_deleted")]
125    BackendDeleted { name: String },
126
127    /// List of backends
128    #[serde(rename = "backends")]
129    Backends { backends: Vec<BackendInfo> },
130
131    /// Single backend info
132    #[serde(rename = "backend")]
133    Backend { backend: Option<BackendInfo> },
134
135    /// Ping response
136    #[serde(rename = "ping")]
137    Ping {
138        name: String,
139        success: bool,
140        message: String,
141    },
142
143    /// Config reloaded
144    #[serde(rename = "reloaded")]
145    Reloaded { count: usize },
146
147    /// Error occurred
148    #[serde(rename = "error")]
149    Error { message: String },
150}
151
152/// Configuration for Registry storage
153#[derive(Debug, Clone)]
154pub struct RegistryStorageConfig {
155    /// Path to SQLite database
156    pub db_path: std::path::PathBuf,
157    /// Optional path to TOML config file
158    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}