use std::sync::Arc;
use serde_json::Value;
use crate::transport::in_memory::{InMemoryBridge, InMemoryBridgeResponse};
use super::command_dispatcher;
use super::error::BridgeError;
use super::servo_backend::ServoBackend;
pub struct CDPRdpBridge {
backend: Arc<dyn ServoBackend>,
}
impl CDPRdpBridge {
pub fn new(backend: Arc<dyn ServoBackend>) -> Self {
Self { backend }
}
pub fn dispatch(
&self,
target_id: &str,
method: &str,
params: Value,
) -> Result<Value, BridgeError> {
command_dispatcher::dispatch_command(&*self.backend, method, params, target_id)
}
pub fn backend(&self) -> &dyn ServoBackend {
&*self.backend
}
pub fn into_in_memory_bridge(self) -> Arc<dyn InMemoryBridge> {
Arc::new(self)
}
}
impl InMemoryBridge for CDPRdpBridge {
fn dispatch_command(
&self,
method: &str,
params: Value,
session_id: Option<&str>,
) -> InMemoryBridgeResponse {
let target_id = session_id.unwrap_or("default");
match self.dispatch(target_id, method, params) {
Ok(v) => InMemoryBridgeResponse::Ok(v),
Err(e) => {
let code = e.cdp_error_code();
let msg = e.message();
let payload = serde_json::json!({
"code": code,
"message": msg,
});
InMemoryBridgeResponse::Err(payload.to_string())
}
}
}
}
#[cfg(test)]
mod tests {
use super::super::servo_backend::MockServoBackend;
use super::*;
use serde_json::json;
#[test]
fn bridge_dispatch_page_navigate_succeeds() {
let backend: Arc<dyn ServoBackend> = Arc::new(MockServoBackend::new());
let bridge = CDPRdpBridge::new(backend);
let r = bridge
.dispatch("1", "Page.navigate", json!({"url":"https://x"}))
.unwrap();
assert_eq!(r["frameId"], "FRAME_0");
}
#[test]
fn bridge_dispatch_heap_profiler_returns_not_supported() {
let backend: Arc<dyn ServoBackend> = Arc::new(MockServoBackend::new());
let bridge = CDPRdpBridge::new(backend);
let err = bridge
.dispatch("1", "HeapProfiler.takeHeapSnapshot", json!({}))
.unwrap_err();
assert!(matches!(err, BridgeError::NotSupported(_)));
assert_eq!(err.cdp_error_code(), -32601);
}
#[test]
fn bridge_implements_in_memory_bridge_trait() {
let backend: Arc<dyn ServoBackend> = Arc::new(MockServoBackend::new());
let bridge = CDPRdpBridge::new(backend);
let in_memory: Arc<dyn InMemoryBridge> = bridge.into_in_memory_bridge();
let r = in_memory.dispatch_command("Page.navigate", json!({"url":"x"}), Some("1"));
match r {
InMemoryBridgeResponse::Ok(v) => assert_eq!(v["frameId"], "FRAME_0"),
InMemoryBridgeResponse::Err(e) => panic!("expected Ok, got Err: {e}"),
}
}
#[test]
fn bridge_in_memory_trait_e_class_returns_error_with_code() {
let backend: Arc<dyn ServoBackend> = Arc::new(MockServoBackend::new());
let bridge = CDPRdpBridge::new(backend);
let in_memory: Arc<dyn InMemoryBridge> = bridge.into_in_memory_bridge();
let r = in_memory.dispatch_command("HeapProfiler.takeHeapSnapshot", json!({}), Some("1"));
match r {
InMemoryBridgeResponse::Err(msg) => {
let v: Value = serde_json::from_str(&msg).unwrap();
assert_eq!(v["code"], -32601);
assert!(v["message"].as_str().unwrap().contains("HeapProfiler"));
}
InMemoryBridgeResponse::Ok(_) => panic!("expected Err"),
}
}
#[test]
fn bridge_default_session_id_used_when_none() {
let backend: Arc<dyn ServoBackend> = Arc::new(MockServoBackend::new());
let bridge = CDPRdpBridge::new(backend);
let in_memory: Arc<dyn InMemoryBridge> = bridge.into_in_memory_bridge();
let r = in_memory.dispatch_command("Page.navigate", json!({"url":"x"}), None);
match r {
InMemoryBridgeResponse::Ok(v) => assert_eq!(v["frameId"], "FRAME_0"),
_ => panic!("expected Ok"),
}
}
#[test]
fn bridge_backend_accessor_returns_reference() {
let backend: Arc<dyn ServoBackend> = Arc::new(MockServoBackend::new());
let bridge = CDPRdpBridge::new(backend);
let _b: &dyn ServoBackend = bridge.backend();
}
#[test]
fn bridge_unknown_method_returns_method_not_found_error() {
let backend: Arc<dyn ServoBackend> = Arc::new(MockServoBackend::new());
let bridge = CDPRdpBridge::new(backend);
let in_memory: Arc<dyn InMemoryBridge> = bridge.into_in_memory_bridge();
let r = in_memory.dispatch_command("Unknown.foo", json!({}), Some("1"));
match r {
InMemoryBridgeResponse::Err(msg) => {
let v: Value = serde_json::from_str(&msg).unwrap();
assert_eq!(v["code"], -32601);
}
_ => panic!("expected Err"),
}
}
}