1use std::fmt;
2
3#[derive(Debug)]
4pub struct Error {
5 pub kind: &'static str,
6 pub message: String,
7 pub page_id: Option<String>,
8}
9
10pub const CONTRACTS: &[(&str, i32, &str)] = &[
11 ("invalid_input", 2, "Invalid arguments"),
12 (
13 "config_error",
14 2,
15 "Invalid or unavailable profile configuration",
16 ),
17 ("read_only", 2, "The selected profile blocks writes"),
18 (
19 "unsupported",
20 2,
21 "Local access requires Windows or WSL; use SSH for a remote Windows desktop",
22 ),
23 ("not_found", 4, "The requested resource is unavailable"),
24 (
25 "desktop_error",
26 5,
27 "OneNote or its PowerShell bridge failed",
28 ),
29 (
30 "conflict",
31 6,
32 "Page changed before the append; review before retrying",
33 ),
34 (
35 "write_uncertain",
36 7,
37 "Write outcome is uncertain; inspect OneNote before retrying",
38 ),
39 ("unexpected_error", 1, "Local input/output failure"),
40];
41
42impl Error {
43 pub fn new(kind: &'static str, message: impl Into<String>) -> Self {
44 Self {
45 kind,
46 message: message.into(),
47 page_id: None,
48 }
49 }
50 pub fn with_page(mut self, id: &str) -> Self {
51 self.page_id = Some(id.to_owned());
52 self
53 }
54 pub fn invalid(message: impl Into<String>) -> Self {
55 Self::new("invalid_input", message)
56 }
57 pub fn desktop(message: impl Into<String>) -> Self {
58 Self::new("desktop_error", message)
59 }
60 pub fn code(&self) -> i32 {
61 CONTRACTS
62 .iter()
63 .find(|c| c.0 == self.kind)
64 .map_or(1, |c| c.1)
65 }
66}
67impl fmt::Display for Error {
68 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69 f.write_str(&self.message)
70 }
71}
72impl std::error::Error for Error {}
73impl From<std::io::Error> for Error {
74 fn from(e: std::io::Error) -> Self {
75 Self::new("unexpected_error", e.to_string())
76 }
77}