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("Browser process exited with status {0:?} before websocket URL could be resolved, stderr: {1:?}")]
37 LaunchExit(ExitStatus, BrowserStderr),
38 #[error("Timeout while resolving websocket URL from browser process, stderr: {0:?}")]
39 LaunchTimeout(BrowserStderr),
40 #[error(
41 "Input/Output error while resolving websocket URL from browser process, stderr: {1:?}: {0}"
42 )]
43 LaunchIo(#[source] io::Error, BrowserStderr),
44 #[error("Request timed out.")]
45 Timeout,
46 #[error("FrameId {0:?} not found.")]
47 FrameNotFound(FrameId),
48 #[error("{0}")]
51 ChromeMessage(String),
52 #[error("{0}")]
53 DecodeError(#[from] DecodeError),
54 #[error("{0}")]
55 ScrollingFailed(String),
56 #[error("Requested value not found.")]
57 NotFound,
58 #[error("{0:?}")]
61 JavascriptException(Box<ExceptionDetails>),
62 #[error("{0}")]
63 Url(#[from] url::ParseError),
64 #[error("{1}")]
65 InvalidMessage(String, serde_json::Error),
66}
67impl CdpError {
68 pub fn msg(msg: impl Into<String>) -> Self {
69 CdpError::ChromeMessage(msg.into())
70 }
71}
72
73#[derive(Debug, Error)]
74pub enum ChannelError {
75 #[error("{0}")]
76 Send(#[from] SendError),
77 #[error("{0}")]
78 Canceled(#[from] Canceled),
79}
80
81impl From<Canceled> for CdpError {
82 fn from(err: Canceled) -> Self {
83 ChannelError::from(err).into()
84 }
85}
86
87impl From<SendError> for CdpError {
88 fn from(err: SendError) -> Self {
89 ChannelError::from(err).into()
90 }
91}
92
93impl From<NavigationError> for CdpError {
94 fn from(err: NavigationError) -> Self {
95 match err {
96 NavigationError::Timeout { .. } => CdpError::Timeout,
97 NavigationError::FrameNotFound { frame, .. } => CdpError::FrameNotFound(frame),
98 }
99 }
100}
101
102#[derive(Debug, Clone)]
104pub struct DeadlineExceeded {
105 pub deadline: Instant,
107 pub now: Instant,
109}
110
111impl DeadlineExceeded {
112 pub fn new(now: Instant, deadline: Instant) -> Self {
116 Self { deadline, now }
118 }
119}
120
121#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
126pub struct BrowserStderr(Vec<u8>);
127
128impl BrowserStderr {
129 pub fn new(stderr: Vec<u8>) -> Self {
130 Self(stderr)
131 }
132
133 pub fn as_slice(&self) -> &[u8] {
134 &self.0
135 }
136
137 pub fn into_vec(self) -> Vec<u8> {
138 self.0
139 }
140}
141
142impl fmt::Debug for BrowserStderr {
143 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
144 let stderr_utf8 = std::str::from_utf8(&self.0);
145 let stderr_debug: &dyn fmt::Debug = match stderr_utf8 {
146 Ok(ref str) => str,
147 Err(_) => &self.0,
148 };
149
150 fmt.debug_tuple("BrowserStderr")
151 .field(stderr_debug)
152 .finish()
153 }
154}