1use std::any::{Any, type_name};
6use std::borrow::Borrow;
7use std::collections::{HashMap, HashSet};
8use std::hash::{Hash, Hasher};
9use std::marker::PhantomData;
10use std::ops::{Deref, DerefMut};
11use std::sync::Arc;
12use std::sync::atomic::{AtomicU32, Ordering};
13
14use log::{debug, warn};
15use malloc_size_of::MallocSizeOf;
16use malloc_size_of_derive::MallocSizeOf;
17use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
18use serde::Serialize;
19use serde_json::{Map, Value, json};
20use servo_base::id::PipelineId;
21
22use crate::StreamId;
23use crate::protocol::{ClientRequest, DevtoolsConnection, JsonPacketStream};
24
25#[derive(Debug)]
29pub enum ActorError {
30 MissingParameter,
31 BadParameterType,
32 UnrecognizedPacketType,
33 Internal,
36}
37
38impl ActorError {
39 pub fn name(&self) -> &'static str {
40 match self {
41 ActorError::MissingParameter => "missingParameter",
42 ActorError::BadParameterType => "badParameterType",
43 ActorError::UnrecognizedPacketType => "unrecognizedPacketType",
44 ActorError::Internal => "",
49 }
50 }
51}
52
53pub(crate) fn base_name<T: ?Sized>() -> &'static str {
55 let prefix = type_name::<T>();
56 prefix.split("::").last().unwrap_or(prefix)
57}
58
59pub(crate) fn new_actor_name<T: ?Sized>() -> String {
61 static COUNTER: AtomicU32 = AtomicU32::new(0);
62 let suffix = COUNTER.fetch_add(1, Ordering::Relaxed);
63 let base = base_name::<T>();
64
65 if base.contains("WorkerTarget") {
68 format!("/workerTarget{suffix}")
69 } else {
70 format!("{base}{suffix}")
71 }
72}
73
74pub(crate) trait Actor: Any + ActorAsAny + Send + Sync + MallocSizeOf {
77 fn handle_message(
78 &self,
79 request: ClientRequest,
80 registry: &ActorRegistry,
81 msg_type: &str,
82 msg: &Map<String, Value>,
83 stream_id: StreamId,
84 ) -> Result<(), ActorError> {
85 let _ = (request, registry, msg_type, msg, stream_id);
86 Err(ActorError::UnrecognizedPacketType)
87 }
88 fn name(&self) -> &str;
89 fn cleanup(&self, _id: StreamId) {}
90}
91
92pub(crate) trait ActorAsAny {
93 fn actor_as_any(&self) -> &dyn Any;
94}
95
96impl<T: Actor> ActorAsAny for T {
97 fn actor_as_any(&self) -> &dyn Any {
98 self
99 }
100}
101
102pub(crate) trait ActorEncode<T: Serialize>: Actor {
103 fn encode(&self, registry: &ActorRegistry) -> T;
104}
105
106pub(crate) struct DowncastableActorArc<T> {
109 actor: Arc<dyn Actor>,
110 _phantom: PhantomData<T>,
111}
112
113impl<T: Actor> From<Arc<T>> for DowncastableActorArc<T> {
114 fn from(actor: Arc<T>) -> Self {
115 Self {
116 actor,
117 _phantom: PhantomData,
118 }
119 }
120}
121
122impl<T: 'static> std::ops::Deref for DowncastableActorArc<T> {
123 type Target = T;
124 fn deref(&self) -> &Self::Target {
125 self.actor
126 .actor_as_any()
127 .downcast_ref::<T>()
128 .unwrap_or_else(|| {
129 panic!(
130 "Failed to downcast {} to type {}",
131 self.actor.name(),
132 type_name::<T>()
133 )
134 })
135 }
136}
137
138#[derive(Clone)]
139struct RegisteredActor(Arc<dyn Actor>);
140
141impl PartialEq for RegisteredActor {
142 fn eq(&self, other: &Self) -> bool {
143 self.0.name() == other.0.name()
144 }
145}
146
147impl Eq for RegisteredActor {}
148
149impl Hash for RegisteredActor {
150 fn hash<H: Hasher>(&self, state: &mut H) {
151 self.0.name().hash(state);
152 }
153}
154
155impl Borrow<str> for RegisteredActor {
156 fn borrow(&self) -> &str {
157 self.0.name()
158 }
159}
160
161impl MallocSizeOf for RegisteredActor {
162 fn size_of(&self, ops: &mut malloc_size_of::MallocSizeOfOps) -> usize {
163 self.0.size_of(ops)
164 }
165}
166
167#[cfg(debug_assertions)]
170thread_local! {
171 static REENTRANCY_GUARD: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
172}
173
174struct WriteGuard<'a>(RwLockWriteGuard<'a, ActorRegistryInner>);
175
176impl<'a> Deref for WriteGuard<'a> {
177 type Target = ActorRegistryInner;
178 fn deref(&self) -> &Self::Target {
179 &self.0
180 }
181}
182
183impl<'a> DerefMut for WriteGuard<'a> {
184 fn deref_mut(&mut self) -> &mut Self::Target {
185 &mut self.0
186 }
187}
188
189impl<'a> Drop for WriteGuard<'a> {
190 fn drop(&mut self) {
191 #[cfg(debug_assertions)]
192 REENTRANCY_GUARD.with(|cell| cell.set(false));
193 }
194}
195
196#[derive(Default, MallocSizeOf)]
197struct ActorRegistryInner {
198 actors: HashSet<RegisteredActor>,
199 script_to_actor: HashMap<String, String>,
200 actor_to_script: HashMap<String, String>,
201 source_actor_names: HashMap<PipelineId, Vec<String>>,
202 inline_source_content: HashMap<PipelineId, String>,
203}
204
205#[derive(Default, MallocSizeOf)]
206pub(crate) struct ActorRegistry(RwLock<ActorRegistryInner>);
207
208impl ActorRegistry {
209 fn read(&self) -> RwLockReadGuard<'_, ActorRegistryInner> {
210 self.0.read()
211 }
212
213 fn write(&self) -> WriteGuard<'_> {
214 #[cfg(debug_assertions)]
215 REENTRANCY_GUARD.with(|cell| {
216 assert!(
217 !cell.get(),
218 "Reentrant write operation detected on the same thread for ActorRegistry"
219 );
220 cell.set(true);
221 });
222 WriteGuard(self.0.write())
223 }
224}
225
226impl ActorRegistry {
227 pub(crate) fn register<T: Actor>(&self, actor: T) -> Arc<T> {
229 let actor = Arc::new(actor);
230 self.write().actors.insert(RegisteredActor(actor.clone()));
231 actor
232 }
233
234 pub(crate) fn find<T: Actor>(&self, name: &str) -> DowncastableActorArc<T> {
236 let actor = self
237 .read()
238 .actors
239 .get(name)
240 .expect("Should never look for a nonexistent actor")
241 .0
242 .clone();
243 DowncastableActorArc {
244 actor,
245 _phantom: PhantomData,
246 }
247 }
248
249 pub(crate) fn encode<T: ActorEncode<S>, S: Serialize>(&self, name: &str) -> S {
251 self.find::<T>(name).encode(self)
252 }
253
254 pub(crate) fn handle_message(
257 &self,
258 msg: &Map<String, Value>,
259 stream: &mut DevtoolsConnection,
260 stream_id: StreamId,
261 ) -> Result<(), ()> {
262 let Some(actor_name) = msg.get("to").and_then(|value| value.as_str()) else {
263 warn!("Received unexpected message: {msg:?}");
264 return Err(());
265 };
266
267 let actor = self
268 .read()
269 .actors
270 .get(actor_name)
271 .map(|registered_actor| registered_actor.0.clone());
272 match actor {
273 None => {
274 let _ = stream
276 .write_json_packet(&json!({ "from": actor_name, "error": "noSuchActor" }));
277 },
278 Some(actor) => {
279 let Some(msg_type) = msg.get("type").and_then(|value| value.as_str()) else {
280 let _ = stream.write_json_packet(
281 &json!({ "from": actor_name, "error": "missingParameter" }),
282 );
283 return Ok(());
284 };
285 if let Err(error) = ClientRequest::handle(stream.clone(), actor_name, |req| {
286 actor.handle_message(req, self, msg_type, msg, stream_id)
287 }) {
288 let error = json!({
290 "from": actor.name(), "error": error.name()
291 });
292 warn!("Sending devtools protocol error: error={error:?} request={msg:?}");
293 let _ = stream.write_json_packet(&error);
294 }
295 },
296 }
297 Ok(())
298 }
299
300 pub(crate) fn register_script_actor(&self, script_id: String, actor: String) {
301 debug!("Registering {actor} ({script_id})");
302 let mut lock = self.write();
303 lock.script_to_actor
304 .insert(script_id.clone(), actor.clone());
305 lock.actor_to_script.insert(actor, script_id);
306 }
307
308 pub(crate) fn script_to_actor(&self, script_id: &str) -> String {
309 if script_id.is_empty() {
310 return String::new();
311 }
312 self.read()
313 .script_to_actor
314 .get(script_id)
315 .unwrap_or_else(|| panic!("No actor for script id {script_id}"))
316 .clone()
317 }
318
319 pub(crate) fn script_actor_registered(&self, script_id: &str) -> bool {
320 self.read().script_to_actor.contains_key(script_id)
321 }
322
323 pub(crate) fn actor_to_script(&self, actor: String) -> String {
324 self.read()
325 .actor_to_script
326 .get(&actor)
327 .unwrap_or_else(|| panic!("No script id for actor {actor}"))
328 .clone()
329 }
330
331 pub(crate) fn register_source_actor(&self, pipeline_id: PipelineId, actor_name: &str) {
332 self.write()
333 .source_actor_names
334 .entry(pipeline_id)
335 .or_default()
336 .push(actor_name.to_owned());
337 }
338
339 pub(crate) fn source_actor_names_for_pipeline(&self, pipeline_id: PipelineId) -> Vec<String> {
340 self.read()
341 .source_actor_names
342 .get(&pipeline_id)
343 .cloned()
344 .unwrap_or_default()
345 }
346
347 pub(crate) fn set_inline_source_content(&self, pipeline_id: PipelineId, content: String) {
348 assert!(
349 self.write()
350 .inline_source_content
351 .insert(pipeline_id, content)
352 .is_none()
353 );
354 }
355
356 pub(crate) fn inline_source_content(&self, pipeline_id: PipelineId) -> Option<String> {
357 self.read().inline_source_content.get(&pipeline_id).cloned()
358 }
359
360 pub(crate) fn remove(&self, _name: String) {}
362
363 pub(crate) fn cleanup(&self, stream_id: StreamId) {
364 let actors = self.read().actors.clone();
365 for actor in actors {
366 actor.0.cleanup(stream_id);
367 }
368 }
369}