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