2014-09-19 17:15:03 +04:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
2015-01-11 19:15:45 +03:00
|
|
|
//! An actor-based remote devtools server implementation. Only tested with
|
|
|
|
//! nightly Firefox versions at time of writing. Largely based on
|
|
|
|
//! reverse-engineering of Firefox chrome devtool logs and reading of
|
|
|
|
//! [code](http://mxr.mozilla.org/mozilla-central/source/toolkit/devtools/server/).
|
|
|
|
|
2014-09-19 17:15:03 +04:00
|
|
|
#![crate_name = "devtools"]
|
|
|
|
#![crate_type = "rlib"]
|
|
|
|
|
2014-09-24 00:20:44 +04:00
|
|
|
#![allow(non_snake_case)]
|
2015-08-12 15:48:07 +03:00
|
|
|
#![deny(unsafe_code)]
|
2017-02-21 16:15:15 +03:00
|
|
|
#![feature(box_syntax)]
|
2014-09-24 00:20:44 +04:00
|
|
|
|
2014-09-19 17:15:03 +04:00
|
|
|
extern crate devtools_traits;
|
2015-09-24 00:02:56 +03:00
|
|
|
extern crate hyper;
|
2015-07-27 20:09:38 +03:00
|
|
|
extern crate ipc_channel;
|
2016-05-27 16:49:43 +03:00
|
|
|
#[macro_use]
|
|
|
|
extern crate log;
|
2015-02-10 13:51:46 +03:00
|
|
|
extern crate msg;
|
2017-06-16 15:03:18 +03:00
|
|
|
#[macro_use] extern crate serde;
|
2016-02-24 21:52:43 +03:00
|
|
|
extern crate serde_json;
|
2015-02-06 00:45:45 +03:00
|
|
|
extern crate time;
|
2014-09-19 17:15:03 +04:00
|
|
|
|
|
|
|
use actor::{Actor, ActorRegistry};
|
|
|
|
use actors::console::ConsoleActor;
|
2015-05-06 08:50:13 +03:00
|
|
|
use actors::framerate::FramerateActor;
|
2014-09-19 17:15:03 +04:00
|
|
|
use actors::inspector::InspectorActor;
|
2016-06-06 05:19:22 +03:00
|
|
|
use actors::network_event::{EventActor, NetworkEventActor, ResponseStartMsg};
|
2015-08-15 17:16:55 +03:00
|
|
|
use actors::performance::PerformanceActor;
|
2015-08-13 23:25:38 +03:00
|
|
|
use actors::profiler::ProfilerActor;
|
2014-09-19 17:15:03 +04:00
|
|
|
use actors::root::RootActor;
|
|
|
|
use actors::tab::TabActor;
|
2016-03-24 13:18:23 +03:00
|
|
|
use actors::thread::ThreadActor;
|
2015-04-13 20:44:49 +03:00
|
|
|
use actors::timeline::TimelineActor;
|
2015-05-06 08:50:13 +03:00
|
|
|
use actors::worker::WorkerActor;
|
2015-07-27 20:09:38 +03:00
|
|
|
use devtools_traits::{ChromeToDevtoolsControlMsg, ConsoleMessage, DevtoolsControlMsg};
|
2015-09-24 00:02:56 +03:00
|
|
|
use devtools_traits::{DevtoolScriptControlMsg, DevtoolsPageInfo, LogLevel, NetworkEvent};
|
2015-12-07 22:23:40 +03:00
|
|
|
use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId};
|
2015-07-27 20:09:38 +03:00
|
|
|
use ipc_channel::ipc::IpcSender;
|
2015-12-07 22:23:40 +03:00
|
|
|
use msg::constellation_msg::PipelineId;
|
2015-09-19 22:34:51 +03:00
|
|
|
use protocol::JsonPacketStream;
|
2015-01-21 13:48:49 +03:00
|
|
|
use std::borrow::ToOwned;
|
2014-09-19 17:15:03 +04:00
|
|
|
use std::cell::RefCell;
|
2014-12-04 08:48:59 +03:00
|
|
|
use std::collections::HashMap;
|
2015-05-05 19:52:44 +03:00
|
|
|
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
2015-09-24 00:02:56 +03:00
|
|
|
use std::net::{Shutdown, TcpListener, TcpStream};
|
2015-01-08 18:00:57 +03:00
|
|
|
use std::sync::{Arc, Mutex};
|
2016-09-09 06:19:19 +03:00
|
|
|
use std::sync::mpsc::{Receiver, Sender, channel};
|
2016-12-15 03:48:42 +03:00
|
|
|
use std::thread;
|
2015-02-06 00:45:45 +03:00
|
|
|
use time::precise_time_ns;
|
2014-09-19 17:15:03 +04:00
|
|
|
|
|
|
|
mod actor;
|
|
|
|
/// Corresponds to http://mxr.mozilla.org/mozilla-central/source/toolkit/devtools/server/actors/
|
|
|
|
mod actors {
|
|
|
|
pub mod console;
|
2015-04-13 20:44:49 +03:00
|
|
|
pub mod framerate;
|
2014-09-19 17:15:03 +04:00
|
|
|
pub mod inspector;
|
2015-08-10 03:27:53 +03:00
|
|
|
pub mod memory;
|
|
|
|
pub mod network_event;
|
|
|
|
pub mod object;
|
2015-08-15 17:16:55 +03:00
|
|
|
pub mod performance;
|
2015-08-13 23:25:38 +03:00
|
|
|
pub mod profiler;
|
2014-09-19 17:15:03 +04:00
|
|
|
pub mod root;
|
|
|
|
pub mod tab;
|
2016-03-24 13:18:23 +03:00
|
|
|
pub mod thread;
|
2015-04-13 20:44:49 +03:00
|
|
|
pub mod timeline;
|
2015-03-27 22:33:56 +03:00
|
|
|
pub mod worker;
|
2014-09-19 17:15:03 +04:00
|
|
|
}
|
|
|
|
mod protocol;
|
|
|
|
|
2016-03-31 16:06:13 +03:00
|
|
|
#[derive(Serialize)]
|
2015-02-06 00:45:45 +03:00
|
|
|
struct ConsoleAPICall {
|
|
|
|
from: String,
|
2016-03-31 16:06:13 +03:00
|
|
|
#[serde(rename = "type")]
|
|
|
|
type_: String,
|
2015-02-06 00:45:45 +03:00
|
|
|
message: ConsoleMsg,
|
|
|
|
}
|
|
|
|
|
2016-03-31 16:06:13 +03:00
|
|
|
#[derive(Serialize)]
|
2015-02-06 00:45:45 +03:00
|
|
|
struct ConsoleMsg {
|
2015-03-20 06:48:48 +03:00
|
|
|
level: String,
|
|
|
|
timeStamp: u64,
|
|
|
|
arguments: Vec<String>,
|
|
|
|
filename: String,
|
2016-02-11 23:15:58 +03:00
|
|
|
lineNumber: usize,
|
|
|
|
columnNumber: usize,
|
2015-02-06 00:45:45 +03:00
|
|
|
}
|
|
|
|
|
2016-03-31 16:06:13 +03:00
|
|
|
#[derive(Serialize)]
|
2015-05-05 19:52:44 +03:00
|
|
|
struct NetworkEventMsg {
|
|
|
|
from: String,
|
2016-03-31 16:06:13 +03:00
|
|
|
#[serde(rename = "type")]
|
|
|
|
type_: String,
|
2015-05-05 19:52:44 +03:00
|
|
|
eventActor: EventActor,
|
|
|
|
}
|
|
|
|
|
2016-03-31 16:06:13 +03:00
|
|
|
#[derive(Serialize)]
|
2016-06-06 05:19:22 +03:00
|
|
|
struct NetworkEventUpdateMsg {
|
2015-12-21 18:47:25 +03:00
|
|
|
from: String,
|
2016-03-31 16:06:13 +03:00
|
|
|
#[serde(rename = "type")]
|
|
|
|
type_: String,
|
2015-12-21 18:47:25 +03:00
|
|
|
updateType: String,
|
|
|
|
}
|
|
|
|
|
2016-03-31 16:06:13 +03:00
|
|
|
#[derive(Serialize)]
|
2016-06-06 05:19:22 +03:00
|
|
|
struct EventTimingsUpdateMsg {
|
|
|
|
totalTime: u64,
|
2015-12-21 18:47:25 +03:00
|
|
|
}
|
|
|
|
|
2016-03-31 16:06:13 +03:00
|
|
|
#[derive(Serialize)]
|
2016-06-06 05:19:22 +03:00
|
|
|
struct SecurityInfoUpdateMsg {
|
|
|
|
state: String,
|
2015-12-21 18:47:25 +03:00
|
|
|
}
|
|
|
|
|
2016-03-31 16:06:13 +03:00
|
|
|
#[derive(Serialize)]
|
2016-06-06 05:19:22 +03:00
|
|
|
struct ResponseStartUpdateMsg {
|
2015-12-21 18:47:25 +03:00
|
|
|
from: String,
|
2016-03-31 16:06:13 +03:00
|
|
|
#[serde(rename = "type")]
|
|
|
|
type_: String,
|
2015-12-21 18:47:25 +03:00
|
|
|
updateType: String,
|
2016-06-06 05:19:22 +03:00
|
|
|
response: ResponseStartMsg,
|
2015-12-21 18:47:25 +03:00
|
|
|
}
|
|
|
|
|
2014-10-08 18:24:36 +04:00
|
|
|
/// Spin up a devtools server that listens for connections on the specified port.
|
|
|
|
pub fn start_server(port: u16) -> Sender<DevtoolsControlMsg> {
|
2015-01-28 04:15:50 +03:00
|
|
|
let (sender, receiver) = channel();
|
2015-03-25 01:39:49 +03:00
|
|
|
{
|
|
|
|
let sender = sender.clone();
|
2016-12-15 03:48:42 +03:00
|
|
|
thread::Builder::new().name("Devtools".to_owned()).spawn(move || {
|
2015-03-25 01:39:49 +03:00
|
|
|
run_server(sender, receiver, port)
|
2016-12-15 03:48:42 +03:00
|
|
|
}).expect("Thread spawning failed");
|
2015-03-25 01:39:49 +03:00
|
|
|
}
|
2014-10-08 18:24:36 +04:00
|
|
|
sender
|
2014-09-19 17:15:03 +04:00
|
|
|
}
|
|
|
|
|
2015-03-25 01:39:49 +03:00
|
|
|
fn run_server(sender: Sender<DevtoolsControlMsg>,
|
|
|
|
receiver: Receiver<DevtoolsControlMsg>,
|
|
|
|
port: u16) {
|
2015-03-25 18:03:51 +03:00
|
|
|
let listener = TcpListener::bind(&("127.0.0.1", port)).unwrap();
|
2014-09-19 17:15:03 +04:00
|
|
|
|
|
|
|
let mut registry = ActorRegistry::new();
|
|
|
|
|
|
|
|
let root = box RootActor {
|
|
|
|
tabs: vec!(),
|
|
|
|
};
|
|
|
|
|
|
|
|
registry.register(root);
|
|
|
|
registry.find::<RootActor>("root");
|
|
|
|
|
2015-04-13 20:44:49 +03:00
|
|
|
let actors = registry.create_shareable();
|
2014-09-19 17:15:03 +04:00
|
|
|
|
2014-11-17 16:15:30 +03:00
|
|
|
let mut accepted_connections: Vec<TcpStream> = Vec::new();
|
|
|
|
|
2014-12-04 08:48:59 +03:00
|
|
|
let mut actor_pipelines: HashMap<PipelineId, String> = HashMap::new();
|
2015-05-05 19:52:44 +03:00
|
|
|
let mut actor_requests: HashMap<String, String> = HashMap::new();
|
2014-12-04 08:48:59 +03:00
|
|
|
|
2015-04-21 16:05:48 +03:00
|
|
|
let mut actor_workers: HashMap<(PipelineId, WorkerId), String> = HashMap::new();
|
|
|
|
|
2015-03-27 22:33:56 +03:00
|
|
|
|
2014-09-19 17:15:03 +04:00
|
|
|
/// Process the input from a single devtools client until EOF.
|
|
|
|
fn handle_client(actors: Arc<Mutex<ActorRegistry>>, mut stream: TcpStream) {
|
2016-05-27 16:49:43 +03:00
|
|
|
debug!("connection established to {}", stream.peer_addr().unwrap());
|
2014-09-19 17:15:03 +04:00
|
|
|
{
|
2015-01-28 04:15:50 +03:00
|
|
|
let actors = actors.lock().unwrap();
|
2014-09-19 17:15:03 +04:00
|
|
|
let msg = actors.find::<RootActor>("root").encodable();
|
|
|
|
stream.write_json_packet(&msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
'outer: loop {
|
2014-11-13 00:42:35 +03:00
|
|
|
match stream.read_json_packet() {
|
2015-05-05 17:11:30 +03:00
|
|
|
Ok(Some(json_packet)) => {
|
2017-01-01 08:28:41 +03:00
|
|
|
if let Err(()) = actors.lock().unwrap().handle_message(json_packet.as_object().unwrap(),
|
|
|
|
&mut stream) {
|
|
|
|
debug!("error: devtools actor stopped responding");
|
|
|
|
let _ = stream.shutdown(Shutdown::Both);
|
|
|
|
break 'outer
|
2014-12-05 04:04:06 +03:00
|
|
|
}
|
|
|
|
}
|
2015-05-05 17:11:30 +03:00
|
|
|
Ok(None) => {
|
2016-05-27 16:49:43 +03:00
|
|
|
debug!("error: EOF");
|
2015-05-05 17:11:30 +03:00
|
|
|
break 'outer
|
|
|
|
}
|
2015-08-06 23:00:26 +03:00
|
|
|
Err(err_msg) => {
|
2016-05-27 16:49:43 +03:00
|
|
|
debug!("error: {}", err_msg);
|
2014-11-13 00:42:35 +03:00
|
|
|
break 'outer
|
2014-09-19 17:15:03 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-06 08:50:13 +03:00
|
|
|
fn handle_framerate_tick(actors: Arc<Mutex<ActorRegistry>>, actor_name: String, tick: f64) {
|
2015-08-14 16:16:19 +03:00
|
|
|
let mut actors = actors.lock().unwrap();
|
|
|
|
let framerate_actor = actors.find_mut::<FramerateActor>(&actor_name);
|
2015-05-06 08:50:13 +03:00
|
|
|
framerate_actor.add_tick(tick);
|
|
|
|
}
|
|
|
|
|
2014-09-19 17:15:03 +04:00
|
|
|
// We need separate actor representations for each script global that exists;
|
|
|
|
// clients can theoretically connect to multiple globals simultaneously.
|
|
|
|
// TODO: move this into the root or tab modules?
|
|
|
|
fn handle_new_global(actors: Arc<Mutex<ActorRegistry>>,
|
2015-03-27 22:33:56 +03:00
|
|
|
ids: (PipelineId, Option<WorkerId>),
|
2015-07-27 20:09:38 +03:00
|
|
|
script_sender: IpcSender<DevtoolScriptControlMsg>,
|
2014-12-13 03:03:45 +03:00
|
|
|
actor_pipelines: &mut HashMap<PipelineId, String>,
|
2015-04-21 16:05:48 +03:00
|
|
|
actor_workers: &mut HashMap<(PipelineId, WorkerId), String>,
|
2014-12-13 03:03:45 +03:00
|
|
|
page_info: DevtoolsPageInfo) {
|
2015-01-28 04:15:50 +03:00
|
|
|
let mut actors = actors.lock().unwrap();
|
2014-09-19 17:15:03 +04:00
|
|
|
|
2015-03-27 22:33:56 +03:00
|
|
|
let (pipeline, worker_id) = ids;
|
|
|
|
|
2014-09-19 17:15:03 +04:00
|
|
|
//TODO: move all this actor creation into a constructor method on TabActor
|
2016-03-24 13:18:23 +03:00
|
|
|
let (tab, console, inspector, timeline, profiler, performance, thread) = {
|
2014-09-19 17:15:03 +04:00
|
|
|
let console = ConsoleActor {
|
|
|
|
name: actors.new_name("console"),
|
2015-05-06 08:50:13 +03:00
|
|
|
script_chan: script_sender.clone(),
|
2014-09-19 17:15:03 +04:00
|
|
|
pipeline: pipeline,
|
2014-12-04 08:48:59 +03:00
|
|
|
streams: RefCell::new(Vec::new()),
|
2014-09-19 17:15:03 +04:00
|
|
|
};
|
|
|
|
let inspector = InspectorActor {
|
|
|
|
name: actors.new_name("inspector"),
|
|
|
|
walker: RefCell::new(None),
|
|
|
|
pageStyle: RefCell::new(None),
|
|
|
|
highlighter: RefCell::new(None),
|
2015-05-06 08:50:13 +03:00
|
|
|
script_chan: script_sender.clone(),
|
2014-09-19 17:15:03 +04:00
|
|
|
pipeline: pipeline,
|
|
|
|
};
|
2014-12-13 03:03:45 +03:00
|
|
|
|
2015-04-13 20:44:49 +03:00
|
|
|
let timeline = TimelineActor::new(actors.new_name("timeline"),
|
|
|
|
pipeline,
|
2015-08-13 21:41:48 +03:00
|
|
|
script_sender);
|
2015-04-13 20:44:49 +03:00
|
|
|
|
2015-08-13 23:25:38 +03:00
|
|
|
let profiler = ProfilerActor::new(actors.new_name("profiler"));
|
2015-08-15 17:16:55 +03:00
|
|
|
let performance = PerformanceActor::new(actors.new_name("performance"));
|
2015-08-13 23:25:38 +03:00
|
|
|
|
2016-03-24 13:18:23 +03:00
|
|
|
let thread = ThreadActor::new(actors.new_name("context"));
|
|
|
|
|
2014-12-13 03:03:45 +03:00
|
|
|
let DevtoolsPageInfo { title, url } = page_info;
|
2014-09-19 17:15:03 +04:00
|
|
|
let tab = TabActor {
|
|
|
|
name: actors.new_name("tab"),
|
2015-11-13 04:47:30 +03:00
|
|
|
title: String::from(title),
|
2016-04-23 21:28:31 +03:00
|
|
|
url: url.into_string(),
|
2014-09-19 17:15:03 +04:00
|
|
|
console: console.name(),
|
|
|
|
inspector: inspector.name(),
|
2015-04-13 20:44:49 +03:00
|
|
|
timeline: timeline.name(),
|
2015-08-13 23:25:38 +03:00
|
|
|
profiler: profiler.name(),
|
2015-08-15 17:16:55 +03:00
|
|
|
performance: performance.name(),
|
2016-03-24 13:18:23 +03:00
|
|
|
thread: thread.name(),
|
2014-09-19 17:15:03 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
let root = actors.find_mut::<RootActor>("root");
|
|
|
|
root.tabs.push(tab.name.clone());
|
2015-08-13 23:25:38 +03:00
|
|
|
|
2016-03-24 13:18:23 +03:00
|
|
|
(tab, console, inspector, timeline, profiler, performance, thread)
|
2014-09-19 17:15:03 +04:00
|
|
|
};
|
|
|
|
|
2015-03-27 22:33:56 +03:00
|
|
|
if let Some(id) = worker_id {
|
|
|
|
let worker = WorkerActor {
|
|
|
|
name: actors.new_name("worker"),
|
2015-08-03 01:05:14 +03:00
|
|
|
console: console.name(),
|
2015-03-27 22:33:56 +03:00
|
|
|
id: id,
|
|
|
|
};
|
|
|
|
actor_workers.insert((pipeline, id), worker.name.clone());
|
|
|
|
actors.register(box worker);
|
|
|
|
}
|
|
|
|
|
2014-12-04 08:48:59 +03:00
|
|
|
actor_pipelines.insert(pipeline, tab.name.clone());
|
2014-09-19 17:15:03 +04:00
|
|
|
actors.register(box tab);
|
|
|
|
actors.register(box console);
|
|
|
|
actors.register(box inspector);
|
2015-04-13 20:44:49 +03:00
|
|
|
actors.register(box timeline);
|
2015-08-13 23:25:38 +03:00
|
|
|
actors.register(box profiler);
|
2015-08-15 17:16:55 +03:00
|
|
|
actors.register(box performance);
|
2016-03-24 13:18:23 +03:00
|
|
|
actors.register(box thread);
|
2014-09-19 17:15:03 +04:00
|
|
|
}
|
|
|
|
|
2015-02-06 00:45:45 +03:00
|
|
|
fn handle_console_message(actors: Arc<Mutex<ActorRegistry>>,
|
|
|
|
id: PipelineId,
|
2015-08-03 01:05:14 +03:00
|
|
|
worker_id: Option<WorkerId>,
|
2015-02-06 00:45:45 +03:00
|
|
|
console_message: ConsoleMessage,
|
2015-08-03 01:05:14 +03:00
|
|
|
actor_pipelines: &HashMap<PipelineId, String>,
|
|
|
|
actor_workers: &HashMap<(PipelineId, WorkerId), String>) {
|
|
|
|
let console_actor_name = match find_console_actor(actors.clone(), id, worker_id, actor_workers,
|
|
|
|
actor_pipelines) {
|
2015-07-07 18:43:36 +03:00
|
|
|
Some(name) => name,
|
|
|
|
None => return,
|
|
|
|
};
|
2015-02-06 00:45:45 +03:00
|
|
|
let actors = actors.lock().unwrap();
|
2015-03-21 21:57:46 +03:00
|
|
|
let console_actor = actors.find::<ConsoleActor>(&console_actor_name);
|
2015-06-02 04:13:30 +03:00
|
|
|
let msg = ConsoleAPICall {
|
|
|
|
from: console_actor.name.clone(),
|
2016-03-31 16:06:13 +03:00
|
|
|
type_: "consoleAPICall".to_owned(),
|
2015-06-02 04:13:30 +03:00
|
|
|
message: ConsoleMsg {
|
|
|
|
level: match console_message.logLevel {
|
|
|
|
LogLevel::Debug => "debug",
|
|
|
|
LogLevel::Info => "info",
|
|
|
|
LogLevel::Warn => "warn",
|
|
|
|
LogLevel::Error => "error",
|
|
|
|
_ => "log"
|
2015-09-02 21:32:44 +03:00
|
|
|
}.to_owned(),
|
2015-06-02 04:13:30 +03:00
|
|
|
timeStamp: precise_time_ns(),
|
|
|
|
arguments: vec!(console_message.message),
|
|
|
|
filename: console_message.filename,
|
|
|
|
lineNumber: console_message.lineNumber,
|
|
|
|
columnNumber: console_message.columnNumber,
|
|
|
|
},
|
|
|
|
};
|
2015-08-18 11:46:46 +03:00
|
|
|
for mut stream in &mut *console_actor.streams.borrow_mut() {
|
2015-06-02 04:13:30 +03:00
|
|
|
stream.write_json_packet(&msg);
|
2015-02-06 00:45:45 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn find_console_actor(actors: Arc<Mutex<ActorRegistry>>,
|
|
|
|
id: PipelineId,
|
2015-08-03 01:05:14 +03:00
|
|
|
worker_id: Option<WorkerId>,
|
|
|
|
actor_workers: &HashMap<(PipelineId, WorkerId), String>,
|
2015-07-07 18:43:36 +03:00
|
|
|
actor_pipelines: &HashMap<PipelineId, String>) -> Option<String> {
|
2015-02-06 00:45:45 +03:00
|
|
|
let actors = actors.lock().unwrap();
|
2015-08-03 01:05:14 +03:00
|
|
|
if let Some(worker_id) = worker_id {
|
|
|
|
let actor_name = match (*actor_workers).get(&(id, worker_id)) {
|
|
|
|
Some(name) => name,
|
|
|
|
None => return None,
|
|
|
|
};
|
|
|
|
Some(actors.find::<WorkerActor>(actor_name).console.clone())
|
|
|
|
} else {
|
|
|
|
let actor_name = match (*actor_pipelines).get(&id) {
|
|
|
|
Some(name) => name,
|
|
|
|
None => return None,
|
|
|
|
};
|
|
|
|
Some(actors.find::<TabActor>(actor_name).console.clone())
|
|
|
|
}
|
2015-02-06 00:45:45 +03:00
|
|
|
}
|
|
|
|
|
2015-05-05 19:52:44 +03:00
|
|
|
fn handle_network_event(actors: Arc<Mutex<ActorRegistry>>,
|
|
|
|
mut connections: Vec<TcpStream>,
|
|
|
|
actor_pipelines: &HashMap<PipelineId, String>,
|
|
|
|
actor_requests: &mut HashMap<String, String>,
|
2015-08-03 01:05:14 +03:00
|
|
|
actor_workers: &HashMap<(PipelineId, WorkerId), String>,
|
2015-05-05 19:52:44 +03:00
|
|
|
pipeline_id: PipelineId,
|
|
|
|
request_id: String,
|
|
|
|
network_event: NetworkEvent) {
|
2015-08-03 01:05:14 +03:00
|
|
|
let console_actor_name = match find_console_actor(actors.clone(), pipeline_id, None,
|
|
|
|
actor_workers, actor_pipelines) {
|
2015-07-07 18:43:36 +03:00
|
|
|
Some(name) => name,
|
|
|
|
None => return,
|
|
|
|
};
|
2015-05-05 19:52:44 +03:00
|
|
|
let netevent_actor_name = find_network_event_actor(actors.clone(), actor_requests, request_id.clone());
|
|
|
|
let mut actors = actors.lock().unwrap();
|
|
|
|
let actor = actors.find_mut::<NetworkEventActor>(&netevent_actor_name);
|
|
|
|
|
|
|
|
match network_event {
|
2015-09-25 20:35:57 +03:00
|
|
|
NetworkEvent::HttpRequest(httprequest) => {
|
2015-05-05 19:52:44 +03:00
|
|
|
//Store the request information in the actor
|
2015-09-25 20:35:57 +03:00
|
|
|
actor.add_request(httprequest);
|
2015-05-05 19:52:44 +03:00
|
|
|
|
|
|
|
//Send a networkEvent message to the client
|
|
|
|
let msg = NetworkEventMsg {
|
|
|
|
from: console_actor_name,
|
2016-03-31 16:06:13 +03:00
|
|
|
type_: "networkEvent".to_owned(),
|
2015-06-02 16:17:03 +03:00
|
|
|
eventActor: actor.event_actor(),
|
2015-05-05 19:52:44 +03:00
|
|
|
};
|
2015-08-15 12:03:21 +03:00
|
|
|
for stream in &mut connections {
|
2015-05-05 19:52:44 +03:00
|
|
|
stream.write_json_packet(&msg);
|
|
|
|
}
|
2015-12-21 18:47:25 +03:00
|
|
|
|
2015-05-05 19:52:44 +03:00
|
|
|
}
|
2015-09-25 20:35:57 +03:00
|
|
|
NetworkEvent::HttpResponse(httpresponse) => {
|
2015-05-05 19:52:44 +03:00
|
|
|
//Store the response information in the actor
|
2015-09-25 20:35:57 +03:00
|
|
|
actor.add_response(httpresponse);
|
2015-05-05 19:52:44 +03:00
|
|
|
|
2016-06-06 05:19:22 +03:00
|
|
|
let msg = NetworkEventUpdateMsg {
|
|
|
|
from: netevent_actor_name.clone(),
|
|
|
|
type_: "networkEventUpdate".to_owned(),
|
|
|
|
updateType: "requestHeaders".to_owned(),
|
|
|
|
};
|
|
|
|
for stream in &mut connections {
|
|
|
|
stream.write_merged_json_packet(&msg, &actor.request_headers());
|
|
|
|
}
|
|
|
|
|
|
|
|
let msg = NetworkEventUpdateMsg {
|
2015-12-21 18:47:25 +03:00
|
|
|
from: netevent_actor_name.clone(),
|
2016-03-31 16:06:13 +03:00
|
|
|
type_: "networkEventUpdate".to_owned(),
|
2015-12-21 18:47:25 +03:00
|
|
|
updateType: "requestCookies".to_owned(),
|
|
|
|
};
|
|
|
|
for stream in &mut connections {
|
2016-06-06 05:19:22 +03:00
|
|
|
stream.write_merged_json_packet(&msg, &actor.request_cookies());
|
2015-12-21 18:47:25 +03:00
|
|
|
}
|
|
|
|
|
2015-05-05 19:52:44 +03:00
|
|
|
//Send a networkEventUpdate (responseStart) to the client
|
2015-12-21 18:47:25 +03:00
|
|
|
let msg = ResponseStartUpdateMsg {
|
|
|
|
from: netevent_actor_name.clone(),
|
2016-03-31 16:06:13 +03:00
|
|
|
type_: "networkEventUpdate".to_owned(),
|
2015-09-02 21:32:44 +03:00
|
|
|
updateType: "responseStart".to_owned(),
|
2015-06-02 16:17:03 +03:00
|
|
|
response: actor.response_start()
|
2015-05-05 19:52:44 +03:00
|
|
|
};
|
|
|
|
|
2015-08-15 12:03:21 +03:00
|
|
|
for stream in &mut connections {
|
2015-05-05 19:52:44 +03:00
|
|
|
stream.write_json_packet(&msg);
|
|
|
|
}
|
2016-06-06 05:19:22 +03:00
|
|
|
let msg = NetworkEventUpdateMsg {
|
2015-12-21 18:47:25 +03:00
|
|
|
from: netevent_actor_name.clone(),
|
2016-03-31 16:06:13 +03:00
|
|
|
type_: "networkEventUpdate".to_owned(),
|
2015-12-21 18:47:25 +03:00
|
|
|
updateType: "eventTimings".to_owned(),
|
|
|
|
};
|
2016-06-06 05:19:22 +03:00
|
|
|
let extra = EventTimingsUpdateMsg {
|
|
|
|
totalTime: actor.total_time(),
|
|
|
|
};
|
2015-12-21 18:47:25 +03:00
|
|
|
for stream in &mut connections {
|
2016-06-06 05:19:22 +03:00
|
|
|
stream.write_merged_json_packet(&msg, &extra);
|
2015-12-21 18:47:25 +03:00
|
|
|
}
|
|
|
|
|
2016-06-06 05:19:22 +03:00
|
|
|
let msg = NetworkEventUpdateMsg {
|
2015-12-21 18:47:25 +03:00
|
|
|
from: netevent_actor_name.clone(),
|
2016-03-31 16:06:13 +03:00
|
|
|
type_: "networkEventUpdate".to_owned(),
|
2015-12-21 18:47:25 +03:00
|
|
|
updateType: "securityInfo".to_owned(),
|
|
|
|
};
|
2016-06-06 05:19:22 +03:00
|
|
|
let extra = SecurityInfoUpdateMsg {
|
|
|
|
state: "insecure".to_owned(),
|
|
|
|
};
|
2015-12-21 18:47:25 +03:00
|
|
|
for stream in &mut connections {
|
2016-06-06 05:19:22 +03:00
|
|
|
stream.write_merged_json_packet(&msg, &extra);
|
2015-12-21 18:47:25 +03:00
|
|
|
}
|
|
|
|
|
2016-06-06 05:19:22 +03:00
|
|
|
let msg = NetworkEventUpdateMsg {
|
2015-12-21 18:47:25 +03:00
|
|
|
from: netevent_actor_name.clone(),
|
2016-03-31 16:06:13 +03:00
|
|
|
type_: "networkEventUpdate".to_owned(),
|
2015-12-21 18:47:25 +03:00
|
|
|
updateType: "responseContent".to_owned(),
|
|
|
|
};
|
|
|
|
for stream in &mut connections {
|
2016-06-06 05:19:22 +03:00
|
|
|
stream.write_merged_json_packet(&msg, &actor.response_content());
|
2015-12-21 18:47:25 +03:00
|
|
|
}
|
|
|
|
|
2016-06-06 05:19:22 +03:00
|
|
|
let msg = NetworkEventUpdateMsg {
|
2015-12-21 18:47:25 +03:00
|
|
|
from: netevent_actor_name.clone(),
|
2016-03-31 16:06:13 +03:00
|
|
|
type_: "networkEventUpdate".to_owned(),
|
2015-12-21 18:47:25 +03:00
|
|
|
updateType: "responseCookies".to_owned(),
|
|
|
|
};
|
|
|
|
for stream in &mut connections {
|
2016-06-06 05:19:22 +03:00
|
|
|
stream.write_merged_json_packet(&msg, &actor.response_cookies());
|
2015-12-21 18:47:25 +03:00
|
|
|
}
|
|
|
|
|
2016-06-06 05:19:22 +03:00
|
|
|
let msg = NetworkEventUpdateMsg {
|
2015-12-21 18:47:25 +03:00
|
|
|
from: netevent_actor_name.clone(),
|
2016-03-31 16:06:13 +03:00
|
|
|
type_: "networkEventUpdate".to_owned(),
|
2015-12-21 18:47:25 +03:00
|
|
|
updateType: "responseHeaders".to_owned(),
|
|
|
|
};
|
|
|
|
for stream in &mut connections {
|
2016-06-06 05:19:22 +03:00
|
|
|
stream.write_merged_json_packet(&msg, &actor.response_headers());
|
2015-12-21 18:47:25 +03:00
|
|
|
}
|
2015-05-05 19:52:44 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find the name of NetworkEventActor corresponding to request_id
|
|
|
|
// Create a new one if it does not exist, add it to the actor_requests hashmap
|
|
|
|
fn find_network_event_actor(actors: Arc<Mutex<ActorRegistry>>,
|
|
|
|
actor_requests: &mut HashMap<String, String>,
|
|
|
|
request_id: String) -> String {
|
|
|
|
let mut actors = actors.lock().unwrap();
|
|
|
|
match (*actor_requests).entry(request_id) {
|
|
|
|
Occupied(name) => {
|
|
|
|
//TODO: Delete from map like Firefox does?
|
|
|
|
name.into_mut().clone()
|
|
|
|
}
|
|
|
|
Vacant(entry) => {
|
|
|
|
let actor_name = actors.new_name("netevent");
|
|
|
|
let actor = NetworkEventActor::new(actor_name.clone());
|
|
|
|
entry.insert(actor_name.clone());
|
|
|
|
actors.register(box actor);
|
|
|
|
actor_name
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-06 08:50:13 +03:00
|
|
|
let sender_clone = sender.clone();
|
2016-12-15 03:48:42 +03:00
|
|
|
thread::Builder::new().name("DevtoolsClientAcceptor".to_owned()).spawn(move || {
|
2016-01-10 13:19:04 +03:00
|
|
|
// accept connections and process them, spawning a new thread for each one
|
2015-03-25 18:03:51 +03:00
|
|
|
for stream in listener.incoming() {
|
2015-03-25 01:39:49 +03:00
|
|
|
// connection succeeded
|
2015-07-27 20:09:38 +03:00
|
|
|
sender_clone.send(DevtoolsControlMsg::FromChrome(
|
|
|
|
ChromeToDevtoolsControlMsg::AddClient(stream.unwrap()))).unwrap();
|
2015-03-25 01:39:49 +03:00
|
|
|
}
|
2016-12-15 03:48:42 +03:00
|
|
|
}).expect("Thread spawning failed");
|
2015-03-25 01:39:49 +03:00
|
|
|
|
2015-11-10 02:03:23 +03:00
|
|
|
while let Ok(msg) = receiver.recv() {
|
|
|
|
match msg {
|
|
|
|
DevtoolsControlMsg::FromChrome(ChromeToDevtoolsControlMsg::AddClient(stream)) => {
|
2014-09-19 17:15:03 +04:00
|
|
|
let actors = actors.clone();
|
2015-03-25 18:03:51 +03:00
|
|
|
accepted_connections.push(stream.try_clone().unwrap());
|
2016-12-15 03:48:42 +03:00
|
|
|
thread::Builder::new().name("DevtoolsClientHandler".to_owned()).spawn(move || {
|
2015-03-25 18:03:51 +03:00
|
|
|
handle_client(actors, stream.try_clone().unwrap())
|
2016-12-15 03:48:42 +03:00
|
|
|
}).expect("Thread spawning failed");
|
2014-09-19 17:15:03 +04:00
|
|
|
}
|
2015-11-10 02:03:23 +03:00
|
|
|
DevtoolsControlMsg::FromScript(ScriptToDevtoolsControlMsg::FramerateTick(
|
|
|
|
actor_name, tick)) =>
|
2015-05-06 08:50:13 +03:00
|
|
|
handle_framerate_tick(actors.clone(), actor_name, tick),
|
2015-11-10 02:03:23 +03:00
|
|
|
DevtoolsControlMsg::FromScript(ScriptToDevtoolsControlMsg::NewGlobal(
|
|
|
|
ids, script_sender, pageinfo)) =>
|
2015-08-13 21:41:48 +03:00
|
|
|
handle_new_global(actors.clone(), ids, script_sender, &mut actor_pipelines,
|
2015-04-21 16:05:48 +03:00
|
|
|
&mut actor_workers, pageinfo),
|
2015-11-10 02:03:23 +03:00
|
|
|
DevtoolsControlMsg::FromScript(ScriptToDevtoolsControlMsg::ConsoleAPI(
|
2015-07-27 20:09:38 +03:00
|
|
|
id,
|
2015-08-03 01:05:14 +03:00
|
|
|
console_message,
|
2015-11-10 02:03:23 +03:00
|
|
|
worker_id)) =>
|
2015-08-03 01:05:14 +03:00
|
|
|
handle_console_message(actors.clone(), id, worker_id, console_message,
|
|
|
|
&actor_pipelines, &actor_workers),
|
2016-01-12 01:17:50 +03:00
|
|
|
DevtoolsControlMsg::FromScript(ScriptToDevtoolsControlMsg::ReportCSSError(
|
|
|
|
id,
|
|
|
|
css_error)) => {
|
|
|
|
let console_message = ConsoleMessage {
|
|
|
|
message: css_error.msg,
|
|
|
|
logLevel: LogLevel::Warn,
|
|
|
|
filename: css_error.filename,
|
2017-06-16 15:03:18 +03:00
|
|
|
lineNumber: css_error.line as usize,
|
|
|
|
columnNumber: css_error.column as usize,
|
2016-01-12 01:17:50 +03:00
|
|
|
};
|
|
|
|
handle_console_message(actors.clone(), id, None, console_message,
|
|
|
|
&actor_pipelines, &actor_workers)
|
|
|
|
},
|
2015-11-10 02:03:23 +03:00
|
|
|
DevtoolsControlMsg::FromChrome(ChromeToDevtoolsControlMsg::NetworkEvent(
|
|
|
|
request_id, network_event)) => {
|
2015-05-05 19:52:44 +03:00
|
|
|
// copy the accepted_connections vector
|
|
|
|
let mut connections = Vec::<TcpStream>::new();
|
2015-08-15 12:03:21 +03:00
|
|
|
for stream in &accepted_connections {
|
2015-05-05 19:52:44 +03:00
|
|
|
connections.push(stream.try_clone().unwrap());
|
|
|
|
}
|
2016-08-27 17:23:13 +03:00
|
|
|
|
|
|
|
let pipeline_id = match network_event {
|
|
|
|
NetworkEvent::HttpResponse(ref response) => response.pipeline_id,
|
|
|
|
NetworkEvent::HttpRequest(ref request) => request.pipeline_id,
|
|
|
|
};
|
2015-05-05 19:52:44 +03:00
|
|
|
handle_network_event(actors.clone(), connections, &actor_pipelines, &mut actor_requests,
|
2016-08-27 17:23:13 +03:00
|
|
|
&actor_workers, pipeline_id, request_id, network_event);
|
2015-05-06 08:50:13 +03:00
|
|
|
},
|
2015-11-10 02:03:23 +03:00
|
|
|
DevtoolsControlMsg::FromChrome(ChromeToDevtoolsControlMsg::ServerExitMsg) => break
|
2014-09-19 17:15:03 +04:00
|
|
|
}
|
|
|
|
}
|
2015-08-15 12:03:21 +03:00
|
|
|
for connection in &mut accepted_connections {
|
2015-03-25 18:03:51 +03:00
|
|
|
let _ = connection.shutdown(Shutdown::Both);
|
2014-11-17 16:15:30 +03:00
|
|
|
}
|
2014-09-19 17:15:03 +04:00
|
|
|
}
|