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