mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +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
|
@ -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(),
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue