mutant_protocol/
lib.rs

1use base64::DecodeError;
2use serde::{Deserialize, Serialize};
3use std::future::Future;
4use std::pin::Pin;
5use std::sync::Arc;
6use thiserror::Error;
7use uuid::Uuid;
8
9pub fn add(left: u64, right: u64) -> u64 {
10    left + right
11}
12
13#[cfg(test)]
14mod tests {
15    use super::*;
16
17    #[test]
18    fn it_works() {
19        let result = add(2, 2);
20        assert_eq!(result, 4);
21    }
22}
23
24// --- Event System Definitions ---
25
26/// Callback type used during `get` operations to report progress and allow cancellation.
27///
28/// The callback receives `GetEvent` variants and returns a `Future` that resolves to:
29/// - `Ok(true)`: Continue the operation.
30/// - `Ok(false)`: Cancel the operation (results in `Error::OperationCancelled`).
31/// - `Err(e)`: Propagate an error from the callback.
32pub type GetCallback = Arc<
33    dyn Fn(
34            GetEvent,
35        ) -> Pin<
36            Box<
37                dyn Future<Output = Result<bool, Box<dyn std::error::Error + Send + Sync>>>
38                    + Send
39                    + Sync,
40            >,
41        > + Send
42        + Sync,
43>;
44
45/// Callback type used during initialization (`init`) operations to report progress
46/// and handle interactive prompts.
47///
48/// The callback receives `InitProgressEvent` variants and returns a `Future` that resolves to:
49/// - `Ok(Some(true))`: User confirmed action (e.g., create remote index).
50/// - `Ok(Some(false))`: User denied action.
51/// - `Ok(None)`: Event acknowledged, no specific user action required.
52/// - `Err(e)`: Propagate an error from the callback.
53pub type InitCallback = Box<
54    dyn Fn(
55            InitProgressEvent,
56        ) -> Pin<
57            Box<
58                dyn Future<Output = Result<Option<bool>, Box<dyn std::error::Error + Send + Sync>>>
59                    + Send
60                    + Sync,
61            >,
62        > + Send
63        + Sync,
64>;
65
66/// Callback type used during `purge` operations to report progress and allow cancellation.
67///
68/// The callback receives `PurgeEvent` variants and returns a `Future` that resolves to:
69/// - `Ok(true)`: Continue the operation.
70/// - `Ok(false)`: Cancel the operation (results in `Error::OperationCancelled`).
71/// - `Err(e)`: Propagate an error from the callback.
72pub type PurgeCallback = Arc<
73    dyn Fn(
74            PurgeEvent,
75        ) -> Pin<
76            Box<
77                dyn Future<Output = Result<bool, Box<dyn std::error::Error + Send + Sync>>>
78                    + Send
79                    + Sync,
80            >,
81        > + Send
82        + Sync,
83>;
84
85/// Callback type used during `sync` operations to report progress and allow cancellation.
86///
87/// The callback receives `SyncEvent` variants and returns a `Future` that resolves to:
88/// - `Ok(true)`: Continue the operation.
89/// - `Ok(false)`: Cancel the operation (results in `Error::OperationCancelled`).
90/// - `Err(e)`: Propagate an error from the callback.
91pub type SyncCallback = Arc<
92    dyn Fn(
93            SyncEvent,
94        ) -> Pin<
95            Box<
96                dyn Future<Output = Result<bool, Box<dyn std::error::Error + Send + Sync>>>
97                    + Send
98                    + Sync,
99            >,
100        > + Send
101        + Sync,
102>;
103
104/// Callback type used during `health_check` operations to report progress and allow cancellation.
105///
106/// The callback receives `HealthCheckEvent` variants and returns a `Future` that resolves to:
107/// - `Ok(true)`: Continue the operation.
108/// - `Ok(false)`: Cancel the operation (results in `Error::OperationCancelled`).
109/// - `Err(e)`: Propagate an error from the callback.
110pub type HealthCheckCallback = Arc<
111    dyn Fn(
112            HealthCheckEvent,
113        ) -> Pin<
114            Box<
115                dyn Future<Output = Result<bool, Box<dyn std::error::Error + Send + Sync>>>
116                    + Send
117                    + Sync,
118            >,
119        > + Send
120        + Sync,
121>;
122
123/// Events emitted during a `get` operation.
124#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
125pub enum GetEvent {
126    /// Indicates the start of the `get` operation.
127    Starting {
128        /// Total number of pads (chunks) to be fetched.
129        total_chunks: usize,
130    },
131    /// Indicates that a single pad (chunk) has been fetched.
132    PadFetched,
133    /// Indicates that the `get` operation has completed successfully.
134    Complete,
135}
136
137/// Events emitted during an `init` (initialization) operation.
138#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
139pub enum InitProgressEvent {
140    /// Indicates the start of the initialization process.
141    Starting {
142        /// An estimated total number of steps for the initialization.
143        total_steps: u64,
144    },
145
146    /// Reports progress on a specific step during initialization.
147    Step {
148        /// The current step number.
149        step: u64,
150        /// A message describing the current step.
151        message: String,
152    },
153
154    /// Indicates that user confirmation is required to create a remote index.
155    /// The `InitCallback` should return `Ok(Some(true))` to proceed or `Ok(Some(false))` to skip.
156    PromptCreateRemoteIndex,
157
158    /// Indicates that the initialization process has failed.
159    Failed {
160        /// A message describing the failure.
161        error_msg: String,
162    },
163
164    /// Indicates that the initialization process has completed successfully.
165    Complete {
166        /// A final message summarizing the outcome.
167        message: String,
168    },
169}
170
171/// Events emitted during a `purge` operation (storage cleanup/verification).
172#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
173pub enum PurgeEvent {
174    /// Indicates the start of the `purge` operation.
175    Starting {
176        /// Total number of pads to be processed.
177        total_count: usize,
178    },
179
180    /// Indicates that a single pad has been processed (verified or marked for cleanup).
181    PadProcessed,
182
183    /// Indicates that the `purge` operation has completed.
184    Complete {
185        /// Number of pads successfully verified.
186        verified_count: usize,
187        /// Number of pads that failed verification or encountered errors.
188        failed_count: usize,
189    },
190}
191
192/// Events emitted during a `sync` operation.
193#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
194pub enum SyncEvent {
195    /// Indicates the remote index is being fetched.
196    FetchingRemoteIndex,
197
198    /// Indicates that the remote index is being merged with the local index.
199    Merging,
200
201    /// Indicates that the remote index is being pushed to the network.
202    PushingRemoteIndex,
203
204    /// Indicates that the remote index is being Verified.
205    VerifyingRemoteIndex,
206
207    /// Indicates that the `sync` operation has completed successfully.
208    Complete,
209}
210
211/// Events emitted during a `health_check` operation.
212#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
213pub enum HealthCheckEvent {
214    /// Indicates the start of the `health_check` operation.
215    Starting {
216        /// Total number of keys to be checked.
217        total_keys: usize,
218    },
219
220    /// Indicates that a key has been processed
221    KeyProcessed,
222
223    /// Indicates that the `health_check` operation has completed successfully.
224    Complete {
225        /// Number of keys marked for reupload
226        nb_keys_updated: usize,
227    },
228}
229
230// --- Task Management System Definitions ---
231
232pub type TaskId = Uuid;
233
234#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
235pub enum TaskType {
236    Put,
237    Get,
238    Sync,
239    Purge,
240    HealthCheck,
241    Rm,
242}
243
244#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
245pub enum TaskStatus {
246    Stopped,
247    Pending,
248    InProgress,
249    Completed,
250    Failed,
251}
252
253#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
254pub enum PutEvent {
255    Starting {
256        total_chunks: usize,
257        initial_written_count: usize,
258        initial_confirmed_count: usize,
259        chunks_to_reserve: usize,
260    },
261    PadReserved,
262    PadsWritten,
263    PadsConfirmed,
264    Complete,
265}
266
267pub type PutCallback = Arc<
268    dyn Fn(
269            PutEvent,
270        ) -> Pin<
271            Box<
272                dyn Future<Output = Result<bool, Box<dyn std::error::Error + Send + Sync>>>
273                    + Send
274                    + Sync,
275            >,
276        > + Send
277        + Sync,
278>;
279
280#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
281pub enum TaskProgress {
282    Put(PutEvent),
283    Get(GetEvent),
284    Sync(SyncEvent),
285    Purge(PurgeEvent),
286    HealthCheck(HealthCheckEvent),
287}
288
289#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
290pub enum TaskResult {
291    Pending,
292    Error(String),
293    Result(TaskResultType),
294}
295
296#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
297pub enum TaskResultType {
298    Put(PutResult),
299    Get(GetResult),
300    Sync(SyncResult),
301    Purge(PurgeResult),
302    HealthCheck(HealthCheckResult),
303}
304
305/// Represents the final result of a successful `put` operation.
306#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
307pub struct PutResult {
308    /// The public address of the key, if it's a public key
309    pub public_address: Option<String>,
310}
311
312#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
313pub struct Task {
314    pub id: TaskId,
315    pub task_type: TaskType,
316    pub status: TaskStatus,
317    pub progress: Option<TaskProgress>,
318    pub result: TaskResult,
319    pub key: Option<String>, // The key this task is operating on, if any
320}
321
322// --- Protocol Definitions (Requests & Responses) ---
323
324// --- Incoming Requests ---
325
326#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
327pub struct PutRequest {
328    pub user_key: String,
329    pub source_path: String, // Path to the file on the daemon's filesystem
330    pub mode: StorageMode,
331    pub public: bool,
332    pub no_verify: bool,
333}
334
335#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
336pub struct GetRequest {
337    pub user_key: String,
338    pub destination_path: String, // Path where the fetched file should be saved on the daemon
339    pub public: bool,
340}
341
342#[derive(Deserialize, Debug, PartialEq, Eq, Serialize, Clone)]
343pub struct QueryTaskRequest {
344    pub task_id: Uuid,
345}
346
347#[derive(Deserialize, Debug, PartialEq, Eq, Serialize, Clone)]
348pub struct ListTasksRequest;
349
350#[derive(Deserialize, Debug, PartialEq, Eq, Serialize, Clone)]
351pub struct StopTaskRequest {
352    pub task_id: Uuid,
353}
354
355#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
356pub struct RmRequest {
357    pub user_key: String,
358}
359
360#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
361pub struct ListKeysRequest;
362
363#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
364pub struct PurgeRequest {
365    pub aggressive: bool,
366}
367
368/// Represents all possible requests the client can send to the daemon.
369#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
370#[serde(tag = "type")]
371pub enum Request {
372    Put(PutRequest),
373    Get(GetRequest),
374    QueryTask(QueryTaskRequest),
375    ListTasks(ListTasksRequest),
376    StopTask(StopTaskRequest),
377    Rm(RmRequest),
378    ListKeys(ListKeysRequest),
379    Stats(StatsRequest),
380    Sync(SyncRequest),
381    Purge(PurgeRequest),
382    Import(ImportRequest),
383    Export(ExportRequest),
384    HealthCheck(HealthCheckRequest),
385}
386
387// --- Outgoing Responses ---
388
389#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
390pub struct TaskCreatedResponse {
391    pub task_id: Uuid,
392}
393
394#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
395pub struct TaskUpdateResponse {
396    pub task_id: TaskId,
397    pub status: TaskStatus,
398    pub progress: Option<TaskProgress>,
399}
400
401#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
402pub struct TaskResultResponse {
403    pub task_id: Uuid,
404    pub status: TaskStatus,
405    pub result: TaskResult,
406}
407
408#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
409pub struct TaskStoppedResponse {
410    pub task_id: Uuid,
411}
412
413#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
414pub struct TaskListEntry {
415    pub task_id: Uuid,
416    pub task_type: TaskType,
417    pub status: TaskStatus,
418}
419
420#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
421pub struct TaskListResponse {
422    pub tasks: Vec<TaskListEntry>,
423}
424
425#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
426pub struct ErrorResponse {
427    pub error: String,
428    pub original_request: Option<String>, // Optional original request string for context
429}
430
431#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
432pub struct RmSuccessResponse {
433    pub user_key: String,
434}
435
436/// Detailed information about a single stored key.
437#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
438pub struct KeyDetails {
439    pub key: String,
440    pub total_size: usize,
441    pub pad_count: usize,
442    pub confirmed_pads: usize,
443    pub is_public: bool,
444    pub public_address: Option<String>, // hex representation
445}
446
447#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
448pub struct ListKeysResponse {
449    pub keys: Vec<KeyDetails>,
450}
451
452// Add these structs
453#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
454pub struct StatsRequest {}
455
456#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
457pub struct StatsResponse {
458    pub total_keys: u64,
459    pub total_pads: u64,
460    pub occupied_pads: u64,
461    pub free_pads: u64,
462    pub pending_verify_pads: u64,
463}
464// End of added structs
465
466#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
467pub struct SyncRequest {
468    pub push_force: bool,
469}
470
471#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
472pub struct SyncResponse {
473    pub result: SyncResult,
474}
475
476#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
477pub struct SyncResult {
478    pub nb_keys_added: usize,
479    pub nb_keys_updated: usize,
480    pub nb_free_pads_added: usize,
481    pub nb_pending_pads_added: usize,
482}
483
484/// Represents the final result of a successful `get` operation.
485#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
486pub struct GetResult {
487    /// Total size of the retrieved data in bytes.
488    pub size: usize,
489}
490
491#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
492pub struct PurgeResponse {
493    pub result: PurgeResult,
494}
495
496#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
497pub struct PurgeResult {
498    pub nb_pads_purged: usize,
499}
500
501#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
502pub struct ImportRequest {
503    pub file_path: String,
504}
505
506#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
507pub struct ImportResponse {
508    pub result: ImportResult,
509}
510
511#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
512pub struct ImportResult {
513    pub nb_keys_imported: usize,
514}
515
516#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
517pub struct ExportRequest {
518    pub destination_path: String,
519}
520
521#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
522pub struct ExportResponse {
523    pub result: ExportResult,
524}
525
526#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
527pub struct ExportResult {
528    pub nb_keys_exported: usize,
529}
530
531#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
532pub struct HealthCheckRequest {
533    pub key_name: String,
534    pub recycle: bool,
535}
536
537#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
538pub struct HealthCheckResponse {
539    pub result: HealthCheckResult,
540}
541
542#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
543pub struct HealthCheckResult {
544    pub nb_keys_reset: usize,
545    pub nb_keys_recycled: usize,
546}
547
548/// Represents all possible responses the daemon can send to the client.
549#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
550#[serde(tag = "type")]
551pub enum Response {
552    Error(ErrorResponse),
553    TaskCreated(TaskCreatedResponse),
554    TaskUpdate(TaskUpdateResponse),
555    TaskResult(TaskResultResponse),
556    TaskStopped(TaskStoppedResponse),
557    TaskList(TaskListResponse),
558    RmSuccess(RmSuccessResponse),
559    ListKeys(ListKeysResponse),
560    Stats(StatsResponse),
561    Import(ImportResponse),
562    Export(ExportResponse),
563}
564
565// Helper moved to where Response is used (client/server)
566// // Helper to create an ErrorResponse
567// impl Response {
568//     pub fn error(msg: String, original_request: Option<String>) -> Self {
569//         Response::Error(ErrorResponse {
570//             error: msg,
571//             original_request,
572//         })
573//     }
574// }
575
576// --- Protocol Error Definition ---
577
578#[derive(Error, Debug)]
579pub enum ProtocolError {
580    #[error("JSON serialization error: {0}")]
581    Serialization(#[from] serde_json::Error),
582
583    // Separate deserialization for potentially better client-side error handling
584    #[error("JSON deserialization error: {0}")]
585    Deserialization(serde_json::Error),
586
587    #[error("Base64 decoding error: {0}")]
588    Base64Decode(#[from] DecodeError),
589
590    #[error("Task not found: {0}")]
591    TaskNotFound(Uuid),
592
593    #[error("Invalid request format: {0}")]
594    InvalidRequest(String),
595
596    #[error("Internal server error: {0}")] // Generic for server-side issues
597    InternalError(String),
598
599    #[error("WebSocket error: {0}")] // Can be used by both client/server
600    WebSocket(String),
601}
602
603pub const LIGHTEST_SCRATCHPAD_SIZE: usize = 512 * 1024;
604pub const LIGHT_SCRATCHPAD_SIZE: usize = 1 * 1024 * 1024;
605pub const MEDIUM_SCRATCHPAD_SIZE: usize = 2 * 1024 * 1024;
606pub const HEAVY_SCRATCHPAD_SIZE: usize = 3 * 1024 * 1024;
607pub const HEAVIEST_SCRATCHPAD_SIZE: usize = (4 * 1024 * 1024) - 4096;
608
609#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
610pub enum StorageMode {
611    /// 0.5 MB per scratchpad
612    Lightest,
613    /// 1 MB per scratchpad
614    Light,
615    /// 2 MB per scratchpad
616    Medium,
617    /// 3 MB per scratchpad
618    Heavy,
619    /// 4 MB per scratchpad
620    Heaviest,
621}
622
623impl StorageMode {
624    pub fn scratchpad_size(&self) -> usize {
625        match self {
626            StorageMode::Lightest => LIGHTEST_SCRATCHPAD_SIZE,
627            StorageMode::Light => LIGHT_SCRATCHPAD_SIZE,
628            StorageMode::Medium => MEDIUM_SCRATCHPAD_SIZE,
629            StorageMode::Heavy => HEAVY_SCRATCHPAD_SIZE,
630            StorageMode::Heaviest => HEAVIEST_SCRATCHPAD_SIZE,
631        }
632    }
633}