makepad_file_protocol/
file_protocol.rs

1use {
2    crate::{
3        makepad_live_id::*,
4        makepad_micro_serde::{SerBin, DeBin, DeBinErr},
5    },
6};
7
8/// Types for the collab protocol.
9/// 
10/// The collab protocol is relatively simple. The collab server can open and close files. Each open
11/// file has a corresponding collaboration session, to/from which clients can add/remove themselves
12/// as participant. When a client requests to open a file, it really requests to be added as a
13/// participant to (the collaboration session of) that file. Similarly, when a client requests to
14/// close a file, it really requests to be removed as a participant from (the collaboration session)
15/// of that file. Files are only opened/closed as necessary, that is, when the first client is added
16/// or the last client removed as a participant.
17/// 
18/// Once the client is a participant for a file, it can request to apply deltas to that file. Deltas
19/// are always applied to a given revision of a file. Because of network latency, different clients
20/// clients may have different revisions of the same file. The server maintains a linear history of
21/// all deltas from the oldest revision to the newest revision. Whenever a delta for an older
22/// revision comes in, it is transformed against these older revisions so it can be applied to the
23/// newest revision. Only when all clients have confirmed that they have seen a revision (by sending
24/// a delta based on that revision) will the server remove that delta from its history.
25/// 
26/// Whenever a server applies a delta to a file, it notifies all the participants of that file
27/// except the one from which the request to apply the delta originated of this fact. This allows
28/// the participants to update their revision of the file accordingly.
29 
30/// A type for representing a request to the collab server.
31#[derive(Clone, Debug, SerBin, DeBin)]
32pub enum FileRequest {
33    /// Requests the collab server to return its file tree. 
34    LoadFileTree{ with_data: bool },
35    /// Requests the collab server to add the client as a participant to the file with the given id.
36    /// If the client is the first participant for the file, this also causes the file to be opened
37    /// on the server.
38    OpenFile{
39        path: String, 
40        id: u64
41    },
42    CreateSnapshot{
43        root: String,
44        message: String,
45    },
46    LoadSnapshotImage{
47        root: String,
48        hash: String,
49    },
50    LoadSnapshot{
51        root: String,
52        hash: String,
53    },
54    SaveSnapshotImage{
55        root: String,
56        hash: String,
57        data: Vec<u8>,
58    },
59    /// Requests the collab server to apply the given delta to the given revision of the file with
60    /// the given id.
61    SaveFile{
62        path: String,
63        data: String,
64        id: u64,
65        patch: bool
66    },
67    Search{
68        id: u64,
69        set: Vec<SearchItem>
70    }
71}
72
73#[derive(Clone, Debug, SerBin, DeBin)]
74pub struct SearchItem{
75    pub needle: String,
76    pub prefixes: Option<Vec<String>>,
77    pub pre_word_boundary: bool,
78    pub post_word_boundary: bool
79}
80
81/// A type for representing either a response or a notification from the collab server.
82#[derive(Clone, Debug, SerBin, DeBin)]
83pub enum FileClientMessage {
84    Response(FileResponse),
85    Notification(FileNotification),
86}
87
88#[derive(Clone, Debug, SerBin, DeBin, PartialEq)]
89pub enum SaveKind{
90    Save,
91    Patch,
92    Observation
93}
94
95/// A type for representing a response from the collab server.
96/// 
97#[derive(Clone, Debug, SerBin, DeBin)]
98pub struct SaveFileResponse{
99    pub path: String, 
100    pub old_data: String, 
101    pub new_data: String, 
102    pub kind: SaveKind,
103    pub id: u64, 
104}
105
106#[derive(Clone, Debug, SerBin, DeBin)]
107pub struct OpenFileResponse{
108    pub path: String, 
109    pub data: String, 
110    pub id: u64, 
111}
112
113#[derive(Clone, Debug, SerBin, DeBin)]
114pub struct LoadSnapshotImageResponse{
115    pub root: String,
116    pub hash: String,
117    pub data: Vec<u8>, 
118}
119
120#[derive(Clone, Debug, SerBin, DeBin)]
121pub struct LoadSnapshotImageError{
122    pub root: String,
123    pub hash: String,
124    pub error: FileError,
125}
126
127
128#[derive(Clone, Debug, SerBin, DeBin)]
129pub struct SaveSnapshotImageResponse{
130    pub root: String,
131    pub hash: String,
132}
133
134
135#[derive(Clone, Debug, SerBin, DeBin)]
136pub struct CreateSnapshotResponse{
137    pub root: String,
138    pub hash: String,
139}
140
141#[derive(Clone, Debug, SerBin, DeBin)]
142pub struct LoadSnapshotResponse{
143    pub root: String,
144    pub hash: String,
145}
146
147
148#[derive(Clone, Debug, SerBin, DeBin)]
149pub struct CreateSnapshotError{
150    pub root: String,
151    pub error:String,
152}
153#[derive(Clone, Debug, SerBin, DeBin)]
154pub struct LoadSnapshotError{
155    pub root: String,
156    pub error:String,
157}
158
159
160/// Each `Response` corresponds to the `Request` with the same name.
161#[derive(Clone, Debug, SerBin, DeBin)]
162pub enum FileResponse {
163    /// The result of requesting the collab server to return its file tree.
164    LoadFileTree(Result<FileTreeData, FileError>),
165    /// The result of requesting the collab server to add the client as a participant to the file
166    /// with the given id.
167    OpenFile(Result<OpenFileResponse, FileError>),
168    /// The result of requesting the collab server to apply a delta to a revision of the file with
169    /// the given id.
170    SaveFile(Result<SaveFileResponse, FileError>),
171    
172    LoadSnapshotImage(Result<LoadSnapshotImageResponse, LoadSnapshotImageError>),
173    SaveSnapshotImage(Result<SaveSnapshotImageResponse, FileError>),
174                
175    CreateSnapshot(Result<CreateSnapshotResponse, CreateSnapshotError>),
176    LoadSnapshot(Result<LoadSnapshotResponse, LoadSnapshotError>),
177    // Existing variants...
178    SearchInProgress(u64)
179}
180
181/// A type for representing data about a file tree.
182#[derive(Clone, Debug, SerBin, DeBin)]
183pub struct FileTreeData {
184    /// The path to the root of this file tree.
185    pub root_path: String,
186    /// Data about the root of this file tree.
187    pub root: FileNodeData,
188}
189
190#[derive(Clone, Debug, SerBin, DeBin)]
191pub struct GitLog{
192    pub root: String,
193    pub commits: Vec<GitCommit>,
194}
195
196#[derive(Clone, Debug, SerBin, DeBin)]
197pub struct GitCommit {
198    pub hash: String,
199    pub message: String,
200}
201
202
203/// A type for representing data about a node in a file tree.
204/// 
205/// Each node is either a directory a file. Directories form the internal nodes of the file tree.
206/// They consist of one or more named entries, each of which is another node. Files form the leaves
207/// of the file tree, and do not contain any further nodes.
208#[derive(Clone, Debug, SerBin, DeBin)]
209pub enum FileNodeData {
210    Directory { git_log: Option<GitLog>, entries: Vec<DirectoryEntry> },
211    File { data: Option<Vec<u8>> },
212}
213
214/// A type for representing an entry in a directory.
215#[derive(Clone, Debug, SerBin, DeBin)]
216pub struct DirectoryEntry {
217    /// The name of this entry.
218    pub name: String,
219    /// The node for this entry.
220    pub node: FileNodeData,
221}
222
223#[derive(Clone, Debug, SerBin, DeBin)]
224pub struct SearchResult{
225    pub file_name: String,
226    pub line: usize,
227    pub column_byte: usize,
228    pub result_line: String,
229}
230
231/// A type for representing a notification from the collab server.
232#[derive(Clone, Debug, SerBin, DeBin)]
233pub enum FileNotification {
234    FileChangedOnDisk(SaveFileResponse),
235    SearchResults{
236        id: u64,
237        results: Vec<SearchResult>
238    }
239    // Notifies the client that another client applied the given delta to the file with the given
240    // id. This is only sent for files for which the client is a participant.
241   // DeltaWasApplied(TextFileId),
242}
243
244/// A type for representing errors from the collab server.
245#[derive(Clone, Debug, SerBin, DeBin)]
246pub enum FileError {
247    Unknown(String),
248    RootNotFound(String),
249    CannotOpen(String),
250}
251
252/// An identifier for files on the collab server.
253#[derive(Clone, Debug, Default, Eq, Hash, Copy, PartialEq, FromLiveId)]
254pub struct TextFileId(pub LiveId);
255
256impl SerBin for TextFileId {
257    fn ser_bin(&self, s: &mut Vec<u8>) {
258        self.0.0.ser_bin(s);
259    }
260}
261
262impl DeBin for TextFileId {
263    fn de_bin(o: &mut usize, d: &[u8]) -> Result<Self, DeBinErr> {
264        Ok(TextFileId(LiveId(DeBin::de_bin(o, d)?)))
265    }
266}