Support connecting to worker globals from remote devtools.

This commit is contained in:
Josh Matthews 2020-04-26 17:34:52 -04:00
parent bce4ec5b70
commit 565e9432c6
13 changed files with 340 additions and 144 deletions

1
Cargo.lock generated
View file

@ -1189,6 +1189,7 @@ dependencies = [
"msg", "msg",
"serde", "serde",
"serde_json", "serde_json",
"servo_url",
"time", "time",
"uuid", "uuid",
] ]

View file

@ -22,5 +22,6 @@ log = "0.4"
msg = {path = "../msg"} msg = {path = "../msg"}
serde = "1.0" serde = "1.0"
serde_json = "1.0" serde_json = "1.0"
servo_url = { path = "../url" }
time = "0.1" time = "0.1"
uuid = {version = "0.8", features = ["v4"]} uuid = {version = "0.8", features = ["v4"]}

View file

@ -10,7 +10,9 @@
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry}; use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
use crate::actors::browsing_context::BrowsingContextActor; use crate::actors::browsing_context::BrowsingContextActor;
use crate::actors::object::ObjectActor; use crate::actors::object::ObjectActor;
use crate::actors::worker::WorkerActor;
use crate::protocol::JsonPacketStream; use crate::protocol::JsonPacketStream;
use crate::UniqueId;
use crate::{ConsoleAPICall, ConsoleMessage, ConsoleMsg, PageErrorMsg}; use crate::{ConsoleAPICall, ConsoleMessage, ConsoleMsg, PageErrorMsg};
use devtools_traits::CachedConsoleMessage; use devtools_traits::CachedConsoleMessage;
use devtools_traits::EvaluateJSReply::{ActorValue, BooleanValue, StringValue}; use devtools_traits::EvaluateJSReply::{ActorValue, BooleanValue, StringValue};
@ -18,10 +20,10 @@ use devtools_traits::EvaluateJSReply::{NullValue, NumberValue, VoidValue};
use devtools_traits::{ use devtools_traits::{
CachedConsoleMessageTypes, ConsoleAPI, DevtoolScriptControlMsg, LogLevel, PageError, CachedConsoleMessageTypes, ConsoleAPI, DevtoolScriptControlMsg, LogLevel, PageError,
}; };
use ipc_channel::ipc; use ipc_channel::ipc::{self, IpcSender};
use msg::constellation_msg::PipelineId; use msg::constellation_msg::TEST_PIPELINE_ID;
use serde_json::{self, Map, Number, Value}; use serde_json::{self, Map, Number, Value};
use std::cell::RefCell; use std::cell::{RefCell, RefMut};
use std::collections::HashMap; use std::collections::HashMap;
use std::net::TcpStream; use std::net::TcpStream;
use time::precise_time_ns; use time::precise_time_ns;
@ -106,25 +108,68 @@ struct SetPreferencesReply {
updated: Vec<String>, updated: Vec<String>,
} }
pub struct ConsoleActor { pub(crate) enum Root {
BrowsingContext(String),
DedicatedWorker(String),
}
pub(crate) struct ConsoleActor {
pub name: String, pub name: String,
pub browsing_context: String, pub root: Root,
pub cached_events: RefCell<HashMap<PipelineId, Vec<CachedConsoleMessage>>>, pub cached_events: RefCell<HashMap<UniqueId, Vec<CachedConsoleMessage>>>,
} }
impl ConsoleActor { impl ConsoleActor {
fn script_chan<'a>(
&self,
registry: &'a ActorRegistry,
) -> &'a IpcSender<DevtoolScriptControlMsg> {
match &self.root {
Root::BrowsingContext(bc) => &registry.find::<BrowsingContextActor>(bc).script_chan,
Root::DedicatedWorker(worker) => &registry.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( fn evaluateJS(
&self, &self,
registry: &ActorRegistry, registry: &ActorRegistry,
msg: &Map<String, Value>, msg: &Map<String, Value>,
) -> Result<EvaluateJSReply, ()> { ) -> Result<EvaluateJSReply, ()> {
let browsing_context = registry.find::<BrowsingContextActor>(&self.browsing_context);
let input = msg.get("text").unwrap().as_str().unwrap().to_owned(); let input = msg.get("text").unwrap().as_str().unwrap().to_owned();
let (chan, port) = ipc::channel().unwrap(); let (chan, port) = ipc::channel().unwrap();
browsing_context // FIXME: redesign messages so we don't have to fake pipeline ids when
.script_chan // 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( .send(DevtoolScriptControlMsg::EvaluateJS(
browsing_context.active_pipeline.get(), pipeline,
input.clone(), input.clone(),
chan, chan,
)) ))
@ -196,21 +241,21 @@ impl ConsoleActor {
pub(crate) fn handle_page_error( pub(crate) fn handle_page_error(
&self, &self,
page_error: PageError, page_error: PageError,
pipeline: PipelineId, id: UniqueId,
browsing_context: &BrowsingContextActor, registry: &ActorRegistry,
) { ) {
self.cached_events self.cached_events
.borrow_mut() .borrow_mut()
.entry(pipeline) .entry(id.clone())
.or_insert(vec![]) .or_insert(vec![])
.push(CachedConsoleMessage::PageError(page_error.clone())); .push(CachedConsoleMessage::PageError(page_error.clone()));
if browsing_context.active_pipeline.get() == pipeline { if id == self.current_unique_id(registry) {
let msg = PageErrorMsg { let msg = PageErrorMsg {
from: self.name(), from: self.name(),
type_: "pageError".to_owned(), type_: "pageError".to_owned(),
pageError: page_error, 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); stream.write_json_packet(&msg);
} }
} }
@ -219,8 +264,8 @@ impl ConsoleActor {
pub(crate) fn handle_console_api( pub(crate) fn handle_console_api(
&self, &self,
console_message: ConsoleMessage, console_message: ConsoleMessage,
pipeline: PipelineId, id: UniqueId,
browsing_context: &BrowsingContextActor, registry: &ActorRegistry,
) { ) {
let level = match console_message.logLevel { let level = match console_message.logLevel {
LogLevel::Debug => "debug", LogLevel::Debug => "debug",
@ -232,7 +277,7 @@ impl ConsoleActor {
.to_owned(); .to_owned();
self.cached_events self.cached_events
.borrow_mut() .borrow_mut()
.entry(pipeline) .entry(id.clone())
.or_insert(vec![]) .or_insert(vec![])
.push(CachedConsoleMessage::ConsoleAPI(ConsoleAPI { .push(CachedConsoleMessage::ConsoleAPI(ConsoleAPI {
type_: "ConsoleAPI".to_owned(), type_: "ConsoleAPI".to_owned(),
@ -244,7 +289,7 @@ impl ConsoleActor {
private: false, private: false,
arguments: vec![console_message.message.clone()], arguments: vec![console_message.message.clone()],
})); }));
if browsing_context.active_pipeline.get() == pipeline { if id == self.current_unique_id(registry) {
let msg = ConsoleAPICall { let msg = ConsoleAPICall {
from: self.name(), from: self.name(),
type_: "consoleAPICall".to_owned(), type_: "consoleAPICall".to_owned(),
@ -257,7 +302,7 @@ impl ConsoleActor {
columnNumber: console_message.columnNumber, 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); stream.write_json_packet(&msg);
} }
} }
@ -278,11 +323,11 @@ impl Actor for ConsoleActor {
) -> Result<ActorMessageStatus, ()> { ) -> Result<ActorMessageStatus, ()> {
Ok(match msg_type { Ok(match msg_type {
"clearMessagesCache" => { "clearMessagesCache" => {
let browsing_context = self.cached_events
registry.find::<BrowsingContextActor>(&self.browsing_context); .borrow_mut()
self.cached_events.borrow_mut().remove(&browsing_context.active_pipeline.get()); .remove(&self.current_unique_id(registry));
ActorMessageStatus::Processed ActorMessageStatus::Processed
} },
"getCachedMessages" => { "getCachedMessages" => {
let str_types = msg let str_types = msg
@ -302,13 +347,11 @@ impl Actor for ConsoleActor {
s => debug!("unrecognized message type requested: \"{}\"", s), s => debug!("unrecognized message type requested: \"{}\"", s),
}; };
} }
let browsing_context =
registry.find::<BrowsingContextActor>(&self.browsing_context);
let mut messages = vec![]; let mut messages = vec![];
for event in self for event in self
.cached_events .cached_events
.borrow() .borrow()
.get(&browsing_context.active_pipeline.get()) .get(&self.current_unique_id(registry))
.unwrap_or(&vec![]) .unwrap_or(&vec![])
.iter() .iter()
{ {

View file

@ -10,6 +10,7 @@ use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
use crate::actors::browsing_context::{BrowsingContextActor, BrowsingContextActorMsg}; use crate::actors::browsing_context::{BrowsingContextActor, BrowsingContextActorMsg};
use crate::actors::device::DeviceActor; use crate::actors::device::DeviceActor;
use crate::actors::performance::PerformanceActor; use crate::actors::performance::PerformanceActor;
use crate::actors::worker::{WorkerActor, WorkerMsg};
use crate::protocol::{ActorDescription, JsonPacketStream}; use crate::protocol::{ActorDescription, JsonPacketStream};
use serde_json::{Map, Value}; use serde_json::{Map, Value};
use std::net::TcpStream; use std::net::TcpStream;
@ -72,11 +73,6 @@ struct ListWorkersReply {
workers: Vec<WorkerMsg>, workers: Vec<WorkerMsg>,
} }
#[derive(Serialize)]
struct WorkerMsg {
id: u32,
}
#[derive(Serialize)] #[derive(Serialize)]
struct ListServiceWorkerRegistrationsReply { struct ListServiceWorkerRegistrationsReply {
from: String, from: String,
@ -110,6 +106,7 @@ struct GetProcessResponse {
pub struct RootActor { pub struct RootActor {
pub tabs: Vec<String>, pub tabs: Vec<String>,
pub workers: Vec<String>,
pub performance: String, pub performance: String,
pub device: String, pub device: String,
pub preference: String, pub preference: String,
@ -203,7 +200,11 @@ impl Actor for RootActor {
"listWorkers" => { "listWorkers" => {
let reply = ListWorkersReply { let reply = ListWorkersReply {
from: self.name(), from: self.name(),
workers: vec![], workers: self
.workers
.iter()
.map(|name| registry.find::<WorkerActor>(name).encodable())
.collect(),
}; };
stream.write_json_packet(&reply); stream.write_json_packet(&reply);
ActorMessageStatus::Processed ActorMessageStatus::Processed

View file

@ -3,14 +3,49 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry}; 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 serde_json::{Map, Value};
use servo_url::ServoUrl;
use std::cell::RefCell;
use std::net::TcpStream; use std::net::TcpStream;
#[derive(Clone, Copy)]
#[allow(dead_code)]
pub enum WorkerType {
Dedicated = 0,
Shared = 1,
Service = 2,
}
pub struct WorkerActor { pub struct WorkerActor {
pub name: String, pub name: String,
pub console: String, pub console: String,
pub thread: String,
pub id: WorkerId, 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 { impl Actor for WorkerActor {
@ -19,11 +54,94 @@ impl Actor for WorkerActor {
} }
fn handle_message( fn handle_message(
&self, &self,
_: &ActorRegistry, _registry: &ActorRegistry,
_: &str, msg_type: &str,
_: &Map<String, Value>, _msg: &Map<String, Value>,
_: &mut TcpStream, stream: &mut TcpStream,
) -> Result<ActorMessageStatus, ()> { ) -> 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,
}

View file

@ -19,7 +19,7 @@ extern crate serde;
use crate::actor::{Actor, ActorRegistry}; use crate::actor::{Actor, ActorRegistry};
use crate::actors::browsing_context::BrowsingContextActor; 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::device::DeviceActor;
use crate::actors::framerate::FramerateActor; use crate::actors::framerate::FramerateActor;
use crate::actors::network_event::{EventActor, NetworkEventActor, ResponseStartMsg}; 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::preference::PreferenceActor;
use crate::actors::process::ProcessActor; use crate::actors::process::ProcessActor;
use crate::actors::root::RootActor; 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 crate::protocol::JsonPacketStream;
use crossbeam_channel::{unbounded, Receiver, Sender}; use crossbeam_channel::{unbounded, Receiver, Sender};
use devtools_traits::{ChromeToDevtoolsControlMsg, ConsoleMessage, DevtoolsControlMsg}; use devtools_traits::{ChromeToDevtoolsControlMsg, ConsoleMessage, DevtoolsControlMsg};
@ -69,6 +70,12 @@ mod actors {
} }
mod protocol; mod protocol;
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
enum UniqueId {
Pipeline(PipelineId),
Worker(WorkerId),
}
#[derive(Serialize)] #[derive(Serialize)]
struct ConsoleAPICall { struct ConsoleAPICall {
from: String, from: String,
@ -176,6 +183,7 @@ fn run_server(
let root = Box::new(RootActor { let root = Box::new(RootActor {
tabs: vec![], tabs: vec![],
workers: vec![],
device: device.name(), device: device.name(),
performance: performance.name(), performance: performance.name(),
preference: preference.name(), preference: preference.name(),
@ -197,7 +205,7 @@ fn run_server(
let mut pipelines: HashMap<PipelineId, BrowsingContextId> = HashMap::new(); let mut pipelines: HashMap<PipelineId, BrowsingContextId> = HashMap::new();
let mut actor_requests: HashMap<String, String> = 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. /// Process the input from a single devtools client until EOF.
fn handle_client(actors: Arc<Mutex<ActorRegistry>>, mut stream: TcpStream) { 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? // TODO: move this into the root or target modules?
fn handle_new_global( fn handle_new_global(
actors: Arc<Mutex<ActorRegistry>>, actors: Arc<Mutex<ActorRegistry>>,
ids: (Option<BrowsingContextId>, PipelineId, Option<WorkerId>), ids: (BrowsingContextId, PipelineId, Option<WorkerId>),
script_sender: IpcSender<DevtoolScriptControlMsg>, script_sender: IpcSender<DevtoolScriptControlMsg>,
browsing_contexts: &mut HashMap<BrowsingContextId, String>, browsing_contexts: &mut HashMap<BrowsingContextId, String>,
pipelines: &mut HashMap<PipelineId, BrowsingContextId>, pipelines: &mut HashMap<PipelineId, BrowsingContextId>,
actor_workers: &mut HashMap<(PipelineId, WorkerId), String>, actor_workers: &mut HashMap<WorkerId, String>,
page_info: DevtoolsPageInfo, page_info: DevtoolsPageInfo,
) { ) {
let mut actors = actors.lock().unwrap(); let mut actors = actors.lock().unwrap();
@ -271,83 +279,70 @@ fn run_server(
let console_name = actors.new_name("console"); let console_name = actors.new_name("console");
let browsing_context_name = if let Some(browsing_context) = browsing_context { let parent_actor = if let Some(id) = worker_id {
pipelines.insert(pipeline, browsing_context); assert!(pipelines.get(&pipeline).is_some());
if let Some(actor) = browsing_contexts.get(&browsing_context) { assert!(browsing_contexts.get(&browsing_context).is_some());
actor.to_owned()
} else { let thread = ThreadActor::new(actors.new_name("context"));
let browsing_context_actor = BrowsingContextActor::new( let thread_name = thread.name();
console_name.clone(), actors.register(Box::new(thread));
browsing_context,
page_info, let worker_name = actors.new_name("worker");
pipeline, let worker = WorkerActor {
script_sender.clone(), name: worker_name.clone(),
&mut *actors, console: console_name.clone(),
); thread: thread_name,
let name = browsing_context_actor.name(); id: id,
browsing_contexts.insert(browsing_context, name.clone()); url: page_info.url.clone(),
actors.register(Box::new(browsing_context_actor)); type_: WorkerType::Dedicated,
name script_chan: script_sender,
} streams: Default::default(),
};
let root = actors.find_mut::<RootActor>("root");
root.workers.push(worker.name.clone());
actor_workers.insert(id, worker_name.clone());
actors.register(Box::new(worker));
Root::DedicatedWorker(worker_name)
} else { } else {
"".to_owned() 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
},
)
}; };
// XXXjdm this new actor is useless if it's not a new worker global
let console = ConsoleActor { let console = ConsoleActor {
name: console_name, name: console_name,
cached_events: Default::default(), cached_events: Default::default(),
browsing_context: browsing_context_name, root: parent_actor,
}; };
if let Some(id) = worker_id {
let worker = WorkerActor {
name: actors.new_name("worker"),
console: console.name(),
id: id,
};
let root = actors.find_mut::<RootActor>("root");
root.tabs.push(worker.name.clone());
actor_workers.insert((pipeline, id), worker.name.clone());
actors.register(Box::new(worker));
}
actors.register(Box::new(console)); actors.register(Box::new(console));
} }
fn handle_page_error( fn handle_page_error(
actors: Arc<Mutex<ActorRegistry>>, actors: Arc<Mutex<ActorRegistry>>,
id: PipelineId, id: PipelineId,
worker_id: Option<WorkerId>,
page_error: PageError, page_error: PageError,
browsing_contexts: &HashMap<BrowsingContextId, String>, browsing_contexts: &HashMap<BrowsingContextId, String>,
pipelines: &HashMap<PipelineId, BrowsingContextId>, actor_workers: &HashMap<WorkerId, String>,
) {
let console_actor_name = match find_console_actor(
actors.clone(),
id,
None,
&HashMap::new(),
browsing_contexts,
pipelines,
) {
Some(name) => name,
None => return,
};
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);
}
fn handle_console_message(
actors: Arc<Mutex<ActorRegistry>>,
id: PipelineId,
worker_id: Option<WorkerId>,
console_message: ConsoleMessage,
browsing_contexts: &HashMap<BrowsingContextId, String>,
actor_workers: &HashMap<(PipelineId, WorkerId), String>,
pipelines: &HashMap<PipelineId, BrowsingContextId>, pipelines: &HashMap<PipelineId, BrowsingContextId>,
) { ) {
let console_actor_name = match find_console_actor( let console_actor_name = match find_console_actor(
@ -363,22 +358,47 @@ fn run_server(
}; };
let actors = actors.lock().unwrap(); let actors = actors.lock().unwrap();
let console_actor = actors.find::<ConsoleActor>(&console_actor_name); let console_actor = actors.find::<ConsoleActor>(&console_actor_name);
let browsing_context_actor = let id = worker_id.map_or(UniqueId::Pipeline(id), UniqueId::Worker);
actors.find::<BrowsingContextActor>(&console_actor.browsing_context); console_actor.handle_page_error(page_error, id, &*actors);
console_actor.handle_console_api(console_message, id, &browsing_context_actor); }
fn handle_console_message(
actors: Arc<Mutex<ActorRegistry>>,
id: PipelineId,
worker_id: Option<WorkerId>,
console_message: ConsoleMessage,
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,
worker_id,
actor_workers,
browsing_contexts,
pipelines,
) {
Some(name) => name,
None => return,
};
let actors = actors.lock().unwrap();
let console_actor = actors.find::<ConsoleActor>(&console_actor_name);
let id = worker_id.map_or(UniqueId::Pipeline(id), UniqueId::Worker);
console_actor.handle_console_api(console_message, id, &*actors);
} }
fn find_console_actor( fn find_console_actor(
actors: Arc<Mutex<ActorRegistry>>, actors: Arc<Mutex<ActorRegistry>>,
pipeline: PipelineId, pipeline: PipelineId,
worker_id: Option<WorkerId>, worker_id: Option<WorkerId>,
actor_workers: &HashMap<(PipelineId, WorkerId), String>, actor_workers: &HashMap<WorkerId, String>,
browsing_contexts: &HashMap<BrowsingContextId, String>, browsing_contexts: &HashMap<BrowsingContextId, String>,
pipelines: &HashMap<PipelineId, BrowsingContextId>, pipelines: &HashMap<PipelineId, BrowsingContextId>,
) -> Option<String> { ) -> Option<String> {
let actors = actors.lock().unwrap(); let actors = actors.lock().unwrap();
if let Some(worker_id) = worker_id { 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()) Some(actors.find::<WorkerActor>(actor_name).console.clone())
} else { } else {
let id = pipelines.get(&pipeline)?; let id = pipelines.get(&pipeline)?;
@ -397,7 +417,7 @@ fn run_server(
mut connections: Vec<TcpStream>, mut connections: Vec<TcpStream>,
browsing_contexts: &HashMap<BrowsingContextId, String>, browsing_contexts: &HashMap<BrowsingContextId, String>,
actor_requests: &mut HashMap<String, String>, actor_requests: &mut HashMap<String, String>,
actor_workers: &HashMap<(PipelineId, WorkerId), String>, actor_workers: &HashMap<WorkerId, String>,
pipelines: &HashMap<PipelineId, BrowsingContextId>, pipelines: &HashMap<PipelineId, BrowsingContextId>,
pipeline_id: PipelineId, pipeline_id: PipelineId,
request_id: String, request_id: String,
@ -570,6 +590,7 @@ fn run_server(
.expect("Thread spawning failed"); .expect("Thread spawning failed");
while let Ok(msg) = receiver.recv() { while let Ok(msg) = receiver.recv() {
debug!("{:?}", msg);
match msg { match msg {
DevtoolsControlMsg::FromChrome(ChromeToDevtoolsControlMsg::AddClient(stream)) => { DevtoolsControlMsg::FromChrome(ChromeToDevtoolsControlMsg::AddClient(stream)) => {
let actors = actors.clone(); let actors = actors.clone();
@ -619,8 +640,10 @@ fn run_server(
)) => handle_page_error( )) => handle_page_error(
actors.clone(), actors.clone(),
id, id,
None,
page_error, page_error,
&browsing_contexts, &browsing_contexts,
&actor_workers,
&pipelines, &pipelines,
), ),
DevtoolsControlMsg::FromScript(ScriptToDevtoolsControlMsg::ReportCSSError( DevtoolsControlMsg::FromScript(ScriptToDevtoolsControlMsg::ReportCSSError(

View file

@ -80,7 +80,7 @@ pub enum ScriptToDevtoolsControlMsg {
/// A new global object was created, associated with a particular pipeline. /// A new global object was created, associated with a particular pipeline.
/// The means of communicating directly with it are provided. /// The means of communicating directly with it are provided.
NewGlobal( NewGlobal(
(Option<BrowsingContextId>, PipelineId, Option<WorkerId>), (BrowsingContextId, PipelineId, Option<WorkerId>),
IpcSender<DevtoolScriptControlMsg>, IpcSender<DevtoolScriptControlMsg>,
DevtoolsPageInfo, DevtoolsPageInfo,
), ),

View file

@ -43,7 +43,7 @@ use js::jsapi::JS_AddInterruptCallback;
use js::jsapi::{Heap, JSContext, JSObject}; use js::jsapi::{Heap, JSContext, JSObject};
use js::jsval::UndefinedValue; use js::jsval::UndefinedValue;
use js::rust::{CustomAutoRooter, CustomAutoRooterGuard, HandleValue}; use js::rust::{CustomAutoRooter, CustomAutoRooterGuard, HandleValue};
use msg::constellation_msg::{PipelineId, TopLevelBrowsingContextId}; use msg::constellation_msg::{BrowsingContextId, PipelineId, TopLevelBrowsingContextId};
use net_traits::image_cache::ImageCache; use net_traits::image_cache::ImageCache;
use net_traits::request::{CredentialsMode, Destination, ParserMetadata}; use net_traits::request::{CredentialsMode, Destination, ParserMetadata};
use net_traits::request::{Referrer, RequestBuilder, RequestMode}; use net_traits::request::{Referrer, RequestBuilder, RequestMode};
@ -180,6 +180,7 @@ pub struct DedicatedWorkerGlobalScope {
parent_sender: Box<dyn ScriptChan + Send>, parent_sender: Box<dyn ScriptChan + Send>,
#[ignore_malloc_size_of = "Arc"] #[ignore_malloc_size_of = "Arc"]
image_cache: Arc<dyn ImageCache>, image_cache: Arc<dyn ImageCache>,
browsing_context: Option<BrowsingContextId>,
} }
impl WorkerEventLoopMethods for DedicatedWorkerGlobalScope { impl WorkerEventLoopMethods for DedicatedWorkerGlobalScope {
@ -221,6 +222,7 @@ impl DedicatedWorkerGlobalScope {
receiver: Receiver<DedicatedWorkerScriptMsg>, receiver: Receiver<DedicatedWorkerScriptMsg>,
closing: Arc<AtomicBool>, closing: Arc<AtomicBool>,
image_cache: Arc<dyn ImageCache>, image_cache: Arc<dyn ImageCache>,
browsing_context: Option<BrowsingContextId>,
) -> DedicatedWorkerGlobalScope { ) -> DedicatedWorkerGlobalScope {
DedicatedWorkerGlobalScope { DedicatedWorkerGlobalScope {
workerglobalscope: WorkerGlobalScope::new_inherited( workerglobalscope: WorkerGlobalScope::new_inherited(
@ -237,6 +239,7 @@ impl DedicatedWorkerGlobalScope {
parent_sender: parent_sender, parent_sender: parent_sender,
worker: DomRefCell::new(None), worker: DomRefCell::new(None),
image_cache: image_cache, image_cache: image_cache,
browsing_context,
} }
} }
@ -253,6 +256,7 @@ impl DedicatedWorkerGlobalScope {
receiver: Receiver<DedicatedWorkerScriptMsg>, receiver: Receiver<DedicatedWorkerScriptMsg>,
closing: Arc<AtomicBool>, closing: Arc<AtomicBool>,
image_cache: Arc<dyn ImageCache>, image_cache: Arc<dyn ImageCache>,
browsing_context: Option<BrowsingContextId>,
) -> DomRoot<DedicatedWorkerGlobalScope> { ) -> DomRoot<DedicatedWorkerGlobalScope> {
let cx = runtime.cx(); let cx = runtime.cx();
let scope = Box::new(DedicatedWorkerGlobalScope::new_inherited( let scope = Box::new(DedicatedWorkerGlobalScope::new_inherited(
@ -267,6 +271,7 @@ impl DedicatedWorkerGlobalScope {
receiver, receiver,
closing, closing,
image_cache, image_cache,
browsing_context,
)); ));
unsafe { DedicatedWorkerGlobalScopeBinding::Wrap(SafeJSContext::from_ptr(cx), scope) } unsafe { DedicatedWorkerGlobalScopeBinding::Wrap(SafeJSContext::from_ptr(cx), scope) }
} }
@ -286,6 +291,7 @@ impl DedicatedWorkerGlobalScope {
worker_type: WorkerType, worker_type: WorkerType,
closing: Arc<AtomicBool>, closing: Arc<AtomicBool>,
image_cache: Arc<dyn ImageCache>, image_cache: Arc<dyn ImageCache>,
browsing_context: Option<BrowsingContextId>,
) { ) {
let serialized_worker_url = worker_url.to_string(); let serialized_worker_url = worker_url.to_string();
let name = format!("WebWorker for {}", serialized_worker_url); let name = format!("WebWorker for {}", serialized_worker_url);
@ -354,6 +360,7 @@ impl DedicatedWorkerGlobalScope {
receiver, receiver,
closing, closing,
image_cache, image_cache,
browsing_context,
); );
// FIXME(njn): workers currently don't have a unique ID suitable for using in reporter // FIXME(njn): workers currently don't have a unique ID suitable for using in reporter
// registration (#6631), so we instead use a random number and cross our fingers. // registration (#6631), so we instead use a random number and cross our fingers.
@ -467,6 +474,7 @@ impl DedicatedWorkerGlobalScope {
} }
fn handle_mixed_message(&self, msg: MixedMessage) { fn handle_mixed_message(&self, msg: MixedMessage) {
// FIXME(#26324): `self.worker` is None in devtools messages.
match msg { match msg {
MixedMessage::FromDevtools(msg) => match msg { MixedMessage::FromDevtools(msg) => match msg {
DevtoolScriptControlMsg::EvaluateJS(_pipe_id, string, sender) => { DevtoolScriptControlMsg::EvaluateJS(_pipe_id, string, sender) => {
@ -551,6 +559,10 @@ impl DedicatedWorkerGlobalScope {
.expect("Sending to parent failed"); .expect("Sending to parent failed");
Ok(()) Ok(())
} }
pub(crate) fn browsing_context(&self) -> Option<BrowsingContextId> {
self.browsing_context
}
} }
#[allow(unsafe_code)] #[allow(unsafe_code)]

View file

@ -112,7 +112,7 @@ impl ServiceWorkerRegistration {
let worker_id = WorkerId(Uuid::new_v4()); let worker_id = WorkerId(Uuid::new_v4());
let devtools_chan = global.devtools_chan().cloned(); let devtools_chan = global.devtools_chan().cloned();
let init = prepare_workerscope_init(&global, None); let init = prepare_workerscope_init(&global, None, None);
ScopeThings { ScopeThings {
script_url: script_url, script_url: script_url,
init: init, init: init,

View file

@ -20,6 +20,7 @@ use crate::dom::dedicatedworkerglobalscope::{
use crate::dom::eventtarget::EventTarget; use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::messageevent::MessageEvent; use crate::dom::messageevent::MessageEvent;
use crate::dom::window::Window;
use crate::dom::workerglobalscope::prepare_workerscope_init; use crate::dom::workerglobalscope::prepare_workerscope_init;
use crate::realms::enter_realm; use crate::realms::enter_realm;
use crate::script_runtime::JSContext; use crate::script_runtime::JSContext;
@ -95,23 +96,34 @@ impl Worker {
pipeline_id: global.pipeline_id(), pipeline_id: global.pipeline_id(),
}; };
let browsing_context = global
.downcast::<Window>()
.map(|w| w.window_proxy().browsing_context_id())
.or_else(|| {
global
.downcast::<DedicatedWorkerGlobalScope>()
.and_then(|w| w.browsing_context())
});
let (devtools_sender, devtools_receiver) = ipc::channel().unwrap(); let (devtools_sender, devtools_receiver) = ipc::channel().unwrap();
let worker_id = WorkerId(Uuid::new_v4()); let worker_id = WorkerId(Uuid::new_v4());
if let Some(ref chan) = global.devtools_chan() { if let Some(ref chan) = global.devtools_chan() {
let pipeline_id = global.pipeline_id(); let pipeline_id = global.pipeline_id();
let title = format!("Worker for {}", worker_url); let title = format!("Worker for {}", worker_url);
let page_info = DevtoolsPageInfo { if let Some(browsing_context) = browsing_context {
title: title, let page_info = DevtoolsPageInfo {
url: worker_url.clone(), title: title,
}; url: worker_url.clone(),
let _ = chan.send(ScriptToDevtoolsControlMsg::NewGlobal( };
(None, pipeline_id, Some(worker_id)), let _ = chan.send(ScriptToDevtoolsControlMsg::NewGlobal(
devtools_sender.clone(), (browsing_context, pipeline_id, Some(worker_id)),
page_info, devtools_sender.clone(),
)); page_info,
));
}
} }
let init = prepare_workerscope_init(global, Some(devtools_sender)); let init = prepare_workerscope_init(global, Some(devtools_sender), Some(worker_id));
DedicatedWorkerGlobalScope::run_worker_scope( DedicatedWorkerGlobalScope::run_worker_scope(
init, init,
@ -126,6 +138,7 @@ impl Worker {
worker_options.type_, worker_options.type_,
closing, closing,
global.image_cache(), global.image_cache(),
browsing_context,
); );
Ok(worker) Ok(worker)

View file

@ -62,6 +62,7 @@ use uuid::Uuid;
pub fn prepare_workerscope_init( pub fn prepare_workerscope_init(
global: &GlobalScope, global: &GlobalScope,
devtools_sender: Option<IpcSender<DevtoolScriptControlMsg>>, devtools_sender: Option<IpcSender<DevtoolScriptControlMsg>>,
worker_id: Option<WorkerId>,
) -> WorkerGlobalScopeInit { ) -> WorkerGlobalScopeInit {
let init = WorkerGlobalScopeInit { let init = WorkerGlobalScopeInit {
resource_threads: global.resource_threads().clone(), resource_threads: global.resource_threads().clone(),
@ -71,7 +72,7 @@ pub fn prepare_workerscope_init(
from_devtools_sender: devtools_sender, from_devtools_sender: devtools_sender,
script_to_constellation_chan: global.script_to_constellation_chan().clone(), script_to_constellation_chan: global.script_to_constellation_chan().clone(),
scheduler_chan: global.scheduler_chan().clone(), scheduler_chan: global.scheduler_chan().clone(),
worker_id: WorkerId(Uuid::new_v4()), worker_id: worker_id.unwrap_or_else(|| WorkerId(Uuid::new_v4())),
pipeline_id: global.pipeline_id(), pipeline_id: global.pipeline_id(),
origin: global.origin().immutable().clone(), origin: global.origin().immutable().clone(),
is_headless: global.is_headless(), is_headless: global.is_headless(),

View file

@ -3384,7 +3384,7 @@ impl ScriptThread {
url: url, url: url,
}; };
chan.send(ScriptToDevtoolsControlMsg::NewGlobal( chan.send(ScriptToDevtoolsControlMsg::NewGlobal(
(Some(bc), p, w), (bc, p, w),
self.devtools_sender.clone(), self.devtools_sender.clone(),
page_info.clone(), page_info.clone(),
)) ))

View file

@ -11,7 +11,6 @@ use crate::dom::abstractworker::WorkerScriptMsg;
use crate::dom::serviceworkerglobalscope::{ServiceWorkerGlobalScope, ServiceWorkerScriptMsg}; use crate::dom::serviceworkerglobalscope::{ServiceWorkerGlobalScope, ServiceWorkerScriptMsg};
use crate::dom::serviceworkerregistration::longest_prefix_match; use crate::dom::serviceworkerregistration::longest_prefix_match;
use crossbeam_channel::{unbounded, Receiver, RecvError, Sender}; use crossbeam_channel::{unbounded, Receiver, RecvError, Sender};
use devtools_traits::{DevtoolsPageInfo, ScriptToDevtoolsControlMsg};
use ipc_channel::ipc::{self, IpcSender}; use ipc_channel::ipc::{self, IpcSender};
use ipc_channel::router::ROUTER; use ipc_channel::router::ROUTER;
use net_traits::{CoreResourceMsg, CustomResponseMediator}; use net_traits::{CoreResourceMsg, CustomResponseMediator};
@ -79,23 +78,7 @@ impl ServiceWorkerManager {
let scope_things = self.registered_workers.get(&scope_url); let scope_things = self.registered_workers.get(&scope_url);
if let Some(scope_things) = scope_things { if let Some(scope_things) = scope_things {
let (sender, receiver) = unbounded(); let (sender, receiver) = unbounded();
let (devtools_sender, devtools_receiver) = ipc::channel().unwrap(); let (_devtools_sender, devtools_receiver) = ipc::channel().unwrap();
if let Some(ref chan) = scope_things.devtools_chan {
let title = format!("ServiceWorker for {}", scope_things.script_url);
let page_info = DevtoolsPageInfo {
title: title,
url: scope_things.script_url.clone(),
};
let _ = chan.send(ScriptToDevtoolsControlMsg::NewGlobal(
(
None,
scope_things.init.pipeline_id,
Some(scope_things.worker_id),
),
devtools_sender,
page_info,
));
};
ServiceWorkerGlobalScope::run_serviceworker_scope( ServiceWorkerGlobalScope::run_serviceworker_scope(
scope_things.clone(), scope_things.clone(),
sender.clone(), sender.clone(),