Skip to main content

vs_daemon/
error.rs

1//! Crate-wide error type for the daemon.
2//!
3//! [`DaemonError`] aggregates the typed errors from the layers below
4//! (`vs-protocol`, `vs-store`, `vs-engine-webkit`) plus daemon-specific
5//! cases (no active session, unknown page, stale token).
6//!
7//! Every error has a wire mapping in [`DaemonError::wire`] — the form
8//! the daemon emits as `! <CODE> [args]` per `docs/PROTOCOL.md`.
9
10use vs_protocol::{ErrorCode, ParseError, StateToken};
11
12#[derive(Debug, thiserror::Error)]
13#[non_exhaustive]
14pub enum DaemonError {
15    #[error("protocol parse: {0}")]
16    Protocol(#[from] ParseError),
17
18    #[error("store: {0}")]
19    Store(#[from] vs_store::StoreError),
20
21    #[error("engine: {0}")]
22    Engine(#[from] vs_engine_webkit::EngineError),
23
24    #[error("io: {0}")]
25    Io(#[from] std::io::Error),
26
27    #[error("anyhow: {0}")]
28    Other(#[from] anyhow::Error),
29
30    /// The agent's pre-image token did not match the page's current
31    /// token.
32    #[error("stale token: current={current}, reason={reason}")]
33    StaleToken {
34        current: StateToken,
35        reason: &'static str,
36    },
37
38    /// No active session for this connection.
39    #[error("no active session")]
40    NoSession,
41
42    /// Session id refers to no known session.
43    #[error("unknown session: {0}")]
44    UnknownSession(String),
45
46    /// Page id refers to no known page in this session.
47    #[error("unknown page: {0}")]
48    UnknownPage(String),
49
50    /// Ref does not exist in the page's current tree.
51    #[error("unknown ref: {0}")]
52    UnknownRef(u32),
53
54    /// The wire request was malformed.
55    #[error("bad request: {0}")]
56    BadRequest(String),
57
58    /// Engine's capability set excludes this primitive on this platform.
59    #[error("unsupported on this engine: {primitive} ({engine})")]
60    Unsupported {
61        engine: &'static str,
62        primitive: &'static str,
63    },
64}
65
66impl DaemonError {
67    /// The wire-format error code and args for this error.
68    #[must_use]
69    pub fn wire(&self) -> (ErrorCode, Vec<String>) {
70        match self {
71            Self::StaleToken { current, reason } => (
72                ErrorCode::StaleToken,
73                vec![current.to_string(), (*reason).to_string()],
74            ),
75            Self::NoSession => (ErrorCode::BadRequest, vec!["no_session".into()]),
76            Self::UnknownSession(id) => (ErrorCode::NotFound, vec![format!("session={id}")]),
77            Self::UnknownPage(id) => (ErrorCode::NotFound, vec![format!("page={id}")]),
78            Self::UnknownRef(r) => (ErrorCode::NotFound, vec![format!("ref={r}")]),
79            Self::BadRequest(msg) => (ErrorCode::BadRequest, vec![msg.clone()]),
80            Self::Unsupported { engine, primitive }
81            | Self::Engine(vs_engine_webkit::EngineError::Unsupported { engine, primitive }) => (
82                ErrorCode::EngineUnsupported,
83                vec![(*primitive).to_string(), (*engine).to_string()],
84            ),
85            Self::Engine(vs_engine_webkit::EngineError::Timeout { primitive, budget }) => (
86                ErrorCode::Timeout,
87                vec![
88                    format!("{}ms", budget.as_millis()),
89                    (*primitive).to_string(),
90                ],
91            ),
92            Self::Engine(vs_engine_webkit::EngineError::NotFound { kind, id }) => {
93                (ErrorCode::NotFound, vec![format!("{kind}={id}")])
94            }
95            Self::Engine(vs_engine_webkit::EngineError::Crashed) => {
96                (ErrorCode::EngineCrash, vec![])
97            }
98            Self::Engine(_) => (ErrorCode::BadRequest, vec![format!("engine: {self}")]),
99            Self::Protocol(_) => (ErrorCode::BadRequest, vec![format!("{self}")]),
100            Self::Store(_) | Self::Io(_) | Self::Other(_) => {
101                (ErrorCode::BadRequest, vec![format!("{self}")])
102            }
103        }
104    }
105}
106
107pub type Result<T> = std::result::Result<T, DaemonError>;