Skip to main content

lb_rs/ipc/
protocol.rs

1use std::io;
2
3use serde::{Deserialize, Serialize};
4use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
5use uuid::Uuid;
6
7use crate::model::account::Account;
8use crate::model::api::{
9    AccountFilter, AccountIdentifier, AdminSetUserTierInfo, ServerIndex, StripeAccountTier,
10};
11use crate::model::file::ShareMode;
12use crate::model::file_metadata::{DocumentHmac, FileType};
13use crate::model::path_ops::Filter;
14use crate::service::activity::RankingWeights;
15use crate::service::events::Event;
16
17#[derive(Debug, Serialize, Deserialize)]
18pub enum Frame {
19    Request { seq: u64, body: Request },
20    Response { seq: u64, output: Vec<u8> },
21    Event { stream_seq: u64, body: Event },
22    EventEnd { stream_seq: u64 },
23}
24
25impl Frame {
26    pub async fn read<R: AsyncRead + Unpin>(r: &mut R) -> io::Result<Self> {
27        let mut len_buf = [0u8; 4];
28        r.read_exact(&mut len_buf).await?;
29        let len = u32::from_le_bytes(len_buf) as usize;
30        let mut buf = vec![0u8; len];
31        r.read_exact(&mut buf).await?;
32        bincode::deserialize(&buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
33    }
34
35    pub async fn write<W: AsyncWrite + Unpin>(&self, w: &mut W) -> io::Result<()> {
36        let bytes =
37            bincode::serialize(self).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
38        let len: u32 = bytes.len().try_into().map_err(|_| {
39            io::Error::new(
40                io::ErrorKind::InvalidData,
41                format!("frame {} bytes does not fit in a u32 length prefix", bytes.len()),
42            )
43        })?;
44        w.write_all(&len.to_le_bytes()).await?;
45        w.write_all(&bytes).await?;
46        w.flush().await
47    }
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize)]
51pub enum Request {
52    CreateAccount {
53        username: String,
54        api_url: String,
55        welcome_doc: bool,
56    },
57    ImportAccount {
58        key: String,
59        api_url: Option<String>,
60    },
61    ImportAccountPrivateKeyV1 {
62        account: Account,
63    },
64    ImportAccountPhrase {
65        phrase: Vec<String>,
66        api_url: String,
67    },
68    DeleteAccount,
69    GetAccount,
70
71    SuggestedDocs {
72        settings: RankingWeights,
73    },
74    ClearSuggested,
75    ClearSuggestedId {
76        id: Uuid,
77    },
78    AppForegrounded,
79
80    DisappearAccount {
81        username: String,
82    },
83    DisappearFile {
84        id: Uuid,
85    },
86    ListUsers {
87        filter: Option<AccountFilter>,
88    },
89    GetAccountInfo {
90        identifier: AccountIdentifier,
91    },
92    AdminValidateAccount {
93        username: String,
94    },
95    AdminValidateServer,
96    AdminFileInfo {
97        id: Uuid,
98    },
99    RebuildIndex {
100        index: ServerIndex,
101    },
102    SetUserTier {
103        username: String,
104        info: AdminSetUserTierInfo,
105    },
106
107    UpgradeAccountStripe {
108        account_tier: StripeAccountTier,
109    },
110    UpgradeAccountGooglePlay {
111        purchase_token: String,
112        account_id: String,
113    },
114    UpgradeAccountAppStore {
115        original_transaction_id: String,
116        app_account_token: String,
117    },
118    CancelSubscription,
119    GetSubscriptionInfo,
120
121    #[cfg(not(target_family = "wasm"))]
122    RecentPanic,
123    #[cfg(not(target_family = "wasm"))]
124    WritePanicToFile {
125        error_header: String,
126        bt: String,
127    },
128    #[cfg(not(target_family = "wasm"))]
129    DebugInfo {
130        os_info: String,
131        check_docs: bool,
132    },
133
134    ReadDocument {
135        id: Uuid,
136        user_activity: bool,
137    },
138    WriteDocument {
139        id: Uuid,
140        content: Vec<u8>,
141    },
142    ReadDocumentWithHmac {
143        id: Uuid,
144        user_activity: bool,
145    },
146    SafeWrite {
147        id: Uuid,
148        old_hmac: Option<DocumentHmac>,
149        content: Vec<u8>,
150    },
151
152    CreateFile {
153        name: String,
154        parent: Uuid,
155        file_type: FileType,
156    },
157    RenameFile {
158        id: Uuid,
159        new_name: String,
160    },
161    MoveFile {
162        id: Uuid,
163        new_parent: Uuid,
164    },
165    Delete {
166        id: Uuid,
167    },
168    Root,
169    ListMetadatas,
170    GetChildren {
171        id: Uuid,
172    },
173    GetAndGetChildrenRecursively {
174        id: Uuid,
175    },
176    GetFileById {
177        id: Uuid,
178    },
179    GetFileLinkUrl {
180        id: Uuid,
181    },
182    LocalChanges,
183
184    TestRepoIntegrity {
185        check_docs: bool,
186    },
187
188    CreateLinkAtPath {
189        path: String,
190        target_id: Uuid,
191    },
192    CreateAtPath {
193        path: String,
194    },
195    GetByPath {
196        path: String,
197    },
198    GetPathById {
199        id: Uuid,
200    },
201    ListPaths {
202        filter: Option<Filter>,
203    },
204    ListPathsWithIds {
205        filter: Option<Filter>,
206    },
207
208    ShareFile {
209        id: Uuid,
210        username: String,
211        mode: ShareMode,
212    },
213    GetPendingShares,
214    GetPendingShareFiles,
215    KnownUsernames,
216    RejectShare {
217        id: Uuid,
218    },
219
220    PinFile {
221        id: Uuid,
222    },
223    UnpinFile {
224        id: Uuid,
225    },
226    ListPinned,
227
228    GetUsage,
229
230    Sync,
231    Status,
232    GetLastSynced,
233    GetLastSyncedHuman,
234    Subscribe,
235}
236
237#[cfg(test)]
238mod tests {
239    use super::*;
240    use tokio::io::duplex;
241
242    #[tokio::test]
243    async fn frame_round_trip() {
244        let (mut a, mut b) = duplex(64 * 1024);
245        let frame = Frame::Request { seq: 7, body: Request::Sync };
246        frame.write(&mut a).await.unwrap();
247        let got = Frame::read(&mut b).await.unwrap();
248        assert!(matches!(got, Frame::Request { seq: 7, body: Request::Sync }));
249    }
250}