use serde_json::Value;
pub mod bao_event;
mod event;
mod protocol;
mod registry;
mod server;
mod session;
mod transport;
pub use bao_event::{BaoEvent, ConsoleMessage};
pub use event::EventBroadcaster;
pub use protocol::{
error_response, ok_empty, ok_response, parse_message, serialize_event, serialize_response,
CdpError, CdpEvent, CdpMessage, CdpResponse, SessionError, ERR_INTERNAL, ERR_INVALID_PARAMS,
ERR_INVALID_REQUEST, ERR_METHOD_NOT_FOUND, ERR_PARSE_ERROR,
};
pub use registry::{DomainRegistry, EmptyHandler, RegistryDispatch, SharedRegistry};
pub use server::CdpServer;
pub use session::{CdpSession, SessionHandle, SessionState};
pub use transport::{
is_websocket_upgrade, parse_activate_request, parse_close_request, parse_new_request,
TargetInfo,
};
pub trait DomainHandler: Send + Sync {
fn domain_name(&self) -> &'static str;
fn handle_command(
&self,
command: &str,
params: Value,
event_sender: &dyn EventSender,
) -> Result<Value, CdpError>;
fn on_session_created(&self, _session_id: &str) {}
fn on_session_destroyed(&self, _session_id: &str) {}
}
pub trait EventSender: Send + Sync {
fn send_event(&self, method: &str, params: Value);
fn send_session_event(&self, session_id: &str, method: &str, params: Value) {
let _ = (session_id, method, params);
}
}
pub trait TargetProvider: Send + Sync {
fn list_targets(&self) -> Vec<TargetInfo>;
fn create_target(&self, url: &str) -> Result<TargetInfo, String>;
fn close_target(&self, target_id: &str) -> Result<(), String>;
fn activate_target(&self, target_id: &str) -> Result<(), String>;
}
pub struct ServerConfig {
pub host: String,
pub port: u16,
pub http_timeout_seconds: u64,
pub max_sessions: usize,
pub browser_name: String,
pub protocol_version: String,
pub user_agent: Option<String>,
pub v8_version: Option<String>,
pub webkit_version: Option<String>,
}
impl Default for ServerConfig {
fn default() -> Self {
ServerConfig {
host: "127.0.0.1".into(),
port: 9222,
http_timeout_seconds: 30,
max_sessions: 100,
browser_name: "Bao/0.1.0".into(),
protocol_version: "1.3".into(),
user_agent: None,
v8_version: None,
webkit_version: None,
}
}
}
impl ServerConfig {
pub fn builder() -> ServerConfigBuilder {
ServerConfigBuilder::default()
}
}
#[derive(Default)]
pub struct ServerConfigBuilder {
inner: ServerConfig,
}
impl ServerConfigBuilder {
pub fn host(mut self, host: impl Into<String>) -> Self {
self.inner.host = host.into();
self
}
pub fn port(mut self, port: u16) -> Self {
self.inner.port = port;
self
}
pub fn http_timeout_seconds(mut self, seconds: u64) -> Self {
self.inner.http_timeout_seconds = seconds;
self
}
pub fn max_sessions(mut self, max: usize) -> Self {
self.inner.max_sessions = max;
self
}
pub fn browser_name(mut self, name: impl Into<String>) -> Self {
self.inner.browser_name = name.into();
self
}
pub fn user_agent(mut self, ua: impl Into<String>) -> Self {
self.inner.user_agent = Some(ua.into());
self
}
pub fn v8_version(mut self, ver: impl Into<String>) -> Self {
self.inner.v8_version = Some(ver.into());
self
}
pub fn webkit_version(mut self, ver: impl Into<String>) -> Self {
self.inner.webkit_version = Some(ver.into());
self
}
pub fn build(self) -> ServerConfig {
self.inner
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn server_config_default_host_is_127_0_0_1() {
assert_eq!(ServerConfig::default().host, "127.0.0.1");
}
#[test]
fn server_config_default_port_is_9222() {
assert_eq!(ServerConfig::default().port, 9222);
}
#[test]
fn server_config_default_timeout_is_30() {
assert_eq!(ServerConfig::default().http_timeout_seconds, 30);
}
#[test]
fn server_config_default_max_sessions_is_100() {
assert_eq!(ServerConfig::default().max_sessions, 100);
}
#[test]
fn server_config_default_browser_name_is_Bao() {
assert_eq!(ServerConfig::default().browser_name, "Bao/0.1.0");
}
#[test]
fn server_config_default_protocol_version_is_1_3() {
assert_eq!(ServerConfig::default().protocol_version, "1.3");
}
#[test]
fn server_config_default_user_agent_is_none() {
assert!(ServerConfig::default().user_agent.is_none());
}
#[test]
fn server_config_default_v8_version_is_none() {
assert!(ServerConfig::default().v8_version.is_none());
}
#[test]
fn server_config_default_webkit_version_is_none() {
assert!(ServerConfig::default().webkit_version.is_none());
}
#[test]
fn builder_sets_host() {
assert_eq!(
ServerConfig::builder().host("0.0.0.0").build().host,
"0.0.0.0"
);
}
#[test]
fn builder_sets_port() {
assert_eq!(ServerConfig::builder().port(8080).build().port, 8080);
}
#[test]
fn builder_sets_timeout() {
assert_eq!(
ServerConfig::builder()
.http_timeout_seconds(60)
.build()
.http_timeout_seconds,
60
);
}
#[test]
fn builder_sets_max_sessions() {
assert_eq!(
ServerConfig::builder()
.max_sessions(50)
.build()
.max_sessions,
50
);
}
#[test]
fn builder_sets_browser_name() {
assert_eq!(
ServerConfig::builder()
.browser_name("Chrome/120")
.build()
.browser_name,
"Chrome/120"
);
}
#[test]
fn builder_sets_user_agent() {
let ua = ServerConfig::builder()
.user_agent("Mozilla/5.0")
.build()
.user_agent;
assert_eq!(ua.as_deref(), Some("Mozilla/5.0"));
}
#[test]
fn builder_sets_v8_version() {
let ver = ServerConfig::builder()
.v8_version("12.0")
.build()
.v8_version;
assert_eq!(ver.as_deref(), Some("12.0"));
}
#[test]
fn builder_sets_webkit_version() {
let ver = ServerConfig::builder()
.webkit_version("537.36")
.build()
.webkit_version;
assert_eq!(ver.as_deref(), Some("537.36"));
}
#[test]
fn builder_chaining_all_fields() {
let cfg = ServerConfig::builder()
.host("0.0.0.0")
.port(9223)
.http_timeout_seconds(120)
.max_sessions(200)
.browser_name("TestBrowser")
.user_agent("TestAgent")
.v8_version("13.0")
.webkit_version("600.0")
.build();
assert_eq!(cfg.host, "0.0.0.0");
assert_eq!(cfg.port, 9223);
assert_eq!(cfg.http_timeout_seconds, 120);
assert_eq!(cfg.max_sessions, 200);
assert_eq!(cfg.browser_name, "TestBrowser");
assert_eq!(cfg.user_agent.as_deref(), Some("TestAgent"));
assert_eq!(cfg.v8_version.as_deref(), Some("13.0"));
assert_eq!(cfg.webkit_version.as_deref(), Some("600.0"));
}
#[test]
fn builder_default_then_build_equals_default_config() {
let built = ServerConfig::builder().build();
let default = ServerConfig::default();
assert_eq!(built.host, default.host);
assert_eq!(built.port, default.port);
assert_eq!(built.http_timeout_seconds, default.http_timeout_seconds);
assert_eq!(built.max_sessions, default.max_sessions);
assert_eq!(built.browser_name, default.browser_name);
assert_eq!(built.protocol_version, default.protocol_version);
assert_eq!(built.user_agent, default.user_agent);
assert_eq!(built.v8_version, default.v8_version);
assert_eq!(built.webkit_version, default.webkit_version);
}
}