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 GetErrorHandling for Error {
96    type ExternalError = WebExtStorageApiError;
97
98    fn get_error_handling(&self) -> ErrorHandling<Self::ExternalError> {
99        match self {
100            Error::QuotaError(reason) => {
101                info!("webext-storage-quota-error");
102                ErrorHandling::convert(WebExtStorageApiError::QuotaError { reason: *reason })
103            }
104            Error::JsonError(e) => {
105                info!("webext-storage-json-error");
106                ErrorHandling::convert(WebExtStorageApiError::JsonError {
107                    reason: e.to_string(),
108                })
109            }
110            _ => {
111                info!("webext-storage-unexpected-error");
112                ErrorHandling::convert(WebExtStorageApiError::UnexpectedError {
113                    reason: self.to_string(),
114                })
115            }
116        }
117    }
118}
119
120impl From<Error> for WebExtStorageApiError {
121    fn from(err: Error) -> WebExtStorageApiError {
122        match err {
123            Error::JsonError(e) => WebExtStorageApiError::JsonError {
124                reason: e.to_string(),
125            },
126            Error::QuotaError(reason) => WebExtStorageApiError::QuotaError { reason },
127            _ => WebExtStorageApiError::UnexpectedError {
128                reason: err.to_string(),
129            },
130        }
131    }
132}
133
134impl From<rusqlite::Error> for WebExtStorageApiError {
135    fn from(value: rusqlite::Error) -> Self {
136        WebExtStorageApiError::UnexpectedError {
137            reason: value.to_string(),
138        }
139    }
140}
141
142impl From<serde_json::Error> for WebExtStorageApiError {
143    fn from(value: serde_json::Error) -> Self {
144        WebExtStorageApiError::JsonError {
145            reason: value.to_string(),
146        }
147    }
148}
149
150impl From<anyhow::Error> for WebExtStorageApiError {
151    fn from(value: anyhow::Error) -> Self {
152        WebExtStorageApiError::UnexpectedError {
153            reason: value.to_string(),
154        }
155    }
156}