1use std::fmt;
2use std::io;
3use std::process::ExitStatus;
4use std::time::Instant;
5
6use base64::DecodeError;
7use futures::channel::mpsc::SendError;
8use futures::channel::oneshot::Canceled;
9use thiserror::Error;
10use tokio_tungstenite::tungstenite;
11use tokio_tungstenite::tungstenite::Message;
12use chromiumoxide_cdp::cdp::browser_protocol::page::FrameId;
14
15use crate::handler::frame::NavigationError;
16use chromiumoxide_cdp::cdp::js_protocol::runtime::ExceptionDetails;
17
18pub type Result<T, E = CdpError> = std::result::Result<T, E>;
19
20#[derive(Debug, Error)]
21pub enum CdpError {
22 #[error("{0}")]
23 Ws(#[from] tungstenite::Error),
24 #[error("{0}")]
25 Io(#[from] io::Error),
26 #[error("{0}")]
27 Serde(#[from] serde_json::Error),
28 #[error("{0}")]
29 #[cfg(feature = "simd")]
30 SerdeSonic(#[from] sonic_rs::Error),
31 #[error("{0}")]
32 Chrome(#[from] chromiumoxide_types::Error),
33 #[error("Received no response from the chromium instance.")]
34 NoResponse,
35 #[error("Received unexpected ws message: {0:?}")]
36 UnexpectedWsMessage(Message),
37 #[error("{0}")]
38 ChannelSendError(#[from] ChannelError),
39 #[error("Browser process exited with status {0:?} before websocket URL could be resolved, stderr: {1:?}")]
40 LaunchExit(ExitStatus, BrowserStderr),
41 #[error("Timeout while resolving websocket URL from browser process, stderr: {0:?}")]
42 LaunchTimeout(BrowserStderr),
43 #[error(
44 "Input/Output error while resolving websocket URL from browser process, stderr: {1:?}: {0}"
45 )]
46 LaunchIo(#[source] io::Error, BrowserStderr),
47 #[error("Request timed out.")]
48 Timeout,
49 #[error("FrameId {0:?} not found.")]
50 FrameNotFound(FrameId),
51 #[error("{0}")]
54 ChromeMessage(String),
55 #[error("{0}")]
56 DecodeError(#[from] DecodeError),
57 #[error("{0}")]
58 ScrollingFailed(String),
59 #[error("Requested value not found.")]
60 NotFound,
61 #[error("{0:?}")]
64 JavascriptException(Box<ExceptionDetails>),
65 #[error("{0}")]
66 Url(#[from] url::ParseError),
67 }
70
71impl CdpError {
72 pub fn msg(msg: impl Into<String>) -> Self {
73 CdpError::ChromeMessage(msg.into())
74 }
75}
76
77#[derive(Debug, Error)]
78pub enum ChannelError {
79 #[error("{0}")]
80 Send(#[from] SendError),
81 #[error("{0}")]
82 Canceled(#[from] Canceled),
83}
84
85impl From<Canceled> for CdpError {
86 fn from(err: Canceled) -> Self {
87 ChannelError::from(err).into()
88 }
89}
90
91impl From<SendError> for CdpError {
92 fn from(err: SendError) -> Self {
93 ChannelError::from(err).into()
94 }
95}
96
97impl From<NavigationError> for CdpError {
98 fn from(err: NavigationError) -> Self {
99 match err {
100 NavigationError::Timeout { .. } => CdpError::Timeout,
101 NavigationError::FrameNotFound { frame, .. } => CdpError::FrameNotFound(frame),
102 }
103 }
104}
105
106#[derive(Debug, Clone)]
108pub struct DeadlineExceeded {
109 pub deadline: Instant,
111 pub now: Instant,
113}
114
115impl DeadlineExceeded {
116 pub fn new(now: Instant, deadline: Instant) -> Self {
120 Self { deadline, now }
122 }
123}
124
125#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
130pub struct BrowserStderr(Vec<u8>);
131
132impl BrowserStderr {
133 pub fn new(stderr: Vec<u8>) -> Self {
134 Self(stderr)
135 }
136
137 pub fn as_slice(&self) -> &[u8] {
138 &self.0
139 }
140
141 pub fn into_vec(self) -> Vec<u8> {
142 self.0
143 }
144}
145
146impl fmt::Debug for BrowserStderr {
147 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
148 let stderr_utf8 = std::str::from_utf8(&self.0);
149 let stderr_debug: &dyn fmt::Debug = match stderr_utf8 {
150 Ok(ref str) => str,
151 Err(_) => &self.0,
152 };
153
154 fmt.debug_tuple("BrowserStderr")
155 .field(stderr_debug)
156 .finish()
157 }
158}