syncthing_types/
events.rs

1use crate::{DeviceID, Timestamp};
2use crate::{FileName, Folder, FolderName};
3use serde::{Deserialize, Serialize};
4use serde_json::value::RawValue;
5use std::collections::HashMap;
6
7//FIXME: complete
8#[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, //FIXME: use enum
27}
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, //FIXME: use enum
164    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, //FIXME: use enum
184    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, //FIXME: use enum
194    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, //FIXME: use enum
205    #[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, //FIXME: use enum
211}
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, //FIXME: use enum
240    #[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}