devtools: save and send cached messages

This commit is contained in:
Paul Rouget 2019-12-06 10:10:43 +01:00
parent 6cd42bdcfb
commit b3b886e837
8 changed files with 137 additions and 107 deletions

View file

@ -10,15 +10,19 @@
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry}; use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
use crate::actors::object::ObjectActor; use crate::actors::object::ObjectActor;
use crate::protocol::JsonPacketStream; use crate::protocol::JsonPacketStream;
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};
use devtools_traits::EvaluateJSReply::{NullValue, NumberValue, VoidValue}; use devtools_traits::EvaluateJSReply::{NullValue, NumberValue, VoidValue};
use devtools_traits::{CachedConsoleMessageTypes, DevtoolScriptControlMsg}; use devtools_traits::{
CachedConsoleMessageTypes, ConsoleAPI, DevtoolScriptControlMsg, LogLevel, PageError,
};
use ipc_channel::ipc::{self, IpcSender}; use ipc_channel::ipc::{self, IpcSender};
use msg::constellation_msg::PipelineId; use msg::constellation_msg::PipelineId;
use serde_json::{self, Map, Number, Value}; use serde_json::{self, Map, Number, Value};
use std::cell::RefCell; use std::cell::RefCell;
use std::net::TcpStream; use std::net::TcpStream;
use time::precise_time_ns;
use uuid::Uuid; use uuid::Uuid;
trait EncodableConsoleMessage { trait EncodableConsoleMessage {
@ -107,6 +111,7 @@ pub struct ConsoleActor {
pub pipeline: PipelineId, pub pipeline: PipelineId,
pub script_chan: IpcSender<DevtoolScriptControlMsg>, pub script_chan: IpcSender<DevtoolScriptControlMsg>,
pub streams: RefCell<Vec<TcpStream>>, pub streams: RefCell<Vec<TcpStream>>,
pub cached_events: RefCell<Vec<CachedConsoleMessage>>,
} }
impl ConsoleActor { impl ConsoleActor {
@ -187,6 +192,58 @@ impl ConsoleActor {
}; };
std::result::Result::Ok(reply) std::result::Result::Ok(reply)
} }
pub(crate) fn handle_page_error(&self, page_error: PageError) {
self.cached_events
.borrow_mut()
.push(CachedConsoleMessage::PageError(page_error.clone()));
let msg = PageErrorMsg {
from: self.name(),
type_: "pageError".to_owned(),
pageError: page_error,
};
for stream in &mut *self.streams.borrow_mut() {
stream.write_json_packet(&msg);
}
}
pub(crate) fn handle_console_api(&self, console_message: ConsoleMessage) {
let level = match console_message.logLevel {
LogLevel::Debug => "debug",
LogLevel::Info => "info",
LogLevel::Warn => "warn",
LogLevel::Error => "error",
_ => "log",
}
.to_owned();
self.cached_events
.borrow_mut()
.push(CachedConsoleMessage::ConsoleAPI(ConsoleAPI {
type_: "ConsoleAPI".to_owned(),
level: level.clone(),
filename: console_message.filename.clone(),
lineNumber: console_message.lineNumber as u32,
functionName: "".to_string(), //TODO
timeStamp: precise_time_ns(),
private: false,
arguments: vec![console_message.message.clone()],
}));
let msg = ConsoleAPICall {
from: self.name(),
type_: "consoleAPICall".to_owned(),
message: ConsoleMsg {
level: level,
timeStamp: precise_time_ns(),
arguments: vec![console_message.message],
filename: console_message.filename,
lineNumber: console_message.lineNumber,
columnNumber: console_message.columnNumber,
},
};
for stream in &mut *self.streams.borrow_mut() {
stream.write_json_packet(&msg);
}
}
} }
impl Actor for ConsoleActor { impl Actor for ConsoleActor {
@ -220,24 +277,27 @@ impl Actor for ConsoleActor {
s => debug!("unrecognized message type requested: \"{}\"", s), s => debug!("unrecognized message type requested: \"{}\"", s),
}; };
} }
let (chan, port) = ipc::channel().unwrap(); let mut messages = vec![];
self.script_chan for event in self.cached_events.borrow().iter() {
.send(DevtoolScriptControlMsg::GetCachedMessages( let include = match event {
self.pipeline, CachedConsoleMessage::PageError(_)
message_types, if message_types.contains(CachedConsoleMessageTypes::PAGE_ERROR) =>
chan, {
)) true
.unwrap(); },
let messages = port CachedConsoleMessage::ConsoleAPI(_)
.recv() if message_types.contains(CachedConsoleMessageTypes::CONSOLE_API) =>
.map_err(|_| ())? {
.into_iter() true
.map(|message| { },
let json_string = message.encode().unwrap(); _ => false,
};
if include {
let json_string = event.encode().unwrap();
let json = serde_json::from_str::<Value>(&json_string).unwrap(); let json = serde_json::from_str::<Value>(&json_string).unwrap();
json.as_object().unwrap().to_owned() messages.push(json.as_object().unwrap().to_owned())
}) }
.collect(); }
let msg = GetCachedMessagesReply { let msg = GetCachedMessagesReply {
from: self.name(), from: self.name(),

View file

@ -36,7 +36,7 @@ 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};
use devtools_traits::{DevtoolScriptControlMsg, DevtoolsPageInfo, LogLevel, NetworkEvent}; use devtools_traits::{DevtoolScriptControlMsg, DevtoolsPageInfo, LogLevel, NetworkEvent};
use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId}; use devtools_traits::{PageError, ScriptToDevtoolsControlMsg, WorkerId};
use ipc_channel::ipc::IpcSender; use ipc_channel::ipc::IpcSender;
use msg::constellation_msg::PipelineId; use msg::constellation_msg::PipelineId;
use std::borrow::ToOwned; use std::borrow::ToOwned;
@ -46,7 +46,6 @@ use std::collections::HashMap;
use std::net::{Shutdown, TcpListener, TcpStream}; use std::net::{Shutdown, TcpListener, TcpStream};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::thread; use std::thread;
use time::precise_time_ns;
mod actor; mod actor;
/// Corresponds to http://mxr.mozilla.org/mozilla-central/source/toolkit/devtools/server/actors/ /// Corresponds to http://mxr.mozilla.org/mozilla-central/source/toolkit/devtools/server/actors/
@ -88,6 +87,14 @@ struct ConsoleMsg {
columnNumber: usize, columnNumber: usize,
} }
#[derive(Serialize)]
struct PageErrorMsg {
from: String,
#[serde(rename = "type")]
type_: String,
pageError: PageError,
}
#[derive(Serialize)] #[derive(Serialize)]
struct NetworkEventMsg { struct NetworkEventMsg {
from: String, from: String,
@ -141,7 +148,7 @@ fn run_server(
receiver: Receiver<DevtoolsControlMsg>, receiver: Receiver<DevtoolsControlMsg>,
port: u16, port: u16,
) { ) {
let listener = TcpListener::bind(&("127.0.0.1", port)).unwrap(); let listener = TcpListener::bind(&("0.0.0.0", port)).unwrap();
let mut registry = ActorRegistry::new(); let mut registry = ActorRegistry::new();
@ -241,6 +248,7 @@ fn run_server(
script_chan: script_sender.clone(), script_chan: script_sender.clone(),
pipeline: pipeline, pipeline: pipeline,
streams: RefCell::new(Vec::new()), streams: RefCell::new(Vec::new()),
cached_events: RefCell::new(Vec::new()),
}; };
let emulation = EmulationActor::new(actors.new_name("emulation")); let emulation = EmulationActor::new(actors.new_name("emulation"));
@ -317,6 +325,22 @@ fn run_server(
actors.register(Box::new(thread)); actors.register(Box::new(thread));
} }
fn handle_page_error(
actors: Arc<Mutex<ActorRegistry>>,
id: PipelineId,
page_error: PageError,
actor_pipelines: &HashMap<PipelineId, String>,
) {
let console_actor_name =
match find_console_actor(actors.clone(), id, None, &HashMap::new(), actor_pipelines) {
Some(name) => name,
None => return,
};
let actors = actors.lock().unwrap();
let console_actor = actors.find::<ConsoleActor>(&console_actor_name);
console_actor.handle_page_error(page_error);
}
fn handle_console_message( fn handle_console_message(
actors: Arc<Mutex<ActorRegistry>>, actors: Arc<Mutex<ActorRegistry>>,
id: PipelineId, id: PipelineId,
@ -337,28 +361,7 @@ 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 msg = ConsoleAPICall { console_actor.handle_console_api(console_message);
from: console_actor.name.clone(),
type_: "consoleAPICall".to_owned(),
message: ConsoleMsg {
level: match console_message.logLevel {
LogLevel::Debug => "debug",
LogLevel::Info => "info",
LogLevel::Warn => "warn",
LogLevel::Error => "error",
_ => "log",
}
.to_owned(),
timeStamp: precise_time_ns(),
arguments: vec![console_message.message],
filename: console_message.filename,
lineNumber: console_message.lineNumber,
columnNumber: console_message.columnNumber,
},
};
for stream in &mut *console_actor.streams.borrow_mut() {
stream.write_json_packet(&msg);
}
} }
fn find_console_actor( fn find_console_actor(
@ -586,6 +589,10 @@ fn run_server(
&actor_pipelines, &actor_pipelines,
&actor_workers, &actor_workers,
), ),
DevtoolsControlMsg::FromScript(ScriptToDevtoolsControlMsg::ReportPageError(
id,
page_error,
)) => handle_page_error(actors.clone(), id, page_error, &actor_pipelines),
DevtoolsControlMsg::FromScript(ScriptToDevtoolsControlMsg::ReportCSSError( DevtoolsControlMsg::FromScript(ScriptToDevtoolsControlMsg::ReportCSSError(
id, id,
css_error, css_error,

View file

@ -82,6 +82,9 @@ pub enum ScriptToDevtoolsControlMsg {
/// Report a CSS parse error for the given pipeline /// Report a CSS parse error for the given pipeline
ReportCSSError(PipelineId, CSSError), ReportCSSError(PipelineId, CSSError),
/// Report a page error for the given pipeline
ReportPageError(PipelineId, PageError),
} }
/// Serialized JS return values /// Serialized JS return values
@ -196,12 +199,6 @@ pub enum DevtoolScriptControlMsg {
GetChildren(PipelineId, String, IpcSender<Option<Vec<NodeInfo>>>), GetChildren(PipelineId, String, IpcSender<Option<Vec<NodeInfo>>>),
/// Retrieve the computed layout properties of the given node in the given pipeline. /// Retrieve the computed layout properties of the given node in the given pipeline.
GetLayout(PipelineId, String, IpcSender<Option<ComputedNodeLayout>>), GetLayout(PipelineId, String, IpcSender<Option<ComputedNodeLayout>>),
/// Retrieve all stored console messages for the given pipeline.
GetCachedMessages(
PipelineId,
CachedConsoleMessageTypes,
IpcSender<Vec<CachedConsoleMessage>>,
),
/// Update a given node's attributes with a list of modifications. /// Update a given node's attributes with a list of modifications.
ModifyAttribute(PipelineId, String, Vec<Modification>), ModifyAttribute(PipelineId, String, Vec<Modification>),
/// Request live console messages for a given pipeline (true if desired, false otherwise). /// Request live console messages for a given pipeline (true if desired, false otherwise).
@ -253,7 +250,7 @@ bitflags! {
} }
} }
#[derive(Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]
pub struct PageError { pub struct PageError {
#[serde(rename = "_type")] #[serde(rename = "_type")]
pub type_: String, pub type_: String,

View file

@ -18,9 +18,7 @@ use crate::dom::globalscope::GlobalScope;
use crate::dom::node::{window_from_node, Node, ShadowIncluding}; use crate::dom::node::{window_from_node, Node, ShadowIncluding};
use crate::dom::window::Window; use crate::dom::window::Window;
use crate::script_thread::Documents; use crate::script_thread::Documents;
use devtools_traits::TimelineMarkerType; use devtools_traits::{AutoMargins, ComputedNodeLayout, TimelineMarkerType};
use devtools_traits::{AutoMargins, CachedConsoleMessage, CachedConsoleMessageTypes};
use devtools_traits::{ComputedNodeLayout, ConsoleAPI, PageError};
use devtools_traits::{EvaluateJSReply, Modification, NodeInfo, TimelineMarker}; use devtools_traits::{EvaluateJSReply, Modification, NodeInfo, TimelineMarker};
use ipc_channel::ipc::IpcSender; use ipc_channel::ipc::IpcSender;
use js::jsval::UndefinedValue; use js::jsval::UndefinedValue;
@ -182,50 +180,6 @@ fn determine_auto_margins(window: &Window, node: &Node) -> AutoMargins {
} }
} }
pub fn handle_get_cached_messages(
_pipeline_id: PipelineId,
message_types: CachedConsoleMessageTypes,
reply: IpcSender<Vec<CachedConsoleMessage>>,
) {
// TODO: check the messageTypes against a global Cache for console messages and page exceptions
let mut messages = Vec::new();
if message_types.contains(CachedConsoleMessageTypes::PAGE_ERROR) {
// TODO: make script error reporter pass all reported errors
// to devtools and cache them for returning here.
let msg = PageError {
type_: "PageError".to_owned(),
errorMessage: "page error test".to_owned(),
sourceName: String::new(),
lineText: String::new(),
lineNumber: 0,
columnNumber: 0,
category: String::new(),
timeStamp: 0,
error: false,
warning: false,
exception: false,
strict: false,
private: false,
};
messages.push(CachedConsoleMessage::PageError(msg));
}
if message_types.contains(CachedConsoleMessageTypes::CONSOLE_API) {
// TODO: do for real
let msg = ConsoleAPI {
type_: "ConsoleAPI".to_owned(),
level: "error".to_owned(),
filename: "http://localhost/~mihai/mozilla/test.html".to_owned(),
lineNumber: 0,
functionName: String::new(),
timeStamp: 0,
private: false,
arguments: vec!["console error test".to_owned()],
};
messages.push(CachedConsoleMessage::ConsoleAPI(msg));
}
reply.send(messages).unwrap();
}
pub fn handle_modify_attribute( pub fn handle_modify_attribute(
documents: &Documents, documents: &Documents,
pipeline: PipelineId, pipeline: PipelineId,

View file

@ -476,9 +476,6 @@ impl DedicatedWorkerGlobalScope {
DevtoolScriptControlMsg::EvaluateJS(_pipe_id, string, sender) => { DevtoolScriptControlMsg::EvaluateJS(_pipe_id, string, sender) => {
devtools::handle_evaluate_js(self.upcast(), string, sender) devtools::handle_evaluate_js(self.upcast(), string, sender)
}, },
DevtoolScriptControlMsg::GetCachedMessages(pipe_id, message_types, sender) => {
devtools::handle_get_cached_messages(pipe_id, message_types, sender)
},
DevtoolScriptControlMsg::WantsLiveNotifications(_pipe_id, bool_val) => { DevtoolScriptControlMsg::WantsLiveNotifications(_pipe_id, bool_val) => {
devtools::handle_wants_live_notifications(self.upcast(), bool_val) devtools::handle_wants_live_notifications(self.upcast(), bool_val)
}, },

View file

@ -46,7 +46,7 @@ use crate::task_source::TaskSourceName;
use crate::timers::{IsInterval, OneshotTimerCallback, OneshotTimerHandle}; use crate::timers::{IsInterval, OneshotTimerCallback, OneshotTimerHandle};
use crate::timers::{OneshotTimers, TimerCallback}; use crate::timers::{OneshotTimers, TimerCallback};
use content_security_policy::CspList; use content_security_policy::CspList;
use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId}; use devtools_traits::{PageError, ScriptToDevtoolsControlMsg, WorkerId};
use dom_struct::dom_struct; use dom_struct::dom_struct;
use ipc_channel::ipc::{self, IpcSender}; use ipc_channel::ipc::{self, IpcSender};
use ipc_channel::router::ROUTER; use ipc_channel::router::ROUTER;
@ -1085,6 +1085,27 @@ impl GlobalScope {
// https://html.spec.whatwg.org/multipage/#runtime-script-errors-2 // https://html.spec.whatwg.org/multipage/#runtime-script-errors-2
if let Some(dedicated) = self.downcast::<DedicatedWorkerGlobalScope>() { if let Some(dedicated) = self.downcast::<DedicatedWorkerGlobalScope>() {
dedicated.forward_error_to_worker_object(error_info); dedicated.forward_error_to_worker_object(error_info);
} else if self.is::<Window>() {
if let Some(ref chan) = self.devtools_chan {
let _ = chan.send(ScriptToDevtoolsControlMsg::ReportPageError(
self.pipeline_id.clone(),
PageError {
type_: "PageError".to_string(),
errorMessage: error_info.message.clone(),
sourceName: error_info.filename.clone(),
lineText: "".to_string(), //TODO
lineNumber: error_info.lineno,
columnNumber: error_info.column,
category: "script".to_string(),
timeStamp: 0, //TODO
error: true,
warning: false,
exception: true,
strict: false,
private: false,
},
));
}
} }
} }
} }

View file

@ -371,9 +371,6 @@ impl ServiceWorkerGlobalScope {
DevtoolScriptControlMsg::EvaluateJS(_pipe_id, string, sender) => { DevtoolScriptControlMsg::EvaluateJS(_pipe_id, string, sender) => {
devtools::handle_evaluate_js(self.upcast(), string, sender) devtools::handle_evaluate_js(self.upcast(), string, sender)
}, },
DevtoolScriptControlMsg::GetCachedMessages(pipe_id, message_types, sender) => {
devtools::handle_get_cached_messages(pipe_id, message_types, sender)
},
DevtoolScriptControlMsg::WantsLiveNotifications(_pipe_id, bool_val) => { DevtoolScriptControlMsg::WantsLiveNotifications(_pipe_id, bool_val) => {
devtools::handle_wants_live_notifications(self.upcast(), bool_val) devtools::handle_wants_live_notifications(self.upcast(), bool_val)
}, },

View file

@ -1991,9 +1991,6 @@ impl ScriptThread {
DevtoolScriptControlMsg::GetLayout(id, node_id, reply) => { DevtoolScriptControlMsg::GetLayout(id, node_id, reply) => {
devtools::handle_get_layout(&*documents, id, node_id, reply) devtools::handle_get_layout(&*documents, id, node_id, reply)
}, },
DevtoolScriptControlMsg::GetCachedMessages(id, message_types, reply) => {
devtools::handle_get_cached_messages(id, message_types, reply)
},
DevtoolScriptControlMsg::ModifyAttribute(id, node_id, modifications) => { DevtoolScriptControlMsg::ModifyAttribute(id, node_id, modifications) => {
devtools::handle_modify_attribute(&*documents, id, node_id, modifications) devtools::handle_modify_attribute(&*documents, id, node_id, modifications)
}, },