syncthing_types/
events.rs

1use crate::DeviceID;
2use crate::{FileName, Folder, FolderName};
3use serde::{Deserialize, Serialize};
4use serde_json::value::RawValue;
5use std::collections::HashMap;
6
7//FIXME: complete
8#[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, //FIXME: use enum
25}
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, //FIXME: use enum
147    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, //FIXME: use enum
165    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, //FIXME: use enum
174    pub action: ItemAction,
175}
176
177#[derive(Debug, Deserialize)]
178pub struct ListenAddressesChangedEvent {}
179
180#[derive(Debug, Deserialize)]
181pub struct LocalChangeDetectedEvent {
182    pub action: String, //FIXME: use enum
183    #[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, //FIXME: use enum
189}
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, //FIXME: use enum
214    #[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}