diff options
-rw-r--r-- | Cargo.lock | 1 | ||||
-rw-r--r-- | components/devtools/Cargo.toml | 1 | ||||
-rw-r--r-- | components/devtools/actors/console.rs | 191 |
3 files changed, 126 insertions, 67 deletions
diff --git a/Cargo.lock b/Cargo.lock index 3d5ffe2c4af..6e065cb4a1f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1017,6 +1017,7 @@ dependencies = [ "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "uuid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] 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 }, |