chromiumoxide/
error.rs

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;
12// use tokio::sync::oneshot::error::RecvError;
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    #[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 message related to a cdp response that is not a
52    /// `chromiumoxide_types::Error`
53    #[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    /// Detailed information about exception (or error) that was thrown during
62    /// script compilation or execution
63    #[error("{0:?}")]
64    JavascriptException(Box<ExceptionDetails>),
65    #[error("{0}")]
66    Url(#[from] url::ParseError),
67    // #[error("{0}")]
68    // RecvError(#[from] RecvError),
69}
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/// An Error where `now > deadline`
107#[derive(Debug, Clone)]
108pub struct DeadlineExceeded {
109    /// The deadline that was set.
110    pub deadline: Instant,
111    /// The current time
112    pub now: Instant,
113}
114
115impl DeadlineExceeded {
116    /// Creates a new instance
117    ///
118    /// panics if `now > deadline`
119    pub fn new(now: Instant, deadline: Instant) -> Self {
120        // assert!(now > deadline);
121        Self { deadline, now }
122    }
123}
124
125/// `stderr` output of the browser child process
126///
127/// This implements a custom `Debug` formatter similar to [`std::process::Output`]. If the output
128/// is valid UTF-8, format as a string; otherwise format the byte sequence.
129#[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}