1use error_support::{ErrorHandling, GetErrorHandling};
7use interrupt_support::Interrupted;
8
9pub type ApiResult<T> = std::result::Result<T, AutofillApiError>;
11
12pub type Result<T> = std::result::Result<T, Error>;
14
15#[derive(Debug, thiserror::Error)]
17pub enum AutofillApiError {
18 #[error("Error executing SQL: {reason}")]
19 SqlError { reason: String },
20
21 #[error("Operation interrupted")]
22 InterruptedError,
23
24 #[error("Crypto Error: {reason}")]
25 CryptoError { reason: String },
26
27 #[error("No record with guid exists: {guid}")]
28 NoSuchRecord { guid: String },
29
30 #[error("Unexpected Error: {reason}")]
31 UnexpectedAutofillApiError { reason: String },
32}
33
34impl From<anyhow::Error> for AutofillApiError {
38 fn from(value: anyhow::Error) -> Self {
39 AutofillApiError::UnexpectedAutofillApiError {
40 reason: value.to_string(),
41 }
42 }
43}
44
45#[derive(Debug, thiserror::Error)]
46pub enum Error {
47 #[error("Error opening database: {0}")]
48 OpenDatabaseError(#[from] sql_support::open_database::Error),
49
50 #[error("Error executing SQL: {0}")]
51 SqlError(#[from] rusqlite::Error),
52
53 #[error("IO error: {0}")]
54 IoError(#[from] std::io::Error),
55
56 #[error("Operation interrupted")]
57 InterruptedError(#[from] Interrupted),
58
59 #[error("Illegal database path: {0:?}")]
63 IllegalDatabasePath(std::path::PathBuf),
64
65 #[error("JSON Error: {0}")]
66 JsonError(#[from] serde_json::Error),
67
68 #[error("Invalid sync payload: {0}")]
69 InvalidSyncPayload(String),
70
71 #[error("Crypto Error: {0}")]
72 CryptoError(#[from] jwcrypto::JwCryptoError),
73
74 #[error("Missing local encryption key")]
75 MissingEncryptionKey,
76
77 #[error("No record with guid exists: {0}")]
78 NoSuchRecord(String),
79
80 #[error("The store is closed")]
81 DatabaseClosed,
82}
83
84impl From<sql_support::path::Error> for Error {
85 fn from(e: sql_support::path::Error) -> Self {
86 match e {
87 sql_support::path::Error::IllegalDatabasePath(path) => Error::IllegalDatabasePath(path),
88 sql_support::path::Error::IoError(e) => Error::IoError(e),
89 }
90 }
91}
92
93impl GetErrorHandling for Error {
96 type ExternalError = AutofillApiError;
97
98 fn get_error_handling(&self) -> ErrorHandling<Self::ExternalError> {
99 match self {
100 Self::OpenDatabaseError(e) => ErrorHandling::convert(AutofillApiError::SqlError {
101 reason: e.to_string(),
102 })
103 .report_error("autofill-open-database-error"),
104
105 Self::SqlError(e) => ErrorHandling::convert(AutofillApiError::SqlError {
106 reason: e.to_string(),
107 })
108 .report_error("autofill-sql-error"),
109
110 Self::IoError(e) => {
111 ErrorHandling::convert(AutofillApiError::UnexpectedAutofillApiError {
112 reason: e.to_string(),
113 })
114 .report_error("autofill-io-error")
115 }
116
117 Self::InterruptedError(_) => ErrorHandling::convert(AutofillApiError::InterruptedError),
118
119 Self::IllegalDatabasePath(path) => ErrorHandling::convert(AutofillApiError::SqlError {
120 reason: format!("Path not found: {}", path.to_string_lossy()),
121 })
122 .report_error("autofill-illegal-database-path"),
123
124 Self::JsonError(e) => {
125 ErrorHandling::convert(AutofillApiError::UnexpectedAutofillApiError {
126 reason: e.to_string(),
127 })
128 .report_error("autofill-json-error")
129 }
130
131 Self::InvalidSyncPayload(reason) => {
132 ErrorHandling::convert(AutofillApiError::UnexpectedAutofillApiError {
133 reason: reason.clone(),
134 })
135 .report_error("autofill-invalid-sync-payload")
136 }
137
138 Self::CryptoError(e) => ErrorHandling::convert(AutofillApiError::CryptoError {
139 reason: e.to_string(),
140 })
141 .report_error("autofill-crypto-error"),
142
143 Self::MissingEncryptionKey => ErrorHandling::convert(AutofillApiError::CryptoError {
144 reason: "Missing encryption key".to_string(),
145 })
146 .report_error("autofill-missing-encryption-key"),
147
148 Self::NoSuchRecord(guid) => {
149 ErrorHandling::convert(AutofillApiError::NoSuchRecord { guid: guid.clone() })
150 .log_warning()
151 }
152
153 Self::DatabaseClosed => {
154 ErrorHandling::convert(AutofillApiError::UnexpectedAutofillApiError {
155 reason: "The store is closed".to_string(),
156 })
157 .report_error("autofill-database-closed")
158 }
159 }
160 }
161}