1use thiserror::Error;
2
3pub type Result<T> = std::result::Result<T, BrowserError>;
5
6#[derive(Error, Debug)]
8pub enum BrowserError {
9 #[error("WebSocket error during {operation}: {message}")]
11 WebSocket {
12 operation: String,
14 message: String,
16 },
17
18 #[error("Failed to connect to '{endpoint}': {reason}")]
20 ConnectionFailed {
21 endpoint: String,
23 reason: String,
25 },
26
27 #[error("Invalid CDP response while {context}: {details}")]
29 InvalidResponse {
30 context: String,
32 details: String,
34 },
35
36 #[error("Command '{command}' failed: {reason}")]
38 CommandFailed {
39 command: String,
41 reason: String,
43 },
44
45 #[error("CDP error {code} in '{method}': {message}")]
47 CdpError {
48 code: i32,
50 method: String,
52 message: String,
54 },
55
56 #[error("Timed out {operation} after {timeout_secs}s")]
58 Timeout {
59 operation: String,
61 timeout_secs: u64,
63 },
64
65 #[error("JSON error: {0}")]
67 Json(#[from] serde_json::Error),
68
69 #[error("IO error: {0}")]
71 Io(#[from] std::io::Error),
72
73 #[error("Page not found: {0}")]
75 PageNotFound(String),
76
77 #[error("Target not found: {0}")]
79 TargetNotFound(String),
80
81 #[error("Browser not launched: {0}")]
83 BrowserNotLaunched(String),
84
85 #[error("Navigation to '{url}' failed: {reason}")]
87 NavigationFailed {
88 url: String,
90 reason: String,
92 },
93}
94
95impl BrowserError {
96 pub fn websocket(operation: impl Into<String>, message: impl Into<String>) -> Self {
98 Self::WebSocket {
99 operation: operation.into(),
100 message: message.into(),
101 }
102 }
103
104 pub fn connection_failed(endpoint: impl Into<String>, reason: impl Into<String>) -> Self {
106 Self::ConnectionFailed {
107 endpoint: endpoint.into(),
108 reason: reason.into(),
109 }
110 }
111
112 pub fn command_failed(command: impl Into<String>, reason: impl Into<String>) -> Self {
114 Self::CommandFailed {
115 command: command.into(),
116 reason: reason.into(),
117 }
118 }
119
120 pub fn invalid_response(context: impl Into<String>, details: impl Into<String>) -> Self {
122 Self::InvalidResponse {
123 context: context.into(),
124 details: details.into(),
125 }
126 }
127
128 pub fn timeout(operation: impl Into<String>, timeout_secs: u64) -> Self {
130 Self::Timeout {
131 operation: operation.into(),
132 timeout_secs,
133 }
134 }
135
136 pub fn navigation_failed(url: impl Into<String>, reason: impl Into<String>) -> Self {
138 Self::NavigationFailed {
139 url: url.into(),
140 reason: reason.into(),
141 }
142 }
143}
144
145pub trait ResultExt<T> {
147 fn context(self, ctx: impl Into<String>) -> Result<T>;
149}
150
151impl<T> ResultExt<T> for Result<T> {
152 fn context(self, ctx: impl Into<String>) -> Result<T> {
153 self.map_err(|e| BrowserError::CommandFailed {
154 command: ctx.into(),
155 reason: e.to_string(),
156 })
157 }
158}