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
15#[cfg(feature = "event-cache")]
16use matrix_sdk_base::event_cache::store::EventCacheStoreError;
17#[cfg(feature = "event-cache")]
18use matrix_sdk_base::media::store::MediaStoreError;
19#[cfg(feature = "state-store")]
20use matrix_sdk_base::store::StoreError as StateStoreError;
21#[cfg(feature = "crypto-store")]
22use matrix_sdk_crypto::CryptoStoreError;
23use thiserror::Error;
24use tokio::io;
25
26use crate::connection::{CreatePoolError, PoolError};
27
28/// All the errors that can occur when opening an SQLite store.
29#[derive(Error, Debug)]
30#[non_exhaustive]
31pub enum OpenStoreError {
32    /// Failed to create the DB's parent directory.
33    #[error("Failed to create the database's parent directory: {0}")]
34    CreateDir(#[source] io::Error),
35
36    /// Failed to create the DB pool.
37    #[error(transparent)]
38    CreatePool(#[from] CreatePoolError),
39
40    /// Failed to load the database's version.
41    #[error("Failed to load database version: {0}")]
42    LoadVersion(#[source] rusqlite::Error),
43
44    /// The version of the database is missing.
45    #[error("Missing database version")]
46    MissingVersion,
47
48    /// The version of the database is invalid.
49    #[error("Invalid database version")]
50    InvalidVersion,
51
52    /// Failed to apply migrations.
53    #[error("Failed to run migrations: {0}")]
54    Migration(#[from] Error),
55
56    /// Failed to get a DB connection from the pool.
57    #[error(transparent)]
58    Pool(#[from] PoolError),
59
60    /// Failed to initialize the store cipher.
61    #[error("Failed to initialize the store cipher: {0}")]
62    InitCipher(#[from] matrix_sdk_store_encryption::Error),
63
64    /// Failed to load the store cipher from the DB.
65    #[error("Failed to load the store cipher from the DB: {0}")]
66    LoadCipher(#[source] rusqlite::Error),
67
68    /// Failed to save the store cipher to the DB.
69    #[error("Failed to save the store cipher to the DB: {0}")]
70    SaveCipher(#[source] rusqlite::Error),
71}
72
73#[derive(Debug, Error)]
74pub enum Error {
75    #[error(transparent)]
76    Sqlite(rusqlite::Error),
77
78    #[error("Failed to compute the maximum variable number from {0}")]
79    SqliteMaximumVariableNumber(i32),
80
81    #[error(transparent)]
82    Pool(PoolError),
83
84    #[error(transparent)]
85    Encode(rmp_serde::encode::Error),
86
87    #[error(transparent)]
88    Decode(rmp_serde::decode::Error),
89
90    #[error(transparent)]
91    Json(#[from] serde_json::Error),
92
93    #[error(transparent)]
94    Encryption(matrix_sdk_store_encryption::Error),
95
96    #[error("can't save/load sessions or group sessions in the store before an account is stored")]
97    AccountUnset,
98
99    #[error(transparent)]
100    Pickle(#[from] vodozemac::PickleError),
101
102    #[error("An object failed to be decrypted while unpickling")]
103    Unpickle,
104
105    #[error("Redaction failed: {0}")]
106    Redaction(#[source] ruma::canonical_json::RedactionError),
107
108    #[error("An update keyed by unique ID touched more than one entry")]
109    InconsistentUpdate,
110
111    #[error("The store contains invalid data: {details}")]
112    InvalidData { details: String },
113}
114
115macro_rules! impl_from {
116    ( $ty:ty => $enum:ident::$variant:ident ) => {
117        impl From<$ty> for $enum {
118            fn from(value: $ty) -> Self {
119                Self::$variant(value)
120            }
121        }
122    };
123}
124
125impl From<rusqlite::Error> for Error {
126    fn from(error: rusqlite::Error) -> Self {
127        if let rusqlite::Error::SqliteFailure(ffi_error, message) = &error {
128            if ffi_error.code == rusqlite::ErrorCode::DatabaseBusy {
129                // Report to sentry.
130                tracing::error!(
131                    sentry = true,
132                    sqlite_message = message,
133                    "observed database busy error"
134                );
135            }
136        }
137        Error::Sqlite(error)
138    }
139}
140
141impl_from!(PoolError => Error::Pool);
142impl_from!(rmp_serde::encode::Error => Error::Encode);
143impl_from!(rmp_serde::decode::Error => Error::Decode);
144impl_from!(matrix_sdk_store_encryption::Error => Error::Encryption);
145
146#[cfg(feature = "crypto-store")]
147impl From<Error> for CryptoStoreError {
148    fn from(e: Error) -> Self {
149        CryptoStoreError::backend(e)
150    }
151}
152
153#[cfg(feature = "state-store")]
154impl From<Error> for StateStoreError {
155    fn from(e: Error) -> Self {
156        match e {
157            Error::Json(e) => StateStoreError::Json(e),
158            Error::Encryption(e) => StateStoreError::Encryption(e),
159            Error::Redaction(e) => StateStoreError::Redaction(e),
160            e => StateStoreError::backend(e),
161        }
162    }
163}
164
165#[cfg(feature = "event-cache")]
166impl From<Error> for EventCacheStoreError {
167    fn from(e: Error) -> Self {
168        match e {
169            Error::Encryption(e) => EventCacheStoreError::Encryption(e),
170            e => EventCacheStoreError::backend(e),
171        }
172    }
173}
174
175#[cfg(feature = "event-cache")]
176impl From<Error> for MediaStoreError {
177    fn from(e: Error) -> Self {
178        match e {
179            Error::Encryption(e) => MediaStoreError::Encryption(e),
180            e => MediaStoreError::backend(e),
181        }
182    }
183}
184
185pub(crate) type Result<T, E = Error> = std::result::Result<T, E>;