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;
6
7use serde::{Deserialize, Serialize};
8use servo_base::generic_channel::{self, GenericReceiver, GenericSender};
9use servo_base::id::WebViewId;
10use servo_url::ImmutableOrigin;
11
12#[derive(Clone, Debug, Deserialize, Serialize)]
13pub struct ClientStorageThreadHandle {
14    sender: GenericSender<ClientStorageThreadMessage>,
15}
16
17impl ClientStorageThreadHandle {
18    pub fn new(sender: GenericSender<ClientStorageThreadMessage>) -> Self {
19        ClientStorageThreadHandle { sender }
20    }
21
22    pub fn obtain_a_storage_bottle_map(
23        &self,
24        storage_type: StorageType,
25        webview: WebViewId,
26        storage_identifier: StorageIdentifier,
27        origin: ImmutableOrigin,
28    ) -> GenericReceiver<Result<StorageProxyMap, String>> {
29        let (sender, receiver) = generic_channel::channel().unwrap();
30        let message = ClientStorageThreadMessage::ObtainBottleMap {
31            storage_type,
32            webview,
33            storage_identifier,
34            origin,
35            sender,
36        };
37        self.sender.send(message).unwrap();
38        receiver
39    }
40
41    pub fn create_database(
42        &self,
43        bottle_id: i64,
44        name: String,
45    ) -> GenericReceiver<Result<PathBuf, String>> {
46        let (sender, receiver) = generic_channel::channel().unwrap();
47        let message = ClientStorageThreadMessage::CreateDatabase {
48            bottle_id,
49            name,
50            sender,
51        };
52        self.sender.send(message).unwrap();
53        receiver
54    }
55
56    pub fn delete_database(
57        &self,
58        bottle_id: i64,
59        name: String,
60    ) -> GenericReceiver<Result<(), String>> {
61        let (sender, receiver) = generic_channel::channel().unwrap();
62        let message = ClientStorageThreadMessage::DeleteDatabase {
63            bottle_id,
64            name,
65            sender,
66        };
67        self.sender.send(message).unwrap();
68        receiver
69    }
70}
71
72impl From<ClientStorageThreadHandle> for GenericSender<ClientStorageThreadMessage> {
73    fn from(handle: ClientStorageThreadHandle) -> Self {
74        handle.sender
75    }
76}
77
78impl Deref for ClientStorageThreadHandle {
79    type Target = GenericSender<ClientStorageThreadMessage>;
80
81    fn deref(&self) -> &Self::Target {
82        &self.sender
83    }
84}
85
86impl DerefMut for ClientStorageThreadHandle {
87    fn deref_mut(&mut self) -> &mut Self::Target {
88        &mut self.sender
89    }
90}
91
92/// <https://storage.spec.whatwg.org/#storage-type>
93#[derive(Debug, Deserialize, Serialize)]
94pub enum StorageType {
95    Local,
96    Session,
97}
98
99impl StorageType {
100    pub fn as_str(&self) -> &str {
101        match self {
102            StorageType::Local => "local",
103            StorageType::Session => "session",
104        }
105    }
106}
107
108/// <https://storage.spec.whatwg.org/#bucket-mode>
109#[derive(Debug, Default, Deserialize, Serialize)]
110pub enum Mode {
111    /// It is initially "best-effort".
112    #[default]
113    BestEffort,
114    Persistent,
115}
116
117impl Mode {
118    pub fn as_str(&self) -> &str {
119        match self {
120            Mode::BestEffort => "best-effort",
121            Mode::Persistent => "persistent",
122        }
123    }
124}
125
126/// <https://storage.spec.whatwg.org/#storage-identifier>
127#[derive(Debug, Deserialize, Serialize)]
128pub enum StorageIdentifier {
129    Caches,
130    IndexedDB,
131    LocalStorage,
132    ServiceWorkerRegistrations,
133    SessionStorage,
134}
135
136impl StorageIdentifier {
137    pub fn as_str(&self) -> &str {
138        match self {
139            StorageIdentifier::Caches => "caches",
140            StorageIdentifier::IndexedDB => "indexeddb",
141            StorageIdentifier::LocalStorage => "localstorage",
142            StorageIdentifier::ServiceWorkerRegistrations => "serviceworkerregistration",
143            StorageIdentifier::SessionStorage => "sessionstorage",
144        }
145    }
146}
147
148#[derive(Debug, Deserialize, Serialize)]
149pub enum CreateBucketError<T> {
150    BucketAlreadyExists,
151    Internal(T),
152}
153
154impl<T> From<T> for CreateBucketError<T> {
155    fn from(err: T) -> Self {
156        CreateBucketError::Internal(err)
157    }
158}
159
160#[derive(Debug, Deserialize, Serialize)]
161pub enum ClientStorageErrorr<T> {
162    BottleAlreadyExists,
163    BucketDoesNotExist,
164    DatabaseAlreadyExists,
165    DatabaseDoesNotExist,
166    DirectoryCreationFailed,
167    DirectoryDeletionFailed,
168    Internal(T),
169}
170
171impl<T> From<T> for ClientStorageErrorr<T> {
172    fn from(err: T) -> Self {
173        ClientStorageErrorr::Internal(err)
174    }
175}
176
177/// <https://storage.spec.whatwg.org/#storage-proxy-map>
178#[derive(Debug, Deserialize, Serialize)]
179pub struct StorageProxyMap {
180    pub bottle_id: i64,
181    pub handle: ClientStorageThreadHandle,
182}
183
184#[derive(Debug, Deserialize, Serialize)]
185pub enum ClientStorageThreadMessage {
186    ObtainBottleMap {
187        storage_type: StorageType,
188        webview: WebViewId,
189        storage_identifier: StorageIdentifier,
190        origin: ImmutableOrigin,
191        sender: GenericSender<Result<StorageProxyMap, String>>,
192    },
193    CreateDatabase {
194        bottle_id: i64,
195        name: String,
196        sender: GenericSender<Result<PathBuf, String>>,
197    },
198    DeleteDatabase {
199        bottle_id: i64,
200        name: String,
201        sender: GenericSender<Result<(), String>>,
202    },
203    /// Send a reply when done cleaning up thread resources and then shut it down
204    Exit(GenericSender<()>),
205}