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 GetErrorHandling for Error {
87 type ExternalError = AutofillApiError;
88
89 fn get_error_handling(&self) -> ErrorHandling<Self::ExternalError> {
90 match self {
91 Self::OpenDatabaseError(e) => ErrorHandling::convert(AutofillApiError::SqlError {
92 reason: e.to_string(),
93 })
94 .report_error("autofill-open-database-error"),
95
96 Self::SqlError(e) => ErrorHandling::convert(AutofillApiError::SqlError {
97 reason: e.to_string(),
98 })
99 .report_error("autofill-sql-error"),
100
101 Self::IoError(e) => {
102 ErrorHandling::convert(AutofillApiError::UnexpectedAutofillApiError {
103 reason: e.to_string(),
104 })
105 .report_error("autofill-io-error")
106 }
107
108 Self::InterruptedError(_) => ErrorHandling::convert(AutofillApiError::InterruptedError),
109
110 Self::IllegalDatabasePath(path) => ErrorHandling::convert(AutofillApiError::SqlError {
111 reason: format!("Path not found: {}", path.to_string_lossy()),
112 })
113 .report_error("autofill-illegal-database-path"),
114
115 Self::JsonError(e) => {
116 ErrorHandling::convert(AutofillApiError::UnexpectedAutofillApiError {
117 reason: e.to_string(),
118 })
119 .report_error("autofill-json-error")
120 }
121
122 Self::InvalidSyncPayload(reason) => {
123 ErrorHandling::convert(AutofillApiError::UnexpectedAutofillApiError {
124 reason: reason.clone(),
125 })
126 .report_error("autofill-invalid-sync-payload")
127 }
128
129 Self::CryptoError(e) => ErrorHandling::convert(AutofillApiError::CryptoError {
130 reason: e.to_string(),
131 })
132 .report_error("autofill-crypto-error"),
133
134 Self::MissingEncryptionKey => ErrorHandling::convert(AutofillApiError::CryptoError {
135 reason: "Missing encryption key".to_string(),
136 })
137 .report_error("autofill-missing-encryption-key"),
138
139 Self::NoSuchRecord(guid) => {
140 ErrorHandling::convert(AutofillApiError::NoSuchRecord { guid: guid.clone() })
141 .log_warning()
142 }
143
144 Self::DatabaseClosed => {
145 ErrorHandling::convert(AutofillApiError::UnexpectedAutofillApiError {
146 reason: "The store is closed".to_string(),
147 })
148 .report_error("autofill-database-closed")
149 }
150 }
151 }
152}