matrix_sdk_sqlite/
error.rs

1// Copyright 2023 The Matrix.org Foundation C.I.C.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use deadpool_sqlite::{CreatePoolError, PoolError};
16#[cfg(feature = "event-cache")]
17use matrix_sdk_base::event_cache::store::EventCacheStoreError;
18#[cfg(feature = "state-store")]
19use matrix_sdk_base::store::StoreError as StateStoreError;
20#[cfg(feature = "crypto-store")]
21use matrix_sdk_crypto::CryptoStoreError;
22use thiserror::Error;
23use tokio::io;
24
25/// All the errors that can occur when opening an SQLite store.
26#[derive(Error, Debug)]
27#[non_exhaustive]
28pub enum OpenStoreError {
29    /// Failed to create the DB's parent directory.
30    #[error("Failed to create the database's parent directory: {0}")]
31    CreateDir(#[source] io::Error),
32
33    /// Failed to create the DB pool.
34    #[error(transparent)]
35    CreatePool(#[from] CreatePoolError),
36
37    /// Failed to load the database's version.
38    #[error("Failed to load database version: {0}")]
39    LoadVersion(#[source] rusqlite::Error),
40
41    /// The version of the database is missing.
42    #[error("Missing database version")]
43    MissingVersion,
44
45    /// The version of the database is invalid.
46    #[error("Invalid database version")]
47    InvalidVersion,
48
49    /// Failed to apply migrations.
50    #[error("Failed to run migrations: {0}")]
51    Migration(#[from] Error),
52
53    /// Failed to get a DB connection from the pool.
54    #[error(transparent)]
55    Pool(#[from] PoolError),
56
57    /// Failed to initialize the store cipher.
58    #[error("Failed to initialize the store cipher: {0}")]
59    InitCipher(#[from] matrix_sdk_store_encryption::Error),
60
61    /// Failed to load the store cipher from the DB.
62    #[error("Failed to load the store cipher from the DB: {0}")]
63    LoadCipher(#[source] rusqlite::Error),
64
65    /// Failed to save the store cipher to the DB.
66    #[error("Failed to save the store cipher to the DB: {0}")]
67    SaveCipher(#[source] rusqlite::Error),
68}
69
70#[derive(Debug, Error)]
71pub enum Error {
72    #[error(transparent)]
73    Sqlite(rusqlite::Error),
74
75    #[error("Failed to compute the maximum variable number from {0}")]
76    SqliteMaximumVariableNumber(i32),
77
78    #[error(transparent)]
79    Pool(PoolError),
80
81    #[error(transparent)]
82    Encode(rmp_serde::encode::Error),
83
84    #[error(transparent)]
85    Decode(rmp_serde::decode::Error),
86
87    #[error(transparent)]
88    Json(#[from] serde_json::Error),
89
90    #[error(transparent)]
91    Encryption(matrix_sdk_store_encryption::Error),
92
93    #[error("can't save/load sessions or group sessions in the store before an account is stored")]
94    AccountUnset,
95
96    #[error(transparent)]
97    Pickle(#[from] vodozemac::PickleError),
98
99    #[error("An object failed to be decrypted while unpickling")]
100    Unpickle,
101
102    #[error("Redaction failed: {0}")]
103    Redaction(#[source] ruma::canonical_json::RedactionError),
104
105    #[error("An update keyed by unique ID touched more than one entry")]
106    InconsistentUpdate,
107
108    #[error("The store contains invalid data: {details}")]
109    InvalidData { details: String },
110}
111
112macro_rules! impl_from {
113    ( $ty:ty => $enum:ident::$variant:ident ) => {
114        impl From<$ty> for $enum {
115            fn from(value: $ty) -> Self {
116                Self::$variant(value)
117            }
118        }
119    };
120}
121
122impl From<rusqlite::Error> for Error {
123    fn from(error: rusqlite::Error) -> Self {
124        if let rusqlite::Error::SqliteFailure(ffi_error, message) = &error {
125            if ffi_error.code == rusqlite::ErrorCode::DatabaseBusy {
126                // Report to sentry.
127                tracing::error!(
128                    sentry = true,
129                    sqlite_message = message,
130                    "observed database busy error"
131                );
132            }
133        }
134        Error::Sqlite(error)
135    }
136}
137
138impl_from!(PoolError => Error::Pool);
139impl_from!(rmp_serde::encode::Error => Error::Encode);
140impl_from!(rmp_serde::decode::Error => Error::Decode);
141impl_from!(matrix_sdk_store_encryption::Error => Error::Encryption);
142
143#[cfg(feature = "crypto-store")]
144impl From<Error> for CryptoStoreError {
145    fn from(e: Error) -> Self {
146        CryptoStoreError::backend(e)
147    }
148}
149
150#[cfg(feature = "state-store")]
151impl From<Error> for StateStoreError {
152    fn from(e: Error) -> Self {
153        match e {
154            Error::Json(e) => StateStoreError::Json(e),
155            Error::Encryption(e) => StateStoreError::Encryption(e),
156            Error::Redaction(e) => StateStoreError::Redaction(e),
157            e => StateStoreError::backend(e),
158        }
159    }
160}
161
162#[cfg(feature = "event-cache")]
163impl From<Error> for EventCacheStoreError {
164    fn from(e: Error) -> Self {
165        match e {
166            Error::Encryption(e) => EventCacheStoreError::Encryption(e),
167            e => EventCacheStoreError::backend(e),
168        }
169    }
170}
171
172pub(crate) type Result<T, E = Error> = std::result::Result<T, E>;