From 6699738cae3a82ae2114897ff5dc0dfdf7c59743 Mon Sep 17 00:00:00 2001 From: Sagar Muchhal Date: Thu, 5 Feb 2015 19:52:35 +0000 Subject: [PATCH] Add console message support to devtools. Does not actually cause logging to occur in the remote console. --- components/devtools/Cargo.toml | 5 ++- components/devtools/lib.rs | 61 ++++++++++++++++++++++++++++++- components/devtools_traits/lib.rs | 8 ++++ components/script/dom/console.rs | 29 ++++++++++++--- components/script/page.rs | 18 ++++++--- components/script/script_task.rs | 6 ++- components/servo/Cargo.lock | 1 + 7 files changed, 112 insertions(+), 16 deletions(-) diff --git a/components/devtools/Cargo.toml b/components/devtools/Cargo.toml index d7bd8e25f33e..23b7bf5fec83 100644 --- a/components/devtools/Cargo.toml +++ b/components/devtools/Cargo.toml @@ -14,4 +14,7 @@ path = "../devtools_traits" path = "../msg" [dependencies.util] -path = "../util" \ No newline at end of file +path = "../util" + +[dependencies] +time = "*" \ No newline at end of file diff --git a/components/devtools/lib.rs b/components/devtools/lib.rs index 15eb292e949f..20f58fd066a7 100644 --- a/components/devtools/lib.rs +++ b/components/devtools/lib.rs @@ -25,6 +25,7 @@ extern crate devtools_traits; extern crate "serialize" as rustc_serialize; extern crate serialize; extern crate "msg" as servo_msg; +extern crate time; extern crate util; use actor::{Actor, ActorRegistry}; @@ -34,7 +35,8 @@ use actors::root::RootActor; use actors::tab::TabActor; use protocol::JsonPacketStream; -use devtools_traits::{ServerExitMsg, DevtoolsControlMsg, NewGlobal, DevtoolScriptControlMsg, DevtoolsPageInfo}; +use devtools_traits::{ServerExitMsg, DevtoolsControlMsg, NewGlobal, DevtoolScriptControlMsg}; +use devtools_traits::{DevtoolsPageInfo, SendConsoleMessage, ConsoleMessage}; use servo_msg::constellation_msg::PipelineId; use util::task::spawn_named; @@ -46,6 +48,7 @@ use std::sync::mpsc::TryRecvError::{Disconnected, Empty}; use std::io::{TcpListener, TcpStream}; use std::io::{Acceptor, Listener, TimedOut}; use std::sync::{Arc, Mutex}; +use time::precise_time_ns; mod actor; /// Corresponds to http://mxr.mozilla.org/mozilla-central/source/toolkit/devtools/server/actors/ @@ -57,6 +60,20 @@ mod actors { } mod protocol; +#[derive(RustcEncodable)] +struct ConsoleAPICall { + from: String, + __type__: String, + message: ConsoleMsg, +} + +#[derive(RustcEncodable)] +struct ConsoleMsg { + logLevel: u32, + timestamp: u64, + message: String, +} + /// Spin up a devtools server that listens for connections on the specified port. pub fn start_server(port: u16) -> Sender { let (sender, receiver) = channel(); @@ -169,6 +186,41 @@ fn run_server(receiver: Receiver, port: u16) { actors.register(box inspector); } + fn handle_console_message(actors: Arc>, + id: PipelineId, + console_message: ConsoleMessage, + actor_pipelines: &HashMap) { + let console_actor_name = find_console_actor(actors.clone(), id, actor_pipelines); + let actors = actors.lock().unwrap(); + let console_actor = actors.find::(console_actor_name.as_slice()); + match console_message { + ConsoleMessage::LogMessage(message) => { + let msg = ConsoleAPICall { + from: console_actor.name.clone(), + __type__: "consoleAPICall".to_string(), + message: ConsoleMsg { + logLevel: 0, + timestamp: precise_time_ns(), + message: message, + }, + }; + for stream in console_actor.streams.borrow_mut().iter_mut() { + stream.write_json_packet(&msg); + } + } + } + } + + fn find_console_actor(actors: Arc>, + id: PipelineId, + actor_pipelines: &HashMap) -> String { + let actors = actors.lock().unwrap(); + let ref tab_actor_name = (*actor_pipelines)[id]; + let tab_actor = actors.find::(tab_actor_name.as_slice()); + let console_actor_name = tab_actor.console.clone(); + return console_actor_name; + } + //TODO: figure out some system that allows us to watch for new connections, // shut down existing ones at arbitrary times, and also watch for messages // from multiple script tasks simultaneously. Polling for new connections @@ -180,7 +232,12 @@ fn run_server(receiver: Receiver, port: u16) { Err(ref e) if e.kind == TimedOut => { match receiver.try_recv() { Ok(ServerExitMsg) | Err(Disconnected) => break, - Ok(NewGlobal(id, sender, pageinfo)) => handle_new_global(actors.clone(), id, sender, &mut actor_pipelines, pageinfo), + Ok(NewGlobal(id, sender, pageinfo)) => + handle_new_global(actors.clone(), id,sender, &mut actor_pipelines, + pageinfo), + Ok(SendConsoleMessage(id, console_message)) => + handle_console_message(actors.clone(), id, console_message, + &actor_pipelines), Err(Empty) => acceptor.set_timeout(Some(POLL_TIMEOUT)), } } diff --git a/components/devtools_traits/lib.rs b/components/devtools_traits/lib.rs index cb54831d852b..7ad368e2cd11 100644 --- a/components/devtools_traits/lib.rs +++ b/components/devtools_traits/lib.rs @@ -45,6 +45,7 @@ pub struct DevtoolsPageInfo { /// according to changes in the browser. pub enum DevtoolsControlMsg { NewGlobal(PipelineId, Sender, DevtoolsPageInfo), + SendConsoleMessage(PipelineId, ConsoleMessage), ServerExitMsg } @@ -123,3 +124,10 @@ impl Decodable for Modification { ) } } + +//TODO: Include options for Warn, Debug, Info, Error messages from Console +#[derive(Clone)] +pub enum ConsoleMessage { + LogMessage(String), + //WarnMessage(String), +} diff --git a/components/script/dom/console.rs b/components/script/dom/console.rs index 70323c510d9d..cff30395d2a7 100644 --- a/components/script/dom/console.rs +++ b/components/script/dom/console.rs @@ -4,31 +4,35 @@ use dom::bindings::codegen::Bindings::ConsoleBinding; use dom::bindings::codegen::Bindings::ConsoleBinding::ConsoleMethods; -use dom::bindings::global::GlobalRef; +use dom::bindings::global::{GlobalRef, GlobalField}; use dom::bindings::js::{JSRef, Temporary}; use dom::bindings::utils::{Reflector, reflect_dom_object}; +use devtools_traits::{SendConsoleMessage, ConsoleMessage}; use util::str::DOMString; #[dom_struct] pub struct Console { - reflector_: Reflector + reflector_: Reflector, + global: GlobalField, } impl Console { - fn new_inherited() -> Console { + fn new_inherited(global: GlobalRef) -> Console { Console { - reflector_: Reflector::new() + reflector_: Reflector::new(), + global: GlobalField::from_rooted(&global), } } pub fn new(global: GlobalRef) -> Temporary { - reflect_dom_object(box Console::new_inherited(), global, ConsoleBinding::Wrap) + reflect_dom_object(box Console::new_inherited(global), global, ConsoleBinding::Wrap) } } impl<'a> ConsoleMethods for JSRef<'a, Console> { fn Log(self, message: DOMString) { println!("{}", message); + propagate_console_msg(&self, ConsoleMessage::LogMessage(message)); } fn Debug(self, message: DOMString) { @@ -58,3 +62,18 @@ impl<'a> ConsoleMethods for JSRef<'a, Console> { } } +fn propagate_console_msg(console: &JSRef, console_message: ConsoleMessage) { + let global = console.global.root(); + match global.r() { + GlobalRef::Window(window_ref) => { + let pipelineId = window_ref.page().id; + console.global.root().r().as_window().page().devtools_chan.as_ref().map(|chan| { + chan.send(SendConsoleMessage(pipelineId, console_message.clone())).unwrap(); + }); + }, + + GlobalRef::Worker(_) => { + // TODO: support worker console logs + } + } +} diff --git a/components/script/page.rs b/components/script/page.rs index a7a24608b4e4..61de79ff038e 100644 --- a/components/script/page.rs +++ b/components/script/page.rs @@ -11,6 +11,7 @@ use dom::document::{Document, DocumentHelpers}; use dom::element::Element; use dom::node::{Node, NodeHelpers}; use dom::window::Window; +use devtools_traits::DevtoolsControlChan; use layout_interface::{ ContentBoxResponse, ContentBoxesResponse, HitTestResponse, LayoutChan, LayoutRPC, MouseOverResponse, Msg, Reflow, @@ -100,6 +101,9 @@ pub struct Page { /// A flag to indicate whether the developer tools have requested live updates of /// page changes. pub devtools_wants_updates: Cell, + + /// For providing instructions to an optional devtools server. + pub devtools_chan: Option, } pub struct PageIterator { @@ -130,12 +134,13 @@ impl IterablePage for Rc { impl Page { pub fn new(id: PipelineId, subpage_id: Option, - layout_chan: LayoutChan, - window_size: WindowSizeData, - resource_task: ResourceTask, - storage_task: StorageTask, - constellation_chan: ConstellationChan, - js_context: Rc) -> Page { + layout_chan: LayoutChan, + window_size: WindowSizeData, + resource_task: ResourceTask, + storage_task: StorageTask, + constellation_chan: ConstellationChan, + js_context: Rc, + devtools_chan: Option) -> Page { let js_info = JSPageInfo { dom_static: GlobalStaticData::new(), js_context: js_context, @@ -166,6 +171,7 @@ impl Page { children: DOMRefCell::new(vec!()), page_clip_rect: Cell::new(MAX_RECT), devtools_wants_updates: Cell::new(false), + devtools_chan: devtools_chan, } } diff --git a/components/script/script_task.rs b/components/script/script_task.rs index 03451b903a78..8440da0dd2a2 100644 --- a/components/script/script_task.rs +++ b/components/script/script_task.rs @@ -379,7 +379,8 @@ impl ScriptTask { resource_task.clone(), storage_task, constellation_chan.clone(), - js_context.clone()); + js_context.clone(), + devtools_chan.clone()); let (devtools_sender, devtools_receiver) = channel(); ScriptTask { @@ -662,7 +663,8 @@ impl ScriptTask { parent_page.resource_task.clone(), parent_page.storage_task.clone(), self.constellation_chan.clone(), - self.js_context.borrow().as_ref().unwrap().clone()) + self.js_context.borrow().as_ref().unwrap().clone(), + self.devtools_chan.clone()) }; parent_page.children.borrow_mut().push(Rc::new(new_page)); } diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index 2e21d3c82cea..f252c7b12dfc 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -145,6 +145,7 @@ version = "0.0.1" dependencies = [ "devtools_traits 0.0.1", "msg 0.0.1", + "time 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", ]