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