1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
7#[serde(tag = "type", content = "data")]
8pub enum ClientMessage {
9 Authenticate {
11 tenant_id: String,
12 client_version: String,
13 #[serde(flatten)]
14 credentials: AuthCredentials,
15 },
16
17 CreateTenant {
19 tenant_id: String,
20 tenant_name: String,
21 },
22
23 DeleteTenant { tenant_id: String },
25
26 CreateService {
28 tenant_id: String,
29 service_name: String,
30 },
31
32 GetService {
34 tenant_id: String,
35 service_name: String,
36 },
37
38 DeleteService {
40 tenant_id: String,
41 service_name: String,
42 },
43
44 AllocateVariable {
46 service_id: String,
47 variable_name: String,
48 initial_data: Vec<u8>,
49 },
50
51 ReadVariable {
53 service_id: String,
54 variable_name: String,
55 },
56
57 WriteVariable {
59 service_id: String,
60 variable_name: String,
61 data: Vec<u8>,
62 },
63
64 DeallocateVariable {
66 service_id: String,
67 variable_name: String,
68 },
69
70 Subscribe {
72 service_id: String,
73 variable_name: String,
74 },
75
76 Unsubscribe {
78 service_id: String,
79 variable_name: String,
80 },
81
82 Heartbeat { client_id: String },
84
85 Disconnect { client_id: String },
87
88 GetServiceFilePath {
90 tenant_id: String,
91 service_name: String,
92 },
93
94 ReportVariableChanges {
96 service_id: String,
97 changed_variables: Vec<String>,
98 new_values: Vec<(String, Vec<u8>)>,
99 },
100}
101
102#[derive(Debug, Clone, Serialize, Deserialize)]
104#[serde(tag = "type", content = "data")]
105pub enum ServerMessage {
106 AuthenticationResult {
108 success: bool,
109 message: String,
110 server_version: String,
111 #[serde(skip_serializing_if = "Option::is_none")]
112 permissions: Option<Vec<String>>,
113 },
114
115 Service {
117 service_id: String,
118 service_name: String,
119 tenant_id: String,
120 #[serde(skip_serializing_if = "Option::is_none")]
121 file_path: Option<String>,
122 },
123
124 Tenant {
126 tenant_id: String,
127 tenant_name: String,
128 },
129
130 TenantResult {
132 success: bool,
133 tenant_id: String,
134 message: String,
135 },
136
137 VariableData {
139 service_id: String,
140 variable_name: String,
141 data: Vec<u8>,
142 version: u64,
143 },
144
145 VariableChanged {
147 service_id: String,
148 variable_name: String,
149 data: Vec<u8>,
150 version: u64,
151 },
152
153 Result {
155 request_id: String,
156 success: bool,
157 message: String,
158 },
159
160 Error { code: ErrorCode, message: String },
162
163 Disconnected { reason: String },
165
166 ServiceFilePath {
168 service_id: String,
169 file_path: String,
170 file_size: u64,
171 },
172
173 VariableChangesAcknowledged {
175 service_id: String,
176 changed_variables: Vec<String>,
177 },
178
179 Heartbeat { timestamp: String },
181}
182
183#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
185#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
186pub enum ErrorCode {
187 NotFound,
189 PermissionDenied,
191 Unauthorized,
193 AlreadyExists,
195 InvalidRequest,
197 InternalError,
199 ConnectionLost,
201 Timeout,
203}
204
205#[derive(Debug, Clone, Serialize, Deserialize)]
207#[serde(tag = "method")]
208pub enum AuthCredentials {
209 #[serde(rename = "api_key")]
211 ApiKey { key: String },
212
213 #[serde(rename = "jwt")]
215 Jwt { token: String },
216
217 #[serde(rename = "basic")]
219 Basic { username: String, password: String },
220
221 #[serde(rename = "custom")]
223 Custom { data: serde_json::Value },
224}
225
226#[derive(Debug, Clone, Serialize, Deserialize)]
228pub struct ServiceMetadata {
229 pub service_id: String,
230 pub service_name: String,
231 pub tenant_id: String,
232 pub created_at: chrono::DateTime<chrono::Utc>,
233 pub file_path: Option<String>,
234}
235
236#[derive(Debug, Clone, Serialize, Deserialize)]
238pub struct VariableMetadata {
239 pub name: String,
240 pub service_id: String,
241 pub offset: u64,
242 pub size: u64,
243 pub version: u64,
244 pub created_at: chrono::DateTime<chrono::Utc>,
245}
246
247#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
249pub enum Permission {
250 Read,
251 Write,
252 Admin,
253 Execute,
254}
255
256impl From<ErrorCode> for crate::error::CommyError {
258 fn from(code: ErrorCode) -> Self {
259 match code {
260 ErrorCode::NotFound => {
261 crate::error::CommyError::NotFound("Resource not found".to_string())
262 }
263 ErrorCode::PermissionDenied => {
264 crate::error::CommyError::PermissionDenied("Permission denied".to_string())
265 }
266 ErrorCode::Unauthorized => {
267 crate::error::CommyError::Unauthorized("Unauthorized".to_string())
268 }
269 ErrorCode::AlreadyExists => {
270 crate::error::CommyError::AlreadyExists("Resource already exists".to_string())
271 }
272 ErrorCode::InvalidRequest => {
273 crate::error::CommyError::InvalidRequest("Invalid request".to_string())
274 }
275 ErrorCode::InternalError => {
276 crate::error::CommyError::Other("Internal server error".to_string())
277 }
278 ErrorCode::ConnectionLost => {
279 crate::error::CommyError::ConnectionLost("Connection lost".to_string())
280 }
281 ErrorCode::Timeout => crate::error::CommyError::Timeout,
282 }
283 }
284}