mirror of
https://github.com/servo/servo.git
synced 2025-07-15 11:23:39 +01:00
Devtools: send error replies instead of ignoring messages (#37686)
Client messages, which are always requests, are dispatched to Actor instances one at a time via Actor::handle_message. Each request must be paired with exactly one reply from the same actor the request was sent to, where a reply is a message with no type (if a message from the server has a type, it’s a notification, not a reply). Failing to reply to a request will almost always permanently break that actor, because either the client gets stuck waiting for a reply, or the client receives the reply for a subsequent request as if it was the reply for the current request. If an actor fails to reply to a request, we want the dispatcher (ActorRegistry::handle_message) to send an error of type `unrecognizedPacketType`, to keep the conversation for that actor in sync. Since replies come in all shapes and sizes, we want to allow Actor types to send replies without having to return them to the dispatcher. This patch adds a wrapper type around a client stream that guarantees request/reply invariants. It allows the dispatcher to check if a valid reply was sent, and guarantees that if the actor tries to send a reply, it’s actually a valid reply (see ClientRequest::is_valid_reply). It does not currently guarantee anything about messages sent via the TcpStream released via ClientRequest::try_clone_stream or the return value of ClientRequest::reply. We also send `unrecognizedPacketType`, `missingParameter`, `badParameterType`, and `noSuchActor` messages per the [protocol](https://firefox-source-docs.mozilla.org/devtools/backend/protocol.html#error-packets) [docs](https://firefox-source-docs.mozilla.org/devtools/backend/protocol.html#packets). Testing: automated tests all pass, and manual testing looks ok Fixes: #37683 and at least six bugs, plus one with a different root cause, plus three with zero impact --------- Signed-off-by: atbrakhi <atbrakhi@igalia.com> Signed-off-by: Delan Azabani <dazabani@igalia.com> Co-authored-by: delan azabani <dazabani@igalia.com> Co-authored-by: Simon Wülker <simon.wuelker@arcor.de> Co-authored-by: the6p4c <me@doggirl.gay>
This commit is contained in:
parent
fcb2a4cd95
commit
71d97bd935
36 changed files with 661 additions and 637 deletions
|
@ -12,14 +12,37 @@ use std::sync::{Arc, Mutex};
|
||||||
use base::cross_process_instant::CrossProcessInstant;
|
use base::cross_process_instant::CrossProcessInstant;
|
||||||
use base::id::PipelineId;
|
use base::id::PipelineId;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use serde_json::{Map, Value};
|
use serde_json::{Map, Value, json};
|
||||||
|
|
||||||
use crate::StreamId;
|
use crate::StreamId;
|
||||||
|
use crate::protocol::{ClientRequest, JsonPacketStream};
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
/// Error replies.
|
||||||
pub enum ActorMessageStatus {
|
///
|
||||||
Processed,
|
/// <https://firefox-source-docs.mozilla.org/devtools/backend/protocol.html#error-packets>
|
||||||
Ignored,
|
#[derive(Debug)]
|
||||||
|
pub enum ActorError {
|
||||||
|
MissingParameter,
|
||||||
|
BadParameterType,
|
||||||
|
UnrecognizedPacketType,
|
||||||
|
/// Custom errors, not defined in the protocol docs.
|
||||||
|
/// This includes send errors, and errors that prevent Servo from sending a reply.
|
||||||
|
Internal,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ActorError {
|
||||||
|
pub fn name(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
ActorError::MissingParameter => "missingParameter",
|
||||||
|
ActorError::BadParameterType => "badParameterType",
|
||||||
|
ActorError::UnrecognizedPacketType => "unrecognizedPacketType",
|
||||||
|
// The devtools frontend always checks for specific protocol errors by catching a JS exception `e` whose
|
||||||
|
// message contains the error name, and checking `e.message.includes("someErrorName")`. As a result, the
|
||||||
|
// only error name we can safely use for custom errors is the empty string, because any other error name we
|
||||||
|
// use may be a substring of some upstream error name.
|
||||||
|
ActorError::Internal => "",
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A common trait for all devtools actors that encompasses an immutable name
|
/// A common trait for all devtools actors that encompasses an immutable name
|
||||||
|
@ -28,12 +51,12 @@ pub enum ActorMessageStatus {
|
||||||
pub(crate) trait Actor: Any + ActorAsAny {
|
pub(crate) trait Actor: Any + ActorAsAny {
|
||||||
fn handle_message(
|
fn handle_message(
|
||||||
&self,
|
&self,
|
||||||
|
request: ClientRequest,
|
||||||
registry: &ActorRegistry,
|
registry: &ActorRegistry,
|
||||||
msg_type: &str,
|
msg_type: &str,
|
||||||
msg: &Map<String, Value>,
|
msg: &Map<String, Value>,
|
||||||
stream: &mut TcpStream,
|
|
||||||
stream_id: StreamId,
|
stream_id: StreamId,
|
||||||
) -> Result<ActorMessageStatus, ()>;
|
) -> Result<(), ActorError>;
|
||||||
fn name(&self) -> String;
|
fn name(&self) -> String;
|
||||||
fn cleanup(&self, _id: StreamId) {}
|
fn cleanup(&self, _id: StreamId) {}
|
||||||
}
|
}
|
||||||
|
@ -169,8 +192,8 @@ impl ActorRegistry {
|
||||||
actor.actor_as_any_mut().downcast_mut::<T>().unwrap()
|
actor.actor_as_any_mut().downcast_mut::<T>().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempt to process a message as directed by its `to` property. If the actor is not
|
/// Attempt to process a message as directed by its `to` property. If the actor is not found, does not support the
|
||||||
/// found or does not indicate that it knew how to process the message, ignore the failure.
|
/// message, or failed to handle the message, send an error reply instead.
|
||||||
pub(crate) fn handle_message(
|
pub(crate) fn handle_message(
|
||||||
&mut self,
|
&mut self,
|
||||||
msg: &Map<String, Value>,
|
msg: &Map<String, Value>,
|
||||||
|
@ -186,17 +209,20 @@ impl ActorRegistry {
|
||||||
};
|
};
|
||||||
|
|
||||||
match self.actors.get(to) {
|
match self.actors.get(to) {
|
||||||
None => log::warn!("message received for unknown actor \"{}\"", to),
|
None => {
|
||||||
|
// <https://firefox-source-docs.mozilla.org/devtools/backend/protocol.html#packets>
|
||||||
|
let msg = json!({ "from": to, "error": "noSuchActor" });
|
||||||
|
let _ = stream.write_json_packet(&msg);
|
||||||
|
},
|
||||||
Some(actor) => {
|
Some(actor) => {
|
||||||
let msg_type = msg.get("type").unwrap().as_str().unwrap();
|
let msg_type = msg.get("type").unwrap().as_str().unwrap();
|
||||||
if actor.handle_message(self, msg_type, msg, stream, stream_id)? !=
|
if let Err(error) = ClientRequest::handle(stream, to, |req| {
|
||||||
ActorMessageStatus::Processed
|
actor.handle_message(req, self, msg_type, msg, stream_id)
|
||||||
{
|
}) {
|
||||||
log::warn!(
|
// <https://firefox-source-docs.mozilla.org/devtools/backend/protocol.html#error-packets>
|
||||||
"unexpected message type \"{}\" found for actor \"{}\"",
|
let _ = stream.write_json_packet(&json!({
|
||||||
msg_type,
|
"from": actor.name(), "error": error.name()
|
||||||
to
|
}));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::EmptyReplyMsg;
|
use crate::EmptyReplyMsg;
|
||||||
use crate::actor::{Actor, ActorMessageStatus};
|
use crate::actor::{Actor, ActorError};
|
||||||
use crate::protocol::JsonPacketStream;
|
use crate::protocol::ClientRequest;
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
pub struct BreakpointListActorMsg {
|
pub struct BreakpointListActorMsg {
|
||||||
|
@ -24,27 +24,24 @@ impl Actor for BreakpointListActor {
|
||||||
|
|
||||||
fn handle_message(
|
fn handle_message(
|
||||||
&self,
|
&self,
|
||||||
|
request: ClientRequest,
|
||||||
_registry: &crate::actor::ActorRegistry,
|
_registry: &crate::actor::ActorRegistry,
|
||||||
msg_type: &str,
|
msg_type: &str,
|
||||||
_msg: &serde_json::Map<String, serde_json::Value>,
|
_msg: &serde_json::Map<String, serde_json::Value>,
|
||||||
stream: &mut std::net::TcpStream,
|
|
||||||
_stream_id: crate::StreamId,
|
_stream_id: crate::StreamId,
|
||||||
) -> Result<crate::actor::ActorMessageStatus, ()> {
|
) -> Result<(), ActorError> {
|
||||||
Ok(match msg_type {
|
match msg_type {
|
||||||
"setBreakpoint" => {
|
"setBreakpoint" => {
|
||||||
let msg = EmptyReplyMsg { from: self.name() };
|
let msg = EmptyReplyMsg { from: self.name() };
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
|
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
"setActiveEventBreakpoints" => {
|
"setActiveEventBreakpoints" => {
|
||||||
let msg = EmptyReplyMsg { from: self.name() };
|
let msg = EmptyReplyMsg { from: self.name() };
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
|
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
_ => ActorMessageStatus::Ignored,
|
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||||
})
|
};
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ use ipc_channel::ipc::{self, IpcSender};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json::{Map, Value};
|
use serde_json::{Map, Value};
|
||||||
|
|
||||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||||
use crate::actors::inspector::InspectorActor;
|
use crate::actors::inspector::InspectorActor;
|
||||||
use crate::actors::inspector::accessibility::AccessibilityActor;
|
use crate::actors::inspector::accessibility::AccessibilityActor;
|
||||||
use crate::actors::inspector::css_properties::CssPropertiesActor;
|
use crate::actors::inspector::css_properties::CssPropertiesActor;
|
||||||
|
@ -30,7 +30,7 @@ use crate::actors::tab::TabDescriptorActor;
|
||||||
use crate::actors::thread::ThreadActor;
|
use crate::actors::thread::ThreadActor;
|
||||||
use crate::actors::watcher::{SessionContext, SessionContextType, WatcherActor};
|
use crate::actors::watcher::{SessionContext, SessionContextType, WatcherActor};
|
||||||
use crate::id::{DevtoolsBrowserId, DevtoolsBrowsingContextId, DevtoolsOuterWindowId, IdMap};
|
use crate::id::{DevtoolsBrowserId, DevtoolsBrowsingContextId, DevtoolsOuterWindowId, IdMap};
|
||||||
use crate::protocol::JsonPacketStream;
|
use crate::protocol::{ClientRequest, JsonPacketStream};
|
||||||
use crate::resource::ResourceAvailable;
|
use crate::resource::ResourceAvailable;
|
||||||
use crate::{EmptyReplyMsg, StreamId};
|
use crate::{EmptyReplyMsg, StreamId};
|
||||||
|
|
||||||
|
@ -166,29 +166,28 @@ impl Actor for BrowsingContextActor {
|
||||||
|
|
||||||
fn handle_message(
|
fn handle_message(
|
||||||
&self,
|
&self,
|
||||||
|
request: ClientRequest,
|
||||||
_registry: &ActorRegistry,
|
_registry: &ActorRegistry,
|
||||||
msg_type: &str,
|
msg_type: &str,
|
||||||
_msg: &Map<String, Value>,
|
_msg: &Map<String, Value>,
|
||||||
stream: &mut TcpStream,
|
|
||||||
_id: StreamId,
|
_id: StreamId,
|
||||||
) -> Result<ActorMessageStatus, ()> {
|
) -> Result<(), ActorError> {
|
||||||
Ok(match msg_type {
|
match msg_type {
|
||||||
"listFrames" => {
|
"listFrames" => {
|
||||||
// TODO: Find out what needs to be listed here
|
// TODO: Find out what needs to be listed here
|
||||||
let msg = EmptyReplyMsg { from: self.name() };
|
let msg = EmptyReplyMsg { from: self.name() };
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
"listWorkers" => {
|
"listWorkers" => {
|
||||||
let _ = stream.write_json_packet(&ListWorkersReply {
|
request.reply_final(&ListWorkersReply {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
// TODO: Find out what needs to be listed here
|
// TODO: Find out what needs to be listed here
|
||||||
workers: vec![],
|
workers: vec![],
|
||||||
});
|
})?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
_ => ActorMessageStatus::Ignored,
|
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||||
})
|
};
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cleanup(&self, id: StreamId) {
|
fn cleanup(&self, id: StreamId) {
|
||||||
|
@ -353,8 +352,8 @@ impl BrowsingContextActor {
|
||||||
*self.title.borrow_mut() = title;
|
*self.title.borrow_mut() = title;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn frame_update(&self, stream: &mut TcpStream) {
|
pub(crate) fn frame_update(&self, request: &mut ClientRequest) {
|
||||||
let _ = stream.write_json_packet(&FrameUpdateReply {
|
let _ = request.write_json_packet(&FrameUpdateReply {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
type_: "frameUpdate".into(),
|
type_: "frameUpdate".into(),
|
||||||
frames: vec![FrameUpdateMsg {
|
frames: vec![FrameUpdateMsg {
|
||||||
|
|
|
@ -25,11 +25,11 @@ use serde::Serialize;
|
||||||
use serde_json::{self, Map, Number, Value};
|
use serde_json::{self, Map, Number, Value};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||||
use crate::actors::browsing_context::BrowsingContextActor;
|
use crate::actors::browsing_context::BrowsingContextActor;
|
||||||
use crate::actors::object::ObjectActor;
|
use crate::actors::object::ObjectActor;
|
||||||
use crate::actors::worker::WorkerActor;
|
use crate::actors::worker::WorkerActor;
|
||||||
use crate::protocol::JsonPacketStream;
|
use crate::protocol::{ClientRequest, JsonPacketStream};
|
||||||
use crate::resource::{ResourceArrayType, ResourceAvailable};
|
use crate::resource::{ResourceArrayType, ResourceAvailable};
|
||||||
use crate::{StreamId, UniqueId};
|
use crate::{StreamId, UniqueId};
|
||||||
|
|
||||||
|
@ -304,18 +304,19 @@ impl Actor for ConsoleActor {
|
||||||
|
|
||||||
fn handle_message(
|
fn handle_message(
|
||||||
&self,
|
&self,
|
||||||
|
request: ClientRequest,
|
||||||
registry: &ActorRegistry,
|
registry: &ActorRegistry,
|
||||||
msg_type: &str,
|
msg_type: &str,
|
||||||
msg: &Map<String, Value>,
|
msg: &Map<String, Value>,
|
||||||
stream: &mut TcpStream,
|
|
||||||
_id: StreamId,
|
_id: StreamId,
|
||||||
) -> Result<ActorMessageStatus, ()> {
|
) -> Result<(), ActorError> {
|
||||||
Ok(match msg_type {
|
match msg_type {
|
||||||
"clearMessagesCache" => {
|
"clearMessagesCache" => {
|
||||||
self.cached_events
|
self.cached_events
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.remove(&self.current_unique_id(registry));
|
.remove(&self.current_unique_id(registry));
|
||||||
ActorMessageStatus::Processed
|
// FIXME: need to send a reply here!
|
||||||
|
return Err(ActorError::UnrecognizedPacketType);
|
||||||
},
|
},
|
||||||
|
|
||||||
"getCachedMessages" => {
|
"getCachedMessages" => {
|
||||||
|
@ -368,8 +369,7 @@ impl Actor for ConsoleActor {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
messages,
|
messages,
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"startListeners" => {
|
"startListeners" => {
|
||||||
|
@ -384,8 +384,7 @@ impl Actor for ConsoleActor {
|
||||||
.collect(),
|
.collect(),
|
||||||
traits: StartedListenersTraits,
|
traits: StartedListenersTraits,
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"stopListeners" => {
|
"stopListeners" => {
|
||||||
|
@ -401,8 +400,7 @@ impl Actor for ConsoleActor {
|
||||||
.map(|listener| listener.as_str().unwrap().to_owned())
|
.map(|listener| listener.as_str().unwrap().to_owned())
|
||||||
.collect(),
|
.collect(),
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
|
|
||||||
//TODO: implement autocompletion like onAutocomplete in
|
//TODO: implement autocompletion like onAutocomplete in
|
||||||
|
@ -413,14 +411,12 @@ impl Actor for ConsoleActor {
|
||||||
matches: vec![],
|
matches: vec![],
|
||||||
match_prop: "".to_owned(),
|
match_prop: "".to_owned(),
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"evaluateJS" => {
|
"evaluateJS" => {
|
||||||
let msg = self.evaluate_js(registry, msg);
|
let msg = self.evaluate_js(registry, msg);
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"evaluateJSAsync" => {
|
"evaluateJSAsync" => {
|
||||||
|
@ -431,14 +427,12 @@ impl Actor for ConsoleActor {
|
||||||
};
|
};
|
||||||
// Emit an eager reply so that the client starts listening
|
// Emit an eager reply so that the client starts listening
|
||||||
// for an async event with the resultID
|
// for an async event with the resultID
|
||||||
if stream.write_json_packet(&early_reply).is_err() {
|
let stream = request.reply(&early_reply)?;
|
||||||
return Ok(ActorMessageStatus::Processed);
|
|
||||||
}
|
|
||||||
|
|
||||||
if msg.get("eager").and_then(|v| v.as_bool()).unwrap_or(false) {
|
if msg.get("eager").and_then(|v| v.as_bool()).unwrap_or(false) {
|
||||||
// We don't support the side-effect free evaluation that eager evalaution
|
// We don't support the side-effect free evaluation that eager evalaution
|
||||||
// really needs.
|
// really needs.
|
||||||
return Ok(ActorMessageStatus::Processed);
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let reply = self.evaluate_js(registry, msg).unwrap();
|
let reply = self.evaluate_js(registry, msg).unwrap();
|
||||||
|
@ -454,8 +448,7 @@ impl Actor for ConsoleActor {
|
||||||
helper_result: reply.helper_result,
|
helper_result: reply.helper_result,
|
||||||
};
|
};
|
||||||
// Send the data from evaluateJS along with a resultID
|
// Send the data from evaluateJS along with a resultID
|
||||||
let _ = stream.write_json_packet(&msg);
|
stream.write_json_packet(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"setPreferences" => {
|
"setPreferences" => {
|
||||||
|
@ -463,11 +456,11 @@ impl Actor for ConsoleActor {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
updated: vec![],
|
updated: vec![],
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_ => ActorMessageStatus::Ignored,
|
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||||
})
|
};
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,14 +2,12 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use std::net::TcpStream;
|
|
||||||
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json::{Map, Value};
|
use serde_json::{Map, Value};
|
||||||
|
|
||||||
use crate::StreamId;
|
use crate::StreamId;
|
||||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||||
use crate::protocol::{ActorDescription, JsonPacketStream, Method};
|
use crate::protocol::{ActorDescription, ClientRequest, Method};
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct GetDescriptionReply {
|
struct GetDescriptionReply {
|
||||||
|
@ -46,13 +44,13 @@ impl Actor for DeviceActor {
|
||||||
}
|
}
|
||||||
fn handle_message(
|
fn handle_message(
|
||||||
&self,
|
&self,
|
||||||
|
request: ClientRequest,
|
||||||
_registry: &ActorRegistry,
|
_registry: &ActorRegistry,
|
||||||
msg_type: &str,
|
msg_type: &str,
|
||||||
_msg: &Map<String, Value>,
|
_msg: &Map<String, Value>,
|
||||||
stream: &mut TcpStream,
|
|
||||||
_id: StreamId,
|
_id: StreamId,
|
||||||
) -> Result<ActorMessageStatus, ()> {
|
) -> Result<(), ActorError> {
|
||||||
Ok(match msg_type {
|
match msg_type {
|
||||||
"getDescription" => {
|
"getDescription" => {
|
||||||
let msg = GetDescriptionReply {
|
let msg = GetDescriptionReply {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
|
@ -64,12 +62,12 @@ impl Actor for DeviceActor {
|
||||||
brand_name: "Servo".to_string(),
|
brand_name: "Servo".to_string(),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_ => ActorMessageStatus::Ignored,
|
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||||
})
|
};
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::net::TcpStream;
|
|
||||||
|
|
||||||
use base::id::PipelineId;
|
use base::id::PipelineId;
|
||||||
use devtools_traits::DevtoolScriptControlMsg;
|
use devtools_traits::DevtoolScriptControlMsg;
|
||||||
|
@ -11,8 +10,9 @@ use ipc_channel::ipc::IpcSender;
|
||||||
use serde_json::{Map, Value};
|
use serde_json::{Map, Value};
|
||||||
|
|
||||||
use crate::StreamId;
|
use crate::StreamId;
|
||||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||||
use crate::actors::timeline::HighResolutionStamp;
|
use crate::actors::timeline::HighResolutionStamp;
|
||||||
|
use crate::protocol::ClientRequest;
|
||||||
|
|
||||||
pub struct FramerateActor {
|
pub struct FramerateActor {
|
||||||
name: String,
|
name: String,
|
||||||
|
@ -29,13 +29,13 @@ impl Actor for FramerateActor {
|
||||||
|
|
||||||
fn handle_message(
|
fn handle_message(
|
||||||
&self,
|
&self,
|
||||||
|
_request: ClientRequest,
|
||||||
_registry: &ActorRegistry,
|
_registry: &ActorRegistry,
|
||||||
_msg_type: &str,
|
_msg_type: &str,
|
||||||
_msg: &Map<String, Value>,
|
_msg: &Map<String, Value>,
|
||||||
_stream: &mut TcpStream,
|
|
||||||
_id: StreamId,
|
_id: StreamId,
|
||||||
) -> Result<ActorMessageStatus, ()> {
|
) -> Result<(), ActorError> {
|
||||||
Ok(ActorMessageStatus::Ignored)
|
Err(ActorError::UnrecognizedPacketType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::net::TcpStream;
|
|
||||||
|
|
||||||
use devtools_traits::DevtoolScriptControlMsg;
|
use devtools_traits::DevtoolScriptControlMsg;
|
||||||
use devtools_traits::DevtoolScriptControlMsg::GetRootNode;
|
use devtools_traits::DevtoolScriptControlMsg::GetRootNode;
|
||||||
|
@ -15,13 +14,13 @@ use serde::Serialize;
|
||||||
use serde_json::{self, Map, Value};
|
use serde_json::{self, Map, Value};
|
||||||
|
|
||||||
use crate::StreamId;
|
use crate::StreamId;
|
||||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||||
use crate::actors::browsing_context::BrowsingContextActor;
|
use crate::actors::browsing_context::BrowsingContextActor;
|
||||||
use crate::actors::inspector::highlighter::{HighlighterActor, HighlighterMsg};
|
use crate::actors::inspector::highlighter::{HighlighterActor, HighlighterMsg};
|
||||||
use crate::actors::inspector::node::NodeInfoToProtocol;
|
use crate::actors::inspector::node::NodeInfoToProtocol;
|
||||||
use crate::actors::inspector::page_style::{PageStyleActor, PageStyleMsg};
|
use crate::actors::inspector::page_style::{PageStyleActor, PageStyleMsg};
|
||||||
use crate::actors::inspector::walker::{WalkerActor, WalkerMsg};
|
use crate::actors::inspector::walker::{WalkerActor, WalkerMsg};
|
||||||
use crate::protocol::JsonPacketStream;
|
use crate::protocol::ClientRequest;
|
||||||
|
|
||||||
pub mod accessibility;
|
pub mod accessibility;
|
||||||
pub mod css_properties;
|
pub mod css_properties;
|
||||||
|
@ -73,19 +72,19 @@ impl Actor for InspectorActor {
|
||||||
|
|
||||||
fn handle_message(
|
fn handle_message(
|
||||||
&self,
|
&self,
|
||||||
|
request: ClientRequest,
|
||||||
registry: &ActorRegistry,
|
registry: &ActorRegistry,
|
||||||
msg_type: &str,
|
msg_type: &str,
|
||||||
_msg: &Map<String, Value>,
|
_msg: &Map<String, Value>,
|
||||||
stream: &mut TcpStream,
|
|
||||||
_id: StreamId,
|
_id: StreamId,
|
||||||
) -> Result<ActorMessageStatus, ()> {
|
) -> Result<(), ActorError> {
|
||||||
let browsing_context = registry.find::<BrowsingContextActor>(&self.browsing_context);
|
let browsing_context = registry.find::<BrowsingContextActor>(&self.browsing_context);
|
||||||
let pipeline = browsing_context.active_pipeline_id.get();
|
let pipeline = browsing_context.active_pipeline_id.get();
|
||||||
Ok(match msg_type {
|
match msg_type {
|
||||||
"getWalker" => {
|
"getWalker" => {
|
||||||
let (tx, rx) = ipc::channel().unwrap();
|
let (tx, rx) = ipc::channel().unwrap();
|
||||||
self.script_chan.send(GetRootNode(pipeline, tx)).unwrap();
|
self.script_chan.send(GetRootNode(pipeline, tx)).unwrap();
|
||||||
let root_info = rx.recv().unwrap().ok_or(())?;
|
let root_info = rx.recv().unwrap().ok_or(ActorError::Internal)?;
|
||||||
|
|
||||||
let name = self
|
let name = self
|
||||||
.walker
|
.walker
|
||||||
|
@ -121,8 +120,7 @@ impl Actor for InspectorActor {
|
||||||
root,
|
root,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"getPageStyle" => {
|
"getPageStyle" => {
|
||||||
|
@ -149,8 +147,7 @@ impl Actor for InspectorActor {
|
||||||
]),
|
]),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"supportsHighlighters" => {
|
"supportsHighlighters" => {
|
||||||
|
@ -158,8 +155,7 @@ impl Actor for InspectorActor {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
value: true,
|
value: true,
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"getHighlighterByType" => {
|
"getHighlighterByType" => {
|
||||||
|
@ -180,11 +176,10 @@ impl Actor for InspectorActor {
|
||||||
actor: self.highlighter.borrow().clone().unwrap(),
|
actor: self.highlighter.borrow().clone().unwrap(),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
|
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||||
_ => ActorMessageStatus::Ignored,
|
};
|
||||||
})
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,14 +5,12 @@
|
||||||
//! The Accessibility actor is responsible for the Accessibility tab in the DevTools page. Right
|
//! The Accessibility actor is responsible for the Accessibility tab in the DevTools page. Right
|
||||||
//! now it is a placeholder for future functionality.
|
//! now it is a placeholder for future functionality.
|
||||||
|
|
||||||
use std::net::TcpStream;
|
|
||||||
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json::{Map, Value};
|
use serde_json::{Map, Value};
|
||||||
|
|
||||||
use crate::StreamId;
|
use crate::StreamId;
|
||||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||||
use crate::protocol::JsonPacketStream;
|
use crate::protocol::ClientRequest;
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct BootstrapState {
|
struct BootstrapState {
|
||||||
|
@ -75,20 +73,19 @@ impl Actor for AccessibilityActor {
|
||||||
/// inspector Walker actor)
|
/// inspector Walker actor)
|
||||||
fn handle_message(
|
fn handle_message(
|
||||||
&self,
|
&self,
|
||||||
|
request: ClientRequest,
|
||||||
registry: &ActorRegistry,
|
registry: &ActorRegistry,
|
||||||
msg_type: &str,
|
msg_type: &str,
|
||||||
_msg: &Map<String, Value>,
|
_msg: &Map<String, Value>,
|
||||||
stream: &mut TcpStream,
|
|
||||||
_id: StreamId,
|
_id: StreamId,
|
||||||
) -> Result<ActorMessageStatus, ()> {
|
) -> Result<(), ActorError> {
|
||||||
Ok(match msg_type {
|
match msg_type {
|
||||||
"bootstrap" => {
|
"bootstrap" => {
|
||||||
let msg = BootstrapReply {
|
let msg = BootstrapReply {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
state: BootstrapState { enabled: false },
|
state: BootstrapState { enabled: false },
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
"getSimulator" => {
|
"getSimulator" => {
|
||||||
// TODO: Create actual simulator
|
// TODO: Create actual simulator
|
||||||
|
@ -97,8 +94,7 @@ impl Actor for AccessibilityActor {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
simulator: ActorMsg { actor: simulator },
|
simulator: ActorMsg { actor: simulator },
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
"getTraits" => {
|
"getTraits" => {
|
||||||
let msg = GetTraitsReply {
|
let msg = GetTraitsReply {
|
||||||
|
@ -107,8 +103,7 @@ impl Actor for AccessibilityActor {
|
||||||
tabbing_order: true,
|
tabbing_order: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
"getWalker" => {
|
"getWalker" => {
|
||||||
// TODO: Create actual accessible walker
|
// TODO: Create actual accessible walker
|
||||||
|
@ -117,11 +112,11 @@ impl Actor for AccessibilityActor {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
walker: ActorMsg { actor: walker },
|
walker: ActorMsg { actor: walker },
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
_ => ActorMessageStatus::Ignored,
|
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||||
})
|
};
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,15 +6,14 @@
|
||||||
//! alternative names
|
//! alternative names
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::net::TcpStream;
|
|
||||||
|
|
||||||
use devtools_traits::CssDatabaseProperty;
|
use devtools_traits::CssDatabaseProperty;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json::{Map, Value};
|
use serde_json::{Map, Value};
|
||||||
|
|
||||||
use crate::StreamId;
|
use crate::StreamId;
|
||||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||||
use crate::protocol::JsonPacketStream;
|
use crate::protocol::ClientRequest;
|
||||||
|
|
||||||
pub struct CssPropertiesActor {
|
pub struct CssPropertiesActor {
|
||||||
name: String,
|
name: String,
|
||||||
|
@ -38,23 +37,20 @@ impl Actor for CssPropertiesActor {
|
||||||
/// inspector can show the available options
|
/// inspector can show the available options
|
||||||
fn handle_message(
|
fn handle_message(
|
||||||
&self,
|
&self,
|
||||||
|
request: ClientRequest,
|
||||||
_registry: &ActorRegistry,
|
_registry: &ActorRegistry,
|
||||||
msg_type: &str,
|
msg_type: &str,
|
||||||
_msg: &Map<String, Value>,
|
_msg: &Map<String, Value>,
|
||||||
stream: &mut TcpStream,
|
|
||||||
_id: StreamId,
|
_id: StreamId,
|
||||||
) -> Result<ActorMessageStatus, ()> {
|
) -> Result<(), ActorError> {
|
||||||
Ok(match msg_type {
|
match msg_type {
|
||||||
"getCSSDatabase" => {
|
"getCSSDatabase" => request.reply_final(&GetCssDatabaseReply {
|
||||||
let _ = stream.write_json_packet(&GetCssDatabaseReply {
|
from: self.name(),
|
||||||
from: self.name(),
|
properties: &self.properties,
|
||||||
properties: &self.properties,
|
})?,
|
||||||
});
|
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||||
|
};
|
||||||
ActorMessageStatus::Processed
|
Ok(())
|
||||||
},
|
|
||||||
_ => ActorMessageStatus::Ignored,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,16 +5,14 @@
|
||||||
//! Handles highlighting selected DOM nodes in the inspector. At the moment it only replies and
|
//! Handles highlighting selected DOM nodes in the inspector. At the moment it only replies and
|
||||||
//! changes nothing on Servo's side.
|
//! changes nothing on Servo's side.
|
||||||
|
|
||||||
use std::net::TcpStream;
|
|
||||||
|
|
||||||
use base::id::PipelineId;
|
use base::id::PipelineId;
|
||||||
use devtools_traits::DevtoolScriptControlMsg;
|
use devtools_traits::DevtoolScriptControlMsg;
|
||||||
use ipc_channel::ipc::IpcSender;
|
use ipc_channel::ipc::IpcSender;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json::{self, Map, Value};
|
use serde_json::{self, Map, Value};
|
||||||
|
|
||||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||||
use crate::protocol::JsonPacketStream;
|
use crate::protocol::ClientRequest;
|
||||||
use crate::{EmptyReplyMsg, StreamId};
|
use crate::{EmptyReplyMsg, StreamId};
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
|
@ -46,22 +44,20 @@ impl Actor for HighlighterActor {
|
||||||
/// - `hide`: Disables highlighting for the selected node
|
/// - `hide`: Disables highlighting for the selected node
|
||||||
fn handle_message(
|
fn handle_message(
|
||||||
&self,
|
&self,
|
||||||
|
request: ClientRequest,
|
||||||
registry: &ActorRegistry,
|
registry: &ActorRegistry,
|
||||||
msg_type: &str,
|
msg_type: &str,
|
||||||
msg: &Map<String, Value>,
|
msg: &Map<String, Value>,
|
||||||
stream: &mut TcpStream,
|
|
||||||
_id: StreamId,
|
_id: StreamId,
|
||||||
) -> Result<ActorMessageStatus, ()> {
|
) -> Result<(), ActorError> {
|
||||||
Ok(match msg_type {
|
match msg_type {
|
||||||
"show" => {
|
"show" => {
|
||||||
let Some(node_actor) = msg.get("node") else {
|
let Some(node_actor) = msg.get("node") else {
|
||||||
// TODO: send missing parameter error
|
return Err(ActorError::MissingParameter);
|
||||||
return Ok(ActorMessageStatus::Ignored);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(node_actor_name) = node_actor.as_str() else {
|
let Some(node_actor_name) = node_actor.as_str() else {
|
||||||
// TODO: send invalid parameter error
|
return Err(ActorError::BadParameterType);
|
||||||
return Ok(ActorMessageStatus::Ignored);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if node_actor_name.starts_with("inspector") {
|
if node_actor_name.starts_with("inspector") {
|
||||||
|
@ -71,8 +67,7 @@ impl Actor for HighlighterActor {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
value: false,
|
value: false,
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
return request.reply_final(&msg);
|
||||||
return Ok(ActorMessageStatus::Processed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.instruct_script_thread_to_highlight_node(
|
self.instruct_script_thread_to_highlight_node(
|
||||||
|
@ -83,20 +78,19 @@ impl Actor for HighlighterActor {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
value: true,
|
value: true,
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"hide" => {
|
"hide" => {
|
||||||
self.instruct_script_thread_to_highlight_node(None, registry);
|
self.instruct_script_thread_to_highlight_node(None, registry);
|
||||||
|
|
||||||
let msg = EmptyReplyMsg { from: self.name() };
|
let msg = EmptyReplyMsg { from: self.name() };
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_ => ActorMessageStatus::Ignored,
|
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||||
})
|
};
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,14 +5,12 @@
|
||||||
//! The layout actor informs the DevTools client of the layout properties of the document, such as
|
//! The layout actor informs the DevTools client of the layout properties of the document, such as
|
||||||
//! grids or flexboxes. It acts as a placeholder for now.
|
//! grids or flexboxes. It acts as a placeholder for now.
|
||||||
|
|
||||||
use std::net::TcpStream;
|
|
||||||
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json::{Map, Value};
|
use serde_json::{Map, Value};
|
||||||
|
|
||||||
use crate::StreamId;
|
use crate::StreamId;
|
||||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||||
use crate::protocol::JsonPacketStream;
|
use crate::protocol::ClientRequest;
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
pub struct LayoutInspectorActorMsg {
|
pub struct LayoutInspectorActorMsg {
|
||||||
|
@ -47,21 +45,20 @@ impl Actor for LayoutInspectorActor {
|
||||||
/// - `getCurrentFlexbox`: Returns the active flexbox, non functional at the moment
|
/// - `getCurrentFlexbox`: Returns the active flexbox, non functional at the moment
|
||||||
fn handle_message(
|
fn handle_message(
|
||||||
&self,
|
&self,
|
||||||
|
request: ClientRequest,
|
||||||
_registry: &ActorRegistry,
|
_registry: &ActorRegistry,
|
||||||
msg_type: &str,
|
msg_type: &str,
|
||||||
_msg: &Map<String, Value>,
|
_msg: &Map<String, Value>,
|
||||||
stream: &mut TcpStream,
|
|
||||||
_id: StreamId,
|
_id: StreamId,
|
||||||
) -> Result<ActorMessageStatus, ()> {
|
) -> Result<(), ActorError> {
|
||||||
Ok(match msg_type {
|
match msg_type {
|
||||||
"getGrids" => {
|
"getGrids" => {
|
||||||
let msg = GetGridsReply {
|
let msg = GetGridsReply {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
// TODO: Actually create a list of grids
|
// TODO: Actually create a list of grids
|
||||||
grids: vec![],
|
grids: vec![],
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
"getCurrentFlexbox" => {
|
"getCurrentFlexbox" => {
|
||||||
let msg = GetCurrentFlexboxReply {
|
let msg = GetCurrentFlexboxReply {
|
||||||
|
@ -69,12 +66,14 @@ impl Actor for LayoutInspectorActor {
|
||||||
// TODO: Create and return the current flexbox object
|
// TODO: Create and return the current flexbox object
|
||||||
flexbox: None,
|
flexbox: None,
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
_ => ActorMessageStatus::Ignored,
|
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||||
})
|
};
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn cleanup(&self, _id: StreamId) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LayoutInspectorActor {
|
impl LayoutInspectorActor {
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::net::TcpStream;
|
|
||||||
|
|
||||||
use base::id::PipelineId;
|
use base::id::PipelineId;
|
||||||
use devtools_traits::DevtoolScriptControlMsg::{GetChildren, GetDocumentElement, ModifyAttribute};
|
use devtools_traits::DevtoolScriptControlMsg::{GetChildren, GetDocumentElement, ModifyAttribute};
|
||||||
|
@ -16,9 +15,9 @@ use ipc_channel::ipc::{self, IpcSender};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json::{self, Map, Value};
|
use serde_json::{self, Map, Value};
|
||||||
|
|
||||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||||
use crate::actors::inspector::walker::WalkerActor;
|
use crate::actors::inspector::walker::WalkerActor;
|
||||||
use crate::protocol::JsonPacketStream;
|
use crate::protocol::ClientRequest;
|
||||||
use crate::{EmptyReplyMsg, StreamId};
|
use crate::{EmptyReplyMsg, StreamId};
|
||||||
|
|
||||||
/// Text node type constant. This is defined again to avoid depending on `script`, where it is defined originally.
|
/// Text node type constant. This is defined again to avoid depending on `script`, where it is defined originally.
|
||||||
|
@ -113,15 +112,19 @@ impl Actor for NodeActor {
|
||||||
/// - `getUniqueSelector`: Returns the display name of this node
|
/// - `getUniqueSelector`: Returns the display name of this node
|
||||||
fn handle_message(
|
fn handle_message(
|
||||||
&self,
|
&self,
|
||||||
|
mut request: ClientRequest,
|
||||||
registry: &ActorRegistry,
|
registry: &ActorRegistry,
|
||||||
msg_type: &str,
|
msg_type: &str,
|
||||||
msg: &Map<String, Value>,
|
msg: &Map<String, Value>,
|
||||||
stream: &mut TcpStream,
|
|
||||||
_id: StreamId,
|
_id: StreamId,
|
||||||
) -> Result<ActorMessageStatus, ()> {
|
) -> Result<(), ActorError> {
|
||||||
Ok(match msg_type {
|
match msg_type {
|
||||||
"modifyAttributes" => {
|
"modifyAttributes" => {
|
||||||
let mods = msg.get("modifications").ok_or(())?.as_array().ok_or(())?;
|
let mods = msg
|
||||||
|
.get("modifications")
|
||||||
|
.ok_or(ActorError::MissingParameter)?
|
||||||
|
.as_array()
|
||||||
|
.ok_or(ActorError::BadParameterType)?;
|
||||||
let modifications: Vec<_> = mods
|
let modifications: Vec<_> = mods
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|json_mod| {
|
.filter_map(|json_mod| {
|
||||||
|
@ -130,7 +133,7 @@ impl Actor for NodeActor {
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let walker = registry.find::<WalkerActor>(&self.walker);
|
let walker = registry.find::<WalkerActor>(&self.walker);
|
||||||
walker.new_mutations(stream, &self.name, &modifications);
|
walker.new_mutations(&mut request, &self.name, &modifications);
|
||||||
|
|
||||||
self.script_chan
|
self.script_chan
|
||||||
.send(ModifyAttribute(
|
.send(ModifyAttribute(
|
||||||
|
@ -138,11 +141,10 @@ impl Actor for NodeActor {
|
||||||
registry.actor_to_script(self.name()),
|
registry.actor_to_script(self.name()),
|
||||||
modifications,
|
modifications,
|
||||||
))
|
))
|
||||||
.map_err(|_| ())?;
|
.map_err(|_| ActorError::Internal)?;
|
||||||
|
|
||||||
let reply = EmptyReplyMsg { from: self.name() };
|
let reply = EmptyReplyMsg { from: self.name() };
|
||||||
let _ = stream.write_json_packet(&reply);
|
request.reply_final(&reply)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"getUniqueSelector" => {
|
"getUniqueSelector" => {
|
||||||
|
@ -150,7 +152,10 @@ impl Actor for NodeActor {
|
||||||
self.script_chan
|
self.script_chan
|
||||||
.send(GetDocumentElement(self.pipeline, tx))
|
.send(GetDocumentElement(self.pipeline, tx))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let doc_elem_info = rx.recv().map_err(|_| ())?.ok_or(())?;
|
let doc_elem_info = rx
|
||||||
|
.recv()
|
||||||
|
.map_err(|_| ActorError::Internal)?
|
||||||
|
.ok_or(ActorError::Internal)?;
|
||||||
let node = doc_elem_info.encode(
|
let node = doc_elem_info.encode(
|
||||||
registry,
|
registry,
|
||||||
true,
|
true,
|
||||||
|
@ -163,12 +168,12 @@ impl Actor for NodeActor {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
value: node.display_name,
|
value: node.display_name,
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_ => ActorMessageStatus::Ignored,
|
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||||
})
|
};
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
use std::iter::once;
|
use std::iter::once;
|
||||||
use std::net::TcpStream;
|
|
||||||
|
|
||||||
use base::id::PipelineId;
|
use base::id::PipelineId;
|
||||||
use devtools_traits::DevtoolScriptControlMsg::{GetLayout, GetSelectors};
|
use devtools_traits::DevtoolScriptControlMsg::{GetLayout, GetSelectors};
|
||||||
|
@ -18,11 +17,11 @@ use serde::Serialize;
|
||||||
use serde_json::{self, Map, Value};
|
use serde_json::{self, Map, Value};
|
||||||
|
|
||||||
use crate::StreamId;
|
use crate::StreamId;
|
||||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||||
use crate::actors::inspector::node::NodeActor;
|
use crate::actors::inspector::node::NodeActor;
|
||||||
use crate::actors::inspector::style_rule::{AppliedRule, ComputedDeclaration, StyleRuleActor};
|
use crate::actors::inspector::style_rule::{AppliedRule, ComputedDeclaration, StyleRuleActor};
|
||||||
use crate::actors::inspector::walker::{WalkerActor, find_child};
|
use crate::actors::inspector::walker::{WalkerActor, find_child};
|
||||||
use crate::protocol::JsonPacketStream;
|
use crate::protocol::ClientRequest;
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct GetAppliedReply {
|
struct GetAppliedReply {
|
||||||
|
@ -114,30 +113,34 @@ impl Actor for PageStyleActor {
|
||||||
/// - `isPositionEditable`: Informs whether you can change a style property in the inspector.
|
/// - `isPositionEditable`: Informs whether you can change a style property in the inspector.
|
||||||
fn handle_message(
|
fn handle_message(
|
||||||
&self,
|
&self,
|
||||||
|
request: ClientRequest,
|
||||||
registry: &ActorRegistry,
|
registry: &ActorRegistry,
|
||||||
msg_type: &str,
|
msg_type: &str,
|
||||||
msg: &Map<String, Value>,
|
msg: &Map<String, Value>,
|
||||||
stream: &mut TcpStream,
|
|
||||||
_id: StreamId,
|
_id: StreamId,
|
||||||
) -> Result<ActorMessageStatus, ()> {
|
) -> Result<(), ActorError> {
|
||||||
Ok(match msg_type {
|
match msg_type {
|
||||||
"getApplied" => self.get_applied(msg, registry, stream)?,
|
"getApplied" => self.get_applied(request, msg, registry),
|
||||||
"getComputed" => self.get_computed(msg, registry, stream)?,
|
"getComputed" => self.get_computed(request, msg, registry),
|
||||||
"getLayout" => self.get_layout(msg, registry, stream)?,
|
"getLayout" => self.get_layout(request, msg, registry),
|
||||||
"isPositionEditable" => self.is_position_editable(stream),
|
"isPositionEditable" => self.is_position_editable(request),
|
||||||
_ => ActorMessageStatus::Ignored,
|
_ => Err(ActorError::UnrecognizedPacketType),
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PageStyleActor {
|
impl PageStyleActor {
|
||||||
fn get_applied(
|
fn get_applied(
|
||||||
&self,
|
&self,
|
||||||
|
request: ClientRequest,
|
||||||
msg: &Map<String, Value>,
|
msg: &Map<String, Value>,
|
||||||
registry: &ActorRegistry,
|
registry: &ActorRegistry,
|
||||||
stream: &mut TcpStream,
|
) -> Result<(), ActorError> {
|
||||||
) -> Result<ActorMessageStatus, ()> {
|
let target = msg
|
||||||
let target = msg.get("node").ok_or(())?.as_str().ok_or(())?;
|
.get("node")
|
||||||
|
.ok_or(ActorError::MissingParameter)?
|
||||||
|
.as_str()
|
||||||
|
.ok_or(ActorError::BadParameterType)?;
|
||||||
let node = registry.find::<NodeActor>(target);
|
let node = registry.find::<NodeActor>(target);
|
||||||
let walker = registry.find::<WalkerActor>(&node.walker);
|
let walker = registry.find::<WalkerActor>(&node.walker);
|
||||||
let entries: Vec<_> = find_child(
|
let entries: Vec<_> = find_child(
|
||||||
|
@ -214,17 +217,20 @@ impl PageStyleActor {
|
||||||
entries,
|
entries,
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)
|
||||||
Ok(ActorMessageStatus::Processed)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_computed(
|
fn get_computed(
|
||||||
&self,
|
&self,
|
||||||
|
request: ClientRequest,
|
||||||
msg: &Map<String, Value>,
|
msg: &Map<String, Value>,
|
||||||
registry: &ActorRegistry,
|
registry: &ActorRegistry,
|
||||||
stream: &mut TcpStream,
|
) -> Result<(), ActorError> {
|
||||||
) -> Result<ActorMessageStatus, ()> {
|
let target = msg
|
||||||
let target = msg.get("node").ok_or(())?.as_str().ok_or(())?;
|
.get("node")
|
||||||
|
.ok_or(ActorError::MissingParameter)?
|
||||||
|
.as_str()
|
||||||
|
.ok_or(ActorError::BadParameterType)?;
|
||||||
let node_actor = registry.find::<NodeActor>(target);
|
let node_actor = registry.find::<NodeActor>(target);
|
||||||
let computed = (|| match node_actor
|
let computed = (|| match node_actor
|
||||||
.style_rules
|
.style_rules
|
||||||
|
@ -249,18 +255,22 @@ impl PageStyleActor {
|
||||||
computed,
|
computed,
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)
|
||||||
Ok(ActorMessageStatus::Processed)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_layout(
|
fn get_layout(
|
||||||
&self,
|
&self,
|
||||||
|
request: ClientRequest,
|
||||||
msg: &Map<String, Value>,
|
msg: &Map<String, Value>,
|
||||||
registry: &ActorRegistry,
|
registry: &ActorRegistry,
|
||||||
stream: &mut TcpStream,
|
) -> Result<(), ActorError> {
|
||||||
) -> Result<ActorMessageStatus, ()> {
|
let target = msg
|
||||||
let target = msg.get("node").ok_or(())?.as_str().ok_or(())?;
|
.get("node")
|
||||||
let (computed_node_sender, computed_node_receiver) = ipc::channel().map_err(|_| ())?;
|
.ok_or(ActorError::MissingParameter)?
|
||||||
|
.as_str()
|
||||||
|
.ok_or(ActorError::BadParameterType)?;
|
||||||
|
let (computed_node_sender, computed_node_receiver) =
|
||||||
|
ipc::channel().map_err(|_| ActorError::Internal)?;
|
||||||
self.script_chan
|
self.script_chan
|
||||||
.send(GetLayout(
|
.send(GetLayout(
|
||||||
self.pipeline,
|
self.pipeline,
|
||||||
|
@ -288,7 +298,10 @@ impl PageStyleActor {
|
||||||
padding_left,
|
padding_left,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
} = computed_node_receiver.recv().map_err(|_| ())?.ok_or(())?;
|
} = computed_node_receiver
|
||||||
|
.recv()
|
||||||
|
.map_err(|_| ActorError::Internal)?
|
||||||
|
.ok_or(ActorError::Internal)?;
|
||||||
let msg_auto_margins = msg
|
let msg_auto_margins = msg
|
||||||
.get("autoMargins")
|
.get("autoMargins")
|
||||||
.and_then(Value::as_bool)
|
.and_then(Value::as_bool)
|
||||||
|
@ -333,18 +346,16 @@ impl PageStyleActor {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
};
|
};
|
||||||
let msg = serde_json::to_string(&msg).map_err(|_| ())?;
|
let msg = serde_json::to_string(&msg).map_err(|_| ActorError::Internal)?;
|
||||||
let msg = serde_json::from_str::<Value>(&msg).map_err(|_| ())?;
|
let msg = serde_json::from_str::<Value>(&msg).map_err(|_| ActorError::Internal)?;
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)
|
||||||
Ok(ActorMessageStatus::Processed)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_position_editable(&self, stream: &mut TcpStream) -> ActorMessageStatus {
|
fn is_position_editable(&self, request: ClientRequest) -> Result<(), ActorError> {
|
||||||
let msg = IsPositionEditableReply {
|
let msg = IsPositionEditableReply {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
value: false,
|
value: false,
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)
|
||||||
ActorMessageStatus::Processed
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
//! A group is either the html style attribute or one selector from one stylesheet.
|
//! A group is either the html style attribute or one selector from one stylesheet.
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::net::TcpStream;
|
|
||||||
|
|
||||||
use devtools_traits::DevtoolScriptControlMsg::{
|
use devtools_traits::DevtoolScriptControlMsg::{
|
||||||
GetAttributeStyle, GetComputedStyle, GetDocumentElement, GetStylesheetStyle, ModifyRule,
|
GetAttributeStyle, GetComputedStyle, GetDocumentElement, GetStylesheetStyle, ModifyRule,
|
||||||
|
@ -17,10 +16,10 @@ use serde::Serialize;
|
||||||
use serde_json::{Map, Value};
|
use serde_json::{Map, Value};
|
||||||
|
|
||||||
use crate::StreamId;
|
use crate::StreamId;
|
||||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||||
use crate::actors::inspector::node::NodeActor;
|
use crate::actors::inspector::node::NodeActor;
|
||||||
use crate::actors::inspector::walker::WalkerActor;
|
use crate::actors::inspector::walker::WalkerActor;
|
||||||
use crate::protocol::JsonPacketStream;
|
use crate::protocol::ClientRequest;
|
||||||
|
|
||||||
const ELEMENT_STYLE_TYPE: u32 = 100;
|
const ELEMENT_STYLE_TYPE: u32 = 100;
|
||||||
|
|
||||||
|
@ -98,16 +97,20 @@ impl Actor for StyleRuleActor {
|
||||||
/// when returning the list of rules.
|
/// when returning the list of rules.
|
||||||
fn handle_message(
|
fn handle_message(
|
||||||
&self,
|
&self,
|
||||||
|
request: ClientRequest,
|
||||||
registry: &ActorRegistry,
|
registry: &ActorRegistry,
|
||||||
msg_type: &str,
|
msg_type: &str,
|
||||||
msg: &Map<String, Value>,
|
msg: &Map<String, Value>,
|
||||||
stream: &mut TcpStream,
|
|
||||||
_id: StreamId,
|
_id: StreamId,
|
||||||
) -> Result<ActorMessageStatus, ()> {
|
) -> Result<(), ActorError> {
|
||||||
Ok(match msg_type {
|
match msg_type {
|
||||||
"setRuleText" => {
|
"setRuleText" => {
|
||||||
// Parse the modifications sent from the client
|
// Parse the modifications sent from the client
|
||||||
let mods = msg.get("modifications").ok_or(())?.as_array().ok_or(())?;
|
let mods = msg
|
||||||
|
.get("modifications")
|
||||||
|
.ok_or(ActorError::MissingParameter)?
|
||||||
|
.as_array()
|
||||||
|
.ok_or(ActorError::BadParameterType)?;
|
||||||
let modifications: Vec<_> = mods
|
let modifications: Vec<_> = mods
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|json_mod| {
|
.filter_map(|json_mod| {
|
||||||
|
@ -125,13 +128,13 @@ impl Actor for StyleRuleActor {
|
||||||
registry.actor_to_script(self.node.clone()),
|
registry.actor_to_script(self.node.clone()),
|
||||||
modifications,
|
modifications,
|
||||||
))
|
))
|
||||||
.map_err(|_| ())?;
|
.map_err(|_| ActorError::Internal)?;
|
||||||
|
|
||||||
let _ = stream.write_json_packet(&self.encodable(registry));
|
request.reply_final(&self.encodable(registry))?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
_ => ActorMessageStatus::Ignored,
|
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||||
})
|
};
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
//! The walker actor is responsible for traversing the DOM tree in various ways to create new nodes
|
//! The walker actor is responsible for traversing the DOM tree in various ways to create new nodes
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::net::TcpStream;
|
|
||||||
|
|
||||||
use base::id::PipelineId;
|
use base::id::PipelineId;
|
||||||
use devtools_traits::DevtoolScriptControlMsg::{GetChildren, GetDocumentElement};
|
use devtools_traits::DevtoolScriptControlMsg::{GetChildren, GetDocumentElement};
|
||||||
|
@ -14,10 +13,10 @@ use ipc_channel::ipc::{self, IpcSender};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json::{self, Map, Value};
|
use serde_json::{self, Map, Value};
|
||||||
|
|
||||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||||
use crate::actors::inspector::layout::{LayoutInspectorActor, LayoutInspectorActorMsg};
|
use crate::actors::inspector::layout::{LayoutInspectorActor, LayoutInspectorActorMsg};
|
||||||
use crate::actors::inspector::node::{NodeActorMsg, NodeInfoToProtocol};
|
use crate::actors::inspector::node::{NodeActorMsg, NodeInfoToProtocol};
|
||||||
use crate::protocol::JsonPacketStream;
|
use crate::protocol::{ClientRequest, JsonPacketStream};
|
||||||
use crate::{EmptyReplyMsg, StreamId};
|
use crate::{EmptyReplyMsg, StreamId};
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
|
@ -64,7 +63,7 @@ struct GetLayoutInspectorReply {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct WatchRootNodeReply {
|
struct WatchRootNodeNotification {
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
type_: String,
|
type_: String,
|
||||||
from: String,
|
from: String,
|
||||||
|
@ -94,7 +93,7 @@ struct GetOffsetParentReply {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct NewMutationsReply {
|
struct NewMutationsNotification {
|
||||||
from: String,
|
from: String,
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
type_: String,
|
type_: String,
|
||||||
|
@ -123,24 +122,31 @@ impl Actor for WalkerActor {
|
||||||
/// node and its ascendents
|
/// node and its ascendents
|
||||||
fn handle_message(
|
fn handle_message(
|
||||||
&self,
|
&self,
|
||||||
|
mut request: ClientRequest,
|
||||||
registry: &ActorRegistry,
|
registry: &ActorRegistry,
|
||||||
msg_type: &str,
|
msg_type: &str,
|
||||||
msg: &Map<String, Value>,
|
msg: &Map<String, Value>,
|
||||||
stream: &mut TcpStream,
|
|
||||||
_id: StreamId,
|
_id: StreamId,
|
||||||
) -> Result<ActorMessageStatus, ()> {
|
) -> Result<(), ActorError> {
|
||||||
Ok(match msg_type {
|
match msg_type {
|
||||||
"children" => {
|
"children" => {
|
||||||
let target = msg.get("node").ok_or(())?.as_str().ok_or(())?;
|
let target = msg
|
||||||
let (tx, rx) = ipc::channel().map_err(|_| ())?;
|
.get("node")
|
||||||
|
.ok_or(ActorError::MissingParameter)?
|
||||||
|
.as_str()
|
||||||
|
.ok_or(ActorError::BadParameterType)?;
|
||||||
|
let (tx, rx) = ipc::channel().map_err(|_| ActorError::Internal)?;
|
||||||
self.script_chan
|
self.script_chan
|
||||||
.send(GetChildren(
|
.send(GetChildren(
|
||||||
self.pipeline,
|
self.pipeline,
|
||||||
registry.actor_to_script(target.into()),
|
registry.actor_to_script(target.into()),
|
||||||
tx,
|
tx,
|
||||||
))
|
))
|
||||||
.map_err(|_| ())?;
|
.map_err(|_| ActorError::Internal)?;
|
||||||
let children = rx.recv().map_err(|_| ())?.ok_or(())?;
|
let children = rx
|
||||||
|
.recv()
|
||||||
|
.map_err(|_| ActorError::Internal)?
|
||||||
|
.ok_or(ActorError::Internal)?;
|
||||||
|
|
||||||
let msg = ChildrenReply {
|
let msg = ChildrenReply {
|
||||||
has_first: true,
|
has_first: true,
|
||||||
|
@ -159,20 +165,21 @@ impl Actor for WalkerActor {
|
||||||
.collect(),
|
.collect(),
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
"clearPseudoClassLocks" => {
|
"clearPseudoClassLocks" => {
|
||||||
let msg = EmptyReplyMsg { from: self.name() };
|
let msg = EmptyReplyMsg { from: self.name() };
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
"documentElement" => {
|
"documentElement" => {
|
||||||
let (tx, rx) = ipc::channel().map_err(|_| ())?;
|
let (tx, rx) = ipc::channel().map_err(|_| ActorError::Internal)?;
|
||||||
self.script_chan
|
self.script_chan
|
||||||
.send(GetDocumentElement(self.pipeline, tx))
|
.send(GetDocumentElement(self.pipeline, tx))
|
||||||
.map_err(|_| ())?;
|
.map_err(|_| ActorError::Internal)?;
|
||||||
let doc_elem_info = rx.recv().map_err(|_| ())?.ok_or(())?;
|
let doc_elem_info = rx
|
||||||
|
.recv()
|
||||||
|
.map_err(|_| ActorError::Internal)?
|
||||||
|
.ok_or(ActorError::Internal)?;
|
||||||
let node = doc_elem_info.encode(
|
let node = doc_elem_info.encode(
|
||||||
registry,
|
registry,
|
||||||
true,
|
true,
|
||||||
|
@ -185,8 +192,7 @@ impl Actor for WalkerActor {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
node,
|
node,
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
"getLayoutInspector" => {
|
"getLayoutInspector" => {
|
||||||
// TODO: Create actual layout inspector actor
|
// TODO: Create actual layout inspector actor
|
||||||
|
@ -198,8 +204,7 @@ impl Actor for WalkerActor {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
actor,
|
actor,
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
"getMutations" => {
|
"getMutations" => {
|
||||||
let msg = GetMutationsReply {
|
let msg = GetMutationsReply {
|
||||||
|
@ -216,20 +221,26 @@ impl Actor for WalkerActor {
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
"getOffsetParent" => {
|
"getOffsetParent" => {
|
||||||
let msg = GetOffsetParentReply {
|
let msg = GetOffsetParentReply {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
node: None,
|
node: None,
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
"querySelector" => {
|
"querySelector" => {
|
||||||
let selector = msg.get("selector").ok_or(())?.as_str().ok_or(())?;
|
let selector = msg
|
||||||
let node = msg.get("node").ok_or(())?.as_str().ok_or(())?;
|
.get("selector")
|
||||||
|
.ok_or(ActorError::MissingParameter)?
|
||||||
|
.as_str()
|
||||||
|
.ok_or(ActorError::BadParameterType)?;
|
||||||
|
let node = msg
|
||||||
|
.get("node")
|
||||||
|
.ok_or(ActorError::MissingParameter)?
|
||||||
|
.as_str()
|
||||||
|
.ok_or(ActorError::BadParameterType)?;
|
||||||
let mut hierarchy = find_child(
|
let mut hierarchy = find_child(
|
||||||
&self.script_chan,
|
&self.script_chan,
|
||||||
self.pipeline,
|
self.pipeline,
|
||||||
|
@ -239,39 +250,38 @@ impl Actor for WalkerActor {
|
||||||
vec![],
|
vec![],
|
||||||
|msg| msg.display_name == selector,
|
|msg| msg.display_name == selector,
|
||||||
)
|
)
|
||||||
.map_err(|_| ())?;
|
.map_err(|_| ActorError::Internal)?;
|
||||||
hierarchy.reverse();
|
hierarchy.reverse();
|
||||||
let node = hierarchy.pop().ok_or(())?;
|
let node = hierarchy.pop().ok_or(ActorError::Internal)?;
|
||||||
|
|
||||||
let msg = QuerySelectorReply {
|
let msg = QuerySelectorReply {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
node,
|
node,
|
||||||
new_parents: hierarchy,
|
new_parents: hierarchy,
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
"watchRootNode" => {
|
"watchRootNode" => {
|
||||||
let msg = WatchRootNodeReply {
|
let msg = WatchRootNodeNotification {
|
||||||
type_: "root-available".into(),
|
type_: "root-available".into(),
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
node: self.root_node.clone(),
|
node: self.root_node.clone(),
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
let _ = request.write_json_packet(&msg);
|
||||||
|
|
||||||
let msg = EmptyReplyMsg { from: self.name() };
|
let msg = EmptyReplyMsg { from: self.name() };
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
_ => ActorMessageStatus::Ignored,
|
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||||
})
|
};
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WalkerActor {
|
impl WalkerActor {
|
||||||
pub(crate) fn new_mutations(
|
pub(crate) fn new_mutations(
|
||||||
&self,
|
&self,
|
||||||
stream: &mut TcpStream,
|
request: &mut ClientRequest,
|
||||||
target: &str,
|
target: &str,
|
||||||
modifications: &[AttrModification],
|
modifications: &[AttrModification],
|
||||||
) {
|
) {
|
||||||
|
@ -279,7 +289,7 @@ impl WalkerActor {
|
||||||
let mut mutations = self.mutations.borrow_mut();
|
let mut mutations = self.mutations.borrow_mut();
|
||||||
mutations.extend(modifications.iter().cloned().map(|m| (m, target.into())));
|
mutations.extend(modifications.iter().cloned().map(|m| (m, target.into())));
|
||||||
}
|
}
|
||||||
let _ = stream.write_json_packet(&NewMutationsReply {
|
let _ = request.write_json_packet(&NewMutationsNotification {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
type_: "newMutations".into(),
|
type_: "newMutations".into(),
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,13 +2,12 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use std::net::TcpStream;
|
|
||||||
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json::{Map, Value};
|
use serde_json::{Map, Value};
|
||||||
|
|
||||||
use crate::StreamId;
|
use crate::StreamId;
|
||||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||||
|
use crate::protocol::ClientRequest;
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
|
@ -36,13 +35,13 @@ impl Actor for MemoryActor {
|
||||||
|
|
||||||
fn handle_message(
|
fn handle_message(
|
||||||
&self,
|
&self,
|
||||||
|
_request: ClientRequest,
|
||||||
_registry: &ActorRegistry,
|
_registry: &ActorRegistry,
|
||||||
_msg_type: &str,
|
_msg_type: &str,
|
||||||
_msg: &Map<String, Value>,
|
_msg: &Map<String, Value>,
|
||||||
_stream: &mut TcpStream,
|
|
||||||
_id: StreamId,
|
_id: StreamId,
|
||||||
) -> Result<ActorMessageStatus, ()> {
|
) -> Result<(), ActorError> {
|
||||||
Ok(ActorMessageStatus::Ignored)
|
Err(ActorError::UnrecognizedPacketType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
//! Liberally derived from the [Firefox JS implementation](http://mxr.mozilla.org/mozilla-central/source/toolkit/devtools/server/actors/webconsole.js).
|
//! Liberally derived from the [Firefox JS implementation](http://mxr.mozilla.org/mozilla-central/source/toolkit/devtools/server/actors/webconsole.js).
|
||||||
//! Handles interaction with the remote web console on network events (HTTP requests, responses) in Servo.
|
//! Handles interaction with the remote web console on network events (HTTP requests, responses) in Servo.
|
||||||
|
|
||||||
use std::net::TcpStream;
|
|
||||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
use chrono::{Local, LocalResult, TimeZone};
|
use chrono::{Local, LocalResult, TimeZone};
|
||||||
|
@ -16,9 +15,9 @@ use serde::Serialize;
|
||||||
use serde_json::{Map, Value};
|
use serde_json::{Map, Value};
|
||||||
|
|
||||||
use crate::StreamId;
|
use crate::StreamId;
|
||||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||||
use crate::network_handler::Cause;
|
use crate::network_handler::Cause;
|
||||||
use crate::protocol::JsonPacketStream;
|
use crate::protocol::ClientRequest;
|
||||||
|
|
||||||
pub struct NetworkEventActor {
|
pub struct NetworkEventActor {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
@ -202,13 +201,13 @@ impl Actor for NetworkEventActor {
|
||||||
|
|
||||||
fn handle_message(
|
fn handle_message(
|
||||||
&self,
|
&self,
|
||||||
|
request: ClientRequest,
|
||||||
_registry: &ActorRegistry,
|
_registry: &ActorRegistry,
|
||||||
msg_type: &str,
|
msg_type: &str,
|
||||||
_msg: &Map<String, Value>,
|
_msg: &Map<String, Value>,
|
||||||
stream: &mut TcpStream,
|
|
||||||
_id: StreamId,
|
_id: StreamId,
|
||||||
) -> Result<ActorMessageStatus, ()> {
|
) -> Result<(), ActorError> {
|
||||||
Ok(match msg_type {
|
match msg_type {
|
||||||
"getRequestHeaders" => {
|
"getRequestHeaders" => {
|
||||||
let mut headers = Vec::new();
|
let mut headers = Vec::new();
|
||||||
let mut raw_headers_string = "".to_owned();
|
let mut raw_headers_string = "".to_owned();
|
||||||
|
@ -232,8 +231,7 @@ impl Actor for NetworkEventActor {
|
||||||
header_size: headers_size,
|
header_size: headers_size,
|
||||||
raw_headers: raw_headers_string,
|
raw_headers: raw_headers_string,
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
"getRequestCookies" => {
|
"getRequestCookies" => {
|
||||||
let mut cookies = Vec::new();
|
let mut cookies = Vec::new();
|
||||||
|
@ -248,8 +246,7 @@ impl Actor for NetworkEventActor {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
cookies,
|
cookies,
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
"getRequestPostData" => {
|
"getRequestPostData" => {
|
||||||
let msg = GetRequestPostDataReply {
|
let msg = GetRequestPostDataReply {
|
||||||
|
@ -257,8 +254,7 @@ impl Actor for NetworkEventActor {
|
||||||
post_data: self.request_body.clone(),
|
post_data: self.request_body.clone(),
|
||||||
post_data_discarded: self.request_body.is_none(),
|
post_data_discarded: self.request_body.is_none(),
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
"getResponseHeaders" => {
|
"getResponseHeaders" => {
|
||||||
if let Some(ref response_headers) = self.response_headers_raw {
|
if let Some(ref response_headers) = self.response_headers_raw {
|
||||||
|
@ -282,9 +278,11 @@ impl Actor for NetworkEventActor {
|
||||||
header_size: headers_size,
|
header_size: headers_size,
|
||||||
raw_headers: raw_headers_string,
|
raw_headers: raw_headers_string,
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?;
|
||||||
|
} else {
|
||||||
|
// FIXME: what happens when there are no response headers?
|
||||||
|
return Err(ActorError::Internal);
|
||||||
}
|
}
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
"getResponseCookies" => {
|
"getResponseCookies" => {
|
||||||
let mut cookies = Vec::new();
|
let mut cookies = Vec::new();
|
||||||
|
@ -300,8 +298,7 @@ impl Actor for NetworkEventActor {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
cookies,
|
cookies,
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
"getResponseContent" => {
|
"getResponseContent" => {
|
||||||
let msg = GetResponseContentReply {
|
let msg = GetResponseContentReply {
|
||||||
|
@ -309,8 +306,7 @@ impl Actor for NetworkEventActor {
|
||||||
content: self.response_body.clone(),
|
content: self.response_body.clone(),
|
||||||
content_discarded: self.response_body.is_none(),
|
content_discarded: self.response_body.is_none(),
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
"getEventTimings" => {
|
"getEventTimings" => {
|
||||||
// TODO: This is a fake timings msg
|
// TODO: This is a fake timings msg
|
||||||
|
@ -323,8 +319,7 @@ impl Actor for NetworkEventActor {
|
||||||
timings: timings_obj,
|
timings: timings_obj,
|
||||||
total_time: total,
|
total_time: total,
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
"getSecurityInfo" => {
|
"getSecurityInfo" => {
|
||||||
// TODO: Send the correct values for securityInfo.
|
// TODO: Send the correct values for securityInfo.
|
||||||
|
@ -334,11 +329,11 @@ impl Actor for NetworkEventActor {
|
||||||
state: "insecure".to_owned(),
|
state: "insecure".to_owned(),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
_ => ActorMessageStatus::Ignored,
|
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||||
})
|
};
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,11 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use std::net::TcpStream;
|
|
||||||
|
|
||||||
use serde_json::{Map, Value};
|
use serde_json::{Map, Value};
|
||||||
|
|
||||||
use crate::StreamId;
|
use crate::StreamId;
|
||||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||||
|
use crate::protocol::ClientRequest;
|
||||||
|
|
||||||
pub struct ObjectActor {
|
pub struct ObjectActor {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
@ -20,14 +19,14 @@ impl Actor for ObjectActor {
|
||||||
}
|
}
|
||||||
fn handle_message(
|
fn handle_message(
|
||||||
&self,
|
&self,
|
||||||
|
_request: ClientRequest,
|
||||||
_: &ActorRegistry,
|
_: &ActorRegistry,
|
||||||
_: &str,
|
_: &str,
|
||||||
_: &Map<String, Value>,
|
_: &Map<String, Value>,
|
||||||
_: &mut TcpStream,
|
|
||||||
_: StreamId,
|
_: StreamId,
|
||||||
) -> Result<ActorMessageStatus, ()> {
|
) -> Result<(), ActorError> {
|
||||||
// TODO: Handle enumSymbols for console object inspection
|
// TODO: Handle enumSymbols for console object inspection
|
||||||
Ok(ActorMessageStatus::Ignored)
|
Err(ActorError::UnrecognizedPacketType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,14 +5,12 @@
|
||||||
// TODO: Is this actor still relevant?
|
// TODO: Is this actor still relevant?
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use std::net::TcpStream;
|
|
||||||
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json::{Map, Value};
|
use serde_json::{Map, Value};
|
||||||
|
|
||||||
use crate::StreamId;
|
use crate::StreamId;
|
||||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||||
use crate::protocol::{ActorDescription, JsonPacketStream, Method};
|
use crate::protocol::{ActorDescription, ClientRequest, Method};
|
||||||
|
|
||||||
pub struct PerformanceActor {
|
pub struct PerformanceActor {
|
||||||
name: String,
|
name: String,
|
||||||
|
@ -62,13 +60,13 @@ impl Actor for PerformanceActor {
|
||||||
|
|
||||||
fn handle_message(
|
fn handle_message(
|
||||||
&self,
|
&self,
|
||||||
|
request: ClientRequest,
|
||||||
_registry: &ActorRegistry,
|
_registry: &ActorRegistry,
|
||||||
msg_type: &str,
|
msg_type: &str,
|
||||||
_msg: &Map<String, Value>,
|
_msg: &Map<String, Value>,
|
||||||
stream: &mut TcpStream,
|
|
||||||
_id: StreamId,
|
_id: StreamId,
|
||||||
) -> Result<ActorMessageStatus, ()> {
|
) -> Result<(), ActorError> {
|
||||||
Ok(match msg_type {
|
match msg_type {
|
||||||
"connect" => {
|
"connect" => {
|
||||||
let msg = ConnectReply {
|
let msg = ConnectReply {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
|
@ -82,8 +80,7 @@ impl Actor for PerformanceActor {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
"canCurrentlyRecord" => {
|
"canCurrentlyRecord" => {
|
||||||
let msg = CanCurrentlyRecordReply {
|
let msg = CanCurrentlyRecordReply {
|
||||||
|
@ -93,11 +90,11 @@ impl Actor for PerformanceActor {
|
||||||
errors: vec![],
|
errors: vec![],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
_ => ActorMessageStatus::Ignored,
|
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||||
})
|
};
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,16 +2,13 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use std::net::TcpStream;
|
|
||||||
|
|
||||||
use log::warn;
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json::{Map, Value};
|
use serde_json::{Map, Value};
|
||||||
use servo_config::pref;
|
use servo_config::pref;
|
||||||
|
|
||||||
use crate::StreamId;
|
use crate::StreamId;
|
||||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||||
use crate::protocol::JsonPacketStream;
|
use crate::protocol::ClientRequest;
|
||||||
|
|
||||||
pub struct PreferenceActor {
|
pub struct PreferenceActor {
|
||||||
name: String,
|
name: String,
|
||||||
|
@ -30,43 +27,44 @@ impl Actor for PreferenceActor {
|
||||||
|
|
||||||
fn handle_message(
|
fn handle_message(
|
||||||
&self,
|
&self,
|
||||||
|
request: ClientRequest,
|
||||||
_registry: &ActorRegistry,
|
_registry: &ActorRegistry,
|
||||||
msg_type: &str,
|
msg_type: &str,
|
||||||
msg: &Map<String, Value>,
|
msg: &Map<String, Value>,
|
||||||
stream: &mut TcpStream,
|
|
||||||
_id: StreamId,
|
_id: StreamId,
|
||||||
) -> Result<ActorMessageStatus, ()> {
|
) -> Result<(), ActorError> {
|
||||||
let Some(key) = msg.get("value").and_then(|v| v.as_str()) else {
|
let key = msg
|
||||||
warn!("PreferenceActor: handle_message: value is not a string");
|
.get("value")
|
||||||
return Ok(ActorMessageStatus::Ignored);
|
.ok_or(ActorError::MissingParameter)?
|
||||||
};
|
.as_str()
|
||||||
|
.ok_or(ActorError::BadParameterType)?;
|
||||||
|
|
||||||
// TODO: Map more preferences onto their Servo values.
|
// TODO: Map more preferences onto their Servo values.
|
||||||
Ok(match key {
|
match key {
|
||||||
"dom.serviceWorkers.enabled" => {
|
"dom.serviceWorkers.enabled" => {
|
||||||
self.write_bool(pref!(dom_serviceworker_enabled), stream)
|
self.write_bool(request, pref!(dom_serviceworker_enabled))
|
||||||
},
|
},
|
||||||
_ => self.handle_missing_preference(msg_type, stream),
|
_ => self.handle_missing_preference(request, msg_type),
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PreferenceActor {
|
impl PreferenceActor {
|
||||||
fn handle_missing_preference(
|
fn handle_missing_preference(
|
||||||
&self,
|
&self,
|
||||||
|
request: ClientRequest,
|
||||||
msg_type: &str,
|
msg_type: &str,
|
||||||
stream: &mut TcpStream,
|
) -> Result<(), ActorError> {
|
||||||
) -> ActorMessageStatus {
|
|
||||||
match msg_type {
|
match msg_type {
|
||||||
"getBoolPref" => self.write_bool(false, stream),
|
"getBoolPref" => self.write_bool(request, false),
|
||||||
"getCharPref" => self.write_char("".into(), stream),
|
"getCharPref" => self.write_char(request, "".into()),
|
||||||
"getIntPref" => self.write_int(0, stream),
|
"getIntPref" => self.write_int(request, 0),
|
||||||
"getFloatPref" => self.write_float(0., stream),
|
"getFloatPref" => self.write_float(request, 0.),
|
||||||
_ => ActorMessageStatus::Ignored,
|
_ => Err(ActorError::UnrecognizedPacketType),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_bool(&self, pref_value: bool, stream: &mut TcpStream) -> ActorMessageStatus {
|
fn write_bool(&self, request: ClientRequest, pref_value: bool) -> Result<(), ActorError> {
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct BoolReply {
|
struct BoolReply {
|
||||||
from: String,
|
from: String,
|
||||||
|
@ -77,11 +75,10 @@ impl PreferenceActor {
|
||||||
from: self.name.clone(),
|
from: self.name.clone(),
|
||||||
value: pref_value,
|
value: pref_value,
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&reply);
|
request.reply_final(&reply)
|
||||||
ActorMessageStatus::Processed
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_char(&self, pref_value: String, stream: &mut TcpStream) -> ActorMessageStatus {
|
fn write_char(&self, request: ClientRequest, pref_value: String) -> Result<(), ActorError> {
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct CharReply {
|
struct CharReply {
|
||||||
from: String,
|
from: String,
|
||||||
|
@ -92,11 +89,10 @@ impl PreferenceActor {
|
||||||
from: self.name.clone(),
|
from: self.name.clone(),
|
||||||
value: pref_value,
|
value: pref_value,
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&reply);
|
request.reply_final(&reply)
|
||||||
ActorMessageStatus::Processed
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_int(&self, pref_value: i64, stream: &mut TcpStream) -> ActorMessageStatus {
|
fn write_int(&self, request: ClientRequest, pref_value: i64) -> Result<(), ActorError> {
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct IntReply {
|
struct IntReply {
|
||||||
from: String,
|
from: String,
|
||||||
|
@ -107,11 +103,10 @@ impl PreferenceActor {
|
||||||
from: self.name.clone(),
|
from: self.name.clone(),
|
||||||
value: pref_value,
|
value: pref_value,
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&reply);
|
request.reply_final(&reply)
|
||||||
ActorMessageStatus::Processed
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_float(&self, pref_value: f64, stream: &mut TcpStream) -> ActorMessageStatus {
|
fn write_float(&self, request: ClientRequest, pref_value: f64) -> Result<(), ActorError> {
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct FloatReply {
|
struct FloatReply {
|
||||||
from: String,
|
from: String,
|
||||||
|
@ -122,7 +117,6 @@ impl PreferenceActor {
|
||||||
from: self.name.clone(),
|
from: self.name.clone(),
|
||||||
value: pref_value,
|
value: pref_value,
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&reply);
|
request.reply_final(&reply)
|
||||||
ActorMessageStatus::Processed
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,15 +6,13 @@
|
||||||
//!
|
//!
|
||||||
//! [Firefox JS implementation]: https://searchfox.org/mozilla-central/source/devtools/server/actors/descriptors/process.js
|
//! [Firefox JS implementation]: https://searchfox.org/mozilla-central/source/devtools/server/actors/descriptors/process.js
|
||||||
|
|
||||||
use std::net::TcpStream;
|
|
||||||
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json::{Map, Value};
|
use serde_json::{Map, Value};
|
||||||
|
|
||||||
use crate::StreamId;
|
use crate::StreamId;
|
||||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||||
use crate::actors::root::DescriptorTraits;
|
use crate::actors::root::DescriptorTraits;
|
||||||
use crate::protocol::JsonPacketStream;
|
use crate::protocol::ClientRequest;
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct ListWorkersReply {
|
struct ListWorkersReply {
|
||||||
|
@ -46,24 +44,24 @@ impl Actor for ProcessActor {
|
||||||
/// - `listWorkers`: Returns a list of web workers, not supported yet.
|
/// - `listWorkers`: Returns a list of web workers, not supported yet.
|
||||||
fn handle_message(
|
fn handle_message(
|
||||||
&self,
|
&self,
|
||||||
|
request: ClientRequest,
|
||||||
_registry: &ActorRegistry,
|
_registry: &ActorRegistry,
|
||||||
msg_type: &str,
|
msg_type: &str,
|
||||||
_msg: &Map<String, Value>,
|
_msg: &Map<String, Value>,
|
||||||
stream: &mut TcpStream,
|
|
||||||
_id: StreamId,
|
_id: StreamId,
|
||||||
) -> Result<ActorMessageStatus, ()> {
|
) -> Result<(), ActorError> {
|
||||||
Ok(match msg_type {
|
match msg_type {
|
||||||
"listWorkers" => {
|
"listWorkers" => {
|
||||||
let reply = ListWorkersReply {
|
let reply = ListWorkersReply {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
workers: vec![],
|
workers: vec![],
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&reply);
|
request.reply_final(&reply)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_ => ActorMessageStatus::Ignored,
|
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||||
})
|
};
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,12 +4,11 @@
|
||||||
|
|
||||||
//! This actor is used for protocol purposes, it forwards the reflow events to clients.
|
//! This actor is used for protocol purposes, it forwards the reflow events to clients.
|
||||||
|
|
||||||
use std::net::TcpStream;
|
|
||||||
|
|
||||||
use serde_json::{Map, Value};
|
use serde_json::{Map, Value};
|
||||||
|
|
||||||
use crate::StreamId;
|
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
use crate::protocol::ClientRequest;
|
||||||
|
use crate::{EmptyReplyMsg, StreamId};
|
||||||
|
|
||||||
pub struct ReflowActor {
|
pub struct ReflowActor {
|
||||||
name: String,
|
name: String,
|
||||||
|
@ -25,20 +24,24 @@ impl Actor for ReflowActor {
|
||||||
/// - `start`: Does nothing yet. This doesn't need a reply like other messages.
|
/// - `start`: Does nothing yet. This doesn't need a reply like other messages.
|
||||||
fn handle_message(
|
fn handle_message(
|
||||||
&self,
|
&self,
|
||||||
|
request: ClientRequest,
|
||||||
_registry: &ActorRegistry,
|
_registry: &ActorRegistry,
|
||||||
msg_type: &str,
|
msg_type: &str,
|
||||||
_msg: &Map<String, Value>,
|
_msg: &Map<String, Value>,
|
||||||
_stream: &mut TcpStream,
|
|
||||||
_id: StreamId,
|
_id: StreamId,
|
||||||
) -> Result<ActorMessageStatus, ()> {
|
) -> Result<(), ActorError> {
|
||||||
Ok(match msg_type {
|
match msg_type {
|
||||||
"start" => {
|
"start" => {
|
||||||
// TODO: Create an observer on "reflows" events
|
// TODO: Create an observer on "reflows" events
|
||||||
ActorMessageStatus::Processed
|
let msg = EmptyReplyMsg { from: self.name() };
|
||||||
|
request.reply_final(&msg)?
|
||||||
},
|
},
|
||||||
_ => ActorMessageStatus::Ignored,
|
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||||
})
|
};
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn cleanup(&self, _id: StreamId) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReflowActor {
|
impl ReflowActor {
|
||||||
|
|
|
@ -10,19 +10,18 @@
|
||||||
//! [Firefox JS implementation]: https://searchfox.org/mozilla-central/source/devtools/server/actors/root.js
|
//! [Firefox JS implementation]: https://searchfox.org/mozilla-central/source/devtools/server/actors/root.js
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::net::TcpStream;
|
|
||||||
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json::{Map, Value, json};
|
use serde_json::{Map, Value, json};
|
||||||
|
|
||||||
use crate::StreamId;
|
use crate::StreamId;
|
||||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||||
use crate::actors::device::DeviceActor;
|
use crate::actors::device::DeviceActor;
|
||||||
use crate::actors::performance::PerformanceActor;
|
use crate::actors::performance::PerformanceActor;
|
||||||
use crate::actors::process::{ProcessActor, ProcessActorMsg};
|
use crate::actors::process::{ProcessActor, ProcessActorMsg};
|
||||||
use crate::actors::tab::{TabDescriptorActor, TabDescriptorActorMsg};
|
use crate::actors::tab::{TabDescriptorActor, TabDescriptorActorMsg};
|
||||||
use crate::actors::worker::{WorkerActor, WorkerMsg};
|
use crate::actors::worker::{WorkerActor, WorkerMsg};
|
||||||
use crate::protocol::{ActorDescription, JsonPacketStream};
|
use crate::protocol::{ActorDescription, ClientRequest};
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
|
@ -116,13 +115,6 @@ struct GetProcessResponse {
|
||||||
process_descriptor: ProcessActorMsg,
|
process_descriptor: ProcessActorMsg,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
|
||||||
struct ErrorResponse {
|
|
||||||
from: String,
|
|
||||||
error: String,
|
|
||||||
message: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct RootActor {
|
pub struct RootActor {
|
||||||
pub tabs: Vec<String>,
|
pub tabs: Vec<String>,
|
||||||
pub workers: Vec<String>,
|
pub workers: Vec<String>,
|
||||||
|
@ -140,27 +132,25 @@ impl Actor for RootActor {
|
||||||
|
|
||||||
fn handle_message(
|
fn handle_message(
|
||||||
&self,
|
&self,
|
||||||
|
request: ClientRequest,
|
||||||
registry: &ActorRegistry,
|
registry: &ActorRegistry,
|
||||||
msg_type: &str,
|
msg_type: &str,
|
||||||
msg: &Map<String, Value>,
|
msg: &Map<String, Value>,
|
||||||
stream: &mut TcpStream,
|
|
||||||
_id: StreamId,
|
_id: StreamId,
|
||||||
) -> Result<ActorMessageStatus, ()> {
|
) -> Result<(), ActorError> {
|
||||||
Ok(match msg_type {
|
match msg_type {
|
||||||
"connect" => {
|
"connect" => {
|
||||||
let message = json!({
|
let message = json!({
|
||||||
"from": "root",
|
"from": "root",
|
||||||
});
|
});
|
||||||
let _ = stream.write_json_packet(&message);
|
request.reply_final(&message)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
"listAddons" => {
|
"listAddons" => {
|
||||||
let actor = ListAddonsReply {
|
let actor = ListAddonsReply {
|
||||||
from: "root".to_owned(),
|
from: "root".to_owned(),
|
||||||
addons: vec![],
|
addons: vec![],
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&actor);
|
request.reply_final(&actor)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"listProcesses" => {
|
"listProcesses" => {
|
||||||
|
@ -169,8 +159,7 @@ impl Actor for RootActor {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
processes: vec![process],
|
processes: vec![process],
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&reply);
|
request.reply_final(&reply)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// TODO: Unexpected message getTarget for process (when inspecting)
|
// TODO: Unexpected message getTarget for process (when inspecting)
|
||||||
|
@ -180,8 +169,7 @@ impl Actor for RootActor {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
process_descriptor: process,
|
process_descriptor: process,
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&reply);
|
request.reply_final(&reply)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"getRoot" => {
|
"getRoot" => {
|
||||||
|
@ -192,8 +180,7 @@ impl Actor for RootActor {
|
||||||
device_actor: self.device.clone(),
|
device_actor: self.device.clone(),
|
||||||
preference_actor: self.preference.clone(),
|
preference_actor: self.preference.clone(),
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&actor);
|
request.reply_final(&actor)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"listTabs" => {
|
"listTabs" => {
|
||||||
|
@ -213,8 +200,7 @@ impl Actor for RootActor {
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&actor);
|
request.reply_final(&actor)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"listServiceWorkerRegistrations" => {
|
"listServiceWorkerRegistrations" => {
|
||||||
|
@ -222,8 +208,7 @@ impl Actor for RootActor {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
registrations: vec![],
|
registrations: vec![],
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&reply);
|
request.reply_final(&reply)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"listWorkers" => {
|
"listWorkers" => {
|
||||||
|
@ -235,26 +220,24 @@ impl Actor for RootActor {
|
||||||
.map(|name| registry.find::<WorkerActor>(name).encodable())
|
.map(|name| registry.find::<WorkerActor>(name).encodable())
|
||||||
.collect(),
|
.collect(),
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&reply);
|
request.reply_final(&reply)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"getTab" => {
|
"getTab" => {
|
||||||
let Some(serde_json::Value::Number(browser_id)) = msg.get("browserId") else {
|
let browser_id = msg
|
||||||
return Ok(ActorMessageStatus::Ignored);
|
.get("browserId")
|
||||||
};
|
.ok_or(ActorError::MissingParameter)?
|
||||||
|
.as_u64()
|
||||||
let browser_id = browser_id.as_u64().unwrap();
|
.ok_or(ActorError::BadParameterType)?;
|
||||||
let Some(tab) = self.get_tab_msg_by_browser_id(registry, browser_id as u32) else {
|
let Some(tab) = self.get_tab_msg_by_browser_id(registry, browser_id as u32) else {
|
||||||
return Ok(ActorMessageStatus::Ignored);
|
return Err(ActorError::Internal);
|
||||||
};
|
};
|
||||||
|
|
||||||
let reply = GetTabReply {
|
let reply = GetTabReply {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
tab,
|
tab,
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&reply);
|
request.reply_final(&reply)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"protocolDescription" => {
|
"protocolDescription" => {
|
||||||
|
@ -265,24 +248,12 @@ impl Actor for RootActor {
|
||||||
device: DeviceActor::description(),
|
device: DeviceActor::description(),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_ => {
|
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||||
let reply = ErrorResponse {
|
};
|
||||||
from: self.name(),
|
Ok(())
|
||||||
error: "unrecognizedPacketType".to_owned(),
|
|
||||||
message: format!(
|
|
||||||
"Actor {} does not recognize the packet type '{}'",
|
|
||||||
self.name(),
|
|
||||||
msg_type,
|
|
||||||
),
|
|
||||||
};
|
|
||||||
let _ = stream.write_json_packet(&reply);
|
|
||||||
ActorMessageStatus::Ignored
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use std::net::TcpStream;
|
|
||||||
|
|
||||||
use base::id::PipelineId;
|
use base::id::PipelineId;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
@ -12,8 +11,8 @@ use serde_json::{Map, Value};
|
||||||
use servo_url::ServoUrl;
|
use servo_url::ServoUrl;
|
||||||
|
|
||||||
use crate::StreamId;
|
use crate::StreamId;
|
||||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||||
use crate::protocol::JsonPacketStream;
|
use crate::protocol::ClientRequest;
|
||||||
|
|
||||||
/// A `sourceForm` as used in responses to thread `sources` requests.
|
/// A `sourceForm` as used in responses to thread `sources` requests.
|
||||||
///
|
///
|
||||||
|
@ -134,13 +133,13 @@ impl Actor for SourceActor {
|
||||||
|
|
||||||
fn handle_message(
|
fn handle_message(
|
||||||
&self,
|
&self,
|
||||||
|
request: ClientRequest,
|
||||||
_registry: &ActorRegistry,
|
_registry: &ActorRegistry,
|
||||||
msg_type: &str,
|
msg_type: &str,
|
||||||
_msg: &Map<String, Value>,
|
_msg: &Map<String, Value>,
|
||||||
stream: &mut TcpStream,
|
|
||||||
_id: StreamId,
|
_id: StreamId,
|
||||||
) -> Result<ActorMessageStatus, ()> {
|
) -> Result<(), ActorError> {
|
||||||
Ok(match msg_type {
|
match msg_type {
|
||||||
// Client has requested contents of the source.
|
// Client has requested contents of the source.
|
||||||
"source" => {
|
"source" => {
|
||||||
let reply = SourceContentReply {
|
let reply = SourceContentReply {
|
||||||
|
@ -154,10 +153,10 @@ impl Actor for SourceActor {
|
||||||
.unwrap_or("<!-- not available; please reload! -->")
|
.unwrap_or("<!-- not available; please reload! -->")
|
||||||
.to_owned(),
|
.to_owned(),
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&reply);
|
request.reply_final(&reply)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
_ => ActorMessageStatus::Ignored,
|
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||||
})
|
};
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,14 +2,12 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use std::net::TcpStream;
|
|
||||||
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json::{Map, Value};
|
use serde_json::{Map, Value};
|
||||||
|
|
||||||
use crate::StreamId;
|
use crate::StreamId;
|
||||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||||
use crate::protocol::JsonPacketStream;
|
use crate::protocol::ClientRequest;
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
|
@ -28,24 +26,24 @@ impl Actor for StyleSheetsActor {
|
||||||
}
|
}
|
||||||
fn handle_message(
|
fn handle_message(
|
||||||
&self,
|
&self,
|
||||||
|
request: ClientRequest,
|
||||||
_registry: &ActorRegistry,
|
_registry: &ActorRegistry,
|
||||||
msg_type: &str,
|
msg_type: &str,
|
||||||
_msg: &Map<String, Value>,
|
_msg: &Map<String, Value>,
|
||||||
stream: &mut TcpStream,
|
|
||||||
_id: StreamId,
|
_id: StreamId,
|
||||||
) -> Result<ActorMessageStatus, ()> {
|
) -> Result<(), ActorError> {
|
||||||
Ok(match msg_type {
|
match msg_type {
|
||||||
"getStyleSheets" => {
|
"getStyleSheets" => {
|
||||||
let msg = GetStyleSheetsReply {
|
let msg = GetStyleSheetsReply {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
style_sheets: vec![],
|
style_sheets: vec![],
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_ => ActorMessageStatus::Ignored,
|
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||||
})
|
};
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,17 +9,15 @@
|
||||||
//!
|
//!
|
||||||
//! [Firefox JS implementation]: https://searchfox.org/mozilla-central/source/devtools/server/actors/descriptors/tab.js
|
//! [Firefox JS implementation]: https://searchfox.org/mozilla-central/source/devtools/server/actors/descriptors/tab.js
|
||||||
|
|
||||||
use std::net::TcpStream;
|
|
||||||
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json::{Map, Value};
|
use serde_json::{Map, Value};
|
||||||
|
|
||||||
use crate::StreamId;
|
use crate::StreamId;
|
||||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||||
use crate::actors::browsing_context::{BrowsingContextActor, BrowsingContextActorMsg};
|
use crate::actors::browsing_context::{BrowsingContextActor, BrowsingContextActorMsg};
|
||||||
use crate::actors::root::{DescriptorTraits, RootActor};
|
use crate::actors::root::{DescriptorTraits, RootActor};
|
||||||
use crate::actors::watcher::{WatcherActor, WatcherActorMsg};
|
use crate::actors::watcher::{WatcherActor, WatcherActorMsg};
|
||||||
use crate::protocol::JsonPacketStream;
|
use crate::protocol::ClientRequest;
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
|
@ -89,42 +87,40 @@ impl Actor for TabDescriptorActor {
|
||||||
/// to describe the debugging capabilities of this tab.
|
/// to describe the debugging capabilities of this tab.
|
||||||
fn handle_message(
|
fn handle_message(
|
||||||
&self,
|
&self,
|
||||||
|
request: ClientRequest,
|
||||||
registry: &ActorRegistry,
|
registry: &ActorRegistry,
|
||||||
msg_type: &str,
|
msg_type: &str,
|
||||||
_msg: &Map<String, Value>,
|
_msg: &Map<String, Value>,
|
||||||
stream: &mut TcpStream,
|
|
||||||
_id: StreamId,
|
_id: StreamId,
|
||||||
) -> Result<ActorMessageStatus, ()> {
|
) -> Result<(), ActorError> {
|
||||||
Ok(match msg_type {
|
match msg_type {
|
||||||
"getTarget" => {
|
"getTarget" => {
|
||||||
let frame = registry
|
let frame = registry
|
||||||
.find::<BrowsingContextActor>(&self.browsing_context_actor)
|
.find::<BrowsingContextActor>(&self.browsing_context_actor)
|
||||||
.encodable();
|
.encodable();
|
||||||
let _ = stream.write_json_packet(&GetTargetReply {
|
request.reply_final(&GetTargetReply {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
frame,
|
frame,
|
||||||
});
|
})?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
"getFavicon" => {
|
"getFavicon" => {
|
||||||
// TODO: Return a favicon when available
|
// TODO: Return a favicon when available
|
||||||
let _ = stream.write_json_packet(&GetFaviconReply {
|
request.reply_final(&GetFaviconReply {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
favicon: String::new(),
|
favicon: String::new(),
|
||||||
});
|
})?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
"getWatcher" => {
|
"getWatcher" => {
|
||||||
let ctx_actor = registry.find::<BrowsingContextActor>(&self.browsing_context_actor);
|
let ctx_actor = registry.find::<BrowsingContextActor>(&self.browsing_context_actor);
|
||||||
let watcher = registry.find::<WatcherActor>(&ctx_actor.watcher);
|
let watcher = registry.find::<WatcherActor>(&ctx_actor.watcher);
|
||||||
let _ = stream.write_json_packet(&GetWatcherReply {
|
request.reply_final(&GetWatcherReply {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
watcher: watcher.encodable(),
|
watcher: watcher.encodable(),
|
||||||
});
|
})?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
_ => ActorMessageStatus::Ignored,
|
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||||
})
|
};
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,14 +2,12 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use std::net::TcpStream;
|
|
||||||
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json::{Map, Value};
|
use serde_json::{Map, Value};
|
||||||
|
|
||||||
use super::source::{SourceManager, SourcesReply};
|
use super::source::{SourceManager, SourcesReply};
|
||||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||||
use crate::protocol::JsonPacketStream;
|
use crate::protocol::{ClientRequest, JsonPacketStream};
|
||||||
use crate::{EmptyReplyMsg, StreamId};
|
use crate::{EmptyReplyMsg, StreamId};
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
|
@ -71,13 +69,13 @@ impl Actor for ThreadActor {
|
||||||
|
|
||||||
fn handle_message(
|
fn handle_message(
|
||||||
&self,
|
&self,
|
||||||
|
mut request: ClientRequest,
|
||||||
registry: &ActorRegistry,
|
registry: &ActorRegistry,
|
||||||
msg_type: &str,
|
msg_type: &str,
|
||||||
_msg: &Map<String, Value>,
|
_msg: &Map<String, Value>,
|
||||||
stream: &mut TcpStream,
|
|
||||||
_id: StreamId,
|
_id: StreamId,
|
||||||
) -> Result<ActorMessageStatus, ()> {
|
) -> Result<(), ActorError> {
|
||||||
Ok(match msg_type {
|
match msg_type {
|
||||||
"attach" => {
|
"attach" => {
|
||||||
let msg = ThreadAttached {
|
let msg = ThreadAttached {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
|
@ -92,9 +90,8 @@ impl Actor for ThreadActor {
|
||||||
type_: "attached".to_owned(),
|
type_: "attached".to_owned(),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.write_json_packet(&msg)?;
|
||||||
let _ = stream.write_json_packet(&EmptyReplyMsg { from: self.name() });
|
request.reply_final(&EmptyReplyMsg { from: self.name() })?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"resume" => {
|
"resume" => {
|
||||||
|
@ -102,9 +99,8 @@ impl Actor for ThreadActor {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
type_: "resumed".to_owned(),
|
type_: "resumed".to_owned(),
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.write_json_packet(&msg)?;
|
||||||
let _ = stream.write_json_packet(&EmptyReplyMsg { from: self.name() });
|
request.reply_final(&EmptyReplyMsg { from: self.name() })?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"interrupt" => {
|
"interrupt" => {
|
||||||
|
@ -112,14 +108,11 @@ impl Actor for ThreadActor {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
type_: "interrupted".to_owned(),
|
type_: "interrupted".to_owned(),
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.write_json_packet(&msg)?;
|
||||||
ActorMessageStatus::Processed
|
request.reply_final(&EmptyReplyMsg { from: self.name() })?
|
||||||
},
|
},
|
||||||
|
|
||||||
"reconfigure" => {
|
"reconfigure" => request.reply_final(&EmptyReplyMsg { from: self.name() })?,
|
||||||
let _ = stream.write_json_packet(&EmptyReplyMsg { from: self.name() });
|
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
|
||||||
|
|
||||||
// Client has attached to the thread and wants to load script sources.
|
// Client has attached to the thread and wants to load script sources.
|
||||||
// <https://firefox-source-docs.mozilla.org/devtools/backend/protocol.html#loading-script-sources>
|
// <https://firefox-source-docs.mozilla.org/devtools/backend/protocol.html#loading-script-sources>
|
||||||
|
@ -128,10 +121,10 @@ impl Actor for ThreadActor {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
sources: self.source_manager.source_forms(registry),
|
sources: self.source_manager.source_forms(registry),
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
_ => ActorMessageStatus::Ignored,
|
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||||
})
|
};
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::error::Error;
|
|
||||||
use std::net::TcpStream;
|
use std::net::TcpStream;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
@ -21,10 +20,10 @@ use serde::{Serialize, Serializer};
|
||||||
use serde_json::{Map, Value};
|
use serde_json::{Map, Value};
|
||||||
|
|
||||||
use crate::StreamId;
|
use crate::StreamId;
|
||||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||||
use crate::actors::framerate::FramerateActor;
|
use crate::actors::framerate::FramerateActor;
|
||||||
use crate::actors::memory::{MemoryActor, TimelineMemoryReply};
|
use crate::actors::memory::{MemoryActor, TimelineMemoryReply};
|
||||||
use crate::protocol::JsonPacketStream;
|
use crate::protocol::{ClientRequest, JsonPacketStream};
|
||||||
|
|
||||||
pub struct TimelineActor {
|
pub struct TimelineActor {
|
||||||
name: String,
|
name: String,
|
||||||
|
@ -191,13 +190,13 @@ impl Actor for TimelineActor {
|
||||||
|
|
||||||
fn handle_message(
|
fn handle_message(
|
||||||
&self,
|
&self,
|
||||||
|
request: ClientRequest,
|
||||||
registry: &ActorRegistry,
|
registry: &ActorRegistry,
|
||||||
msg_type: &str,
|
msg_type: &str,
|
||||||
msg: &Map<String, Value>,
|
msg: &Map<String, Value>,
|
||||||
stream: &mut TcpStream,
|
|
||||||
_id: StreamId,
|
_id: StreamId,
|
||||||
) -> Result<ActorMessageStatus, ()> {
|
) -> Result<(), ActorError> {
|
||||||
Ok(match msg_type {
|
match msg_type {
|
||||||
"start" => {
|
"start" => {
|
||||||
**self.is_recording.lock().as_mut().unwrap() = true;
|
**self.is_recording.lock().as_mut().unwrap() = true;
|
||||||
|
|
||||||
|
@ -211,7 +210,7 @@ impl Actor for TimelineActor {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
//TODO: support multiple connections by using root actor's streams instead.
|
//TODO: support multiple connections by using root actor's streams instead.
|
||||||
*self.stream.borrow_mut() = stream.try_clone().ok();
|
*self.stream.borrow_mut() = request.try_clone_stream().ok();
|
||||||
|
|
||||||
// init memory actor
|
// init memory actor
|
||||||
if let Some(with_memory) = msg.get("withMemory") {
|
if let Some(with_memory) = msg.get("withMemory") {
|
||||||
|
@ -236,7 +235,7 @@ impl Actor for TimelineActor {
|
||||||
self.name(),
|
self.name(),
|
||||||
registry.shareable(),
|
registry.shareable(),
|
||||||
registry.start_stamp(),
|
registry.start_stamp(),
|
||||||
stream.try_clone().unwrap(),
|
request.try_clone_stream().unwrap(),
|
||||||
self.memory_actor.borrow().clone(),
|
self.memory_actor.borrow().clone(),
|
||||||
self.framerate_actor.borrow().clone(),
|
self.framerate_actor.borrow().clone(),
|
||||||
);
|
);
|
||||||
|
@ -250,8 +249,7 @@ impl Actor for TimelineActor {
|
||||||
CrossProcessInstant::now(),
|
CrossProcessInstant::now(),
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"stop" => {
|
"stop" => {
|
||||||
|
@ -263,7 +261,6 @@ impl Actor for TimelineActor {
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
let _ = stream.write_json_packet(&msg);
|
|
||||||
self.script_sender
|
self.script_sender
|
||||||
.send(DropTimelineMarkers(
|
.send(DropTimelineMarkers(
|
||||||
self.pipeline_id,
|
self.pipeline_id,
|
||||||
|
@ -282,7 +279,7 @@ impl Actor for TimelineActor {
|
||||||
|
|
||||||
**self.is_recording.lock().as_mut().unwrap() = false;
|
**self.is_recording.lock().as_mut().unwrap() = false;
|
||||||
self.stream.borrow_mut().take();
|
self.stream.borrow_mut().take();
|
||||||
ActorMessageStatus::Processed
|
request.reply_final(&msg)?
|
||||||
},
|
},
|
||||||
|
|
||||||
"isRecording" => {
|
"isRecording" => {
|
||||||
|
@ -291,12 +288,12 @@ impl Actor for TimelineActor {
|
||||||
value: *self.is_recording.lock().unwrap(),
|
value: *self.is_recording.lock().unwrap(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_ => ActorMessageStatus::Ignored,
|
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||||
})
|
};
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -330,7 +327,7 @@ impl Emitter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send(&mut self, markers: Vec<TimelineMarkerReply>) -> Result<(), Box<dyn Error>> {
|
fn send(&mut self, markers: Vec<TimelineMarkerReply>) -> Result<(), ActorError> {
|
||||||
let end_time = CrossProcessInstant::now();
|
let end_time = CrossProcessInstant::now();
|
||||||
let reply = MarkersEmitterReply {
|
let reply = MarkersEmitterReply {
|
||||||
type_: "markers".to_owned(),
|
type_: "markers".to_owned(),
|
||||||
|
|
|
@ -24,7 +24,7 @@ use self::network_parent::{NetworkParentActor, NetworkParentActorMsg};
|
||||||
use super::breakpoint::BreakpointListActor;
|
use super::breakpoint::BreakpointListActor;
|
||||||
use super::thread::ThreadActor;
|
use super::thread::ThreadActor;
|
||||||
use super::worker::WorkerMsg;
|
use super::worker::WorkerMsg;
|
||||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||||
use crate::actors::browsing_context::{BrowsingContextActor, BrowsingContextActorMsg};
|
use crate::actors::browsing_context::{BrowsingContextActor, BrowsingContextActorMsg};
|
||||||
use crate::actors::root::RootActor;
|
use crate::actors::root::RootActor;
|
||||||
use crate::actors::watcher::target_configuration::{
|
use crate::actors::watcher::target_configuration::{
|
||||||
|
@ -33,7 +33,7 @@ use crate::actors::watcher::target_configuration::{
|
||||||
use crate::actors::watcher::thread_configuration::{
|
use crate::actors::watcher::thread_configuration::{
|
||||||
ThreadConfigurationActor, ThreadConfigurationActorMsg,
|
ThreadConfigurationActor, ThreadConfigurationActorMsg,
|
||||||
};
|
};
|
||||||
use crate::protocol::JsonPacketStream;
|
use crate::protocol::{ClientRequest, JsonPacketStream};
|
||||||
use crate::resource::{ResourceArrayType, ResourceAvailable};
|
use crate::resource::{ResourceArrayType, ResourceAvailable};
|
||||||
use crate::{EmptyReplyMsg, IdMap, StreamId, WorkerActor};
|
use crate::{EmptyReplyMsg, IdMap, StreamId, WorkerActor};
|
||||||
|
|
||||||
|
@ -230,15 +230,15 @@ impl Actor for WatcherActor {
|
||||||
/// - `getThreadConfigurationActor`: The same but with the configuration actor for the thread
|
/// - `getThreadConfigurationActor`: The same but with the configuration actor for the thread
|
||||||
fn handle_message(
|
fn handle_message(
|
||||||
&self,
|
&self,
|
||||||
|
mut request: ClientRequest,
|
||||||
registry: &ActorRegistry,
|
registry: &ActorRegistry,
|
||||||
msg_type: &str,
|
msg_type: &str,
|
||||||
msg: &Map<String, Value>,
|
msg: &Map<String, Value>,
|
||||||
stream: &mut TcpStream,
|
|
||||||
_id: StreamId,
|
_id: StreamId,
|
||||||
) -> Result<ActorMessageStatus, ()> {
|
) -> Result<(), ActorError> {
|
||||||
let target = registry.find::<BrowsingContextActor>(&self.browsing_context_actor);
|
let target = registry.find::<BrowsingContextActor>(&self.browsing_context_actor);
|
||||||
let root = registry.find::<RootActor>("root");
|
let root = registry.find::<RootActor>("root");
|
||||||
Ok(match msg_type {
|
match msg_type {
|
||||||
"watchTargets" => {
|
"watchTargets" => {
|
||||||
// As per logs we either get targetType as "frame" or "worker"
|
// As per logs we either get targetType as "frame" or "worker"
|
||||||
let target_type = msg
|
let target_type = msg
|
||||||
|
@ -252,9 +252,9 @@ impl Actor for WatcherActor {
|
||||||
type_: "target-available-form".into(),
|
type_: "target-available-form".into(),
|
||||||
target: TargetActorMsg::BrowsingContext(target.encodable()),
|
target: TargetActorMsg::BrowsingContext(target.encodable()),
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
let _ = request.write_json_packet(&msg);
|
||||||
|
|
||||||
target.frame_update(stream);
|
target.frame_update(&mut request);
|
||||||
} else if target_type == "worker" {
|
} else if target_type == "worker" {
|
||||||
for worker_name in &root.workers {
|
for worker_name in &root.workers {
|
||||||
let worker = registry.find::<WorkerActor>(worker_name);
|
let worker = registry.find::<WorkerActor>(worker_name);
|
||||||
|
@ -263,11 +263,10 @@ impl Actor for WatcherActor {
|
||||||
type_: "target-available-form".into(),
|
type_: "target-available-form".into(),
|
||||||
target: TargetActorMsg::Worker(worker.encodable()),
|
target: TargetActorMsg::Worker(worker.encodable()),
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&worker_msg);
|
let _ = request.write_json_packet(&worker_msg);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
warn!("Unexpected target_type: {}", target_type);
|
warn!("Unexpected target_type: {}", target_type);
|
||||||
return Ok(ActorMessageStatus::Ignored);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Messages that contain a `type` field are used to send event callbacks, but they
|
// Messages that contain a `type` field are used to send event callbacks, but they
|
||||||
|
@ -275,15 +274,14 @@ impl Actor for WatcherActor {
|
||||||
// extra empty packet to the devtools host to inform that we successfully received
|
// extra empty packet to the devtools host to inform that we successfully received
|
||||||
// and processed the message so that it can continue
|
// and processed the message so that it can continue
|
||||||
let msg = EmptyReplyMsg { from: self.name() };
|
let msg = EmptyReplyMsg { from: self.name() };
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
"watchResources" => {
|
"watchResources" => {
|
||||||
let Some(resource_types) = msg.get("resourceTypes") else {
|
let Some(resource_types) = msg.get("resourceTypes") else {
|
||||||
return Ok(ActorMessageStatus::Ignored);
|
return Err(ActorError::MissingParameter);
|
||||||
};
|
};
|
||||||
let Some(resource_types) = resource_types.as_array() else {
|
let Some(resource_types) = resource_types.as_array() else {
|
||||||
return Ok(ActorMessageStatus::Ignored);
|
return Err(ActorError::BadParameterType);
|
||||||
};
|
};
|
||||||
|
|
||||||
for resource in resource_types {
|
for resource in resource_types {
|
||||||
|
@ -311,7 +309,7 @@ impl Actor for WatcherActor {
|
||||||
event,
|
event,
|
||||||
"document-event".into(),
|
"document-event".into(),
|
||||||
ResourceArrayType::Available,
|
ResourceArrayType::Available,
|
||||||
stream,
|
&mut request,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -321,7 +319,7 @@ impl Actor for WatcherActor {
|
||||||
thread_actor.source_manager.source_forms(registry),
|
thread_actor.source_manager.source_forms(registry),
|
||||||
"source".into(),
|
"source".into(),
|
||||||
ResourceArrayType::Available,
|
ResourceArrayType::Available,
|
||||||
stream,
|
&mut request,
|
||||||
);
|
);
|
||||||
|
|
||||||
for worker_name in &root.workers {
|
for worker_name in &root.workers {
|
||||||
|
@ -332,7 +330,7 @@ impl Actor for WatcherActor {
|
||||||
thread.source_manager.source_forms(registry),
|
thread.source_manager.source_forms(registry),
|
||||||
"source".into(),
|
"source".into(),
|
||||||
ResourceArrayType::Available,
|
ResourceArrayType::Available,
|
||||||
stream,
|
&mut request,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -340,19 +338,16 @@ impl Actor for WatcherActor {
|
||||||
"network-event" => {},
|
"network-event" => {},
|
||||||
_ => warn!("resource {} not handled yet", resource),
|
_ => warn!("resource {} not handled yet", resource),
|
||||||
}
|
}
|
||||||
|
|
||||||
let msg = EmptyReplyMsg { from: self.name() };
|
|
||||||
let _ = stream.write_json_packet(&msg);
|
|
||||||
}
|
}
|
||||||
ActorMessageStatus::Processed
|
let msg = EmptyReplyMsg { from: self.name() };
|
||||||
|
request.reply_final(&msg)?
|
||||||
},
|
},
|
||||||
"getParentBrowsingContextID" => {
|
"getParentBrowsingContextID" => {
|
||||||
let msg = GetParentBrowsingContextIDReply {
|
let msg = GetParentBrowsingContextIDReply {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
browsing_context_id: target.browsing_context_id.value(),
|
browsing_context_id: target.browsing_context_id.value(),
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
"getNetworkParentActor" => {
|
"getNetworkParentActor" => {
|
||||||
let network_parent = registry.find::<NetworkParentActor>(&self.network_parent);
|
let network_parent = registry.find::<NetworkParentActor>(&self.network_parent);
|
||||||
|
@ -360,8 +355,7 @@ impl Actor for WatcherActor {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
network: network_parent.encodable(),
|
network: network_parent.encodable(),
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
"getTargetConfigurationActor" => {
|
"getTargetConfigurationActor" => {
|
||||||
let target_configuration =
|
let target_configuration =
|
||||||
|
@ -370,8 +364,7 @@ impl Actor for WatcherActor {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
configuration: target_configuration.encodable(),
|
configuration: target_configuration.encodable(),
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
"getThreadConfigurationActor" => {
|
"getThreadConfigurationActor" => {
|
||||||
let thread_configuration =
|
let thread_configuration =
|
||||||
|
@ -380,24 +373,23 @@ impl Actor for WatcherActor {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
configuration: thread_configuration.encodable(),
|
configuration: thread_configuration.encodable(),
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
"getBreakpointListActor" => {
|
"getBreakpointListActor" => {
|
||||||
let breakpoint_list_name = registry.new_name("breakpoint-list");
|
let breakpoint_list_name = registry.new_name("breakpoint-list");
|
||||||
let breakpoint_list = BreakpointListActor::new(breakpoint_list_name.clone());
|
let breakpoint_list = BreakpointListActor::new(breakpoint_list_name.clone());
|
||||||
registry.register_later(Box::new(breakpoint_list));
|
registry.register_later(Box::new(breakpoint_list));
|
||||||
|
|
||||||
let _ = stream.write_json_packet(&GetBreakpointListActorReply {
|
request.reply_final(&GetBreakpointListActorReply {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
breakpoint_list: GetBreakpointListActorReplyInner {
|
breakpoint_list: GetBreakpointListActorReplyInner {
|
||||||
actor: breakpoint_list_name,
|
actor: breakpoint_list_name,
|
||||||
},
|
},
|
||||||
});
|
})?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
_ => ActorMessageStatus::Ignored,
|
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||||
})
|
};
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,13 +2,11 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use std::net::TcpStream;
|
|
||||||
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json::{Map, Value};
|
use serde_json::{Map, Value};
|
||||||
|
|
||||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||||
use crate::protocol::JsonPacketStream;
|
use crate::protocol::ClientRequest;
|
||||||
use crate::{EmptyReplyMsg, StreamId};
|
use crate::{EmptyReplyMsg, StreamId};
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
|
@ -30,20 +28,20 @@ impl Actor for NetworkParentActor {
|
||||||
/// - `setSaveRequestAndResponseBodies`: Doesn't do anything yet
|
/// - `setSaveRequestAndResponseBodies`: Doesn't do anything yet
|
||||||
fn handle_message(
|
fn handle_message(
|
||||||
&self,
|
&self,
|
||||||
|
request: ClientRequest,
|
||||||
_registry: &ActorRegistry,
|
_registry: &ActorRegistry,
|
||||||
msg_type: &str,
|
msg_type: &str,
|
||||||
_msg: &Map<String, Value>,
|
_msg: &Map<String, Value>,
|
||||||
stream: &mut TcpStream,
|
|
||||||
_id: StreamId,
|
_id: StreamId,
|
||||||
) -> Result<ActorMessageStatus, ()> {
|
) -> Result<(), ActorError> {
|
||||||
Ok(match msg_type {
|
match msg_type {
|
||||||
"setSaveRequestAndResponseBodies" => {
|
"setSaveRequestAndResponseBodies" => {
|
||||||
let msg = EmptyReplyMsg { from: self.name() };
|
let msg = EmptyReplyMsg { from: self.name() };
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
_ => ActorMessageStatus::Ignored,
|
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||||
})
|
};
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,17 +6,16 @@
|
||||||
//! This actor manages the configuration flags that the devtools host can apply to the targets.
|
//! This actor manages the configuration flags that the devtools host can apply to the targets.
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::net::TcpStream;
|
|
||||||
|
|
||||||
use embedder_traits::Theme;
|
use embedder_traits::Theme;
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json::{Map, Value};
|
use serde_json::{Map, Value};
|
||||||
|
|
||||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||||
use crate::actors::browsing_context::BrowsingContextActor;
|
use crate::actors::browsing_context::BrowsingContextActor;
|
||||||
use crate::actors::tab::TabDescriptorActor;
|
use crate::actors::tab::TabDescriptorActor;
|
||||||
use crate::protocol::JsonPacketStream;
|
use crate::protocol::ClientRequest;
|
||||||
use crate::{EmptyReplyMsg, RootActor, StreamId};
|
use crate::{EmptyReplyMsg, RootActor, StreamId};
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
|
@ -48,22 +47,19 @@ impl Actor for TargetConfigurationActor {
|
||||||
/// - `updateConfiguration`: Receives new configuration flags from the devtools host.
|
/// - `updateConfiguration`: Receives new configuration flags from the devtools host.
|
||||||
fn handle_message(
|
fn handle_message(
|
||||||
&self,
|
&self,
|
||||||
|
request: ClientRequest,
|
||||||
registry: &ActorRegistry,
|
registry: &ActorRegistry,
|
||||||
msg_type: &str,
|
msg_type: &str,
|
||||||
msg: &Map<String, Value>,
|
msg: &Map<String, Value>,
|
||||||
stream: &mut TcpStream,
|
|
||||||
_id: StreamId,
|
_id: StreamId,
|
||||||
) -> Result<ActorMessageStatus, ()> {
|
) -> Result<(), ActorError> {
|
||||||
Ok(match msg_type {
|
match msg_type {
|
||||||
"updateConfiguration" => {
|
"updateConfiguration" => {
|
||||||
let config = match msg.get("configuration").and_then(|v| v.as_object()) {
|
let config = msg
|
||||||
Some(config) => config,
|
.get("configuration")
|
||||||
None => {
|
.ok_or(ActorError::MissingParameter)?
|
||||||
let msg = EmptyReplyMsg { from: self.name() };
|
.as_object()
|
||||||
let _ = stream.write_json_packet(&msg);
|
.ok_or(ActorError::BadParameterType)?;
|
||||||
return Ok(ActorMessageStatus::Processed);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
if let Some(scheme) = config.get("colorSchemeSimulation").and_then(|v| v.as_str()) {
|
if let Some(scheme) = config.get("colorSchemeSimulation").and_then(|v| v.as_str()) {
|
||||||
let theme = match scheme {
|
let theme = match scheme {
|
||||||
"dark" => Theme::Dark,
|
"dark" => Theme::Dark,
|
||||||
|
@ -76,17 +72,19 @@ impl Actor for TargetConfigurationActor {
|
||||||
let browsing_context_name = tab_actor.browsing_context();
|
let browsing_context_name = tab_actor.browsing_context();
|
||||||
let browsing_context_actor =
|
let browsing_context_actor =
|
||||||
registry.find::<BrowsingContextActor>(&browsing_context_name);
|
registry.find::<BrowsingContextActor>(&browsing_context_name);
|
||||||
browsing_context_actor.simulate_color_scheme(theme)?;
|
browsing_context_actor
|
||||||
|
.simulate_color_scheme(theme)
|
||||||
|
.map_err(|_| ActorError::Internal)?;
|
||||||
} else {
|
} else {
|
||||||
warn!("No active tab for updateConfiguration");
|
warn!("No active tab for updateConfiguration");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let msg = EmptyReplyMsg { from: self.name() };
|
let msg = EmptyReplyMsg { from: self.name() };
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
_ => ActorMessageStatus::Ignored,
|
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||||
})
|
};
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,13 +6,12 @@
|
||||||
//! This actor manages the configuration flags that the devtools host can apply to threads.
|
//! This actor manages the configuration flags that the devtools host can apply to threads.
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::net::TcpStream;
|
|
||||||
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json::{Map, Value};
|
use serde_json::{Map, Value};
|
||||||
|
|
||||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||||
use crate::protocol::JsonPacketStream;
|
use crate::protocol::ClientRequest;
|
||||||
use crate::{EmptyReplyMsg, StreamId};
|
use crate::{EmptyReplyMsg, StreamId};
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
|
@ -35,21 +34,21 @@ impl Actor for ThreadConfigurationActor {
|
||||||
/// - `updateConfiguration`: Receives new configuration flags from the devtools host.
|
/// - `updateConfiguration`: Receives new configuration flags from the devtools host.
|
||||||
fn handle_message(
|
fn handle_message(
|
||||||
&self,
|
&self,
|
||||||
|
request: ClientRequest,
|
||||||
_registry: &ActorRegistry,
|
_registry: &ActorRegistry,
|
||||||
msg_type: &str,
|
msg_type: &str,
|
||||||
_msg: &Map<String, Value>,
|
_msg: &Map<String, Value>,
|
||||||
stream: &mut TcpStream,
|
|
||||||
_id: StreamId,
|
_id: StreamId,
|
||||||
) -> Result<ActorMessageStatus, ()> {
|
) -> Result<(), ActorError> {
|
||||||
Ok(match msg_type {
|
match msg_type {
|
||||||
"updateConfiguration" => {
|
"updateConfiguration" => {
|
||||||
// TODO: Actually update configuration
|
// TODO: Actually update configuration
|
||||||
let msg = EmptyReplyMsg { from: self.name() };
|
let msg = EmptyReplyMsg { from: self.name() };
|
||||||
let _ = stream.write_json_packet(&msg);
|
request.reply_final(&msg)?
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
_ => ActorMessageStatus::Ignored,
|
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||||
})
|
};
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,8 @@ use serde_json::{Map, Value};
|
||||||
use servo_url::ServoUrl;
|
use servo_url::ServoUrl;
|
||||||
|
|
||||||
use crate::StreamId;
|
use crate::StreamId;
|
||||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||||
use crate::protocol::JsonPacketStream;
|
use crate::protocol::{ClientRequest, JsonPacketStream};
|
||||||
use crate::resource::ResourceAvailable;
|
use crate::resource::ResourceAvailable;
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
@ -68,30 +68,28 @@ impl Actor for WorkerActor {
|
||||||
}
|
}
|
||||||
fn handle_message(
|
fn handle_message(
|
||||||
&self,
|
&self,
|
||||||
|
mut request: ClientRequest,
|
||||||
_registry: &ActorRegistry,
|
_registry: &ActorRegistry,
|
||||||
msg_type: &str,
|
msg_type: &str,
|
||||||
_msg: &Map<String, Value>,
|
_msg: &Map<String, Value>,
|
||||||
stream: &mut TcpStream,
|
|
||||||
stream_id: StreamId,
|
stream_id: StreamId,
|
||||||
) -> Result<ActorMessageStatus, ()> {
|
) -> Result<(), ActorError> {
|
||||||
Ok(match msg_type {
|
match msg_type {
|
||||||
"attach" => {
|
"attach" => {
|
||||||
let msg = AttachedReply {
|
let msg = AttachedReply {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
type_: "attached".to_owned(),
|
type_: "attached".to_owned(),
|
||||||
url: self.url.as_str().to_owned(),
|
url: self.url.as_str().to_owned(),
|
||||||
};
|
};
|
||||||
if stream.write_json_packet(&msg).is_err() {
|
// FIXME: we don’t send an actual reply (message without type), which seems to be a bug?
|
||||||
return Ok(ActorMessageStatus::Processed);
|
request.write_json_packet(&msg)?;
|
||||||
}
|
|
||||||
self.streams
|
self.streams
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.insert(stream_id, stream.try_clone().unwrap());
|
.insert(stream_id, request.try_clone_stream().unwrap());
|
||||||
// FIXME: fix messages to not require forging a pipeline for worker messages
|
// FIXME: fix messages to not require forging a pipeline for worker messages
|
||||||
self.script_chan
|
self.script_chan
|
||||||
.send(WantsLiveNotifications(TEST_PIPELINE_ID, true))
|
.send(WantsLiveNotifications(TEST_PIPELINE_ID, true))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
ActorMessageStatus::Processed
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"connect" => {
|
"connect" => {
|
||||||
|
@ -101,8 +99,8 @@ impl Actor for WorkerActor {
|
||||||
thread_actor: self.thread.clone(),
|
thread_actor: self.thread.clone(),
|
||||||
console_actor: self.console.clone(),
|
console_actor: self.console.clone(),
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
// FIXME: we don’t send an actual reply (message without type), which seems to be a bug?
|
||||||
ActorMessageStatus::Processed
|
request.write_json_packet(&msg)?;
|
||||||
},
|
},
|
||||||
|
|
||||||
"detach" => {
|
"detach" => {
|
||||||
|
@ -110,13 +108,14 @@ impl Actor for WorkerActor {
|
||||||
from: self.name(),
|
from: self.name(),
|
||||||
type_: "detached".to_string(),
|
type_: "detached".to_string(),
|
||||||
};
|
};
|
||||||
let _ = stream.write_json_packet(&msg);
|
|
||||||
self.cleanup(stream_id);
|
self.cleanup(stream_id);
|
||||||
ActorMessageStatus::Processed
|
// FIXME: we don’t send an actual reply (message without type), which seems to be a bug?
|
||||||
|
request.write_json_packet(&msg)?;
|
||||||
},
|
},
|
||||||
|
|
||||||
_ => ActorMessageStatus::Ignored,
|
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||||
})
|
};
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cleanup(&self, stream_id: StreamId) {
|
fn cleanup(&self, stream_id: StreamId) {
|
||||||
|
|
|
@ -28,7 +28,7 @@ use devtools_traits::{
|
||||||
};
|
};
|
||||||
use embedder_traits::{AllowOrDeny, EmbedderMsg, EmbedderProxy};
|
use embedder_traits::{AllowOrDeny, EmbedderMsg, EmbedderProxy};
|
||||||
use ipc_channel::ipc::{self, IpcSender};
|
use ipc_channel::ipc::{self, IpcSender};
|
||||||
use log::trace;
|
use log::{trace, warn};
|
||||||
use resource::{ResourceArrayType, ResourceAvailable};
|
use resource::{ResourceArrayType, ResourceAvailable};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use servo_rand::RngCore;
|
use servo_rand::RngCore;
|
||||||
|
@ -646,8 +646,8 @@ fn allow_devtools_client(stream: &mut TcpStream, embedder: &EmbedderProxy, token
|
||||||
fn handle_client(actors: Arc<Mutex<ActorRegistry>>, mut stream: TcpStream, stream_id: StreamId) {
|
fn handle_client(actors: Arc<Mutex<ActorRegistry>>, mut stream: TcpStream, stream_id: StreamId) {
|
||||||
log::info!("Connection established to {}", stream.peer_addr().unwrap());
|
log::info!("Connection established to {}", stream.peer_addr().unwrap());
|
||||||
let msg = actors.lock().unwrap().find::<RootActor>("root").encodable();
|
let msg = actors.lock().unwrap().find::<RootActor>("root").encodable();
|
||||||
if let Err(e) = stream.write_json_packet(&msg) {
|
if let Err(error) = stream.write_json_packet(&msg) {
|
||||||
log::warn!("Error writing response: {:?}", e);
|
warn!("Failed to send initial packet from root actor: {error:?}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,13 +5,14 @@
|
||||||
//! Low-level wire protocol implementation. Currently only supports
|
//! Low-level wire protocol implementation. Currently only supports
|
||||||
//! [JSON packets](https://firefox-source-docs.mozilla.org/devtools/backend/protocol.html#json-packets).
|
//! [JSON packets](https://firefox-source-docs.mozilla.org/devtools/backend/protocol.html#json-packets).
|
||||||
|
|
||||||
use std::error::Error;
|
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::net::TcpStream;
|
use std::net::TcpStream;
|
||||||
|
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json::{self, Value};
|
use serde_json::{self, Value, json};
|
||||||
|
|
||||||
|
use crate::actor::ActorError;
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
|
@ -29,42 +30,18 @@ pub struct Method {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait JsonPacketStream {
|
pub trait JsonPacketStream {
|
||||||
fn write_json_packet<T: Serialize>(&mut self, obj: &T) -> Result<(), Box<dyn Error>>;
|
fn write_json_packet<T: Serialize>(&mut self, message: &T) -> Result<(), ActorError>;
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
fn write_merged_json_packet<T: Serialize, U: Serialize>(
|
|
||||||
&mut self,
|
|
||||||
base: &T,
|
|
||||||
extra: &U,
|
|
||||||
) -> Result<(), Box<dyn Error>>;
|
|
||||||
fn read_json_packet(&mut self) -> Result<Option<Value>, String>;
|
fn read_json_packet(&mut self) -> Result<Option<Value>, String>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JsonPacketStream for TcpStream {
|
impl JsonPacketStream for TcpStream {
|
||||||
fn write_json_packet<T: Serialize>(&mut self, obj: &T) -> Result<(), Box<dyn Error>> {
|
fn write_json_packet<T: Serialize>(&mut self, message: &T) -> Result<(), ActorError> {
|
||||||
let s = serde_json::to_string(obj)?;
|
let s = serde_json::to_string(message).map_err(|_| ActorError::Internal)?;
|
||||||
debug!("<- {}", s);
|
debug!("<- {}", s);
|
||||||
write!(self, "{}:{}", s.len(), s)?;
|
write!(self, "{}:{}", s.len(), s).map_err(|_| ActorError::Internal)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_merged_json_packet<T: Serialize, U: Serialize>(
|
|
||||||
&mut self,
|
|
||||||
base: &T,
|
|
||||||
extra: &U,
|
|
||||||
) -> Result<(), Box<dyn Error>> {
|
|
||||||
let mut obj = serde_json::to_value(base)?;
|
|
||||||
let obj = obj.as_object_mut().unwrap();
|
|
||||||
let extra = serde_json::to_value(extra)?;
|
|
||||||
let extra = extra.as_object().unwrap();
|
|
||||||
|
|
||||||
for (key, value) in extra {
|
|
||||||
obj.insert(key.to_owned(), value.to_owned());
|
|
||||||
}
|
|
||||||
|
|
||||||
self.write_json_packet(obj)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_json_packet(&mut self) -> Result<Option<Value>, String> {
|
fn read_json_packet(&mut self) -> Result<Option<Value>, String> {
|
||||||
// https://firefox-source-docs.mozilla.org/devtools/backend/protocol.html#stream-transport
|
// https://firefox-source-docs.mozilla.org/devtools/backend/protocol.html#stream-transport
|
||||||
// In short, each JSON packet is [ascii length]:[JSON data of given length]
|
// In short, each JSON packet is [ascii length]:[JSON data of given length]
|
||||||
|
@ -102,3 +79,106 @@ impl JsonPacketStream for TcpStream {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Wrapper around a client stream that guarantees request/reply invariants.
|
||||||
|
///
|
||||||
|
/// Client messages, which are always requests, are dispatched to Actor instances one at a time via
|
||||||
|
/// [`crate::Actor::handle_message`]. Each request must be paired with exactly one reply from the
|
||||||
|
/// same actor the request was sent to, where a reply is a message with no type (if a message from
|
||||||
|
/// the server has a type, it’s a notification, not a reply).
|
||||||
|
///
|
||||||
|
/// Failing to reply to a request will almost always permanently break that actor, because either
|
||||||
|
/// the client gets stuck waiting for a reply, or the client receives the reply for a subsequent
|
||||||
|
/// request as if it was the reply for the current request. If an actor fails to reply to a request,
|
||||||
|
/// we want the dispatcher ([`crate::ActorRegistry::handle_message`]) to send an error of type
|
||||||
|
/// `unrecognizedPacketType`, to keep the conversation for that actor in sync.
|
||||||
|
///
|
||||||
|
/// Since replies come in all shapes and sizes, we want to allow Actor types to send replies without
|
||||||
|
/// having to return them to the dispatcher. This wrapper type allows the dispatcher to check if a
|
||||||
|
/// valid reply was sent, and guarantees that if the actor tries to send a reply, it’s actually a
|
||||||
|
/// valid reply (see [`Self::is_valid_reply`]).
|
||||||
|
///
|
||||||
|
/// It does not currently guarantee anything about messages sent via the [`TcpStream`] released via
|
||||||
|
/// [`Self::try_clone_stream`] or the return value of [`Self::reply`].
|
||||||
|
pub struct ClientRequest<'req, 'sent> {
|
||||||
|
/// Client stream.
|
||||||
|
stream: &'req mut TcpStream,
|
||||||
|
/// Expected actor name.
|
||||||
|
actor_name: &'req str,
|
||||||
|
/// Sent flag, allowing ActorRegistry to check for unhandled requests.
|
||||||
|
sent: &'sent mut bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClientRequest<'_, '_> {
|
||||||
|
/// Run the given handler, with a new request that wraps the given client stream and expected actor name.
|
||||||
|
///
|
||||||
|
/// Returns [`ActorError::UnrecognizedPacketType`] if the actor did not send a reply.
|
||||||
|
pub fn handle<'req>(
|
||||||
|
client: &'req mut TcpStream,
|
||||||
|
actor_name: &'req str,
|
||||||
|
handler: impl FnOnce(ClientRequest<'req, '_>) -> Result<(), ActorError>,
|
||||||
|
) -> Result<(), ActorError> {
|
||||||
|
let mut sent = false;
|
||||||
|
let request = ClientRequest {
|
||||||
|
stream: client,
|
||||||
|
actor_name,
|
||||||
|
sent: &mut sent,
|
||||||
|
};
|
||||||
|
handler(request)?;
|
||||||
|
|
||||||
|
if sent {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ActorError::UnrecognizedPacketType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'req> ClientRequest<'req, '_> {
|
||||||
|
/// Send the given reply to the request being handled.
|
||||||
|
///
|
||||||
|
/// If successful, sets the sent flag and returns the underlying stream,
|
||||||
|
/// allowing other messages to be sent after replying to a request.
|
||||||
|
pub fn reply<T: Serialize>(self, reply: &T) -> Result<&'req mut TcpStream, ActorError> {
|
||||||
|
debug_assert!(self.is_valid_reply(reply), "Message is not a valid reply");
|
||||||
|
self.stream.write_json_packet(reply)?;
|
||||||
|
*self.sent = true;
|
||||||
|
Ok(self.stream)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Like `reply`, but for cases where the actor no longer needs the stream.
|
||||||
|
pub fn reply_final<T: Serialize>(self, reply: &T) -> Result<(), ActorError> {
|
||||||
|
debug_assert!(self.is_valid_reply(reply), "Message is not a valid reply");
|
||||||
|
let _stream = self.reply(reply)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_clone_stream(&self) -> std::io::Result<TcpStream> {
|
||||||
|
self.stream.try_clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return true iff the given message is a reply (has no `type` or `to`), and is from the expected actor.
|
||||||
|
///
|
||||||
|
/// This incurs a runtime conversion to a BTreeMap, so it should only be used in debug assertions.
|
||||||
|
fn is_valid_reply<T: Serialize>(&self, message: &T) -> bool {
|
||||||
|
let reply = json!(message);
|
||||||
|
reply.get("from").and_then(|from| from.as_str()) == Some(self.actor_name) &&
|
||||||
|
reply.get("to").is_none() &&
|
||||||
|
reply.get("type").is_none()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Actors can also send other messages before replying to a request.
|
||||||
|
impl JsonPacketStream for ClientRequest<'_, '_> {
|
||||||
|
fn write_json_packet<T: Serialize>(&mut self, message: &T) -> Result<(), ActorError> {
|
||||||
|
debug_assert!(
|
||||||
|
!self.is_valid_reply(message),
|
||||||
|
"Replies must use reply() or reply_final()"
|
||||||
|
);
|
||||||
|
self.stream.write_json_packet(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_json_packet(&mut self) -> Result<Option<Value>, String> {
|
||||||
|
self.stream.read_json_packet()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use std::net::TcpStream;
|
|
||||||
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::protocol::JsonPacketStream;
|
use crate::protocol::JsonPacketStream;
|
||||||
|
@ -24,22 +22,22 @@ pub(crate) struct ResourceAvailableReply<T: Serialize> {
|
||||||
pub(crate) trait ResourceAvailable {
|
pub(crate) trait ResourceAvailable {
|
||||||
fn actor_name(&self) -> String;
|
fn actor_name(&self) -> String;
|
||||||
|
|
||||||
fn resource_array<T: Serialize>(
|
fn resource_array<T: Serialize, S: JsonPacketStream>(
|
||||||
&self,
|
&self,
|
||||||
resource: T,
|
resource: T,
|
||||||
resource_type: String,
|
resource_type: String,
|
||||||
array_type: ResourceArrayType,
|
array_type: ResourceArrayType,
|
||||||
stream: &mut TcpStream,
|
stream: &mut S,
|
||||||
) {
|
) {
|
||||||
self.resources_array(vec![resource], resource_type, array_type, stream);
|
self.resources_array(vec![resource], resource_type, array_type, stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resources_array<T: Serialize>(
|
fn resources_array<T: Serialize, S: JsonPacketStream>(
|
||||||
&self,
|
&self,
|
||||||
resources: Vec<T>,
|
resources: Vec<T>,
|
||||||
resource_type: String,
|
resource_type: String,
|
||||||
array_type: ResourceArrayType,
|
array_type: ResourceArrayType,
|
||||||
stream: &mut TcpStream,
|
stream: &mut S,
|
||||||
) {
|
) {
|
||||||
let msg = ResourceAvailableReply::<T> {
|
let msg = ResourceAvailableReply::<T> {
|
||||||
from: self.actor_name(),
|
from: self.actor_name(),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue