Skip to main content

chaser_oxide/
error.rs

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 message related to a cdp response that is not a
51    /// `chromiumoxide_types::Error`
52    #[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    /// Detailed information about exception (or error) that was thrown during
61    /// script compilation or execution
62    #[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/// An Error where `now > deadline`
105#[derive(Debug, Clone)]
106pub struct DeadlineExceeded {
107    /// The deadline that was set.
108    pub deadline: Instant,
109    /// The current time
110    pub now: Instant,
111}
112
113impl DeadlineExceeded {
114    /// Creates a new instance
115    ///
116    /// panics if `now > deadline`
117    pub fn new(now: Instant, deadline: Instant) -> Self {
118        // assert!(now > deadline);
119        Self { deadline, now }
120    }
121}
122
123/// `stderr` output of the browser child process
124///
125/// This implements a custom `Debug` formatter similar to [`std::process::Output`]. If the output
126/// is valid UTF-8, format as a string; otherwise format the byte sequence.
127#[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}