1use serde_json::Value;
9
10pub mod bao_event;
11mod event;
12mod protocol;
13mod registry;
14mod server;
15mod session;
16mod transport;
17
18pub use bao_event::{BaoEvent, ConsoleMessage};
19pub use event::EventBroadcaster;
20pub use protocol::{
21 error_response, ok_empty, ok_response, parse_message, serialize_event, serialize_response,
22 CdpError, CdpEvent, CdpMessage, CdpResponse, SessionError, ERR_INTERNAL, ERR_INVALID_PARAMS,
23 ERR_INVALID_REQUEST, ERR_METHOD_NOT_FOUND, ERR_PARSE_ERROR,
24};
25pub use registry::{DomainRegistry, EmptyHandler, RegistryDispatch, SharedRegistry};
26pub use server::CdpServer;
27pub use session::{CdpSession, SessionHandle, SessionState};
28pub use transport::{
29 is_websocket_upgrade, parse_activate_request, parse_close_request, parse_new_request,
30 TargetInfo,
31};
32
33pub trait DomainHandler: Send + Sync {
42 fn domain_name(&self) -> &'static str;
44
45 fn handle_command(
48 &self,
49 command: &str,
50 params: Value,
51 event_sender: &dyn EventSender,
52 ) -> Result<Value, CdpError>;
53
54 fn on_session_created(&self, _session_id: &str) {}
56
57 fn on_session_destroyed(&self, _session_id: &str) {}
59}
60
61pub trait EventSender: Send + Sync {
70 fn send_event(&self, method: &str, params: Value);
73
74 fn send_session_event(&self, session_id: &str, method: &str, params: Value) {
79 let _ = (session_id, method, params);
80 }
81}
82
83pub trait TargetProvider: Send + Sync {
92 fn list_targets(&self) -> Vec<TargetInfo>;
94
95 fn create_target(&self, url: &str) -> Result<TargetInfo, String>;
97
98 fn close_target(&self, target_id: &str) -> Result<(), String>;
100
101 fn activate_target(&self, target_id: &str) -> Result<(), String>;
103}
104
105pub struct ServerConfig {
112 pub host: String,
113 pub port: u16,
114 pub http_timeout_seconds: u64,
115 pub max_sessions: usize,
116 pub browser_name: String,
117 pub protocol_version: String,
118 pub user_agent: Option<String>,
119 pub v8_version: Option<String>,
120 pub webkit_version: Option<String>,
121}
122
123impl Default for ServerConfig {
124 fn default() -> Self {
125 ServerConfig {
126 host: "127.0.0.1".into(),
127 port: 9222,
128 http_timeout_seconds: 30,
129 max_sessions: 100,
130 browser_name: "Bao/0.1.0".into(),
131 protocol_version: "1.3".into(),
132 user_agent: None,
133 v8_version: None,
134 webkit_version: None,
135 }
136 }
137}
138
139impl ServerConfig {
140 pub fn builder() -> ServerConfigBuilder {
141 ServerConfigBuilder::default()
142 }
143}
144
145#[derive(Default)]
146pub struct ServerConfigBuilder {
147 inner: ServerConfig,
148}
149
150impl ServerConfigBuilder {
151 pub fn host(mut self, host: impl Into<String>) -> Self {
152 self.inner.host = host.into();
153 self
154 }
155
156 pub fn port(mut self, port: u16) -> Self {
157 self.inner.port = port;
158 self
159 }
160
161 pub fn http_timeout_seconds(mut self, seconds: u64) -> Self {
162 self.inner.http_timeout_seconds = seconds;
163 self
164 }
165
166 pub fn max_sessions(mut self, max: usize) -> Self {
167 self.inner.max_sessions = max;
168 self
169 }
170
171 pub fn browser_name(mut self, name: impl Into<String>) -> Self {
172 self.inner.browser_name = name.into();
173 self
174 }
175
176 pub fn user_agent(mut self, ua: impl Into<String>) -> Self {
177 self.inner.user_agent = Some(ua.into());
178 self
179 }
180
181 pub fn v8_version(mut self, ver: impl Into<String>) -> Self {
182 self.inner.v8_version = Some(ver.into());
183 self
184 }
185
186 pub fn webkit_version(mut self, ver: impl Into<String>) -> Self {
187 self.inner.webkit_version = Some(ver.into());
188 self
189 }
190
191 pub fn build(self) -> ServerConfig {
192 self.inner
193 }
194}
195
196#[cfg(test)]
197mod tests {
198 use super::*;
199
200 #[test]
203 fn server_config_default_host_is_127_0_0_1() {
204 assert_eq!(ServerConfig::default().host, "127.0.0.1");
205 }
206
207 #[test]
208 fn server_config_default_port_is_9222() {
209 assert_eq!(ServerConfig::default().port, 9222);
210 }
211
212 #[test]
213 fn server_config_default_timeout_is_30() {
214 assert_eq!(ServerConfig::default().http_timeout_seconds, 30);
215 }
216
217 #[test]
218 fn server_config_default_max_sessions_is_100() {
219 assert_eq!(ServerConfig::default().max_sessions, 100);
220 }
221
222 #[test]
223 fn server_config_default_browser_name_is_Bao() {
224 assert_eq!(ServerConfig::default().browser_name, "Bao/0.1.0");
225 }
226
227 #[test]
228 fn server_config_default_protocol_version_is_1_3() {
229 assert_eq!(ServerConfig::default().protocol_version, "1.3");
230 }
231
232 #[test]
233 fn server_config_default_user_agent_is_none() {
234 assert!(ServerConfig::default().user_agent.is_none());
235 }
236
237 #[test]
238 fn server_config_default_v8_version_is_none() {
239 assert!(ServerConfig::default().v8_version.is_none());
240 }
241
242 #[test]
243 fn server_config_default_webkit_version_is_none() {
244 assert!(ServerConfig::default().webkit_version.is_none());
245 }
246
247 #[test]
250 fn builder_sets_host() {
251 assert_eq!(
252 ServerConfig::builder().host("0.0.0.0").build().host,
253 "0.0.0.0"
254 );
255 }
256
257 #[test]
258 fn builder_sets_port() {
259 assert_eq!(ServerConfig::builder().port(8080).build().port, 8080);
260 }
261
262 #[test]
263 fn builder_sets_timeout() {
264 assert_eq!(
265 ServerConfig::builder()
266 .http_timeout_seconds(60)
267 .build()
268 .http_timeout_seconds,
269 60
270 );
271 }
272
273 #[test]
274 fn builder_sets_max_sessions() {
275 assert_eq!(
276 ServerConfig::builder()
277 .max_sessions(50)
278 .build()
279 .max_sessions,
280 50
281 );
282 }
283
284 #[test]
285 fn builder_sets_browser_name() {
286 assert_eq!(
287 ServerConfig::builder()
288 .browser_name("Chrome/120")
289 .build()
290 .browser_name,
291 "Chrome/120"
292 );
293 }
294
295 #[test]
296 fn builder_sets_user_agent() {
297 let ua = ServerConfig::builder()
298 .user_agent("Mozilla/5.0")
299 .build()
300 .user_agent;
301 assert_eq!(ua.as_deref(), Some("Mozilla/5.0"));
302 }
303
304 #[test]
305 fn builder_sets_v8_version() {
306 let ver = ServerConfig::builder()
307 .v8_version("12.0")
308 .build()
309 .v8_version;
310 assert_eq!(ver.as_deref(), Some("12.0"));
311 }
312
313 #[test]
314 fn builder_sets_webkit_version() {
315 let ver = ServerConfig::builder()
316 .webkit_version("537.36")
317 .build()
318 .webkit_version;
319 assert_eq!(ver.as_deref(), Some("537.36"));
320 }
321
322 #[test]
323 fn builder_chaining_all_fields() {
324 let cfg = ServerConfig::builder()
325 .host("0.0.0.0")
326 .port(9223)
327 .http_timeout_seconds(120)
328 .max_sessions(200)
329 .browser_name("TestBrowser")
330 .user_agent("TestAgent")
331 .v8_version("13.0")
332 .webkit_version("600.0")
333 .build();
334 assert_eq!(cfg.host, "0.0.0.0");
335 assert_eq!(cfg.port, 9223);
336 assert_eq!(cfg.http_timeout_seconds, 120);
337 assert_eq!(cfg.max_sessions, 200);
338 assert_eq!(cfg.browser_name, "TestBrowser");
339 assert_eq!(cfg.user_agent.as_deref(), Some("TestAgent"));
340 assert_eq!(cfg.v8_version.as_deref(), Some("13.0"));
341 assert_eq!(cfg.webkit_version.as_deref(), Some("600.0"));
342 }
343
344 #[test]
345 fn builder_default_then_build_equals_default_config() {
346 let built = ServerConfig::builder().build();
347 let default = ServerConfig::default();
348 assert_eq!(built.host, default.host);
349 assert_eq!(built.port, default.port);
350 assert_eq!(built.http_timeout_seconds, default.http_timeout_seconds);
351 assert_eq!(built.max_sessions, default.max_sessions);
352 assert_eq!(built.browser_name, default.browser_name);
353 assert_eq!(built.protocol_version, default.protocol_version);
354 assert_eq!(built.user_agent, default.user_agent);
355 assert_eq!(built.v8_version, default.v8_version);
356 assert_eq!(built.webkit_version, default.webkit_version);
357 }
358}