Initial Release
This commit is contained in:
1 parent
2e5d63cc35
commit
8749725b45
52 files changed
+19804
No files matched your search
@@ -0,0 +1,136 @@
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use obscura_browser::{BrowserContext, Page};
|
||||
use obscura_js::ops::{InterceptResolution, InterceptedRequest};
|
||||
use serde_json::json;
|
||||
|
||||
use crate::domains;
|
||||
use crate::domains::fetch::FetchInterceptState;
|
||||
use crate::types::{CdpEvent, CdpRequest, CdpResponse};
|
||||
|
||||
pub struct CdpContext {
|
||||
pub pages: Vec<Page>,
|
||||
pub sessions: HashMap<String, String>, // session_id -> page_id
|
||||
pub pending_events: Vec<CdpEvent>,
|
||||
pub default_context: Arc<BrowserContext>,
|
||||
page_counter: u32,
|
||||
pub preload_scripts: Vec<(String, String)>, // (identifier, source)
|
||||
pub preload_counter: u32,
|
||||
pub fetch_intercept: FetchInterceptState,
|
||||
pub intercept_tx: Option<tokio::sync::mpsc::UnboundedSender<InterceptedRequest>>,
|
||||
}
|
||||
|
||||
impl CdpContext {
|
||||
pub fn new() -> Self {
|
||||
Self::new_with_proxy(None)
|
||||
}
|
||||
|
||||
pub fn new_with_proxy(proxy: Option<String>) -> Self {
|
||||
let default_context = Arc::new(BrowserContext::with_proxy("default".to_string(), proxy));
|
||||
CdpContext {
|
||||
pages: Vec::new(),
|
||||
sessions: HashMap::new(),
|
||||
pending_events: Vec::new(),
|
||||
default_context,
|
||||
page_counter: 0,
|
||||
preload_scripts: Vec::new(),
|
||||
preload_counter: 0,
|
||||
fetch_intercept: FetchInterceptState::new(),
|
||||
intercept_tx: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_page(&mut self) -> String {
|
||||
self.page_counter += 1;
|
||||
let page_id = format!("page-{}", self.page_counter);
|
||||
let mut page = Page::new(page_id.clone(), self.default_context.clone());
|
||||
page.navigate_blank();
|
||||
self.pages.push(page);
|
||||
page_id
|
||||
}
|
||||
|
||||
pub fn get_page(&self, id: &str) -> Option<&Page> {
|
||||
self.pages.iter().find(|p| p.id == id)
|
||||
}
|
||||
|
||||
pub fn get_page_mut(&mut self, id: &str) -> Option<&mut Page> {
|
||||
self.pages.iter_mut().find(|p| p.id == id)
|
||||
}
|
||||
|
||||
pub fn remove_page(&mut self, id: &str) {
|
||||
self.pages.retain(|p| p.id != id);
|
||||
self.sessions.retain(|_, v| v != id);
|
||||
}
|
||||
|
||||
pub fn get_session_page(&self, session_id: &Option<String>) -> Option<&Page> {
|
||||
let page_id = session_id
|
||||
.as_ref()
|
||||
.and_then(|sid| self.sessions.get(sid))?;
|
||||
self.get_page(page_id)
|
||||
}
|
||||
|
||||
pub fn get_session_page_mut(&mut self, session_id: &Option<String>) -> Option<&mut Page> {
|
||||
let page_id = session_id
|
||||
.as_ref()
|
||||
.and_then(|sid| self.sessions.get(sid))
|
||||
.cloned()?;
|
||||
|
||||
let target_has_js = self.pages.iter().any(|p| p.id == page_id && p.has_js());
|
||||
|
||||
if !target_has_js {
|
||||
for page in &mut self.pages {
|
||||
if page.id != page_id && page.has_js() {
|
||||
page.suspend_js();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if let Some(target) = self.pages.iter_mut().find(|p| p.id == page_id) {
|
||||
target.resume_js();
|
||||
}
|
||||
}
|
||||
|
||||
self.get_page_mut(&page_id)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn dispatch(req: &CdpRequest, ctx: &mut CdpContext) -> CdpResponse {
|
||||
let (domain, method) = match req.method.split_once('.') {
|
||||
Some((d, m)) => (d, m),
|
||||
None => {
|
||||
return CdpResponse::error(
|
||||
req.id,
|
||||
-32601,
|
||||
format!("Invalid method format: {}", req.method),
|
||||
req.session_id.clone(),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
let result = match domain {
|
||||
"Target" => domains::target::handle(method, &req.params, ctx).await,
|
||||
"Browser" => domains::browser::handle(method, &req.params).await,
|
||||
"Page" => domains::page::handle(method, &req.params, ctx, &req.session_id).await,
|
||||
"DOM" => domains::dom::handle(method, &req.params, ctx, &req.session_id).await,
|
||||
"Runtime" => domains::runtime::handle(method, &req.params, ctx, &req.session_id).await,
|
||||
"Network" => domains::network::handle(method, &req.params, ctx, &req.session_id).await,
|
||||
"Fetch" => domains::fetch::handle(method, &req.params, ctx, &req.session_id).await,
|
||||
"Input" => domains::input::handle(method, &req.params, ctx, &req.session_id).await,
|
||||
"Storage" => domains::storage::handle(method, &req.params, ctx, &req.session_id).await,
|
||||
"LP" => domains::lp::handle(method, &req.params, ctx, &req.session_id).await,
|
||||
"Emulation" | "Log" | "Performance" | "Security" | "CSS"
|
||||
| "Accessibility" | "ServiceWorker" | "Inspector"
|
||||
| "Debugger" | "Profiler" | "HeapProfiler" | "Overlay" => {
|
||||
Ok(json!({}))
|
||||
}
|
||||
_ => Err(format!("Unknown domain: {}", domain)),
|
||||
};
|
||||
|
||||
match result {
|
||||
Ok(value) => CdpResponse::success(req.id, value, req.session_id.clone()),
|
||||
Err(msg) => {
|
||||
tracing::warn!("CDP error for {}: {}", req.method, msg);
|
||||
CdpResponse::error(req.id, -32601, msg, req.session_id.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user