Skip to main content

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