Files
servo/components/devtools/actors/worker.rs
eri deb172492e devtools: ActorEncode trait (#41139)
Unify various `encodable` and `encode` methods from actors in an
`ActorEncode` trait, making it more consistent.

Add an `ActorRegistry::encode` method that finds an actor by name and
then returns its serialized version.

Add an `ActorMsg` struct to avoid creating repeated structs for simple
serializations.

There are two exceptions: `EncodableConsoleMessage` and `NodeInfo`.
These also have an `encode` method, but they are not actors, so
including them in this trait doesn't make much sense. Besides, they have
special requirements so it is better to keep them separate.

Testing: Manual testing in `about:debugging`.

Signed-off-by: eri <eri@igalia.com>
2025-12-08 14:05:01 +00:00

177 lines
5.1 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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::cell::RefCell;
use std::collections::HashMap;
use std::net::TcpStream;
use base::generic_channel::GenericSender;
use base::id::TEST_PIPELINE_ID;
use devtools_traits::DevtoolScriptControlMsg::WantsLiveNotifications;
use devtools_traits::{DevtoolScriptControlMsg, WorkerId};
use serde::Serialize;
use serde_json::{Map, Value};
use servo_url::ServoUrl;
use crate::StreamId;
use crate::actor::{Actor, ActorEncode, ActorError, ActorRegistry};
use crate::protocol::{ClientRequest, JsonPacketStream};
use crate::resource::ResourceAvailable;
#[derive(Clone, Copy)]
#[expect(dead_code)]
pub enum WorkerType {
Dedicated = 0,
Shared = 1,
Service = 2,
}
pub(crate) struct WorkerActor {
pub name: String,
pub console: String,
pub thread: String,
pub worker_id: WorkerId,
pub url: ServoUrl,
pub type_: WorkerType,
pub script_chan: GenericSender<DevtoolScriptControlMsg>,
pub streams: RefCell<HashMap<StreamId, TcpStream>>,
}
impl ResourceAvailable for WorkerActor {
fn actor_name(&self) -> String {
self.name.clone()
}
}
impl Actor for WorkerActor {
fn name(&self) -> String {
self.name.clone()
}
fn handle_message(
&self,
mut request: ClientRequest,
_registry: &ActorRegistry,
msg_type: &str,
_msg: &Map<String, Value>,
stream_id: StreamId,
) -> Result<(), ActorError> {
match msg_type {
"attach" => {
let msg = AttachedReply {
from: self.name(),
type_: "attached".to_owned(),
url: self.url.as_str().to_owned(),
};
// FIXME: we dont 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, 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();
},
"connect" => {
let msg = ConnectReply {
from: self.name(),
type_: "connected".to_owned(),
thread_actor: self.thread.clone(),
console_actor: self.console.clone(),
};
// FIXME: we dont send an actual reply (message without type), which seems to be a bug?
request.write_json_packet(&msg)?;
},
"detach" => {
let msg = DetachedReply {
from: self.name(),
type_: "detached".to_string(),
};
self.cleanup(stream_id);
// FIXME: we dont send an actual reply (message without type), which seems to be a bug?
request.write_json_packet(&msg)?;
},
_ => return Err(ActorError::UnrecognizedPacketType),
};
Ok(())
}
fn cleanup(&self, stream_id: StreamId) {
self.streams.borrow_mut().remove(&stream_id);
if self.streams.borrow().is_empty() {
self.script_chan
.send(WantsLiveNotifications(TEST_PIPELINE_ID, false))
.unwrap();
}
}
}
#[derive(Serialize)]
struct DetachedReply {
from: String,
#[serde(rename = "type")]
type_: String,
}
#[derive(Serialize)]
struct AttachedReply {
from: String,
#[serde(rename = "type")]
type_: String,
url: String,
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct ConnectReply {
from: String,
#[serde(rename = "type")]
type_: String,
thread_actor: String,
console_actor: String,
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct WorkerTraits {
is_parent_intercept_enabled: bool,
supports_top_level_target_flag: bool,
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct WorkerActorMsg {
actor: String,
console_actor: String,
thread_actor: String,
id: String,
url: String,
traits: WorkerTraits,
#[serde(rename = "type")]
type_: u32,
#[serde(rename = "targetType")]
target_type: String,
}
impl ActorEncode<WorkerActorMsg> for WorkerActor {
fn encode(&self, _: &ActorRegistry) -> WorkerActorMsg {
WorkerActorMsg {
actor: self.name(),
console_actor: self.console.clone(),
thread_actor: self.thread.clone(),
id: self.worker_id.0.to_string(),
url: self.url.to_string(),
traits: WorkerTraits {
is_parent_intercept_enabled: false,
supports_top_level_target_flag: false,
},
type_: self.type_ as u32,
target_type: "worker".to_string(),
}
}
}