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
34#[derive(Debug, thiserror::Error)]
35pub enum Error {
36 #[error("Error opening database: {0}")]
37 OpenDatabaseError(#[from] sql_support::open_database::Error),
38
39 #[error("Error executing SQL: {0}")]
40 SqlError(#[from] rusqlite::Error),
41
42 #[error("IO error: {0}")]
43 IoError(#[from] std::io::Error),
44
45 #[error("Operation interrupted")]
46 InterruptedError(#[from] Interrupted),
47
48 #[error("Illegal database path: {0:?}")]
52 IllegalDatabasePath(std::path::PathBuf),
53
54 #[error("JSON Error: {0}")]
55 JsonError(#[from] serde_json::Error),
56
57 #[error("Invalid sync payload: {0}")]
58 InvalidSyncPayload(String),
59
60 #[error("Crypto Error: {0}")]
61 CryptoError(#[from] jwcrypto::JwCryptoError),
62
63 #[error("Missing local encryption key")]
64 MissingEncryptionKey,
65
66 #[error("No record with guid exists: {0}")]
67 NoSuchRecord(String),
68
69 #[error("The store is closed")]
70 DatabaseClosed,
71}
72
73impl GetErrorHandling for Error {
76 type ExternalError = AutofillApiError;
77
78 fn get_error_handling(&self) -> ErrorHandling<Self::ExternalError> {
79 match self {
80 Self::OpenDatabaseError(e) => ErrorHandling::convert(AutofillApiError::SqlError {
81 reason: e.to_string(),
82 })
83 .report_error("autofill-open-database-error"),
84
85 Self::SqlError(e) => ErrorHandling::convert(AutofillApiError::SqlError {
86 reason: e.to_string(),
87 })
88 .report_error("autofill-sql-error"),
89
90 Self::IoError(e) => {
91 ErrorHandling::convert(AutofillApiError::UnexpectedAutofillApiError {
92 reason: e.to_string(),
93 })
94 .report_error("autofill-io-error")
95 }
96
97 Self::InterruptedError(_) => ErrorHandling::convert(AutofillApiError::InterruptedError),
98
99 Self::IllegalDatabasePath(path) => ErrorHandling::convert(AutofillApiError::SqlError {
100 reason: format!("Path not found: {}", path.to_string_lossy()),
101 })
102 .report_error("autofill-illegal-database-path"),
103
104 Self::JsonError(e) => {
105 ErrorHandling::convert(AutofillApiError::UnexpectedAutofillApiError {
106 reason: e.to_string(),
107 })
108 .report_error("autofill-json-error")
109 }
110
111 Self::InvalidSyncPayload(reason) => {
112 ErrorHandling::convert(AutofillApiError::UnexpectedAutofillApiError {
113 reason: reason.clone(),
114 })
115 .report_error("autofill-invalid-sync-payload")
116 }
117
118 Self::CryptoError(e) => ErrorHandling::convert(AutofillApiError::CryptoError {
119 reason: e.to_string(),
120 })
121 .report_error("autofill-crypto-error"),
122
123 Self::MissingEncryptionKey => ErrorHandling::convert(AutofillApiError::CryptoError {
124 reason: "Missing encryption key".to_string(),
125 })
126 .report_error("autofill-missing-encryption-key"),
127
128 Self::NoSuchRecord(guid) => {
129 ErrorHandling::convert(AutofillApiError::NoSuchRecord { guid: guid.clone() })
130 .log_warning()
131 }
132
133 Self::DatabaseClosed => {
134 ErrorHandling::convert(AutofillApiError::UnexpectedAutofillApiError {
135 reason: "The store is closed".to_string(),
136 })
137 .report_error("autofill-database-closed")
138 }
139 }
140 }
141}