Skip to main content

computer_protocol/
transfer.rs

1use serde::{Deserialize, Serialize};
2
3/// Skipped entries a reply or an archive lists before it only counts the rest.
4pub const MAX_LISTED_SKIPS: usize = 50;
5
6/// Name of the last archive entry, which carries the sender's [`SkipList`] as JSON.
7pub const SKIP_REPORT_ENTRY: &str = ".computerd-skipped";
8
9/// Query of `POST /sessions/{id}/files/upload`. The body is a tar archive.
10#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
11pub struct UploadQuery {
12    /// Where the archive's root lands on the computer.
13    pub path: String,
14    /// Replace files that already exist. Folders merge.
15    #[serde(default)]
16    pub overwrite: bool,
17}
18
19/// Body of `POST /sessions/{id}/files/upload-check`, sent before the data so a refusal arrives at once.
20#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
21pub struct UploadCheck {
22    pub path: String,
23    #[serde(default)]
24    pub overwrite: bool,
25    /// Name the root will have in the archive.
26    pub name: String,
27    /// Whether the root is a folder, not a file.
28    pub folder: bool,
29}
30
31/// Body of `POST /sessions/{id}/files/download`. The reply body is a tar archive.
32#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
33pub struct DownloadRequest {
34    /// File or folder on the computer to send.
35    pub path: String,
36}
37
38/// One entry a transfer left out, and why.
39#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
40pub struct Skipped {
41    pub path: String,
42    pub reason: String,
43}
44
45/// The first skipped entries and how many more there were.
46#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
47pub struct SkipList {
48    pub entries: Vec<Skipped>,
49    pub omitted: u64,
50}
51
52impl SkipList {
53    pub fn push(&mut self, path: impl Into<String>, reason: impl Into<String>) {
54        if self.entries.len() < MAX_LISTED_SKIPS {
55            self.entries.push(Skipped {
56                path: path.into(),
57                reason: reason.into(),
58            });
59        } else {
60            self.omitted += 1;
61        }
62    }
63
64    /// Adds the entries of `other` after this list's own.
65    pub fn merge(&mut self, other: Self) {
66        self.omitted += other.omitted;
67        for entry in other.entries {
68            self.push(entry.path, entry.reason);
69        }
70    }
71
72    #[must_use]
73    pub fn is_empty(&self) -> bool {
74        self.entries.is_empty() && self.omitted == 0
75    }
76}
77
78/// What a finished transfer put in place.
79#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
80pub struct TransferReply {
81    /// Final path of the file or folder that was created or merged into.
82    pub path: String,
83    pub files: u64,
84    pub folders: u64,
85    /// File content bytes written.
86    pub bytes: u64,
87    pub skipped: SkipList,
88}