diff options
Diffstat (limited to 'components/devtools')
-rw-r--r-- | components/devtools/Cargo.toml | 1 | ||||
-rw-r--r-- | components/devtools/actors/console.rs | 97 | ||||
-rw-r--r-- | components/devtools/actors/root.rs | 13 | ||||
-rw-r--r-- | components/devtools/actors/worker.rs | 130 | ||||
-rw-r--r-- | components/devtools/lib.rs | 123 |
5 files changed, 275 insertions, 89 deletions
diff --git a/components/devtools/Cargo.toml b/components/devtools/Cargo.toml index 69d440f0f7a..8b7c6d6e199 100644 --- a/components/devtools/Cargo.toml +++ b/components/devtools/Cargo.toml @@ -22,5 +22,6 @@ log = "0.4" msg = {path = "../msg"} serde = "1.0" serde_json = "1.0" +servo_url = { path = "../url" } time = "0.1" uuid = {version = "0.8", features = ["v4"]} diff --git a/components/devtools/actors/console.rs b/components/devtools/actors/console.rs index 3f23a0c0ee5..6a6ef1243d4 100644 --- a/components/devtools/actors/console.rs +++ b/components/devtools/actors/console.rs @@ -10,7 +10,9 @@ use crate::actor::{Actor, ActorMessageStatus, ActorRegistry}; use crate::actors::browsing_context::BrowsingContextActor; use crate::actors::object::ObjectActor; +use crate::actors::worker::WorkerActor; use crate::protocol::JsonPacketStream; +use crate::UniqueId; use crate::{ConsoleAPICall, ConsoleMessage, ConsoleMsg, PageErrorMsg}; use devtools_traits::CachedConsoleMessage; use devtools_traits::EvaluateJSReply::{ActorValue, BooleanValue, StringValue}; @@ -18,10 +20,10 @@ use devtools_traits::EvaluateJSReply::{NullValue, NumberValue, VoidValue}; use devtools_traits::{ CachedConsoleMessageTypes, ConsoleAPI, DevtoolScriptControlMsg, LogLevel, PageError, }; -use ipc_channel::ipc; -use msg::constellation_msg::PipelineId; +use ipc_channel::ipc::{self, IpcSender}; +use msg::constellation_msg::TEST_PIPELINE_ID; use serde_json::{self, Map, Number, Value}; -use std::cell::RefCell; +use std::cell::{RefCell, RefMut}; use std::collections::HashMap; use std::net::TcpStream; use time::precise_time_ns; @@ -106,25 +108,68 @@ struct SetPreferencesReply { updated: Vec<String>, } -pub struct ConsoleActor { +pub(crate) enum Root { + BrowsingContext(String), + DedicatedWorker(String), +} + +pub(crate) struct ConsoleActor { pub name: String, - pub browsing_context: String, - pub cached_events: RefCell<HashMap<PipelineId, Vec<CachedConsoleMessage>>>, + pub root: Root, + pub cached_events: RefCell<HashMap<UniqueId, Vec<CachedConsoleMessage>>>, } impl ConsoleActor { + fn script_chan<'a>( + &self, + registry: &'a ActorRegistry, + ) -> &'a IpcSender<DevtoolScriptControlMsg> { + match &self.root { + Root::BrowsingContext(bc) => ®istry.find::<BrowsingContextActor>(bc).script_chan, + Root::DedicatedWorker(worker) => ®istry.find::<WorkerActor>(worker).script_chan, + } + } + + fn streams_mut<'a>(&self, registry: &'a ActorRegistry) -> RefMut<'a, Vec<TcpStream>> { + match &self.root { + Root::BrowsingContext(bc) => registry + .find::<BrowsingContextActor>(bc) + .streams + .borrow_mut(), + Root::DedicatedWorker(worker) => { + registry.find::<WorkerActor>(worker).streams.borrow_mut() + }, + } + } + + fn current_unique_id(&self, registry: &ActorRegistry) -> UniqueId { + match &self.root { + Root::BrowsingContext(bc) => UniqueId::Pipeline( + registry + .find::<BrowsingContextActor>(bc) + .active_pipeline + .get(), + ), + Root::DedicatedWorker(w) => UniqueId::Worker(registry.find::<WorkerActor>(w).id), + } + } + fn evaluateJS( &self, registry: &ActorRegistry, msg: &Map<String, Value>, ) -> Result<EvaluateJSReply, ()> { - let browsing_context = registry.find::<BrowsingContextActor>(&self.browsing_context); let input = msg.get("text").unwrap().as_str().unwrap().to_owned(); let (chan, port) = ipc::channel().unwrap(); - browsing_context - .script_chan + // FIXME: redesign messages so we don't have to fake pipeline ids when + // communicating with workers. + let pipeline = match self.current_unique_id(registry) { + UniqueId::Pipeline(p) => p, + UniqueId::Worker(_) => TEST_PIPELINE_ID, + }; + self.script_chan(registry) .send(DevtoolScriptControlMsg::EvaluateJS( - browsing_context.active_pipeline.get(), + pipeline, input.clone(), chan, )) @@ -196,21 +241,21 @@ impl ConsoleActor { pub(crate) fn handle_page_error( &self, page_error: PageError, - pipeline: PipelineId, - browsing_context: &BrowsingContextActor, + id: UniqueId, + registry: &ActorRegistry, ) { self.cached_events .borrow_mut() - .entry(pipeline) + .entry(id.clone()) .or_insert(vec![]) .push(CachedConsoleMessage::PageError(page_error.clone())); - if browsing_context.active_pipeline.get() == pipeline { + if id == self.current_unique_id(registry) { let msg = PageErrorMsg { from: self.name(), type_: "pageError".to_owned(), pageError: page_error, }; - for stream in &mut *browsing_context.streams.borrow_mut() { + for stream in &mut *self.streams_mut(registry) { stream.write_json_packet(&msg); } } @@ -219,8 +264,8 @@ impl ConsoleActor { pub(crate) fn handle_console_api( &self, console_message: ConsoleMessage, - pipeline: PipelineId, - browsing_context: &BrowsingContextActor, + id: UniqueId, + registry: &ActorRegistry, ) { let level = match console_message.logLevel { LogLevel::Debug => "debug", @@ -232,7 +277,7 @@ impl ConsoleActor { .to_owned(); self.cached_events .borrow_mut() - .entry(pipeline) + .entry(id.clone()) .or_insert(vec![]) .push(CachedConsoleMessage::ConsoleAPI(ConsoleAPI { type_: "ConsoleAPI".to_owned(), @@ -244,7 +289,7 @@ impl ConsoleActor { private: false, arguments: vec![console_message.message.clone()], })); - if browsing_context.active_pipeline.get() == pipeline { + if id == self.current_unique_id(registry) { let msg = ConsoleAPICall { from: self.name(), type_: "consoleAPICall".to_owned(), @@ -257,7 +302,7 @@ impl ConsoleActor { columnNumber: console_message.columnNumber, }, }; - for stream in &mut *browsing_context.streams.borrow_mut() { + for stream in &mut *self.streams_mut(registry) { stream.write_json_packet(&msg); } } @@ -278,11 +323,11 @@ impl Actor for ConsoleActor { ) -> Result<ActorMessageStatus, ()> { Ok(match msg_type { "clearMessagesCache" => { - let browsing_context = - registry.find::<BrowsingContextActor>(&self.browsing_context); - self.cached_events.borrow_mut().remove(&browsing_context.active_pipeline.get()); + self.cached_events + .borrow_mut() + .remove(&self.current_unique_id(registry)); ActorMessageStatus::Processed - } + }, "getCachedMessages" => { let str_types = msg @@ -302,13 +347,11 @@ impl Actor for ConsoleActor { s => debug!("unrecognized message type requested: \"{}\"", s), }; } - let browsing_context = - registry.find::<BrowsingContextActor>(&self.browsing_context); let mut messages = vec![]; for event in self .cached_events .borrow() - .get(&browsing_context.active_pipeline.get()) + .get(&self.current_unique_id(registry)) .unwrap_or(&vec![]) .iter() { diff --git a/components/devtools/actors/root.rs b/components/devtools/actors/root.rs index da7483ffb34..0010afd3b9f 100644 --- a/components/devtools/actors/root.rs +++ b/components/devtools/actors/root.rs @@ -10,6 +10,7 @@ use crate::actor::{Actor, ActorMessageStatus, ActorRegistry}; use crate::actors::browsing_context::{BrowsingContextActor, BrowsingContextActorMsg}; use crate::actors::device::DeviceActor; use crate::actors::performance::PerformanceActor; +use crate::actors::worker::{WorkerActor, WorkerMsg}; use crate::protocol::{ActorDescription, JsonPacketStream}; use serde_json::{Map, Value}; use std::net::TcpStream; @@ -73,11 +74,6 @@ struct ListWorkersReply { } #[derive(Serialize)] -struct WorkerMsg { - id: u32, -} - -#[derive(Serialize)] struct ListServiceWorkerRegistrationsReply { from: String, registrations: Vec<u32>, // TODO: follow actual JSON structure. @@ -110,6 +106,7 @@ struct GetProcessResponse { pub struct RootActor { pub tabs: Vec<String>, + pub workers: Vec<String>, pub performance: String, pub device: String, pub preference: String, @@ -203,7 +200,11 @@ impl Actor for RootActor { "listWorkers" => { let reply = ListWorkersReply { from: self.name(), - workers: vec![], + workers: self + .workers + .iter() + .map(|name| registry.find::<WorkerActor>(name).encodable()) + .collect(), }; stream.write_json_packet(&reply); ActorMessageStatus::Processed diff --git a/components/devtools/actors/worker.rs b/components/devtools/actors/worker.rs index 082d719de20..fd578d0d3dc 100644 --- a/components/devtools/actors/worker.rs +++ b/components/devtools/actors/worker.rs @@ -3,14 +3,49 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use crate::actor::{Actor, ActorMessageStatus, ActorRegistry}; -use devtools_traits::WorkerId; +use crate::protocol::JsonPacketStream; +use devtools_traits::DevtoolScriptControlMsg::WantsLiveNotifications; +use devtools_traits::{DevtoolScriptControlMsg, WorkerId}; +use ipc_channel::ipc::IpcSender; +use msg::constellation_msg::TEST_PIPELINE_ID; use serde_json::{Map, Value}; +use servo_url::ServoUrl; +use std::cell::RefCell; use std::net::TcpStream; +#[derive(Clone, Copy)] +#[allow(dead_code)] +pub enum WorkerType { + Dedicated = 0, + Shared = 1, + Service = 2, +} + pub struct WorkerActor { pub name: String, pub console: String, + pub thread: String, pub id: WorkerId, + pub url: ServoUrl, + pub type_: WorkerType, + pub script_chan: IpcSender<DevtoolScriptControlMsg>, + pub streams: RefCell<Vec<TcpStream>>, +} + +impl WorkerActor { + pub(crate) fn encodable(&self) -> WorkerMsg { + WorkerMsg { + actor: self.name.clone(), + consoleActor: self.console.clone(), + threadActor: self.thread.clone(), + id: self.id.0.to_string(), + url: self.url.to_string(), + traits: WorkerTraits { + isParentInterceptEnabled: false, + }, + type_: self.type_ as u32, + } + } } impl Actor for WorkerActor { @@ -19,11 +54,94 @@ impl Actor for WorkerActor { } fn handle_message( &self, - _: &ActorRegistry, - _: &str, - _: &Map<String, Value>, - _: &mut TcpStream, + _registry: &ActorRegistry, + msg_type: &str, + _msg: &Map<String, Value>, + stream: &mut TcpStream, ) -> Result<ActorMessageStatus, ()> { - Ok(ActorMessageStatus::Processed) + Ok(match msg_type { + "attach" => { + let msg = AttachedReply { + from: self.name(), + type_: "attached".to_owned(), + url: self.url.as_str().to_owned(), + }; + self.streams.borrow_mut().push(stream.try_clone().unwrap()); + stream.write_json_packet(&msg); + // FIXME: fix messages to not require forging a pipeline for worker messages + self.script_chan + .send(WantsLiveNotifications(TEST_PIPELINE_ID, true)) + .unwrap(); + ActorMessageStatus::Processed + }, + + "connect" => { + let msg = ConnectReply { + from: self.name(), + type_: "connected".to_owned(), + threadActor: self.thread.clone(), + consoleActor: self.console.clone(), + }; + stream.write_json_packet(&msg); + ActorMessageStatus::Processed + }, + + "detach" => { + let msg = DetachedReply { + from: self.name(), + type_: "detached".to_string(), + }; + // FIXME: we should ensure we're removing the correct stream. + self.streams.borrow_mut().pop(); + stream.write_json_packet(&msg); + self.script_chan + .send(WantsLiveNotifications(TEST_PIPELINE_ID, false)) + .unwrap(); + ActorMessageStatus::Processed + }, + + _ => ActorMessageStatus::Ignored, + }) } } + +#[derive(Serialize)] +struct DetachedReply { + from: String, + #[serde(rename = "type")] + type_: String, +} + +#[derive(Serialize)] +struct AttachedReply { + from: String, + #[serde(rename = "type")] + type_: String, + url: String, +} + +#[derive(Serialize)] +struct ConnectReply { + from: String, + #[serde(rename = "type")] + type_: String, + threadActor: String, + consoleActor: String, +} + +#[derive(Serialize)] +struct WorkerTraits { + isParentInterceptEnabled: bool, +} + +#[derive(Serialize)] +pub(crate) struct WorkerMsg { + actor: String, + consoleActor: String, + threadActor: String, + id: String, + url: String, + traits: WorkerTraits, + #[serde(rename = "type")] + type_: u32, +} diff --git a/components/devtools/lib.rs b/components/devtools/lib.rs index 6d9bd938e14..477e44494ee 100644 --- a/components/devtools/lib.rs +++ b/components/devtools/lib.rs @@ -19,7 +19,7 @@ extern crate serde; use crate::actor::{Actor, ActorRegistry}; use crate::actors::browsing_context::BrowsingContextActor; -use crate::actors::console::ConsoleActor; +use crate::actors::console::{ConsoleActor, Root}; use crate::actors::device::DeviceActor; use crate::actors::framerate::FramerateActor; use crate::actors::network_event::{EventActor, NetworkEventActor, ResponseStartMsg}; @@ -27,7 +27,8 @@ use crate::actors::performance::PerformanceActor; use crate::actors::preference::PreferenceActor; use crate::actors::process::ProcessActor; use crate::actors::root::RootActor; -use crate::actors::worker::WorkerActor; +use crate::actors::thread::ThreadActor; +use crate::actors::worker::{WorkerActor, WorkerType}; use crate::protocol::JsonPacketStream; use crossbeam_channel::{unbounded, Receiver, Sender}; use devtools_traits::{ChromeToDevtoolsControlMsg, ConsoleMessage, DevtoolsControlMsg}; @@ -69,6 +70,12 @@ mod actors { } mod protocol; +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +enum UniqueId { + Pipeline(PipelineId), + Worker(WorkerId), +} + #[derive(Serialize)] struct ConsoleAPICall { from: String, @@ -176,6 +183,7 @@ fn run_server( let root = Box::new(RootActor { tabs: vec![], + workers: vec![], device: device.name(), performance: performance.name(), preference: preference.name(), @@ -197,7 +205,7 @@ fn run_server( let mut pipelines: HashMap<PipelineId, BrowsingContextId> = HashMap::new(); let mut actor_requests: HashMap<String, String> = HashMap::new(); - let mut actor_workers: HashMap<(PipelineId, WorkerId), String> = HashMap::new(); + let mut actor_workers: HashMap<WorkerId, String> = HashMap::new(); /// Process the input from a single devtools client until EOF. fn handle_client(actors: Arc<Mutex<ActorRegistry>>, mut stream: TcpStream) { @@ -258,11 +266,11 @@ fn run_server( // TODO: move this into the root or target modules? fn handle_new_global( actors: Arc<Mutex<ActorRegistry>>, - ids: (Option<BrowsingContextId>, PipelineId, Option<WorkerId>), + ids: (BrowsingContextId, PipelineId, Option<WorkerId>), script_sender: IpcSender<DevtoolScriptControlMsg>, browsing_contexts: &mut HashMap<BrowsingContextId, String>, pipelines: &mut HashMap<PipelineId, BrowsingContextId>, - actor_workers: &mut HashMap<(PipelineId, WorkerId), String>, + actor_workers: &mut HashMap<WorkerId, String>, page_info: DevtoolsPageInfo, ) { let mut actors = actors.lock().unwrap(); @@ -271,47 +279,59 @@ fn run_server( let console_name = actors.new_name("console"); - let browsing_context_name = if let Some(browsing_context) = browsing_context { - pipelines.insert(pipeline, browsing_context); - if let Some(actor) = browsing_contexts.get(&browsing_context) { - actor.to_owned() - } else { - let browsing_context_actor = BrowsingContextActor::new( - console_name.clone(), - browsing_context, - page_info, - pipeline, - script_sender.clone(), - &mut *actors, - ); - let name = browsing_context_actor.name(); - browsing_contexts.insert(browsing_context, name.clone()); - actors.register(Box::new(browsing_context_actor)); - name - } - } else { - "".to_owned() - }; + let parent_actor = if let Some(id) = worker_id { + assert!(pipelines.get(&pipeline).is_some()); + assert!(browsing_contexts.get(&browsing_context).is_some()); - // XXXjdm this new actor is useless if it's not a new worker global - let console = ConsoleActor { - name: console_name, - cached_events: Default::default(), - browsing_context: browsing_context_name, - }; + let thread = ThreadActor::new(actors.new_name("context")); + let thread_name = thread.name(); + actors.register(Box::new(thread)); - if let Some(id) = worker_id { + let worker_name = actors.new_name("worker"); let worker = WorkerActor { - name: actors.new_name("worker"), - console: console.name(), + name: worker_name.clone(), + console: console_name.clone(), + thread: thread_name, id: id, + url: page_info.url.clone(), + type_: WorkerType::Dedicated, + script_chan: script_sender, + streams: Default::default(), }; let root = actors.find_mut::<RootActor>("root"); - root.tabs.push(worker.name.clone()); + root.workers.push(worker.name.clone()); - actor_workers.insert((pipeline, id), worker.name.clone()); + actor_workers.insert(id, worker_name.clone()); actors.register(Box::new(worker)); - } + + Root::DedicatedWorker(worker_name) + } else { + pipelines.insert(pipeline, browsing_context); + Root::BrowsingContext( + if let Some(actor) = browsing_contexts.get(&browsing_context) { + actor.to_owned() + } else { + let browsing_context_actor = BrowsingContextActor::new( + console_name.clone(), + browsing_context, + page_info, + pipeline, + script_sender, + &mut *actors, + ); + let name = browsing_context_actor.name(); + browsing_contexts.insert(browsing_context, name.clone()); + actors.register(Box::new(browsing_context_actor)); + name + }, + ) + }; + + let console = ConsoleActor { + name: console_name, + cached_events: Default::default(), + root: parent_actor, + }; actors.register(Box::new(console)); } @@ -319,15 +339,17 @@ fn run_server( fn handle_page_error( actors: Arc<Mutex<ActorRegistry>>, id: PipelineId, + worker_id: Option<WorkerId>, page_error: PageError, browsing_contexts: &HashMap<BrowsingContextId, String>, + actor_workers: &HashMap<WorkerId, String>, pipelines: &HashMap<PipelineId, BrowsingContextId>, ) { let console_actor_name = match find_console_actor( actors.clone(), id, - None, - &HashMap::new(), + worker_id, + actor_workers, browsing_contexts, pipelines, ) { @@ -336,9 +358,8 @@ fn run_server( }; let actors = actors.lock().unwrap(); let console_actor = actors.find::<ConsoleActor>(&console_actor_name); - let browsing_context_actor = - actors.find::<BrowsingContextActor>(&console_actor.browsing_context); - console_actor.handle_page_error(page_error, id, &browsing_context_actor); + let id = worker_id.map_or(UniqueId::Pipeline(id), UniqueId::Worker); + console_actor.handle_page_error(page_error, id, &*actors); } fn handle_console_message( @@ -347,7 +368,7 @@ fn run_server( worker_id: Option<WorkerId>, console_message: ConsoleMessage, browsing_contexts: &HashMap<BrowsingContextId, String>, - actor_workers: &HashMap<(PipelineId, WorkerId), String>, + actor_workers: &HashMap<WorkerId, String>, pipelines: &HashMap<PipelineId, BrowsingContextId>, ) { let console_actor_name = match find_console_actor( @@ -363,22 +384,21 @@ fn run_server( }; let actors = actors.lock().unwrap(); let console_actor = actors.find::<ConsoleActor>(&console_actor_name); - let browsing_context_actor = - actors.find::<BrowsingContextActor>(&console_actor.browsing_context); - console_actor.handle_console_api(console_message, id, &browsing_context_actor); + let id = worker_id.map_or(UniqueId::Pipeline(id), UniqueId::Worker); + console_actor.handle_console_api(console_message, id, &*actors); } fn find_console_actor( actors: Arc<Mutex<ActorRegistry>>, pipeline: PipelineId, worker_id: Option<WorkerId>, - actor_workers: &HashMap<(PipelineId, WorkerId), String>, + actor_workers: &HashMap<WorkerId, String>, browsing_contexts: &HashMap<BrowsingContextId, String>, pipelines: &HashMap<PipelineId, BrowsingContextId>, ) -> Option<String> { let actors = actors.lock().unwrap(); if let Some(worker_id) = worker_id { - let actor_name = (*actor_workers).get(&(pipeline, worker_id))?; + let actor_name = actor_workers.get(&worker_id)?; Some(actors.find::<WorkerActor>(actor_name).console.clone()) } else { let id = pipelines.get(&pipeline)?; @@ -397,7 +417,7 @@ fn run_server( mut connections: Vec<TcpStream>, browsing_contexts: &HashMap<BrowsingContextId, String>, actor_requests: &mut HashMap<String, String>, - actor_workers: &HashMap<(PipelineId, WorkerId), String>, + actor_workers: &HashMap<WorkerId, String>, pipelines: &HashMap<PipelineId, BrowsingContextId>, pipeline_id: PipelineId, request_id: String, @@ -570,6 +590,7 @@ fn run_server( .expect("Thread spawning failed"); while let Ok(msg) = receiver.recv() { + debug!("{:?}", msg); match msg { DevtoolsControlMsg::FromChrome(ChromeToDevtoolsControlMsg::AddClient(stream)) => { let actors = actors.clone(); @@ -619,8 +640,10 @@ fn run_server( )) => handle_page_error( actors.clone(), id, + None, page_error, &browsing_contexts, + &actor_workers, &pipelines, ), DevtoolsControlMsg::FromScript(ScriptToDevtoolsControlMsg::ReportCSSError( |