mirror of
https://github.com/servo/servo.git
synced 2025-07-14 19:03:40 +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::id::PipelineId;
|
||||
use log::debug;
|
||||
use serde_json::{Map, Value};
|
||||
use serde_json::{Map, Value, json};
|
||||
|
||||
use crate::StreamId;
|
||||
use crate::protocol::{ClientRequest, JsonPacketStream};
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum ActorMessageStatus {
|
||||
Processed,
|
||||
Ignored,
|
||||
/// Error replies.
|
||||
///
|
||||
/// <https://firefox-source-docs.mozilla.org/devtools/backend/protocol.html#error-packets>
|
||||
#[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
|
||||
|
@ -28,12 +51,12 @@ pub enum ActorMessageStatus {
|
|||
pub(crate) trait Actor: Any + ActorAsAny {
|
||||
fn handle_message(
|
||||
&self,
|
||||
request: ClientRequest,
|
||||
registry: &ActorRegistry,
|
||||
msg_type: &str,
|
||||
msg: &Map<String, Value>,
|
||||
stream: &mut TcpStream,
|
||||
stream_id: StreamId,
|
||||
) -> Result<ActorMessageStatus, ()>;
|
||||
) -> Result<(), ActorError>;
|
||||
fn name(&self) -> String;
|
||||
fn cleanup(&self, _id: StreamId) {}
|
||||
}
|
||||
|
@ -169,8 +192,8 @@ impl ActorRegistry {
|
|||
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
|
||||
/// found or does not indicate that it knew how to process the message, ignore the failure.
|
||||
/// Attempt to process a message as directed by its `to` property. If the actor is not found, does not support the
|
||||
/// message, or failed to handle the message, send an error reply instead.
|
||||
pub(crate) fn handle_message(
|
||||
&mut self,
|
||||
msg: &Map<String, Value>,
|
||||
|
@ -186,17 +209,20 @@ impl ActorRegistry {
|
|||
};
|
||||
|
||||
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) => {
|
||||
let msg_type = msg.get("type").unwrap().as_str().unwrap();
|
||||
if actor.handle_message(self, msg_type, msg, stream, stream_id)? !=
|
||||
ActorMessageStatus::Processed
|
||||
{
|
||||
log::warn!(
|
||||
"unexpected message type \"{}\" found for actor \"{}\"",
|
||||
msg_type,
|
||||
to
|
||||
);
|
||||
if let Err(error) = ClientRequest::handle(stream, to, |req| {
|
||||
actor.handle_message(req, self, msg_type, msg, stream_id)
|
||||
}) {
|
||||
// <https://firefox-source-docs.mozilla.org/devtools/backend/protocol.html#error-packets>
|
||||
let _ = stream.write_json_packet(&json!({
|
||||
"from": actor.name(), "error": error.name()
|
||||
}));
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
use serde::Serialize;
|
||||
|
||||
use crate::EmptyReplyMsg;
|
||||
use crate::actor::{Actor, ActorMessageStatus};
|
||||
use crate::protocol::JsonPacketStream;
|
||||
use crate::actor::{Actor, ActorError};
|
||||
use crate::protocol::ClientRequest;
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct BreakpointListActorMsg {
|
||||
|
@ -24,27 +24,24 @@ impl Actor for BreakpointListActor {
|
|||
|
||||
fn handle_message(
|
||||
&self,
|
||||
request: ClientRequest,
|
||||
_registry: &crate::actor::ActorRegistry,
|
||||
msg_type: &str,
|
||||
_msg: &serde_json::Map<String, serde_json::Value>,
|
||||
stream: &mut std::net::TcpStream,
|
||||
_stream_id: crate::StreamId,
|
||||
) -> Result<crate::actor::ActorMessageStatus, ()> {
|
||||
Ok(match msg_type {
|
||||
) -> Result<(), ActorError> {
|
||||
match msg_type {
|
||||
"setBreakpoint" => {
|
||||
let msg = EmptyReplyMsg { from: self.name() };
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
"setActiveEventBreakpoints" => {
|
||||
let msg = EmptyReplyMsg { from: self.name() };
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
_ => ActorMessageStatus::Ignored,
|
||||
})
|
||||
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ use ipc_channel::ipc::{self, IpcSender};
|
|||
use serde::Serialize;
|
||||
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::accessibility::AccessibilityActor;
|
||||
use crate::actors::inspector::css_properties::CssPropertiesActor;
|
||||
|
@ -30,7 +30,7 @@ use crate::actors::tab::TabDescriptorActor;
|
|||
use crate::actors::thread::ThreadActor;
|
||||
use crate::actors::watcher::{SessionContext, SessionContextType, WatcherActor};
|
||||
use crate::id::{DevtoolsBrowserId, DevtoolsBrowsingContextId, DevtoolsOuterWindowId, IdMap};
|
||||
use crate::protocol::JsonPacketStream;
|
||||
use crate::protocol::{ClientRequest, JsonPacketStream};
|
||||
use crate::resource::ResourceAvailable;
|
||||
use crate::{EmptyReplyMsg, StreamId};
|
||||
|
||||
|
@ -166,29 +166,28 @@ impl Actor for BrowsingContextActor {
|
|||
|
||||
fn handle_message(
|
||||
&self,
|
||||
request: ClientRequest,
|
||||
_registry: &ActorRegistry,
|
||||
msg_type: &str,
|
||||
_msg: &Map<String, Value>,
|
||||
stream: &mut TcpStream,
|
||||
_id: StreamId,
|
||||
) -> Result<ActorMessageStatus, ()> {
|
||||
Ok(match msg_type {
|
||||
) -> Result<(), ActorError> {
|
||||
match msg_type {
|
||||
"listFrames" => {
|
||||
// TODO: Find out what needs to be listed here
|
||||
let msg = EmptyReplyMsg { from: self.name() };
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
"listWorkers" => {
|
||||
let _ = stream.write_json_packet(&ListWorkersReply {
|
||||
request.reply_final(&ListWorkersReply {
|
||||
from: self.name(),
|
||||
// TODO: Find out what needs to be listed here
|
||||
workers: vec![],
|
||||
});
|
||||
ActorMessageStatus::Processed
|
||||
})?
|
||||
},
|
||||
_ => ActorMessageStatus::Ignored,
|
||||
})
|
||||
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn cleanup(&self, id: StreamId) {
|
||||
|
@ -353,8 +352,8 @@ impl BrowsingContextActor {
|
|||
*self.title.borrow_mut() = title;
|
||||
}
|
||||
|
||||
pub(crate) fn frame_update(&self, stream: &mut TcpStream) {
|
||||
let _ = stream.write_json_packet(&FrameUpdateReply {
|
||||
pub(crate) fn frame_update(&self, request: &mut ClientRequest) {
|
||||
let _ = request.write_json_packet(&FrameUpdateReply {
|
||||
from: self.name(),
|
||||
type_: "frameUpdate".into(),
|
||||
frames: vec![FrameUpdateMsg {
|
||||
|
|
|
@ -25,11 +25,11 @@ use serde::Serialize;
|
|||
use serde_json::{self, Map, Number, Value};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
||||
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||
use crate::actors::browsing_context::BrowsingContextActor;
|
||||
use crate::actors::object::ObjectActor;
|
||||
use crate::actors::worker::WorkerActor;
|
||||
use crate::protocol::JsonPacketStream;
|
||||
use crate::protocol::{ClientRequest, JsonPacketStream};
|
||||
use crate::resource::{ResourceArrayType, ResourceAvailable};
|
||||
use crate::{StreamId, UniqueId};
|
||||
|
||||
|
@ -304,18 +304,19 @@ impl Actor for ConsoleActor {
|
|||
|
||||
fn handle_message(
|
||||
&self,
|
||||
request: ClientRequest,
|
||||
registry: &ActorRegistry,
|
||||
msg_type: &str,
|
||||
msg: &Map<String, Value>,
|
||||
stream: &mut TcpStream,
|
||||
_id: StreamId,
|
||||
) -> Result<ActorMessageStatus, ()> {
|
||||
Ok(match msg_type {
|
||||
) -> Result<(), ActorError> {
|
||||
match msg_type {
|
||||
"clearMessagesCache" => {
|
||||
self.cached_events
|
||||
.borrow_mut()
|
||||
.remove(&self.current_unique_id(registry));
|
||||
ActorMessageStatus::Processed
|
||||
// FIXME: need to send a reply here!
|
||||
return Err(ActorError::UnrecognizedPacketType);
|
||||
},
|
||||
|
||||
"getCachedMessages" => {
|
||||
|
@ -368,8 +369,7 @@ impl Actor for ConsoleActor {
|
|||
from: self.name(),
|
||||
messages,
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
|
||||
"startListeners" => {
|
||||
|
@ -384,8 +384,7 @@ impl Actor for ConsoleActor {
|
|||
.collect(),
|
||||
traits: StartedListenersTraits,
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
|
||||
"stopListeners" => {
|
||||
|
@ -401,8 +400,7 @@ impl Actor for ConsoleActor {
|
|||
.map(|listener| listener.as_str().unwrap().to_owned())
|
||||
.collect(),
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
|
||||
//TODO: implement autocompletion like onAutocomplete in
|
||||
|
@ -413,14 +411,12 @@ impl Actor for ConsoleActor {
|
|||
matches: vec![],
|
||||
match_prop: "".to_owned(),
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
|
||||
"evaluateJS" => {
|
||||
let msg = self.evaluate_js(registry, msg);
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
|
||||
"evaluateJSAsync" => {
|
||||
|
@ -431,14 +427,12 @@ impl Actor for ConsoleActor {
|
|||
};
|
||||
// Emit an eager reply so that the client starts listening
|
||||
// for an async event with the resultID
|
||||
if stream.write_json_packet(&early_reply).is_err() {
|
||||
return Ok(ActorMessageStatus::Processed);
|
||||
}
|
||||
let stream = request.reply(&early_reply)?;
|
||||
|
||||
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
|
||||
// really needs.
|
||||
return Ok(ActorMessageStatus::Processed);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let reply = self.evaluate_js(registry, msg).unwrap();
|
||||
|
@ -454,8 +448,7 @@ impl Actor for ConsoleActor {
|
|||
helper_result: reply.helper_result,
|
||||
};
|
||||
// Send the data from evaluateJS along with a resultID
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
stream.write_json_packet(&msg)?
|
||||
},
|
||||
|
||||
"setPreferences" => {
|
||||
|
@ -463,11 +456,11 @@ impl Actor for ConsoleActor {
|
|||
from: self.name(),
|
||||
updated: vec![],
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
|
||||
_ => 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
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::net::TcpStream;
|
||||
|
||||
use serde::Serialize;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
use crate::StreamId;
|
||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
||||
use crate::protocol::{ActorDescription, JsonPacketStream, Method};
|
||||
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||
use crate::protocol::{ActorDescription, ClientRequest, Method};
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct GetDescriptionReply {
|
||||
|
@ -46,13 +44,13 @@ impl Actor for DeviceActor {
|
|||
}
|
||||
fn handle_message(
|
||||
&self,
|
||||
request: ClientRequest,
|
||||
_registry: &ActorRegistry,
|
||||
msg_type: &str,
|
||||
_msg: &Map<String, Value>,
|
||||
stream: &mut TcpStream,
|
||||
_id: StreamId,
|
||||
) -> Result<ActorMessageStatus, ()> {
|
||||
Ok(match msg_type {
|
||||
) -> Result<(), ActorError> {
|
||||
match msg_type {
|
||||
"getDescription" => {
|
||||
let msg = GetDescriptionReply {
|
||||
from: self.name(),
|
||||
|
@ -64,12 +62,12 @@ impl Actor for DeviceActor {
|
|||
brand_name: "Servo".to_string(),
|
||||
},
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
|
||||
_ => ActorMessageStatus::Ignored,
|
||||
})
|
||||
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::mem;
|
||||
use std::net::TcpStream;
|
||||
|
||||
use base::id::PipelineId;
|
||||
use devtools_traits::DevtoolScriptControlMsg;
|
||||
|
@ -11,8 +10,9 @@ use ipc_channel::ipc::IpcSender;
|
|||
use serde_json::{Map, Value};
|
||||
|
||||
use crate::StreamId;
|
||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
||||
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||
use crate::actors::timeline::HighResolutionStamp;
|
||||
use crate::protocol::ClientRequest;
|
||||
|
||||
pub struct FramerateActor {
|
||||
name: String,
|
||||
|
@ -29,13 +29,13 @@ impl Actor for FramerateActor {
|
|||
|
||||
fn handle_message(
|
||||
&self,
|
||||
_request: ClientRequest,
|
||||
_registry: &ActorRegistry,
|
||||
_msg_type: &str,
|
||||
_msg: &Map<String, Value>,
|
||||
_stream: &mut TcpStream,
|
||||
_id: StreamId,
|
||||
) -> Result<ActorMessageStatus, ()> {
|
||||
Ok(ActorMessageStatus::Ignored)
|
||||
) -> Result<(), ActorError> {
|
||||
Err(ActorError::UnrecognizedPacketType)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::net::TcpStream;
|
||||
|
||||
use devtools_traits::DevtoolScriptControlMsg;
|
||||
use devtools_traits::DevtoolScriptControlMsg::GetRootNode;
|
||||
|
@ -15,13 +14,13 @@ use serde::Serialize;
|
|||
use serde_json::{self, Map, Value};
|
||||
|
||||
use crate::StreamId;
|
||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
||||
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||
use crate::actors::browsing_context::BrowsingContextActor;
|
||||
use crate::actors::inspector::highlighter::{HighlighterActor, HighlighterMsg};
|
||||
use crate::actors::inspector::node::NodeInfoToProtocol;
|
||||
use crate::actors::inspector::page_style::{PageStyleActor, PageStyleMsg};
|
||||
use crate::actors::inspector::walker::{WalkerActor, WalkerMsg};
|
||||
use crate::protocol::JsonPacketStream;
|
||||
use crate::protocol::ClientRequest;
|
||||
|
||||
pub mod accessibility;
|
||||
pub mod css_properties;
|
||||
|
@ -73,19 +72,19 @@ impl Actor for InspectorActor {
|
|||
|
||||
fn handle_message(
|
||||
&self,
|
||||
request: ClientRequest,
|
||||
registry: &ActorRegistry,
|
||||
msg_type: &str,
|
||||
_msg: &Map<String, Value>,
|
||||
stream: &mut TcpStream,
|
||||
_id: StreamId,
|
||||
) -> Result<ActorMessageStatus, ()> {
|
||||
) -> Result<(), ActorError> {
|
||||
let browsing_context = registry.find::<BrowsingContextActor>(&self.browsing_context);
|
||||
let pipeline = browsing_context.active_pipeline_id.get();
|
||||
Ok(match msg_type {
|
||||
match msg_type {
|
||||
"getWalker" => {
|
||||
let (tx, rx) = ipc::channel().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
|
||||
.walker
|
||||
|
@ -121,8 +120,7 @@ impl Actor for InspectorActor {
|
|||
root,
|
||||
},
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
|
||||
"getPageStyle" => {
|
||||
|
@ -149,8 +147,7 @@ impl Actor for InspectorActor {
|
|||
]),
|
||||
},
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
|
||||
"supportsHighlighters" => {
|
||||
|
@ -158,8 +155,7 @@ impl Actor for InspectorActor {
|
|||
from: self.name(),
|
||||
value: true,
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
|
||||
"getHighlighterByType" => {
|
||||
|
@ -180,11 +176,10 @@ impl Actor for InspectorActor {
|
|||
actor: self.highlighter.borrow().clone().unwrap(),
|
||||
},
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
|
||||
_ => ActorMessageStatus::Ignored,
|
||||
})
|
||||
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,14 +5,12 @@
|
|||
//! The Accessibility actor is responsible for the Accessibility tab in the DevTools page. Right
|
||||
//! now it is a placeholder for future functionality.
|
||||
|
||||
use std::net::TcpStream;
|
||||
|
||||
use serde::Serialize;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
use crate::StreamId;
|
||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
||||
use crate::protocol::JsonPacketStream;
|
||||
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||
use crate::protocol::ClientRequest;
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct BootstrapState {
|
||||
|
@ -75,20 +73,19 @@ impl Actor for AccessibilityActor {
|
|||
/// inspector Walker actor)
|
||||
fn handle_message(
|
||||
&self,
|
||||
request: ClientRequest,
|
||||
registry: &ActorRegistry,
|
||||
msg_type: &str,
|
||||
_msg: &Map<String, Value>,
|
||||
stream: &mut TcpStream,
|
||||
_id: StreamId,
|
||||
) -> Result<ActorMessageStatus, ()> {
|
||||
Ok(match msg_type {
|
||||
) -> Result<(), ActorError> {
|
||||
match msg_type {
|
||||
"bootstrap" => {
|
||||
let msg = BootstrapReply {
|
||||
from: self.name(),
|
||||
state: BootstrapState { enabled: false },
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
"getSimulator" => {
|
||||
// TODO: Create actual simulator
|
||||
|
@ -97,8 +94,7 @@ impl Actor for AccessibilityActor {
|
|||
from: self.name(),
|
||||
simulator: ActorMsg { actor: simulator },
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
"getTraits" => {
|
||||
let msg = GetTraitsReply {
|
||||
|
@ -107,8 +103,7 @@ impl Actor for AccessibilityActor {
|
|||
tabbing_order: true,
|
||||
},
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
"getWalker" => {
|
||||
// TODO: Create actual accessible walker
|
||||
|
@ -117,11 +112,11 @@ impl Actor for AccessibilityActor {
|
|||
from: self.name(),
|
||||
walker: ActorMsg { actor: walker },
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
_ => ActorMessageStatus::Ignored,
|
||||
})
|
||||
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,15 +6,14 @@
|
|||
//! alternative names
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::net::TcpStream;
|
||||
|
||||
use devtools_traits::CssDatabaseProperty;
|
||||
use serde::Serialize;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
use crate::StreamId;
|
||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
||||
use crate::protocol::JsonPacketStream;
|
||||
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||
use crate::protocol::ClientRequest;
|
||||
|
||||
pub struct CssPropertiesActor {
|
||||
name: String,
|
||||
|
@ -38,23 +37,20 @@ impl Actor for CssPropertiesActor {
|
|||
/// inspector can show the available options
|
||||
fn handle_message(
|
||||
&self,
|
||||
request: ClientRequest,
|
||||
_registry: &ActorRegistry,
|
||||
msg_type: &str,
|
||||
_msg: &Map<String, Value>,
|
||||
stream: &mut TcpStream,
|
||||
_id: StreamId,
|
||||
) -> Result<ActorMessageStatus, ()> {
|
||||
Ok(match msg_type {
|
||||
"getCSSDatabase" => {
|
||||
let _ = stream.write_json_packet(&GetCssDatabaseReply {
|
||||
from: self.name(),
|
||||
properties: &self.properties,
|
||||
});
|
||||
|
||||
ActorMessageStatus::Processed
|
||||
},
|
||||
_ => ActorMessageStatus::Ignored,
|
||||
})
|
||||
) -> Result<(), ActorError> {
|
||||
match msg_type {
|
||||
"getCSSDatabase" => request.reply_final(&GetCssDatabaseReply {
|
||||
from: self.name(),
|
||||
properties: &self.properties,
|
||||
})?,
|
||||
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,16 +5,14 @@
|
|||
//! Handles highlighting selected DOM nodes in the inspector. At the moment it only replies and
|
||||
//! changes nothing on Servo's side.
|
||||
|
||||
use std::net::TcpStream;
|
||||
|
||||
use base::id::PipelineId;
|
||||
use devtools_traits::DevtoolScriptControlMsg;
|
||||
use ipc_channel::ipc::IpcSender;
|
||||
use serde::Serialize;
|
||||
use serde_json::{self, Map, Value};
|
||||
|
||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
||||
use crate::protocol::JsonPacketStream;
|
||||
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||
use crate::protocol::ClientRequest;
|
||||
use crate::{EmptyReplyMsg, StreamId};
|
||||
|
||||
#[derive(Serialize)]
|
||||
|
@ -46,22 +44,20 @@ impl Actor for HighlighterActor {
|
|||
/// - `hide`: Disables highlighting for the selected node
|
||||
fn handle_message(
|
||||
&self,
|
||||
request: ClientRequest,
|
||||
registry: &ActorRegistry,
|
||||
msg_type: &str,
|
||||
msg: &Map<String, Value>,
|
||||
stream: &mut TcpStream,
|
||||
_id: StreamId,
|
||||
) -> Result<ActorMessageStatus, ()> {
|
||||
Ok(match msg_type {
|
||||
) -> Result<(), ActorError> {
|
||||
match msg_type {
|
||||
"show" => {
|
||||
let Some(node_actor) = msg.get("node") else {
|
||||
// TODO: send missing parameter error
|
||||
return Ok(ActorMessageStatus::Ignored);
|
||||
return Err(ActorError::MissingParameter);
|
||||
};
|
||||
|
||||
let Some(node_actor_name) = node_actor.as_str() else {
|
||||
// TODO: send invalid parameter error
|
||||
return Ok(ActorMessageStatus::Ignored);
|
||||
return Err(ActorError::BadParameterType);
|
||||
};
|
||||
|
||||
if node_actor_name.starts_with("inspector") {
|
||||
|
@ -71,8 +67,7 @@ impl Actor for HighlighterActor {
|
|||
from: self.name(),
|
||||
value: false,
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
return Ok(ActorMessageStatus::Processed);
|
||||
return request.reply_final(&msg);
|
||||
}
|
||||
|
||||
self.instruct_script_thread_to_highlight_node(
|
||||
|
@ -83,20 +78,19 @@ impl Actor for HighlighterActor {
|
|||
from: self.name(),
|
||||
value: true,
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
|
||||
"hide" => {
|
||||
self.instruct_script_thread_to_highlight_node(None, registry);
|
||||
|
||||
let msg = EmptyReplyMsg { from: self.name() };
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
|
||||
_ => 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
|
||||
//! grids or flexboxes. It acts as a placeholder for now.
|
||||
|
||||
use std::net::TcpStream;
|
||||
|
||||
use serde::Serialize;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
use crate::StreamId;
|
||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
||||
use crate::protocol::JsonPacketStream;
|
||||
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||
use crate::protocol::ClientRequest;
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct LayoutInspectorActorMsg {
|
||||
|
@ -47,21 +45,20 @@ impl Actor for LayoutInspectorActor {
|
|||
/// - `getCurrentFlexbox`: Returns the active flexbox, non functional at the moment
|
||||
fn handle_message(
|
||||
&self,
|
||||
request: ClientRequest,
|
||||
_registry: &ActorRegistry,
|
||||
msg_type: &str,
|
||||
_msg: &Map<String, Value>,
|
||||
stream: &mut TcpStream,
|
||||
_id: StreamId,
|
||||
) -> Result<ActorMessageStatus, ()> {
|
||||
Ok(match msg_type {
|
||||
) -> Result<(), ActorError> {
|
||||
match msg_type {
|
||||
"getGrids" => {
|
||||
let msg = GetGridsReply {
|
||||
from: self.name(),
|
||||
// TODO: Actually create a list of grids
|
||||
grids: vec![],
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
"getCurrentFlexbox" => {
|
||||
let msg = GetCurrentFlexboxReply {
|
||||
|
@ -69,12 +66,14 @@ impl Actor for LayoutInspectorActor {
|
|||
// TODO: Create and return the current flexbox object
|
||||
flexbox: None,
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
_ => ActorMessageStatus::Ignored,
|
||||
})
|
||||
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn cleanup(&self, _id: StreamId) {}
|
||||
}
|
||||
|
||||
impl LayoutInspectorActor {
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::net::TcpStream;
|
||||
|
||||
use base::id::PipelineId;
|
||||
use devtools_traits::DevtoolScriptControlMsg::{GetChildren, GetDocumentElement, ModifyAttribute};
|
||||
|
@ -16,9 +15,9 @@ use ipc_channel::ipc::{self, IpcSender};
|
|||
use serde::Serialize;
|
||||
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::protocol::JsonPacketStream;
|
||||
use crate::protocol::ClientRequest;
|
||||
use crate::{EmptyReplyMsg, StreamId};
|
||||
|
||||
/// 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
|
||||
fn handle_message(
|
||||
&self,
|
||||
mut request: ClientRequest,
|
||||
registry: &ActorRegistry,
|
||||
msg_type: &str,
|
||||
msg: &Map<String, Value>,
|
||||
stream: &mut TcpStream,
|
||||
_id: StreamId,
|
||||
) -> Result<ActorMessageStatus, ()> {
|
||||
Ok(match msg_type {
|
||||
) -> Result<(), ActorError> {
|
||||
match msg_type {
|
||||
"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
|
||||
.iter()
|
||||
.filter_map(|json_mod| {
|
||||
|
@ -130,7 +133,7 @@ impl Actor for NodeActor {
|
|||
.collect();
|
||||
|
||||
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
|
||||
.send(ModifyAttribute(
|
||||
|
@ -138,11 +141,10 @@ impl Actor for NodeActor {
|
|||
registry.actor_to_script(self.name()),
|
||||
modifications,
|
||||
))
|
||||
.map_err(|_| ())?;
|
||||
.map_err(|_| ActorError::Internal)?;
|
||||
|
||||
let reply = EmptyReplyMsg { from: self.name() };
|
||||
let _ = stream.write_json_packet(&reply);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&reply)?
|
||||
},
|
||||
|
||||
"getUniqueSelector" => {
|
||||
|
@ -150,7 +152,10 @@ impl Actor for NodeActor {
|
|||
self.script_chan
|
||||
.send(GetDocumentElement(self.pipeline, tx))
|
||||
.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(
|
||||
registry,
|
||||
true,
|
||||
|
@ -163,12 +168,12 @@ impl Actor for NodeActor {
|
|||
from: self.name(),
|
||||
value: node.display_name,
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
|
||||
_ => ActorMessageStatus::Ignored,
|
||||
})
|
||||
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
use std::collections::HashMap;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::iter::once;
|
||||
use std::net::TcpStream;
|
||||
|
||||
use base::id::PipelineId;
|
||||
use devtools_traits::DevtoolScriptControlMsg::{GetLayout, GetSelectors};
|
||||
|
@ -18,11 +17,11 @@ use serde::Serialize;
|
|||
use serde_json::{self, Map, Value};
|
||||
|
||||
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::style_rule::{AppliedRule, ComputedDeclaration, StyleRuleActor};
|
||||
use crate::actors::inspector::walker::{WalkerActor, find_child};
|
||||
use crate::protocol::JsonPacketStream;
|
||||
use crate::protocol::ClientRequest;
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct GetAppliedReply {
|
||||
|
@ -114,30 +113,34 @@ impl Actor for PageStyleActor {
|
|||
/// - `isPositionEditable`: Informs whether you can change a style property in the inspector.
|
||||
fn handle_message(
|
||||
&self,
|
||||
request: ClientRequest,
|
||||
registry: &ActorRegistry,
|
||||
msg_type: &str,
|
||||
msg: &Map<String, Value>,
|
||||
stream: &mut TcpStream,
|
||||
_id: StreamId,
|
||||
) -> Result<ActorMessageStatus, ()> {
|
||||
Ok(match msg_type {
|
||||
"getApplied" => self.get_applied(msg, registry, stream)?,
|
||||
"getComputed" => self.get_computed(msg, registry, stream)?,
|
||||
"getLayout" => self.get_layout(msg, registry, stream)?,
|
||||
"isPositionEditable" => self.is_position_editable(stream),
|
||||
_ => ActorMessageStatus::Ignored,
|
||||
})
|
||||
) -> Result<(), ActorError> {
|
||||
match msg_type {
|
||||
"getApplied" => self.get_applied(request, msg, registry),
|
||||
"getComputed" => self.get_computed(request, msg, registry),
|
||||
"getLayout" => self.get_layout(request, msg, registry),
|
||||
"isPositionEditable" => self.is_position_editable(request),
|
||||
_ => Err(ActorError::UnrecognizedPacketType),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PageStyleActor {
|
||||
fn get_applied(
|
||||
&self,
|
||||
request: ClientRequest,
|
||||
msg: &Map<String, Value>,
|
||||
registry: &ActorRegistry,
|
||||
stream: &mut TcpStream,
|
||||
) -> Result<ActorMessageStatus, ()> {
|
||||
let target = msg.get("node").ok_or(())?.as_str().ok_or(())?;
|
||||
) -> Result<(), ActorError> {
|
||||
let target = msg
|
||||
.get("node")
|
||||
.ok_or(ActorError::MissingParameter)?
|
||||
.as_str()
|
||||
.ok_or(ActorError::BadParameterType)?;
|
||||
let node = registry.find::<NodeActor>(target);
|
||||
let walker = registry.find::<WalkerActor>(&node.walker);
|
||||
let entries: Vec<_> = find_child(
|
||||
|
@ -214,17 +217,20 @@ impl PageStyleActor {
|
|||
entries,
|
||||
from: self.name(),
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
Ok(ActorMessageStatus::Processed)
|
||||
request.reply_final(&msg)
|
||||
}
|
||||
|
||||
fn get_computed(
|
||||
&self,
|
||||
request: ClientRequest,
|
||||
msg: &Map<String, Value>,
|
||||
registry: &ActorRegistry,
|
||||
stream: &mut TcpStream,
|
||||
) -> Result<ActorMessageStatus, ()> {
|
||||
let target = msg.get("node").ok_or(())?.as_str().ok_or(())?;
|
||||
) -> Result<(), ActorError> {
|
||||
let target = msg
|
||||
.get("node")
|
||||
.ok_or(ActorError::MissingParameter)?
|
||||
.as_str()
|
||||
.ok_or(ActorError::BadParameterType)?;
|
||||
let node_actor = registry.find::<NodeActor>(target);
|
||||
let computed = (|| match node_actor
|
||||
.style_rules
|
||||
|
@ -249,18 +255,22 @@ impl PageStyleActor {
|
|||
computed,
|
||||
from: self.name(),
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
Ok(ActorMessageStatus::Processed)
|
||||
request.reply_final(&msg)
|
||||
}
|
||||
|
||||
fn get_layout(
|
||||
&self,
|
||||
request: ClientRequest,
|
||||
msg: &Map<String, Value>,
|
||||
registry: &ActorRegistry,
|
||||
stream: &mut TcpStream,
|
||||
) -> Result<ActorMessageStatus, ()> {
|
||||
let target = msg.get("node").ok_or(())?.as_str().ok_or(())?;
|
||||
let (computed_node_sender, computed_node_receiver) = ipc::channel().map_err(|_| ())?;
|
||||
) -> Result<(), ActorError> {
|
||||
let target = msg
|
||||
.get("node")
|
||||
.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
|
||||
.send(GetLayout(
|
||||
self.pipeline,
|
||||
|
@ -288,7 +298,10 @@ impl PageStyleActor {
|
|||
padding_left,
|
||||
width,
|
||||
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
|
||||
.get("autoMargins")
|
||||
.and_then(Value::as_bool)
|
||||
|
@ -333,18 +346,16 @@ impl PageStyleActor {
|
|||
width,
|
||||
height,
|
||||
};
|
||||
let msg = serde_json::to_string(&msg).map_err(|_| ())?;
|
||||
let msg = serde_json::from_str::<Value>(&msg).map_err(|_| ())?;
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
Ok(ActorMessageStatus::Processed)
|
||||
let msg = serde_json::to_string(&msg).map_err(|_| ActorError::Internal)?;
|
||||
let msg = serde_json::from_str::<Value>(&msg).map_err(|_| ActorError::Internal)?;
|
||||
request.reply_final(&msg)
|
||||
}
|
||||
|
||||
fn is_position_editable(&self, stream: &mut TcpStream) -> ActorMessageStatus {
|
||||
fn is_position_editable(&self, request: ClientRequest) -> Result<(), ActorError> {
|
||||
let msg = IsPositionEditableReply {
|
||||
from: self.name(),
|
||||
value: false,
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
//! A group is either the html style attribute or one selector from one stylesheet.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::net::TcpStream;
|
||||
|
||||
use devtools_traits::DevtoolScriptControlMsg::{
|
||||
GetAttributeStyle, GetComputedStyle, GetDocumentElement, GetStylesheetStyle, ModifyRule,
|
||||
|
@ -17,10 +16,10 @@ use serde::Serialize;
|
|||
use serde_json::{Map, Value};
|
||||
|
||||
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::walker::WalkerActor;
|
||||
use crate::protocol::JsonPacketStream;
|
||||
use crate::protocol::ClientRequest;
|
||||
|
||||
const ELEMENT_STYLE_TYPE: u32 = 100;
|
||||
|
||||
|
@ -98,16 +97,20 @@ impl Actor for StyleRuleActor {
|
|||
/// when returning the list of rules.
|
||||
fn handle_message(
|
||||
&self,
|
||||
request: ClientRequest,
|
||||
registry: &ActorRegistry,
|
||||
msg_type: &str,
|
||||
msg: &Map<String, Value>,
|
||||
stream: &mut TcpStream,
|
||||
_id: StreamId,
|
||||
) -> Result<ActorMessageStatus, ()> {
|
||||
Ok(match msg_type {
|
||||
) -> Result<(), ActorError> {
|
||||
match msg_type {
|
||||
"setRuleText" => {
|
||||
// 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
|
||||
.iter()
|
||||
.filter_map(|json_mod| {
|
||||
|
@ -125,13 +128,13 @@ impl Actor for StyleRuleActor {
|
|||
registry.actor_to_script(self.node.clone()),
|
||||
modifications,
|
||||
))
|
||||
.map_err(|_| ())?;
|
||||
.map_err(|_| ActorError::Internal)?;
|
||||
|
||||
let _ = stream.write_json_packet(&self.encodable(registry));
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&self.encodable(registry))?
|
||||
},
|
||||
_ => 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
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::net::TcpStream;
|
||||
|
||||
use base::id::PipelineId;
|
||||
use devtools_traits::DevtoolScriptControlMsg::{GetChildren, GetDocumentElement};
|
||||
|
@ -14,10 +13,10 @@ use ipc_channel::ipc::{self, IpcSender};
|
|||
use serde::Serialize;
|
||||
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::node::{NodeActorMsg, NodeInfoToProtocol};
|
||||
use crate::protocol::JsonPacketStream;
|
||||
use crate::protocol::{ClientRequest, JsonPacketStream};
|
||||
use crate::{EmptyReplyMsg, StreamId};
|
||||
|
||||
#[derive(Serialize)]
|
||||
|
@ -64,7 +63,7 @@ struct GetLayoutInspectorReply {
|
|||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct WatchRootNodeReply {
|
||||
struct WatchRootNodeNotification {
|
||||
#[serde(rename = "type")]
|
||||
type_: String,
|
||||
from: String,
|
||||
|
@ -94,7 +93,7 @@ struct GetOffsetParentReply {
|
|||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct NewMutationsReply {
|
||||
struct NewMutationsNotification {
|
||||
from: String,
|
||||
#[serde(rename = "type")]
|
||||
type_: String,
|
||||
|
@ -123,24 +122,31 @@ impl Actor for WalkerActor {
|
|||
/// node and its ascendents
|
||||
fn handle_message(
|
||||
&self,
|
||||
mut request: ClientRequest,
|
||||
registry: &ActorRegistry,
|
||||
msg_type: &str,
|
||||
msg: &Map<String, Value>,
|
||||
stream: &mut TcpStream,
|
||||
_id: StreamId,
|
||||
) -> Result<ActorMessageStatus, ()> {
|
||||
Ok(match msg_type {
|
||||
) -> Result<(), ActorError> {
|
||||
match msg_type {
|
||||
"children" => {
|
||||
let target = msg.get("node").ok_or(())?.as_str().ok_or(())?;
|
||||
let (tx, rx) = ipc::channel().map_err(|_| ())?;
|
||||
let target = msg
|
||||
.get("node")
|
||||
.ok_or(ActorError::MissingParameter)?
|
||||
.as_str()
|
||||
.ok_or(ActorError::BadParameterType)?;
|
||||
let (tx, rx) = ipc::channel().map_err(|_| ActorError::Internal)?;
|
||||
self.script_chan
|
||||
.send(GetChildren(
|
||||
self.pipeline,
|
||||
registry.actor_to_script(target.into()),
|
||||
tx,
|
||||
))
|
||||
.map_err(|_| ())?;
|
||||
let children = rx.recv().map_err(|_| ())?.ok_or(())?;
|
||||
.map_err(|_| ActorError::Internal)?;
|
||||
let children = rx
|
||||
.recv()
|
||||
.map_err(|_| ActorError::Internal)?
|
||||
.ok_or(ActorError::Internal)?;
|
||||
|
||||
let msg = ChildrenReply {
|
||||
has_first: true,
|
||||
|
@ -159,20 +165,21 @@ impl Actor for WalkerActor {
|
|||
.collect(),
|
||||
from: self.name(),
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
"clearPseudoClassLocks" => {
|
||||
let msg = EmptyReplyMsg { from: self.name() };
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
"documentElement" => {
|
||||
let (tx, rx) = ipc::channel().map_err(|_| ())?;
|
||||
let (tx, rx) = ipc::channel().map_err(|_| ActorError::Internal)?;
|
||||
self.script_chan
|
||||
.send(GetDocumentElement(self.pipeline, tx))
|
||||
.map_err(|_| ())?;
|
||||
let doc_elem_info = rx.recv().map_err(|_| ())?.ok_or(())?;
|
||||
.map_err(|_| ActorError::Internal)?;
|
||||
let doc_elem_info = rx
|
||||
.recv()
|
||||
.map_err(|_| ActorError::Internal)?
|
||||
.ok_or(ActorError::Internal)?;
|
||||
let node = doc_elem_info.encode(
|
||||
registry,
|
||||
true,
|
||||
|
@ -185,8 +192,7 @@ impl Actor for WalkerActor {
|
|||
from: self.name(),
|
||||
node,
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
"getLayoutInspector" => {
|
||||
// TODO: Create actual layout inspector actor
|
||||
|
@ -198,8 +204,7 @@ impl Actor for WalkerActor {
|
|||
from: self.name(),
|
||||
actor,
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
"getMutations" => {
|
||||
let msg = GetMutationsReply {
|
||||
|
@ -216,20 +221,26 @@ impl Actor for WalkerActor {
|
|||
})
|
||||
.collect(),
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
"getOffsetParent" => {
|
||||
let msg = GetOffsetParentReply {
|
||||
from: self.name(),
|
||||
node: None,
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
"querySelector" => {
|
||||
let selector = msg.get("selector").ok_or(())?.as_str().ok_or(())?;
|
||||
let node = msg.get("node").ok_or(())?.as_str().ok_or(())?;
|
||||
let selector = msg
|
||||
.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(
|
||||
&self.script_chan,
|
||||
self.pipeline,
|
||||
|
@ -239,39 +250,38 @@ impl Actor for WalkerActor {
|
|||
vec![],
|
||||
|msg| msg.display_name == selector,
|
||||
)
|
||||
.map_err(|_| ())?;
|
||||
.map_err(|_| ActorError::Internal)?;
|
||||
hierarchy.reverse();
|
||||
let node = hierarchy.pop().ok_or(())?;
|
||||
let node = hierarchy.pop().ok_or(ActorError::Internal)?;
|
||||
|
||||
let msg = QuerySelectorReply {
|
||||
from: self.name(),
|
||||
node,
|
||||
new_parents: hierarchy,
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
"watchRootNode" => {
|
||||
let msg = WatchRootNodeReply {
|
||||
let msg = WatchRootNodeNotification {
|
||||
type_: "root-available".into(),
|
||||
from: self.name(),
|
||||
node: self.root_node.clone(),
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
let _ = request.write_json_packet(&msg);
|
||||
|
||||
let msg = EmptyReplyMsg { from: self.name() };
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
_ => ActorMessageStatus::Ignored,
|
||||
})
|
||||
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl WalkerActor {
|
||||
pub(crate) fn new_mutations(
|
||||
&self,
|
||||
stream: &mut TcpStream,
|
||||
request: &mut ClientRequest,
|
||||
target: &str,
|
||||
modifications: &[AttrModification],
|
||||
) {
|
||||
|
@ -279,7 +289,7 @@ impl WalkerActor {
|
|||
let mut mutations = self.mutations.borrow_mut();
|
||||
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(),
|
||||
type_: "newMutations".into(),
|
||||
});
|
||||
|
|
|
@ -2,13 +2,12 @@
|
|||
* 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/. */
|
||||
|
||||
use std::net::TcpStream;
|
||||
|
||||
use serde::Serialize;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
use crate::StreamId;
|
||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
||||
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||
use crate::protocol::ClientRequest;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
|
@ -36,13 +35,13 @@ impl Actor for MemoryActor {
|
|||
|
||||
fn handle_message(
|
||||
&self,
|
||||
_request: ClientRequest,
|
||||
_registry: &ActorRegistry,
|
||||
_msg_type: &str,
|
||||
_msg: &Map<String, Value>,
|
||||
_stream: &mut TcpStream,
|
||||
_id: StreamId,
|
||||
) -> Result<ActorMessageStatus, ()> {
|
||||
Ok(ActorMessageStatus::Ignored)
|
||||
) -> Result<(), ActorError> {
|
||||
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).
|
||||
//! 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 chrono::{Local, LocalResult, TimeZone};
|
||||
|
@ -16,9 +15,9 @@ use serde::Serialize;
|
|||
use serde_json::{Map, Value};
|
||||
|
||||
use crate::StreamId;
|
||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
||||
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||
use crate::network_handler::Cause;
|
||||
use crate::protocol::JsonPacketStream;
|
||||
use crate::protocol::ClientRequest;
|
||||
|
||||
pub struct NetworkEventActor {
|
||||
pub name: String,
|
||||
|
@ -202,13 +201,13 @@ impl Actor for NetworkEventActor {
|
|||
|
||||
fn handle_message(
|
||||
&self,
|
||||
request: ClientRequest,
|
||||
_registry: &ActorRegistry,
|
||||
msg_type: &str,
|
||||
_msg: &Map<String, Value>,
|
||||
stream: &mut TcpStream,
|
||||
_id: StreamId,
|
||||
) -> Result<ActorMessageStatus, ()> {
|
||||
Ok(match msg_type {
|
||||
) -> Result<(), ActorError> {
|
||||
match msg_type {
|
||||
"getRequestHeaders" => {
|
||||
let mut headers = Vec::new();
|
||||
let mut raw_headers_string = "".to_owned();
|
||||
|
@ -232,8 +231,7 @@ impl Actor for NetworkEventActor {
|
|||
header_size: headers_size,
|
||||
raw_headers: raw_headers_string,
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
"getRequestCookies" => {
|
||||
let mut cookies = Vec::new();
|
||||
|
@ -248,8 +246,7 @@ impl Actor for NetworkEventActor {
|
|||
from: self.name(),
|
||||
cookies,
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
"getRequestPostData" => {
|
||||
let msg = GetRequestPostDataReply {
|
||||
|
@ -257,8 +254,7 @@ impl Actor for NetworkEventActor {
|
|||
post_data: self.request_body.clone(),
|
||||
post_data_discarded: self.request_body.is_none(),
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
"getResponseHeaders" => {
|
||||
if let Some(ref response_headers) = self.response_headers_raw {
|
||||
|
@ -282,9 +278,11 @@ impl Actor for NetworkEventActor {
|
|||
header_size: headers_size,
|
||||
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" => {
|
||||
let mut cookies = Vec::new();
|
||||
|
@ -300,8 +298,7 @@ impl Actor for NetworkEventActor {
|
|||
from: self.name(),
|
||||
cookies,
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
"getResponseContent" => {
|
||||
let msg = GetResponseContentReply {
|
||||
|
@ -309,8 +306,7 @@ impl Actor for NetworkEventActor {
|
|||
content: self.response_body.clone(),
|
||||
content_discarded: self.response_body.is_none(),
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
"getEventTimings" => {
|
||||
// TODO: This is a fake timings msg
|
||||
|
@ -323,8 +319,7 @@ impl Actor for NetworkEventActor {
|
|||
timings: timings_obj,
|
||||
total_time: total,
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
"getSecurityInfo" => {
|
||||
// TODO: Send the correct values for securityInfo.
|
||||
|
@ -334,11 +329,11 @@ impl Actor for NetworkEventActor {
|
|||
state: "insecure".to_owned(),
|
||||
},
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
_ => 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
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::net::TcpStream;
|
||||
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
use crate::StreamId;
|
||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
||||
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||
use crate::protocol::ClientRequest;
|
||||
|
||||
pub struct ObjectActor {
|
||||
pub name: String,
|
||||
|
@ -20,14 +19,14 @@ impl Actor for ObjectActor {
|
|||
}
|
||||
fn handle_message(
|
||||
&self,
|
||||
_request: ClientRequest,
|
||||
_: &ActorRegistry,
|
||||
_: &str,
|
||||
_: &Map<String, Value>,
|
||||
_: &mut TcpStream,
|
||||
_: StreamId,
|
||||
) -> Result<ActorMessageStatus, ()> {
|
||||
) -> Result<(), ActorError> {
|
||||
// TODO: Handle enumSymbols for console object inspection
|
||||
Ok(ActorMessageStatus::Ignored)
|
||||
Err(ActorError::UnrecognizedPacketType)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,14 +5,12 @@
|
|||
// TODO: Is this actor still relevant?
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::net::TcpStream;
|
||||
|
||||
use serde::Serialize;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
use crate::StreamId;
|
||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
||||
use crate::protocol::{ActorDescription, JsonPacketStream, Method};
|
||||
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||
use crate::protocol::{ActorDescription, ClientRequest, Method};
|
||||
|
||||
pub struct PerformanceActor {
|
||||
name: String,
|
||||
|
@ -62,13 +60,13 @@ impl Actor for PerformanceActor {
|
|||
|
||||
fn handle_message(
|
||||
&self,
|
||||
request: ClientRequest,
|
||||
_registry: &ActorRegistry,
|
||||
msg_type: &str,
|
||||
_msg: &Map<String, Value>,
|
||||
stream: &mut TcpStream,
|
||||
_id: StreamId,
|
||||
) -> Result<ActorMessageStatus, ()> {
|
||||
Ok(match msg_type {
|
||||
) -> Result<(), ActorError> {
|
||||
match msg_type {
|
||||
"connect" => {
|
||||
let msg = ConnectReply {
|
||||
from: self.name(),
|
||||
|
@ -82,8 +80,7 @@ impl Actor for PerformanceActor {
|
|||
},
|
||||
},
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
"canCurrentlyRecord" => {
|
||||
let msg = CanCurrentlyRecordReply {
|
||||
|
@ -93,11 +90,11 @@ impl Actor for PerformanceActor {
|
|||
errors: vec![],
|
||||
},
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
_ => 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
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::net::TcpStream;
|
||||
|
||||
use log::warn;
|
||||
use serde::Serialize;
|
||||
use serde_json::{Map, Value};
|
||||
use servo_config::pref;
|
||||
|
||||
use crate::StreamId;
|
||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
||||
use crate::protocol::JsonPacketStream;
|
||||
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||
use crate::protocol::ClientRequest;
|
||||
|
||||
pub struct PreferenceActor {
|
||||
name: String,
|
||||
|
@ -30,43 +27,44 @@ impl Actor for PreferenceActor {
|
|||
|
||||
fn handle_message(
|
||||
&self,
|
||||
request: ClientRequest,
|
||||
_registry: &ActorRegistry,
|
||||
msg_type: &str,
|
||||
msg: &Map<String, Value>,
|
||||
stream: &mut TcpStream,
|
||||
_id: StreamId,
|
||||
) -> Result<ActorMessageStatus, ()> {
|
||||
let Some(key) = msg.get("value").and_then(|v| v.as_str()) else {
|
||||
warn!("PreferenceActor: handle_message: value is not a string");
|
||||
return Ok(ActorMessageStatus::Ignored);
|
||||
};
|
||||
) -> Result<(), ActorError> {
|
||||
let key = msg
|
||||
.get("value")
|
||||
.ok_or(ActorError::MissingParameter)?
|
||||
.as_str()
|
||||
.ok_or(ActorError::BadParameterType)?;
|
||||
|
||||
// TODO: Map more preferences onto their Servo values.
|
||||
Ok(match key {
|
||||
match key {
|
||||
"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 {
|
||||
fn handle_missing_preference(
|
||||
&self,
|
||||
request: ClientRequest,
|
||||
msg_type: &str,
|
||||
stream: &mut TcpStream,
|
||||
) -> ActorMessageStatus {
|
||||
) -> Result<(), ActorError> {
|
||||
match msg_type {
|
||||
"getBoolPref" => self.write_bool(false, stream),
|
||||
"getCharPref" => self.write_char("".into(), stream),
|
||||
"getIntPref" => self.write_int(0, stream),
|
||||
"getFloatPref" => self.write_float(0., stream),
|
||||
_ => ActorMessageStatus::Ignored,
|
||||
"getBoolPref" => self.write_bool(request, false),
|
||||
"getCharPref" => self.write_char(request, "".into()),
|
||||
"getIntPref" => self.write_int(request, 0),
|
||||
"getFloatPref" => self.write_float(request, 0.),
|
||||
_ => 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)]
|
||||
struct BoolReply {
|
||||
from: String,
|
||||
|
@ -77,11 +75,10 @@ impl PreferenceActor {
|
|||
from: self.name.clone(),
|
||||
value: pref_value,
|
||||
};
|
||||
let _ = stream.write_json_packet(&reply);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&reply)
|
||||
}
|
||||
|
||||
fn write_char(&self, pref_value: String, stream: &mut TcpStream) -> ActorMessageStatus {
|
||||
fn write_char(&self, request: ClientRequest, pref_value: String) -> Result<(), ActorError> {
|
||||
#[derive(Serialize)]
|
||||
struct CharReply {
|
||||
from: String,
|
||||
|
@ -92,11 +89,10 @@ impl PreferenceActor {
|
|||
from: self.name.clone(),
|
||||
value: pref_value,
|
||||
};
|
||||
let _ = stream.write_json_packet(&reply);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&reply)
|
||||
}
|
||||
|
||||
fn write_int(&self, pref_value: i64, stream: &mut TcpStream) -> ActorMessageStatus {
|
||||
fn write_int(&self, request: ClientRequest, pref_value: i64) -> Result<(), ActorError> {
|
||||
#[derive(Serialize)]
|
||||
struct IntReply {
|
||||
from: String,
|
||||
|
@ -107,11 +103,10 @@ impl PreferenceActor {
|
|||
from: self.name.clone(),
|
||||
value: pref_value,
|
||||
};
|
||||
let _ = stream.write_json_packet(&reply);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&reply)
|
||||
}
|
||||
|
||||
fn write_float(&self, pref_value: f64, stream: &mut TcpStream) -> ActorMessageStatus {
|
||||
fn write_float(&self, request: ClientRequest, pref_value: f64) -> Result<(), ActorError> {
|
||||
#[derive(Serialize)]
|
||||
struct FloatReply {
|
||||
from: String,
|
||||
|
@ -122,7 +117,6 @@ impl PreferenceActor {
|
|||
from: self.name.clone(),
|
||||
value: pref_value,
|
||||
};
|
||||
let _ = stream.write_json_packet(&reply);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&reply)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,15 +6,13 @@
|
|||
//!
|
||||
//! [Firefox JS implementation]: https://searchfox.org/mozilla-central/source/devtools/server/actors/descriptors/process.js
|
||||
|
||||
use std::net::TcpStream;
|
||||
|
||||
use serde::Serialize;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
use crate::StreamId;
|
||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
||||
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||
use crate::actors::root::DescriptorTraits;
|
||||
use crate::protocol::JsonPacketStream;
|
||||
use crate::protocol::ClientRequest;
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct ListWorkersReply {
|
||||
|
@ -46,24 +44,24 @@ impl Actor for ProcessActor {
|
|||
/// - `listWorkers`: Returns a list of web workers, not supported yet.
|
||||
fn handle_message(
|
||||
&self,
|
||||
request: ClientRequest,
|
||||
_registry: &ActorRegistry,
|
||||
msg_type: &str,
|
||||
_msg: &Map<String, Value>,
|
||||
stream: &mut TcpStream,
|
||||
_id: StreamId,
|
||||
) -> Result<ActorMessageStatus, ()> {
|
||||
Ok(match msg_type {
|
||||
) -> Result<(), ActorError> {
|
||||
match msg_type {
|
||||
"listWorkers" => {
|
||||
let reply = ListWorkersReply {
|
||||
from: self.name(),
|
||||
workers: vec![],
|
||||
};
|
||||
let _ = stream.write_json_packet(&reply);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&reply)?
|
||||
},
|
||||
|
||||
_ => 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.
|
||||
|
||||
use std::net::TcpStream;
|
||||
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
use crate::StreamId;
|
||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
||||
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||
use crate::protocol::ClientRequest;
|
||||
use crate::{EmptyReplyMsg, StreamId};
|
||||
|
||||
pub struct ReflowActor {
|
||||
name: String,
|
||||
|
@ -25,20 +24,24 @@ impl Actor for ReflowActor {
|
|||
/// - `start`: Does nothing yet. This doesn't need a reply like other messages.
|
||||
fn handle_message(
|
||||
&self,
|
||||
request: ClientRequest,
|
||||
_registry: &ActorRegistry,
|
||||
msg_type: &str,
|
||||
_msg: &Map<String, Value>,
|
||||
_stream: &mut TcpStream,
|
||||
_id: StreamId,
|
||||
) -> Result<ActorMessageStatus, ()> {
|
||||
Ok(match msg_type {
|
||||
) -> Result<(), ActorError> {
|
||||
match msg_type {
|
||||
"start" => {
|
||||
// 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 {
|
||||
|
|
|
@ -10,19 +10,18 @@
|
|||
//! [Firefox JS implementation]: https://searchfox.org/mozilla-central/source/devtools/server/actors/root.js
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::net::TcpStream;
|
||||
|
||||
use serde::Serialize;
|
||||
use serde_json::{Map, Value, json};
|
||||
|
||||
use crate::StreamId;
|
||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
||||
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||
use crate::actors::device::DeviceActor;
|
||||
use crate::actors::performance::PerformanceActor;
|
||||
use crate::actors::process::{ProcessActor, ProcessActorMsg};
|
||||
use crate::actors::tab::{TabDescriptorActor, TabDescriptorActorMsg};
|
||||
use crate::actors::worker::{WorkerActor, WorkerMsg};
|
||||
use crate::protocol::{ActorDescription, JsonPacketStream};
|
||||
use crate::protocol::{ActorDescription, ClientRequest};
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
|
@ -116,13 +115,6 @@ struct GetProcessResponse {
|
|||
process_descriptor: ProcessActorMsg,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct ErrorResponse {
|
||||
from: String,
|
||||
error: String,
|
||||
message: String,
|
||||
}
|
||||
|
||||
pub struct RootActor {
|
||||
pub tabs: Vec<String>,
|
||||
pub workers: Vec<String>,
|
||||
|
@ -140,27 +132,25 @@ impl Actor for RootActor {
|
|||
|
||||
fn handle_message(
|
||||
&self,
|
||||
request: ClientRequest,
|
||||
registry: &ActorRegistry,
|
||||
msg_type: &str,
|
||||
msg: &Map<String, Value>,
|
||||
stream: &mut TcpStream,
|
||||
_id: StreamId,
|
||||
) -> Result<ActorMessageStatus, ()> {
|
||||
Ok(match msg_type {
|
||||
) -> Result<(), ActorError> {
|
||||
match msg_type {
|
||||
"connect" => {
|
||||
let message = json!({
|
||||
"from": "root",
|
||||
});
|
||||
let _ = stream.write_json_packet(&message);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&message)?
|
||||
},
|
||||
"listAddons" => {
|
||||
let actor = ListAddonsReply {
|
||||
from: "root".to_owned(),
|
||||
addons: vec![],
|
||||
};
|
||||
let _ = stream.write_json_packet(&actor);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&actor)?
|
||||
},
|
||||
|
||||
"listProcesses" => {
|
||||
|
@ -169,8 +159,7 @@ impl Actor for RootActor {
|
|||
from: self.name(),
|
||||
processes: vec![process],
|
||||
};
|
||||
let _ = stream.write_json_packet(&reply);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&reply)?
|
||||
},
|
||||
|
||||
// TODO: Unexpected message getTarget for process (when inspecting)
|
||||
|
@ -180,8 +169,7 @@ impl Actor for RootActor {
|
|||
from: self.name(),
|
||||
process_descriptor: process,
|
||||
};
|
||||
let _ = stream.write_json_packet(&reply);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&reply)?
|
||||
},
|
||||
|
||||
"getRoot" => {
|
||||
|
@ -192,8 +180,7 @@ impl Actor for RootActor {
|
|||
device_actor: self.device.clone(),
|
||||
preference_actor: self.preference.clone(),
|
||||
};
|
||||
let _ = stream.write_json_packet(&actor);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&actor)?
|
||||
},
|
||||
|
||||
"listTabs" => {
|
||||
|
@ -213,8 +200,7 @@ impl Actor for RootActor {
|
|||
})
|
||||
.collect(),
|
||||
};
|
||||
let _ = stream.write_json_packet(&actor);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&actor)?
|
||||
},
|
||||
|
||||
"listServiceWorkerRegistrations" => {
|
||||
|
@ -222,8 +208,7 @@ impl Actor for RootActor {
|
|||
from: self.name(),
|
||||
registrations: vec![],
|
||||
};
|
||||
let _ = stream.write_json_packet(&reply);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&reply)?
|
||||
},
|
||||
|
||||
"listWorkers" => {
|
||||
|
@ -235,26 +220,24 @@ impl Actor for RootActor {
|
|||
.map(|name| registry.find::<WorkerActor>(name).encodable())
|
||||
.collect(),
|
||||
};
|
||||
let _ = stream.write_json_packet(&reply);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&reply)?
|
||||
},
|
||||
|
||||
"getTab" => {
|
||||
let Some(serde_json::Value::Number(browser_id)) = msg.get("browserId") else {
|
||||
return Ok(ActorMessageStatus::Ignored);
|
||||
};
|
||||
|
||||
let browser_id = browser_id.as_u64().unwrap();
|
||||
let browser_id = msg
|
||||
.get("browserId")
|
||||
.ok_or(ActorError::MissingParameter)?
|
||||
.as_u64()
|
||||
.ok_or(ActorError::BadParameterType)?;
|
||||
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 {
|
||||
from: self.name(),
|
||||
tab,
|
||||
};
|
||||
let _ = stream.write_json_packet(&reply);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&reply)?
|
||||
},
|
||||
|
||||
"protocolDescription" => {
|
||||
|
@ -265,24 +248,12 @@ impl Actor for RootActor {
|
|||
device: DeviceActor::description(),
|
||||
},
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
|
||||
_ => {
|
||||
let reply = ErrorResponse {
|
||||
from: self.name(),
|
||||
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
|
||||
},
|
||||
})
|
||||
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
use std::cell::RefCell;
|
||||
use std::collections::BTreeSet;
|
||||
use std::net::TcpStream;
|
||||
|
||||
use base::id::PipelineId;
|
||||
use serde::Serialize;
|
||||
|
@ -12,8 +11,8 @@ use serde_json::{Map, Value};
|
|||
use servo_url::ServoUrl;
|
||||
|
||||
use crate::StreamId;
|
||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
||||
use crate::protocol::JsonPacketStream;
|
||||
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||
use crate::protocol::ClientRequest;
|
||||
|
||||
/// A `sourceForm` as used in responses to thread `sources` requests.
|
||||
///
|
||||
|
@ -134,13 +133,13 @@ impl Actor for SourceActor {
|
|||
|
||||
fn handle_message(
|
||||
&self,
|
||||
request: ClientRequest,
|
||||
_registry: &ActorRegistry,
|
||||
msg_type: &str,
|
||||
_msg: &Map<String, Value>,
|
||||
stream: &mut TcpStream,
|
||||
_id: StreamId,
|
||||
) -> Result<ActorMessageStatus, ()> {
|
||||
Ok(match msg_type {
|
||||
) -> Result<(), ActorError> {
|
||||
match msg_type {
|
||||
// Client has requested contents of the source.
|
||||
"source" => {
|
||||
let reply = SourceContentReply {
|
||||
|
@ -154,10 +153,10 @@ impl Actor for SourceActor {
|
|||
.unwrap_or("<!-- not available; please reload! -->")
|
||||
.to_owned(),
|
||||
};
|
||||
let _ = stream.write_json_packet(&reply);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&reply)?
|
||||
},
|
||||
_ => 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
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::net::TcpStream;
|
||||
|
||||
use serde::Serialize;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
use crate::StreamId;
|
||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
||||
use crate::protocol::JsonPacketStream;
|
||||
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||
use crate::protocol::ClientRequest;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
|
@ -28,24 +26,24 @@ impl Actor for StyleSheetsActor {
|
|||
}
|
||||
fn handle_message(
|
||||
&self,
|
||||
request: ClientRequest,
|
||||
_registry: &ActorRegistry,
|
||||
msg_type: &str,
|
||||
_msg: &Map<String, Value>,
|
||||
stream: &mut TcpStream,
|
||||
_id: StreamId,
|
||||
) -> Result<ActorMessageStatus, ()> {
|
||||
Ok(match msg_type {
|
||||
) -> Result<(), ActorError> {
|
||||
match msg_type {
|
||||
"getStyleSheets" => {
|
||||
let msg = GetStyleSheetsReply {
|
||||
from: self.name(),
|
||||
style_sheets: vec![],
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
|
||||
_ => 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
|
||||
|
||||
use std::net::TcpStream;
|
||||
|
||||
use serde::Serialize;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
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::root::{DescriptorTraits, RootActor};
|
||||
use crate::actors::watcher::{WatcherActor, WatcherActorMsg};
|
||||
use crate::protocol::JsonPacketStream;
|
||||
use crate::protocol::ClientRequest;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
|
@ -89,42 +87,40 @@ impl Actor for TabDescriptorActor {
|
|||
/// to describe the debugging capabilities of this tab.
|
||||
fn handle_message(
|
||||
&self,
|
||||
request: ClientRequest,
|
||||
registry: &ActorRegistry,
|
||||
msg_type: &str,
|
||||
_msg: &Map<String, Value>,
|
||||
stream: &mut TcpStream,
|
||||
_id: StreamId,
|
||||
) -> Result<ActorMessageStatus, ()> {
|
||||
Ok(match msg_type {
|
||||
) -> Result<(), ActorError> {
|
||||
match msg_type {
|
||||
"getTarget" => {
|
||||
let frame = registry
|
||||
.find::<BrowsingContextActor>(&self.browsing_context_actor)
|
||||
.encodable();
|
||||
let _ = stream.write_json_packet(&GetTargetReply {
|
||||
request.reply_final(&GetTargetReply {
|
||||
from: self.name(),
|
||||
frame,
|
||||
});
|
||||
ActorMessageStatus::Processed
|
||||
})?
|
||||
},
|
||||
"getFavicon" => {
|
||||
// TODO: Return a favicon when available
|
||||
let _ = stream.write_json_packet(&GetFaviconReply {
|
||||
request.reply_final(&GetFaviconReply {
|
||||
from: self.name(),
|
||||
favicon: String::new(),
|
||||
});
|
||||
ActorMessageStatus::Processed
|
||||
})?
|
||||
},
|
||||
"getWatcher" => {
|
||||
let ctx_actor = registry.find::<BrowsingContextActor>(&self.browsing_context_actor);
|
||||
let watcher = registry.find::<WatcherActor>(&ctx_actor.watcher);
|
||||
let _ = stream.write_json_packet(&GetWatcherReply {
|
||||
request.reply_final(&GetWatcherReply {
|
||||
from: self.name(),
|
||||
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
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::net::TcpStream;
|
||||
|
||||
use serde::Serialize;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
use super::source::{SourceManager, SourcesReply};
|
||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
||||
use crate::protocol::JsonPacketStream;
|
||||
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||
use crate::protocol::{ClientRequest, JsonPacketStream};
|
||||
use crate::{EmptyReplyMsg, StreamId};
|
||||
|
||||
#[derive(Serialize)]
|
||||
|
@ -71,13 +69,13 @@ impl Actor for ThreadActor {
|
|||
|
||||
fn handle_message(
|
||||
&self,
|
||||
mut request: ClientRequest,
|
||||
registry: &ActorRegistry,
|
||||
msg_type: &str,
|
||||
_msg: &Map<String, Value>,
|
||||
stream: &mut TcpStream,
|
||||
_id: StreamId,
|
||||
) -> Result<ActorMessageStatus, ()> {
|
||||
Ok(match msg_type {
|
||||
) -> Result<(), ActorError> {
|
||||
match msg_type {
|
||||
"attach" => {
|
||||
let msg = ThreadAttached {
|
||||
from: self.name(),
|
||||
|
@ -92,9 +90,8 @@ impl Actor for ThreadActor {
|
|||
type_: "attached".to_owned(),
|
||||
},
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
let _ = stream.write_json_packet(&EmptyReplyMsg { from: self.name() });
|
||||
ActorMessageStatus::Processed
|
||||
request.write_json_packet(&msg)?;
|
||||
request.reply_final(&EmptyReplyMsg { from: self.name() })?
|
||||
},
|
||||
|
||||
"resume" => {
|
||||
|
@ -102,9 +99,8 @@ impl Actor for ThreadActor {
|
|||
from: self.name(),
|
||||
type_: "resumed".to_owned(),
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
let _ = stream.write_json_packet(&EmptyReplyMsg { from: self.name() });
|
||||
ActorMessageStatus::Processed
|
||||
request.write_json_packet(&msg)?;
|
||||
request.reply_final(&EmptyReplyMsg { from: self.name() })?
|
||||
},
|
||||
|
||||
"interrupt" => {
|
||||
|
@ -112,14 +108,11 @@ impl Actor for ThreadActor {
|
|||
from: self.name(),
|
||||
type_: "interrupted".to_owned(),
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.write_json_packet(&msg)?;
|
||||
request.reply_final(&EmptyReplyMsg { from: self.name() })?
|
||||
},
|
||||
|
||||
"reconfigure" => {
|
||||
let _ = stream.write_json_packet(&EmptyReplyMsg { from: self.name() });
|
||||
ActorMessageStatus::Processed
|
||||
},
|
||||
"reconfigure" => request.reply_final(&EmptyReplyMsg { from: self.name() })?,
|
||||
|
||||
// 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>
|
||||
|
@ -128,10 +121,10 @@ impl Actor for ThreadActor {
|
|||
from: self.name(),
|
||||
sources: self.source_manager.source_forms(registry),
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
_ => ActorMessageStatus::Ignored,
|
||||
})
|
||||
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::error::Error;
|
||||
use std::net::TcpStream;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
|
@ -21,10 +20,10 @@ use serde::{Serialize, Serializer};
|
|||
use serde_json::{Map, Value};
|
||||
|
||||
use crate::StreamId;
|
||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
||||
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||
use crate::actors::framerate::FramerateActor;
|
||||
use crate::actors::memory::{MemoryActor, TimelineMemoryReply};
|
||||
use crate::protocol::JsonPacketStream;
|
||||
use crate::protocol::{ClientRequest, JsonPacketStream};
|
||||
|
||||
pub struct TimelineActor {
|
||||
name: String,
|
||||
|
@ -191,13 +190,13 @@ impl Actor for TimelineActor {
|
|||
|
||||
fn handle_message(
|
||||
&self,
|
||||
request: ClientRequest,
|
||||
registry: &ActorRegistry,
|
||||
msg_type: &str,
|
||||
msg: &Map<String, Value>,
|
||||
stream: &mut TcpStream,
|
||||
_id: StreamId,
|
||||
) -> Result<ActorMessageStatus, ()> {
|
||||
Ok(match msg_type {
|
||||
) -> Result<(), ActorError> {
|
||||
match msg_type {
|
||||
"start" => {
|
||||
**self.is_recording.lock().as_mut().unwrap() = true;
|
||||
|
||||
|
@ -211,7 +210,7 @@ impl Actor for TimelineActor {
|
|||
.unwrap();
|
||||
|
||||
//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
|
||||
if let Some(with_memory) = msg.get("withMemory") {
|
||||
|
@ -236,7 +235,7 @@ impl Actor for TimelineActor {
|
|||
self.name(),
|
||||
registry.shareable(),
|
||||
registry.start_stamp(),
|
||||
stream.try_clone().unwrap(),
|
||||
request.try_clone_stream().unwrap(),
|
||||
self.memory_actor.borrow().clone(),
|
||||
self.framerate_actor.borrow().clone(),
|
||||
);
|
||||
|
@ -250,8 +249,7 @@ impl Actor for TimelineActor {
|
|||
CrossProcessInstant::now(),
|
||||
),
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
|
||||
"stop" => {
|
||||
|
@ -263,7 +261,6 @@ impl Actor for TimelineActor {
|
|||
),
|
||||
};
|
||||
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
self.script_sender
|
||||
.send(DropTimelineMarkers(
|
||||
self.pipeline_id,
|
||||
|
@ -282,7 +279,7 @@ impl Actor for TimelineActor {
|
|||
|
||||
**self.is_recording.lock().as_mut().unwrap() = false;
|
||||
self.stream.borrow_mut().take();
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
|
||||
"isRecording" => {
|
||||
|
@ -291,12 +288,12 @@ impl Actor for TimelineActor {
|
|||
value: *self.is_recording.lock().unwrap(),
|
||||
};
|
||||
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
|
||||
_ => 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 reply = MarkersEmitterReply {
|
||||
type_: "markers".to_owned(),
|
||||
|
|
|
@ -24,7 +24,7 @@ use self::network_parent::{NetworkParentActor, NetworkParentActorMsg};
|
|||
use super::breakpoint::BreakpointListActor;
|
||||
use super::thread::ThreadActor;
|
||||
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::root::RootActor;
|
||||
use crate::actors::watcher::target_configuration::{
|
||||
|
@ -33,7 +33,7 @@ use crate::actors::watcher::target_configuration::{
|
|||
use crate::actors::watcher::thread_configuration::{
|
||||
ThreadConfigurationActor, ThreadConfigurationActorMsg,
|
||||
};
|
||||
use crate::protocol::JsonPacketStream;
|
||||
use crate::protocol::{ClientRequest, JsonPacketStream};
|
||||
use crate::resource::{ResourceArrayType, ResourceAvailable};
|
||||
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
|
||||
fn handle_message(
|
||||
&self,
|
||||
mut request: ClientRequest,
|
||||
registry: &ActorRegistry,
|
||||
msg_type: &str,
|
||||
msg: &Map<String, Value>,
|
||||
stream: &mut TcpStream,
|
||||
_id: StreamId,
|
||||
) -> Result<ActorMessageStatus, ()> {
|
||||
) -> Result<(), ActorError> {
|
||||
let target = registry.find::<BrowsingContextActor>(&self.browsing_context_actor);
|
||||
let root = registry.find::<RootActor>("root");
|
||||
Ok(match msg_type {
|
||||
match msg_type {
|
||||
"watchTargets" => {
|
||||
// As per logs we either get targetType as "frame" or "worker"
|
||||
let target_type = msg
|
||||
|
@ -252,9 +252,9 @@ impl Actor for WatcherActor {
|
|||
type_: "target-available-form".into(),
|
||||
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" {
|
||||
for worker_name in &root.workers {
|
||||
let worker = registry.find::<WorkerActor>(worker_name);
|
||||
|
@ -263,11 +263,10 @@ impl Actor for WatcherActor {
|
|||
type_: "target-available-form".into(),
|
||||
target: TargetActorMsg::Worker(worker.encodable()),
|
||||
};
|
||||
let _ = stream.write_json_packet(&worker_msg);
|
||||
let _ = request.write_json_packet(&worker_msg);
|
||||
}
|
||||
} else {
|
||||
warn!("Unexpected target_type: {}", target_type);
|
||||
return Ok(ActorMessageStatus::Ignored);
|
||||
}
|
||||
|
||||
// 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
|
||||
// and processed the message so that it can continue
|
||||
let msg = EmptyReplyMsg { from: self.name() };
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
"watchResources" => {
|
||||
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 {
|
||||
return Ok(ActorMessageStatus::Ignored);
|
||||
return Err(ActorError::BadParameterType);
|
||||
};
|
||||
|
||||
for resource in resource_types {
|
||||
|
@ -311,7 +309,7 @@ impl Actor for WatcherActor {
|
|||
event,
|
||||
"document-event".into(),
|
||||
ResourceArrayType::Available,
|
||||
stream,
|
||||
&mut request,
|
||||
);
|
||||
}
|
||||
},
|
||||
|
@ -321,7 +319,7 @@ impl Actor for WatcherActor {
|
|||
thread_actor.source_manager.source_forms(registry),
|
||||
"source".into(),
|
||||
ResourceArrayType::Available,
|
||||
stream,
|
||||
&mut request,
|
||||
);
|
||||
|
||||
for worker_name in &root.workers {
|
||||
|
@ -332,7 +330,7 @@ impl Actor for WatcherActor {
|
|||
thread.source_manager.source_forms(registry),
|
||||
"source".into(),
|
||||
ResourceArrayType::Available,
|
||||
stream,
|
||||
&mut request,
|
||||
);
|
||||
}
|
||||
},
|
||||
|
@ -340,19 +338,16 @@ impl Actor for WatcherActor {
|
|||
"network-event" => {},
|
||||
_ => 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" => {
|
||||
let msg = GetParentBrowsingContextIDReply {
|
||||
from: self.name(),
|
||||
browsing_context_id: target.browsing_context_id.value(),
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
"getNetworkParentActor" => {
|
||||
let network_parent = registry.find::<NetworkParentActor>(&self.network_parent);
|
||||
|
@ -360,8 +355,7 @@ impl Actor for WatcherActor {
|
|||
from: self.name(),
|
||||
network: network_parent.encodable(),
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
"getTargetConfigurationActor" => {
|
||||
let target_configuration =
|
||||
|
@ -370,8 +364,7 @@ impl Actor for WatcherActor {
|
|||
from: self.name(),
|
||||
configuration: target_configuration.encodable(),
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
"getThreadConfigurationActor" => {
|
||||
let thread_configuration =
|
||||
|
@ -380,24 +373,23 @@ impl Actor for WatcherActor {
|
|||
from: self.name(),
|
||||
configuration: thread_configuration.encodable(),
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
"getBreakpointListActor" => {
|
||||
let breakpoint_list_name = registry.new_name("breakpoint-list");
|
||||
let breakpoint_list = BreakpointListActor::new(breakpoint_list_name.clone());
|
||||
registry.register_later(Box::new(breakpoint_list));
|
||||
|
||||
let _ = stream.write_json_packet(&GetBreakpointListActorReply {
|
||||
request.reply_final(&GetBreakpointListActorReply {
|
||||
from: self.name(),
|
||||
breakpoint_list: GetBreakpointListActorReplyInner {
|
||||
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
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::net::TcpStream;
|
||||
|
||||
use serde::Serialize;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
||||
use crate::protocol::JsonPacketStream;
|
||||
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||
use crate::protocol::ClientRequest;
|
||||
use crate::{EmptyReplyMsg, StreamId};
|
||||
|
||||
#[derive(Serialize)]
|
||||
|
@ -30,20 +28,20 @@ impl Actor for NetworkParentActor {
|
|||
/// - `setSaveRequestAndResponseBodies`: Doesn't do anything yet
|
||||
fn handle_message(
|
||||
&self,
|
||||
request: ClientRequest,
|
||||
_registry: &ActorRegistry,
|
||||
msg_type: &str,
|
||||
_msg: &Map<String, Value>,
|
||||
stream: &mut TcpStream,
|
||||
_id: StreamId,
|
||||
) -> Result<ActorMessageStatus, ()> {
|
||||
Ok(match msg_type {
|
||||
) -> Result<(), ActorError> {
|
||||
match msg_type {
|
||||
"setSaveRequestAndResponseBodies" => {
|
||||
let msg = EmptyReplyMsg { from: self.name() };
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
_ => 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.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::net::TcpStream;
|
||||
|
||||
use embedder_traits::Theme;
|
||||
use log::warn;
|
||||
use serde::Serialize;
|
||||
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::tab::TabDescriptorActor;
|
||||
use crate::protocol::JsonPacketStream;
|
||||
use crate::protocol::ClientRequest;
|
||||
use crate::{EmptyReplyMsg, RootActor, StreamId};
|
||||
|
||||
#[derive(Serialize)]
|
||||
|
@ -48,22 +47,19 @@ impl Actor for TargetConfigurationActor {
|
|||
/// - `updateConfiguration`: Receives new configuration flags from the devtools host.
|
||||
fn handle_message(
|
||||
&self,
|
||||
request: ClientRequest,
|
||||
registry: &ActorRegistry,
|
||||
msg_type: &str,
|
||||
msg: &Map<String, Value>,
|
||||
stream: &mut TcpStream,
|
||||
_id: StreamId,
|
||||
) -> Result<ActorMessageStatus, ()> {
|
||||
Ok(match msg_type {
|
||||
) -> Result<(), ActorError> {
|
||||
match msg_type {
|
||||
"updateConfiguration" => {
|
||||
let config = match msg.get("configuration").and_then(|v| v.as_object()) {
|
||||
Some(config) => config,
|
||||
None => {
|
||||
let msg = EmptyReplyMsg { from: self.name() };
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
return Ok(ActorMessageStatus::Processed);
|
||||
},
|
||||
};
|
||||
let config = msg
|
||||
.get("configuration")
|
||||
.ok_or(ActorError::MissingParameter)?
|
||||
.as_object()
|
||||
.ok_or(ActorError::BadParameterType)?;
|
||||
if let Some(scheme) = config.get("colorSchemeSimulation").and_then(|v| v.as_str()) {
|
||||
let theme = match scheme {
|
||||
"dark" => Theme::Dark,
|
||||
|
@ -76,17 +72,19 @@ impl Actor for TargetConfigurationActor {
|
|||
let browsing_context_name = tab_actor.browsing_context();
|
||||
let browsing_context_actor =
|
||||
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 {
|
||||
warn!("No active tab for updateConfiguration");
|
||||
}
|
||||
}
|
||||
let msg = EmptyReplyMsg { from: self.name() };
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
_ => 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.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::net::TcpStream;
|
||||
|
||||
use serde::Serialize;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
||||
use crate::protocol::JsonPacketStream;
|
||||
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||
use crate::protocol::ClientRequest;
|
||||
use crate::{EmptyReplyMsg, StreamId};
|
||||
|
||||
#[derive(Serialize)]
|
||||
|
@ -35,21 +34,21 @@ impl Actor for ThreadConfigurationActor {
|
|||
/// - `updateConfiguration`: Receives new configuration flags from the devtools host.
|
||||
fn handle_message(
|
||||
&self,
|
||||
request: ClientRequest,
|
||||
_registry: &ActorRegistry,
|
||||
msg_type: &str,
|
||||
_msg: &Map<String, Value>,
|
||||
stream: &mut TcpStream,
|
||||
_id: StreamId,
|
||||
) -> Result<ActorMessageStatus, ()> {
|
||||
Ok(match msg_type {
|
||||
) -> Result<(), ActorError> {
|
||||
match msg_type {
|
||||
"updateConfiguration" => {
|
||||
// TODO: Actually update configuration
|
||||
let msg = EmptyReplyMsg { from: self.name() };
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
request.reply_final(&msg)?
|
||||
},
|
||||
_ => ActorMessageStatus::Ignored,
|
||||
})
|
||||
_ => return Err(ActorError::UnrecognizedPacketType),
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,8 +15,8 @@ use serde_json::{Map, Value};
|
|||
use servo_url::ServoUrl;
|
||||
|
||||
use crate::StreamId;
|
||||
use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
|
||||
use crate::protocol::JsonPacketStream;
|
||||
use crate::actor::{Actor, ActorError, ActorRegistry};
|
||||
use crate::protocol::{ClientRequest, JsonPacketStream};
|
||||
use crate::resource::ResourceAvailable;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
|
@ -68,30 +68,28 @@ impl Actor for WorkerActor {
|
|||
}
|
||||
fn handle_message(
|
||||
&self,
|
||||
mut request: ClientRequest,
|
||||
_registry: &ActorRegistry,
|
||||
msg_type: &str,
|
||||
_msg: &Map<String, Value>,
|
||||
stream: &mut TcpStream,
|
||||
stream_id: StreamId,
|
||||
) -> Result<ActorMessageStatus, ()> {
|
||||
Ok(match msg_type {
|
||||
) -> Result<(), ActorError> {
|
||||
match msg_type {
|
||||
"attach" => {
|
||||
let msg = AttachedReply {
|
||||
from: self.name(),
|
||||
type_: "attached".to_owned(),
|
||||
url: self.url.as_str().to_owned(),
|
||||
};
|
||||
if stream.write_json_packet(&msg).is_err() {
|
||||
return Ok(ActorMessageStatus::Processed);
|
||||
}
|
||||
// FIXME: we don’t send an actual reply (message without type), which seems to be a bug?
|
||||
request.write_json_packet(&msg)?;
|
||||
self.streams
|
||||
.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
|
||||
self.script_chan
|
||||
.send(WantsLiveNotifications(TEST_PIPELINE_ID, true))
|
||||
.unwrap();
|
||||
ActorMessageStatus::Processed
|
||||
},
|
||||
|
||||
"connect" => {
|
||||
|
@ -101,8 +99,8 @@ impl Actor for WorkerActor {
|
|||
thread_actor: self.thread.clone(),
|
||||
console_actor: self.console.clone(),
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
// FIXME: we don’t send an actual reply (message without type), which seems to be a bug?
|
||||
request.write_json_packet(&msg)?;
|
||||
},
|
||||
|
||||
"detach" => {
|
||||
|
@ -110,13 +108,14 @@ impl Actor for WorkerActor {
|
|||
from: self.name(),
|
||||
type_: "detached".to_string(),
|
||||
};
|
||||
let _ = stream.write_json_packet(&msg);
|
||||
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) {
|
||||
|
|
|
@ -28,7 +28,7 @@ use devtools_traits::{
|
|||
};
|
||||
use embedder_traits::{AllowOrDeny, EmbedderMsg, EmbedderProxy};
|
||||
use ipc_channel::ipc::{self, IpcSender};
|
||||
use log::trace;
|
||||
use log::{trace, warn};
|
||||
use resource::{ResourceArrayType, ResourceAvailable};
|
||||
use serde::Serialize;
|
||||
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) {
|
||||
log::info!("Connection established to {}", stream.peer_addr().unwrap());
|
||||
let msg = actors.lock().unwrap().find::<RootActor>("root").encodable();
|
||||
if let Err(e) = stream.write_json_packet(&msg) {
|
||||
log::warn!("Error writing response: {:?}", e);
|
||||
if let Err(error) = stream.write_json_packet(&msg) {
|
||||
warn!("Failed to send initial packet from root actor: {error:?}");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,13 +5,14 @@
|
|||
//! Low-level wire protocol implementation. Currently only supports
|
||||
//! [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::net::TcpStream;
|
||||
|
||||
use log::debug;
|
||||
use serde::Serialize;
|
||||
use serde_json::{self, Value};
|
||||
use serde_json::{self, Value, json};
|
||||
|
||||
use crate::actor::ActorError;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
|
@ -29,42 +30,18 @@ pub struct Method {
|
|||
}
|
||||
|
||||
pub trait JsonPacketStream {
|
||||
fn write_json_packet<T: Serialize>(&mut self, obj: &T) -> Result<(), Box<dyn Error>>;
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn write_merged_json_packet<T: Serialize, U: Serialize>(
|
||||
&mut self,
|
||||
base: &T,
|
||||
extra: &U,
|
||||
) -> Result<(), Box<dyn Error>>;
|
||||
fn write_json_packet<T: Serialize>(&mut self, message: &T) -> Result<(), ActorError>;
|
||||
fn read_json_packet(&mut self) -> Result<Option<Value>, String>;
|
||||
}
|
||||
|
||||
impl JsonPacketStream for TcpStream {
|
||||
fn write_json_packet<T: Serialize>(&mut self, obj: &T) -> Result<(), Box<dyn Error>> {
|
||||
let s = serde_json::to_string(obj)?;
|
||||
fn write_json_packet<T: Serialize>(&mut self, message: &T) -> Result<(), ActorError> {
|
||||
let s = serde_json::to_string(message).map_err(|_| ActorError::Internal)?;
|
||||
debug!("<- {}", s);
|
||||
write!(self, "{}:{}", s.len(), s)?;
|
||||
write!(self, "{}:{}", s.len(), s).map_err(|_| ActorError::Internal)?;
|
||||
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> {
|
||||
// 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]
|
||||
|
@ -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
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::net::TcpStream;
|
||||
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::protocol::JsonPacketStream;
|
||||
|
@ -24,22 +22,22 @@ pub(crate) struct ResourceAvailableReply<T: Serialize> {
|
|||
pub(crate) trait ResourceAvailable {
|
||||
fn actor_name(&self) -> String;
|
||||
|
||||
fn resource_array<T: Serialize>(
|
||||
fn resource_array<T: Serialize, S: JsonPacketStream>(
|
||||
&self,
|
||||
resource: T,
|
||||
resource_type: String,
|
||||
array_type: ResourceArrayType,
|
||||
stream: &mut TcpStream,
|
||||
stream: &mut S,
|
||||
) {
|
||||
self.resources_array(vec![resource], resource_type, array_type, stream);
|
||||
}
|
||||
|
||||
fn resources_array<T: Serialize>(
|
||||
fn resources_array<T: Serialize, S: JsonPacketStream>(
|
||||
&self,
|
||||
resources: Vec<T>,
|
||||
resource_type: String,
|
||||
array_type: ResourceArrayType,
|
||||
stream: &mut TcpStream,
|
||||
stream: &mut S,
|
||||
) {
|
||||
let msg = ResourceAvailableReply::<T> {
|
||||
from: self.actor_name(),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue