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

View file

@ -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) => &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(
&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()
{

View file

@ -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;
@ -72,11 +73,6 @@ struct ListWorkersReply {
workers: Vec<WorkerMsg>,
}
#[derive(Serialize)]
struct WorkerMsg {
id: u32,
}
#[derive(Serialize)]
struct ListServiceWorkerRegistrationsReply {
from: String,
@ -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

View file

@ -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,
}