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