webext_storage/
error.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 http://mozilla.org/MPL/2.0/. */
4
5use error_support::{ErrorHandling, GetErrorHandling};
6// reexport logging helpers.
7pub use error_support::{debug, error, info, trace, warn};
8
9use interrupt_support::Interrupted;
10use std::fmt;
11
12/// Result enum used by all implementation functions in this crate.
13/// These will be automagically turned into `WebExtStorageApiError` at the
14/// FFI layer.
15pub type Result<T> = std::result::Result<T, Error>;
16
17#[derive(Debug, Clone, Copy)]
18pub enum QuotaReason {
19    TotalBytes,
20    ItemBytes,
21    MaxItems,
22}
23
24impl fmt::Display for QuotaReason {
25    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26        match self {
27            QuotaReason::ItemBytes => write!(f, "ItemBytes"),
28            QuotaReason::MaxItems => write!(f, "MaxItems"),
29            QuotaReason::TotalBytes => write!(f, "TotalBytes"),
30        }
31    }
32}
33
34#[derive(Debug, thiserror::Error)]
35pub enum WebExtStorageApiError {
36    #[error("Unexpected webext-storage error: {reason}")]
37    UnexpectedError { reason: String },
38
39    #[error("Error parsing JSON data: {reason}")]
40    JsonError { reason: String },
41
42    #[error("Quota exceeded: {reason}")]
43    QuotaError { reason: QuotaReason },
44}
45
46#[derive(Debug, thiserror::Error)]
47pub enum Error {
48    #[error("Quota exceeded: {0:?}")]
49    QuotaError(QuotaReason),
50
51    #[error("Error parsing JSON data: {0}")]
52    JsonError(#[from] serde_json::Error),
53
54    #[error("Error executing SQL: {0}")]
55    SqlError(#[from] rusqlite::Error),
56
57    #[error("A connection of this type is already open")]
58    ConnectionAlreadyOpen,
59
60    #[error("An invalid connection type was specified")]
61    InvalidConnectionType,
62
63    #[error("IO error: {0}")]
64    IoError(#[from] std::io::Error),
65
66    #[error("Operation interrupted")]
67    InterruptedError(#[from] Interrupted),
68
69    #[error("Tried to close connection on wrong StorageApi instance")]
70    WrongApiForClose,
71
72    // This will happen if you provide something absurd like
73    // "/" or "" as your database path. For more subtley broken paths,
74    // we'll likely return an IoError.
75    #[error("Illegal database path: {0:?}")]
76    IllegalDatabasePath(std::path::PathBuf),
77
78    #[error("UTF8 Error: {0}")]
79    Utf8Error(#[from] std::str::Utf8Error),
80
81    #[error("Error opening database: {0}")]
82    OpenDatabaseError(#[from] sql_support::open_database::Error),
83
84    // When trying to close a connection but we aren't the exclusive owner of the containing Arc<>
85    #[error("Other shared references to this connection are alive")]
86    OtherConnectionReferencesExist,
87
88    #[error("The storage database has been closed")]
89    DatabaseConnectionClosed,
90
91    #[error("Sync Error: {0}")]
92    SyncError(String),
93}
94
95impl From<sql_support::path::Error> for Error {
96    fn from(e: sql_support::path::Error) -> Self {
97        match e {
98            sql_support::path::Error::IllegalDatabasePath(path) => Error::IllegalDatabasePath(path),
99            sql_support::path::Error::IoError(e) => Error::IoError(e),
100        }
101    }
102}
103
104impl GetErrorHandling for Error {
105    type ExternalError = WebExtStorageApiError;
106
107    fn get_error_handling(&self) -> ErrorHandling<Self::ExternalError> {
108        match self {
109            Error::QuotaError(reason) => {
110                info!("webext-storage-quota-error");
111                ErrorHandling::convert(WebExtStorageApiError::QuotaError { reason: *reason })
112            }
113            Error::JsonError(e) => {
114                info!("webext-storage-json-error");
115                ErrorHandling::convert(WebExtStorageApiError::JsonError {
116                    reason: e.to_string(),
117                })
118            }
119            _ => {
120                info!("webext-storage-unexpected-error");
121                ErrorHandling::convert(WebExtStorageApiError::UnexpectedError {
122                    reason: self.to_string(),
123                })
124            }
125        }
126    }
127}
128
129impl From<Error> for WebExtStorageApiError {
130    fn from(err: Error) -> WebExtStorageApiError {
131        match err {
132            Error::JsonError(e) => WebExtStorageApiError::JsonError {
133                reason: e.to_string(),
134            },
135            Error::QuotaError(reason) => WebExtStorageApiError::QuotaError { reason },
136            _ => WebExtStorageApiError::UnexpectedError {
137                reason: err.to_string(),
138            },
139        }
140    }
141}
142
143impl From<rusqlite::Error> for WebExtStorageApiError {
144    fn from(value: rusqlite::Error) -> Self {
145        WebExtStorageApiError::UnexpectedError {
146            reason: value.to_string(),
147        }
148    }
149}
150
151impl From<serde_json::Error> for WebExtStorageApiError {
152    fn from(value: serde_json::Error) -> Self {
153        WebExtStorageApiError::JsonError {
154            reason: value.to_string(),
155        }
156    }
157}
158
159impl From<anyhow::Error> for WebExtStorageApiError {
160    fn from(value: anyhow::Error) -> Self {
161        WebExtStorageApiError::UnexpectedError {
162            reason: value.to_string(),
163        }
164    }
165}