diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2019-05-08 21:57:19 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-05-08 21:57:19 -0400 |
commit | e39b2b96fe13fe72dd009e8bd84cf3bfd79592fe (patch) | |
tree | 05049ced53381bc074f418d2eca8669d61125e40 /components | |
parent | cfe64a26359ea9e7ccb4b1b0e831165674588541 (diff) | |
parent | 8d8f48242af7c8af6cc229169695a51b22cdc67a (diff) | |
download | servo-e39b2b96fe13fe72dd009e8bd84cf3bfd79592fe.tar.gz servo-e39b2b96fe13fe72dd009e8bd84cf3bfd79592fe.zip |
Auto merge of #23296 - codehag:evaluate-js-fix, r=Manishearth
Enable evaluating javascript in the firefox devtools console
This enables one to use the Firefox Devtools console to evaluate things in servo.
Steps:
start servo: ./mach run tests/html/about-mozilla.html -d --devtools 6000
start firefox and go to Tools -> Web Developer -> Connect...
Set the port to connect to as 6000
Try evaluating things in the console.
<img width="901" alt="Screenshot 2019-05-01 at 13 02 37" src="https://user-images.githubusercontent.com/26968615/57015054-0aa0ce80-6c13-11e9-8031-9299f2da5dba.png">
---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [ ] These changes fix #___ (GitHub issue number if applicable)
<!-- Either: -->
- [ ] There are tests for these changes OR
- [ ] These changes do not require tests because ___
<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->
<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/23296)
<!-- Reviewable:end -->
Diffstat (limited to 'components')
-rw-r--r-- | components/devtools/Cargo.toml | 1 | ||||
-rw-r--r-- | components/devtools/actors/console.rs | 191 |
2 files changed, 125 insertions, 67 deletions
diff --git a/components/devtools/Cargo.toml b/components/devtools/Cargo.toml index 20c2ff5abc8..8ec3b58ae83 100644 --- a/components/devtools/Cargo.toml +++ b/components/devtools/Cargo.toml @@ -24,3 +24,4 @@ msg = {path = "../msg"} serde = "1.0" serde_json = "1.0" time = "0.1" +uuid = {version = "0.7", features = ["v4"]} diff --git a/components/devtools/actors/console.rs b/components/devtools/actors/console.rs index 82d44266afe..a4d8f0b1591 100644 --- a/components/devtools/actors/console.rs +++ b/components/devtools/actors/console.rs @@ -19,6 +19,7 @@ use msg::constellation_msg::PipelineId; use serde_json::{self, Map, Number, Value}; use std::cell::RefCell; use std::net::TcpStream; +use uuid::Uuid; trait EncodableConsoleMessage { fn encode(&self) -> serde_json::Result<String>; @@ -72,11 +73,30 @@ struct EvaluateJSReply { result: Value, timestamp: u64, exception: Value, - exceptionMessage: String, + exceptionMessage: Value, helperResult: Value, } #[derive(Serialize)] +struct EvaluateJSEvent { + from: String, + r#type: String, + input: String, + result: Value, + timestamp: u64, + resultID: String, + exception: Value, + exceptionMessage: Value, + helperResult: Value, +} + +#[derive(Serialize)] +struct EvaluateJSAsyncReply { + from: String, + resultID: String, +} + +#[derive(Serialize)] struct SetPreferencesReply { from: String, updated: Vec<String>, @@ -89,6 +109,86 @@ pub struct ConsoleActor { pub streams: RefCell<Vec<TcpStream>>, } +impl ConsoleActor { + fn evaluateJS( + &self, + registry: &ActorRegistry, + msg: &Map<String, Value>, + ) -> Result<EvaluateJSReply, ()> { + let input = msg.get("text").unwrap().as_str().unwrap().to_owned(); + let (chan, port) = ipc::channel().unwrap(); + self.script_chan + .send(DevtoolScriptControlMsg::EvaluateJS( + self.pipeline, + input.clone(), + chan, + )) + .unwrap(); + + //TODO: extract conversion into protocol module or some other useful place + let result = match port.recv().map_err(|_| ())? { + VoidValue => { + let mut m = Map::new(); + m.insert("type".to_owned(), Value::String("undefined".to_owned())); + Value::Object(m) + }, + NullValue => { + let mut m = Map::new(); + m.insert("type".to_owned(), Value::String("null".to_owned())); + Value::Object(m) + }, + BooleanValue(val) => Value::Bool(val), + NumberValue(val) => { + if val.is_nan() { + let mut m = Map::new(); + m.insert("type".to_owned(), Value::String("NaN".to_owned())); + Value::Object(m) + } else if val.is_infinite() { + let mut m = Map::new(); + if val < 0. { + m.insert("type".to_owned(), Value::String("-Infinity".to_owned())); + } else { + m.insert("type".to_owned(), Value::String("Infinity".to_owned())); + } + Value::Object(m) + } else if val == 0. && val.is_sign_negative() { + let mut m = Map::new(); + m.insert("type".to_owned(), Value::String("-0".to_owned())); + Value::Object(m) + } else { + Value::Number(Number::from_f64(val).unwrap()) + } + }, + StringValue(s) => Value::String(s), + ActorValue { class, uuid } => { + //TODO: make initial ActorValue message include these properties? + let mut m = Map::new(); + let actor = ObjectActor::new(registry, uuid); + + m.insert("type".to_owned(), Value::String("object".to_owned())); + m.insert("class".to_owned(), Value::String(class)); + m.insert("actor".to_owned(), Value::String(actor)); + m.insert("extensible".to_owned(), Value::Bool(true)); + m.insert("frozen".to_owned(), Value::Bool(false)); + m.insert("sealed".to_owned(), Value::Bool(false)); + Value::Object(m) + }, + }; + + //TODO: catch and return exception values from JS evaluation + let reply = EvaluateJSReply { + from: self.name(), + input: input, + result: result, + timestamp: 0, + exception: Value::Null, + exceptionMessage: Value::Null, + helperResult: Value::Null, + }; + std::result::Result::Ok(reply) + } +} + impl Actor for ConsoleActor { fn name(&self) -> String { self.name.clone() @@ -191,76 +291,33 @@ impl Actor for ConsoleActor { }, "evaluateJS" => { - let input = msg.get("text").unwrap().as_str().unwrap().to_owned(); - let (chan, port) = ipc::channel().unwrap(); - self.script_chan - .send(DevtoolScriptControlMsg::EvaluateJS( - self.pipeline, - input.clone(), - chan, - )) - .unwrap(); - - //TODO: extract conversion into protocol module or some other useful place - let result = match port.recv().map_err(|_| ())? { - VoidValue => { - let mut m = Map::new(); - m.insert("type".to_owned(), Value::String("undefined".to_owned())); - Value::Object(m) - }, - NullValue => { - let mut m = Map::new(); - m.insert("type".to_owned(), Value::String("null".to_owned())); - Value::Object(m) - }, - BooleanValue(val) => Value::Bool(val), - NumberValue(val) => { - if val.is_nan() { - let mut m = Map::new(); - m.insert("type".to_owned(), Value::String("NaN".to_owned())); - Value::Object(m) - } else if val.is_infinite() { - let mut m = Map::new(); - if val < 0. { - m.insert("type".to_owned(), Value::String("-Infinity".to_owned())); - } else { - m.insert("type".to_owned(), Value::String("Infinity".to_owned())); - } - Value::Object(m) - } else if val == 0. && val.is_sign_negative() { - let mut m = Map::new(); - m.insert("type".to_owned(), Value::String("-0".to_owned())); - Value::Object(m) - } else { - Value::Number(Number::from_f64(val).unwrap()) - } - }, - StringValue(s) => Value::String(s), - ActorValue { class, uuid } => { - //TODO: make initial ActorValue message include these properties? - let mut m = Map::new(); - let actor = ObjectActor::new(registry, uuid); + let msg = self.evaluateJS(®istry, &msg); + stream.write_json_packet(&msg); + ActorMessageStatus::Processed + }, - m.insert("type".to_owned(), Value::String("object".to_owned())); - m.insert("class".to_owned(), Value::String(class)); - m.insert("actor".to_owned(), Value::String(actor)); - m.insert("extensible".to_owned(), Value::Bool(true)); - m.insert("frozen".to_owned(), Value::Bool(false)); - m.insert("sealed".to_owned(), Value::Bool(false)); - Value::Object(m) - }, + "evaluateJSAsync" => { + let resultID = Uuid::new_v4().to_string(); + let early_reply = EvaluateJSAsyncReply { + from: self.name(), + resultID: resultID.clone(), }; - - //TODO: catch and return exception values from JS evaluation - let msg = EvaluateJSReply { + // Emit an eager reply so that the client starts listening + // for an async event with the resultID + stream.write_json_packet(&early_reply); + let reply = self.evaluateJS(®istry, &msg).unwrap(); + let msg = EvaluateJSEvent { from: self.name(), - input: input, - result: result, - timestamp: 0, - exception: Value::Object(Map::new()), - exceptionMessage: "".to_owned(), - helperResult: Value::Object(Map::new()), + r#type: "evaluationResult".to_owned(), + input: reply.input, + result: reply.result, + timestamp: reply.timestamp, + resultID: resultID, + exception: reply.exception, + exceptionMessage: reply.exceptionMessage, + helperResult: reply.helperResult, }; + // Send the data from evaluateJS along with a resultID stream.write_json_packet(&msg); ActorMessageStatus::Processed }, |