Skip to main content

storage_traits/
client_storage.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4use std::ops::{Deref, DerefMut};
5use std::path::PathBuf;
6use std::str::FromStr;
7
8use malloc_size_of_derive::MallocSizeOf;
9use serde::{Deserialize, Serialize};
10use servo_base::generic_channel::{
11    self, GenericCallback, GenericReceiver, GenericSender, SendResult,
12};
13use servo_base::id::WebViewId;
14use servo_url::ImmutableOrigin;
15
16#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
17pub struct ClientStorageThreadHandle {
18    sender: GenericSender<ClientStorageThreadMessage>,
19}
20
21impl ClientStorageThreadHandle {
22    pub fn new(sender: GenericSender<ClientStorageThreadMessage>) -> Self {
23        ClientStorageThreadHandle { sender }
24    }
25
26    pub fn obtain_a_storage_bottle_map(
27        &self,
28        storage_type: StorageType,
29        webview: Option<WebViewId>,
30        storage_identifier: StorageIdentifier,
31        origin: ImmutableOrigin,
32    ) -> GenericReceiver<Result<StorageProxyMap, String>> {
33        let (sender, receiver) = generic_channel::channel().unwrap();
34        let message = ClientStorageThreadMessage::ObtainBottleMap {
35            storage_type,
36            webview,
37            storage_identifier,
38            origin,
39            sender,
40        };
41        self.sender.send(message).unwrap();
42        receiver
43    }
44
45    pub fn create_database(
46        &self,
47        bottle_id: i64,
48        name: String,
49    ) -> GenericReceiver<Result<(PathBuf, bool), String>> {
50        let (sender, receiver) = generic_channel::channel().unwrap();
51        let message = ClientStorageThreadMessage::CreateDatabase {
52            bottle_id,
53            name,
54            sender,
55        };
56        self.sender.send(message).unwrap();
57        receiver
58    }
59
60    pub fn delete_database(
61        &self,
62        bottle_id: i64,
63        name: String,
64    ) -> GenericReceiver<Result<(), String>> {
65        let (sender, receiver) = generic_channel::channel().unwrap();
66        let message = ClientStorageThreadMessage::DeleteDatabase {
67            bottle_id,
68            name,
69            sender,
70        };
71        self.sender.send(message).unwrap();
72        receiver
73    }
74
75    pub fn persisted(
76        &self,
77        origin: ImmutableOrigin,
78        sender: GenericCallback<Result<bool, String>>,
79    ) -> SendResult {
80        self.sender
81            .send(ClientStorageThreadMessage::Persisted { origin, sender })
82    }
83
84    pub fn persist(
85        &self,
86        origin: ImmutableOrigin,
87        permission_granted: bool,
88        sender: GenericCallback<Result<bool, String>>,
89    ) -> SendResult {
90        self.sender.send(ClientStorageThreadMessage::Persist {
91            origin,
92            permission_granted,
93            sender,
94        })
95    }
96
97    pub fn estimate(
98        &self,
99        origin: ImmutableOrigin,
100        sender: GenericCallback<Result<(u64, u64), String>>,
101    ) -> SendResult {
102        self.sender
103            .send(ClientStorageThreadMessage::Estimate { origin, sender })
104    }
105}
106
107impl From<ClientStorageThreadHandle> for GenericSender<ClientStorageThreadMessage> {
108    fn from(handle: ClientStorageThreadHandle) -> Self {
109        handle.sender
110    }
111}
112
113impl From<GenericSender<ClientStorageThreadMessage>> for ClientStorageThreadHandle {
114    fn from(sender: GenericSender<ClientStorageThreadMessage>) -> Self {
115        ClientStorageThreadHandle::new(sender)
116    }
117}
118
119impl Deref for ClientStorageThreadHandle {
120    type Target = GenericSender<ClientStorageThreadMessage>;
121
122    fn deref(&self) -> &Self::Target {
123        &self.sender
124    }
125}
126
127impl DerefMut for ClientStorageThreadHandle {
128    fn deref_mut(&mut self) -> &mut Self::Target {
129        &mut self.sender
130    }
131}
132
133/// <https://storage.spec.whatwg.org/#storage-type>
134#[derive(Debug, Deserialize, Serialize)]
135pub enum StorageType {
136    Local,
137    Session,
138}
139
140impl StorageType {
141    pub fn as_str(&self) -> &str {
142        match self {
143            StorageType::Local => "local",
144            StorageType::Session => "session",
145        }
146    }
147}
148
149/// <https://storage.spec.whatwg.org/#bucket-mode>
150#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
151pub enum Mode {
152    /// It is initially "best-effort".
153    #[default]
154    BestEffort,
155    Persistent,
156}
157
158impl Mode {
159    pub fn as_str(&self) -> &str {
160        match self {
161            Mode::BestEffort => "best-effort",
162            Mode::Persistent => "persistent",
163        }
164    }
165}
166
167impl FromStr for Mode {
168    type Err = ();
169
170    /// <https://storage.spec.whatwg.org/#bucket-mode>
171    fn from_str(value: &str) -> Result<Self, Self::Err> {
172        match value {
173            "best-effort" => Ok(Mode::BestEffort),
174            "persistent" => Ok(Mode::Persistent),
175            _ => Err(()),
176        }
177    }
178}
179
180/// <https://storage.spec.whatwg.org/#storage-identifier>
181#[derive(Debug, Deserialize, Serialize)]
182pub enum StorageIdentifier {
183    Caches,
184    IndexedDB,
185    LocalStorage,
186    ServiceWorkerRegistrations,
187    SessionStorage,
188}
189
190impl StorageIdentifier {
191    pub fn as_str(&self) -> &str {
192        match self {
193            StorageIdentifier::Caches => "caches",
194            StorageIdentifier::IndexedDB => "indexeddb",
195            StorageIdentifier::LocalStorage => "localstorage",
196            StorageIdentifier::ServiceWorkerRegistrations => "serviceworkerregistration",
197            StorageIdentifier::SessionStorage => "sessionstorage",
198        }
199    }
200}
201
202#[derive(Debug, Deserialize, Serialize)]
203pub enum CreateBucketError<T> {
204    BucketAlreadyExists,
205    Internal(T),
206}
207
208impl<T> From<T> for CreateBucketError<T> {
209    fn from(err: T) -> Self {
210        CreateBucketError::Internal(err)
211    }
212}
213
214#[derive(Debug, Deserialize, Serialize)]
215pub enum ClientStorageErrorr<T> {
216    BottleAlreadyExists,
217    BucketDoesNotExist,
218    DatabaseAlreadyExists,
219    DatabaseDoesNotExist,
220    DirectoryCreationFailed,
221    DirectoryDeletionFailed,
222    SessionStorageRequiresWindow,
223    Internal(T),
224}
225
226impl<T> From<T> for ClientStorageErrorr<T> {
227    fn from(err: T) -> Self {
228        ClientStorageErrorr::Internal(err)
229    }
230}
231
232/// <https://storage.spec.whatwg.org/#storage-proxy-map>
233#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
234pub struct StorageProxyMap {
235    pub bottle_id: i64,
236    pub handle: ClientStorageThreadHandle,
237}
238
239#[derive(Debug, Deserialize, Serialize)]
240pub enum ClientStorageThreadMessage {
241    ObtainBottleMap {
242        storage_type: StorageType,
243        webview: Option<WebViewId>,
244        storage_identifier: StorageIdentifier,
245        origin: ImmutableOrigin,
246        sender: GenericSender<Result<StorageProxyMap, String>>,
247    },
248    CreateDatabase {
249        bottle_id: i64,
250        name: String,
251        /// Boolean stands for "created".
252        sender: GenericSender<Result<(PathBuf, bool), String>>,
253    },
254    DeleteDatabase {
255        bottle_id: i64,
256        name: String,
257        sender: GenericSender<Result<(), String>>,
258    },
259    Persisted {
260        origin: ImmutableOrigin,
261        sender: GenericCallback<Result<bool, String>>,
262    },
263    Persist {
264        origin: ImmutableOrigin,
265        permission_granted: bool,
266        sender: GenericCallback<Result<bool, String>>,
267    },
268    Estimate {
269        origin: ImmutableOrigin,
270        sender: GenericCallback<Result<(u64, u64), String>>,
271    },
272    Exit(GenericSender<()>),
273}