use crate::error::Result;
use serde_json::Value;
use std::time::Duration;
use super::TransportKind;
#[derive(Debug, Clone)]
pub struct CdpEvent {
pub method: String,
pub params: Value,
pub session_id: Option<String>,
}
impl CdpEvent {
pub fn new(method: impl Into<String>, params: Value) -> Self {
Self {
method: method.into(),
params,
session_id: None,
}
}
pub fn with_session(mut self, session_id: impl Into<String>) -> Self {
self.session_id = Some(session_id.into());
self
}
}
pub trait Transport: Send {
fn kind(&self) -> TransportKind;
fn send_command(
&mut self,
method: &str,
params: Value,
session_id: Option<&str>,
) -> Result<Value>;
fn recv_event(&mut self) -> Result<Option<CdpEvent>>;
fn close(&mut self) -> Result<()>;
fn set_command_timeout(&mut self, _timeout: Duration) {}
fn set_event_timeout(&mut self, _timeout: Duration) {}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cdp_event_new_basic() {
let e = CdpEvent::new(
"Page.frameNavigated",
serde_json::json!({"url": "about:blank"}),
);
assert_eq!(e.method, "Page.frameNavigated");
assert_eq!(e.params["url"], "about:blank");
assert!(e.session_id.is_none());
}
#[test]
fn cdp_event_with_session() {
let e = CdpEvent::new("Network.requestWillBeSent", serde_json::json!({}))
.with_session("TARGET-1");
assert_eq!(e.session_id.as_deref(), Some("TARGET-1"));
}
#[test]
fn cdp_event_clone_preserves_fields() {
let e1 = CdpEvent::new("Log.entryAdded", serde_json::json!({"text": "hi"}));
let e2 = e1.clone();
assert_eq!(e1.method, e2.method);
assert_eq!(e1.params, e2.params);
assert_eq!(e1.session_id, e2.session_id);
}
struct TestTransport {
kind: TransportKind,
closed: bool,
next_event: Option<CdpEvent>,
}
impl Transport for TestTransport {
fn kind(&self) -> TransportKind {
self.kind
}
fn send_command(
&mut self,
_method: &str,
_params: Value,
_session_id: Option<&str>,
) -> Result<Value> {
if self.closed {
return Err(crate::error::CdpError::ConnectionClosed);
}
Ok(Value::Null)
}
fn recv_event(&mut self) -> Result<Option<CdpEvent>> {
if self.closed {
return Err(crate::error::CdpError::ConnectionClosed);
}
Ok(self.next_event.take())
}
fn close(&mut self) -> Result<()> {
self.closed = true;
Ok(())
}
}
#[test]
fn transport_trait_object_works() {
let mut t: Box<dyn Transport> = Box::new(TestTransport {
kind: TransportKind::InMemory,
closed: false,
next_event: Some(CdpEvent::new("E", Value::Null)),
});
assert_eq!(t.kind(), TransportKind::InMemory);
let r = t.send_command("Test.method", Value::Null, None).unwrap();
assert!(r.is_null());
let ev = t.recv_event().unwrap();
assert!(ev.is_some());
assert_eq!(ev.unwrap().method, "E");
let ev2 = t.recv_event().unwrap();
assert!(ev2.is_none());
t.close().unwrap();
let err = t.send_command("X", Value::Null, None).unwrap_err();
assert!(matches!(err, crate::error::CdpError::ConnectionClosed));
}
}