1use crate::DeviceID;
2use crate::{FileName, Folder, FolderName};
3use serde::{Deserialize, Serialize};
4use serde_json::value::RawValue;
5use std::collections::HashMap;
6
7#[derive(Debug, Deserialize)]
9pub struct ConfigSavedEvent {
10 #[serde(rename = "Version")]
11 pub version: u64,
12}
13
14#[derive(Debug, Deserialize)]
15#[serde(rename_all(deserialize = "camelCase"))]
16pub struct DeviceConnectedEvent {
17 pub addr: String,
18 #[serde(rename = "id")]
19 pub device_id: DeviceID,
20 pub device_name: String,
21 pub client_name: String,
22 pub client_version: String,
23 #[serde(rename = "type")]
24 pub client_type: String, }
26
27#[derive(Debug, Deserialize)]
28pub struct DeviceDisconnectedEvent {
29 #[serde(rename = "id")]
30 pub device_id: DeviceID,
31 pub error: String,
32}
33
34#[derive(Debug, Deserialize)]
35pub struct DeviceDiscoveredEvent {
36 #[serde(rename = "device")]
37 pub device_id: DeviceID,
38 pub addrs: Vec<String>,
39}
40
41#[derive(Debug, Deserialize)]
42pub struct DevicePausedEvent {
43 #[serde(rename = "device")]
44 pub device_id: DeviceID,
45}
46
47#[derive(Debug, Deserialize)]
48pub struct DeviceRejectedEvent {
49 #[serde(rename = "device")]
50 pub device_id: DeviceID,
51 pub name: String,
52 pub address: String,
53}
54
55#[derive(Debug, Deserialize)]
56pub struct DeviceResumedEvent {
57 #[serde(rename = "device")]
58 pub device_id: DeviceID,
59}
60
61#[derive(Debug, Deserialize)]
62pub struct ClusterConfigReceivedEvent {
63 #[serde(rename = "device")]
64 pub device_id: DeviceID,
65}
66
67#[derive(Debug, Deserialize)]
68#[serde(rename_all(deserialize = "camelCase"))]
69pub struct FolderCompletionEvent {
70 #[serde(rename = "device")]
71 pub device_id: DeviceID,
72 #[serde(rename = "folder")]
73 pub folder_id: String,
74 pub completion: f64,
75 pub global_bytes: u64,
76 pub need_bytes: u64,
77 pub need_deletes: u64,
78 pub need_items: u64,
79}
80
81#[derive(Debug, Deserialize)]
82pub struct FolderErrorsEvent {
83 pub folder: String,
84 pub errors: Vec<FolderError>,
85}
86
87#[derive(Debug, Deserialize)]
88pub struct FolderError {
89 pub error: String,
90 pub path: String,
91}
92
93#[derive(Debug, Deserialize)]
94pub struct FolderRejectedEvent {
95 #[serde(rename = "device")]
96 pub device_id: DeviceID,
97 #[serde(rename = "folder")]
98 pub folder_id: String,
99 #[serde(rename = "folderLabel")]
100 pub folder_label: String,
101}
102
103#[derive(Debug, Deserialize)]
104pub struct FolderScanProgressEvent {
105 pub total: u64,
106 pub rate: u64,
107 pub current: u64,
108 #[serde(rename = "folder")]
109 pub folder_id: String,
110}
111
112#[derive(Debug, Deserialize)]
113pub struct FolderSummaryEvent {
114 pub folder: String,
115 pub summary: FolderSummaryData,
116}
117
118#[derive(Debug, Deserialize)]
119#[serde(rename_all(deserialize = "camelCase"))]
120pub struct FolderSummaryData {
121 pub global_bytes: u64,
122 pub global_deleted: u64,
123 pub global_directories: u64,
124 pub global_files: u64,
125 pub global_symlinks: u64,
126 pub global_total_items: u64,
127 pub ignore_patterns: bool,
128 pub in_sync_bytes: u64,
129 pub in_sync_files: u64,
130 pub invalid: Option<String>,
131 pub local_bytes: u64,
132 pub local_deleted: u64,
133 pub local_directories: u64,
134 pub local_files: u64,
135 pub local_symlinks: u64,
136 pub local_total_items: u64,
137 pub need_bytes: u64,
138 pub need_deletes: u64,
139 pub need_directories: u64,
140 pub need_files: u64,
141 pub need_symlinks: u64,
142 pub need_total_items: u64,
143 pub pull_errors: u64,
144 pub sequence: u64,
145 pub state: String,
146 pub state_changed: String, pub version: u64,
148}
149
150#[derive(Debug, Deserialize)]
151#[serde(rename_all(deserialize = "lowercase"))]
152pub enum ItemAction {
153 Update,
154 Metadata,
155 Delete,
156}
157
158#[derive(Debug, Deserialize)]
159pub struct ItemFinishedEvent {
160 pub item: String,
161 pub folder: String,
162 pub error: Option<String>,
163 #[serde(rename = "type")]
164 pub item_type: String, pub action: ItemAction,
166}
167
168#[derive(Debug, Deserialize)]
169pub struct ItemStartedEvent {
170 pub item: String,
171 pub folder: String,
172 #[serde(rename = "type")]
173 pub item_type: String, pub action: ItemAction,
175}
176
177#[derive(Debug, Deserialize)]
178pub struct ListenAddressesChangedEvent {}
179
180#[derive(Debug, Deserialize)]
181pub struct LocalChangeDetectedEvent {
182 pub action: String, #[serde(rename = "folderID")]
184 pub folder_id: String,
185 pub label: String,
186 pub path: String,
187 #[serde(rename = "type")]
188 pub item_type: String, }
190
191#[derive(Debug, Deserialize)]
192pub struct LocalIndexUpdatedEvent {
193 #[serde(rename = "folder")]
194 pub folder_id: String,
195 pub items: u64,
196 pub version: u64,
197 pub filenames: Vec<FileName>,
198}
199
200#[derive(Debug, Deserialize)]
201pub struct LoginAttemptEvent {
202 pub username: String,
203 pub success: bool,
204}
205#[derive(Debug, Deserialize)]
206pub struct RemoteChangeDetectedEvent {
207 pub action: String,
208 #[serde(rename = "folderID")]
209 pub folder_id: String,
210 pub label: String,
211 pub path: String,
212 #[serde(rename = "type")]
213 pub item_type: String, #[serde(rename = "modifiedBy")]
215 pub modified_by: String,
216}
217
218#[derive(Debug, Deserialize)]
219pub struct RemoteDownloadProgressEvent {
220 #[serde(rename = "device")]
221 pub device_id: DeviceID,
222 pub folder: String,
223 pub state: HashMap<FileName, u64>,
224}
225
226#[derive(Debug, Deserialize)]
227pub struct RemoteIndexUpdatedEvent {
228 #[serde(rename = "device")]
229 pub device_id: DeviceID,
230 #[serde(rename = "folder")]
231 pub folder_id: String,
232 pub items: u64,
233 pub version: u64,
234}
235
236#[derive(Debug, Deserialize)]
237pub struct StartingEvent {
238 #[serde(rename = "myID")]
239 pub device_id: DeviceID,
240 pub home: String,
241}
242
243#[derive(Debug, Deserialize)]
244#[serde(rename_all(deserialize = "kebab-case"))]
245pub enum FolderState {
246 Idle,
247 Scanning,
248 ScanWaiting,
249 SyncWaiting,
250 SyncPreparing,
251 Syncing,
252 Cleaning,
253 CleanWaiting,
254 Error,
255 Unknown,
256}
257
258#[derive(Debug, Deserialize)]
259pub struct StateChangedEvent {
260 #[serde(rename = "folder")]
261 pub folder_id: String,
262 pub duration: Option<f64>,
263 pub from: FolderState,
264 pub to: FolderState,
265 pub error: Option<String>,
266}
267
268#[derive(Debug, Deserialize)]
269pub enum EventData {
270 ConfigSaved(ConfigSavedEvent),
271 DeviceConnected(DeviceConnectedEvent),
272 DeviceDisconnected(DeviceDisconnectedEvent),
273 DeviceDiscovered(DeviceDiscoveredEvent),
274 DevicePaused(DevicePausedEvent),
275 DeviceRejected(DeviceRejectedEvent),
276 DeviceResumed(DeviceResumedEvent),
277 ClusterConfigReceived(ClusterConfigReceivedEvent),
278 DownloadProgress(HashMap<FolderName, Folder>),
279 FolderCompletion(FolderCompletionEvent),
280 FolderErrors(FolderErrorsEvent),
281 FolderRejected(FolderRejectedEvent),
282 FolderScanProgress(FolderScanProgressEvent),
283 FolderSummary(Box<FolderSummaryEvent>),
284 ItemFinished(ItemFinishedEvent),
285 ItemStarted(ItemStartedEvent),
286 ListenAddressesChanged(ListenAddressesChangedEvent),
287 LocalChangeDetected(LocalChangeDetectedEvent),
288 LocalIndexUpdated(LocalIndexUpdatedEvent),
289 LoginAttempt(LoginAttemptEvent),
290 RemoteChangeDetected(RemoteChangeDetectedEvent),
291 RemoteDownloadProgress(RemoteDownloadProgressEvent),
292 RemoteIndexUpdated(RemoteIndexUpdatedEvent),
293 Starting(StartingEvent),
294 StartupComplete,
295 StateChanged(StateChangedEvent),
296}
297
298#[derive(Debug, Deserialize)]
299pub(super) struct RawEvent {
300 pub id: u64,
301 #[serde(rename = "globalID")]
302 pub global_id: u64,
303 #[serde(rename = "type")]
304 pub event_type: EventType,
305 pub time: String,
306 pub data: Box<RawValue>,
307}
308
309#[derive(Debug, Copy, Clone, PartialEq, Deserialize, Serialize)]
310#[non_exhaustive]
311pub enum EventType {
312 ConfigSaved,
313 DeviceConnected,
314 DeviceDisconnected,
315 DeviceDiscovered,
316 DevicePaused,
317 DeviceRejected,
318 DeviceResumed,
319 ClusterConfigReceived,
320 DownloadProgress,
321 FolderCompletion,
322 FolderErrors,
323 FolderRejected,
324 FolderScanProgress,
325 FolderSummary,
326 ItemFinished,
327 ItemStarted,
328 ListenAddressesChanged,
329 LocalChangeDetected,
330 LocalIndexUpdated,
331 LoginAttempt,
332 RemoteChangeDetected,
333 RemoteDownloadProgress,
334 RemoteIndexUpdated,
335 Starting,
336 StartupComplete,
337 StateChanged,
338}
339
340#[derive(Debug, Deserialize)]
341#[serde(try_from = "RawEvent")]
342pub struct Event {
343 pub id: u64,
344 pub global_id: u64,
345 pub time: String,
346 pub data: EventData,
347}
348
349impl core::convert::TryFrom<RawEvent> for Event {
350 type Error = serde_json::Error;
351
352 fn try_from(raw_event: RawEvent) -> Result<Self, Self::Error> {
353 use EventData::*;
354 let RawEvent {
355 id,
356 global_id,
357 event_type,
358 time,
359 data,
360 } = raw_event;
361 let data = data.get();
362 Ok(Event {
363 id,
364 global_id,
365 time,
366 data: match event_type {
367 EventType::ConfigSaved => ConfigSaved(serde_json::from_str(data)?),
368 EventType::DeviceConnected => DeviceConnected(serde_json::from_str(data)?),
369 EventType::DeviceDisconnected => DeviceDisconnected(serde_json::from_str(data)?),
370 EventType::DeviceDiscovered => DeviceDiscovered(serde_json::from_str(data)?),
371 EventType::DevicePaused => DevicePaused(serde_json::from_str(data)?),
372 EventType::DeviceRejected => DeviceRejected(serde_json::from_str(data)?),
373 EventType::DeviceResumed => DeviceResumed(serde_json::from_str(data)?),
374 EventType::DownloadProgress => DownloadProgress(serde_json::from_str(data)?),
375 EventType::FolderCompletion => FolderCompletion(serde_json::from_str(data)?),
376 EventType::FolderErrors => FolderErrors(serde_json::from_str(data)?),
377 EventType::FolderRejected => FolderRejected(serde_json::from_str(data)?),
378 EventType::FolderScanProgress => FolderScanProgress(serde_json::from_str(data)?),
379 EventType::FolderSummary => FolderSummary(serde_json::from_str(data)?),
380 EventType::ItemFinished => ItemFinished(serde_json::from_str(data)?),
381 EventType::ItemStarted => ItemStarted(serde_json::from_str(data)?),
382 EventType::ListenAddressesChanged => {
383 ListenAddressesChanged(serde_json::from_str(data)?)
384 }
385 EventType::LocalChangeDetected => LocalChangeDetected(serde_json::from_str(data)?),
386 EventType::LocalIndexUpdated => LocalIndexUpdated(serde_json::from_str(data)?),
387 EventType::LoginAttempt => LoginAttempt(serde_json::from_str(data)?),
388 EventType::RemoteChangeDetected => {
389 RemoteChangeDetected(serde_json::from_str(data)?)
390 }
391 EventType::RemoteDownloadProgress => {
392 RemoteDownloadProgress(serde_json::from_str(data)?)
393 }
394 EventType::RemoteIndexUpdated => RemoteIndexUpdated(serde_json::from_str(data)?),
395 EventType::Starting => Starting(serde_json::from_str(data)?),
396 EventType::StartupComplete => StartupComplete,
397 EventType::StateChanged => StateChanged(serde_json::from_str(data)?),
398 EventType::ClusterConfigReceived => {
399 ClusterConfigReceived(serde_json::from_str(data)?)
400 }
401 },
402 })
403 }
404}