1use std::collections::HashMap;
13
14use atomic_refcell::AtomicRefCell;
15use malloc_size_of_derive::MallocSizeOf;
16use serde::Serialize;
17use serde_json::{Map, Value};
18
19use crate::actor::{Actor, ActorEncode, ActorError, ActorRegistry};
20use crate::actors::device::DeviceActor;
21use crate::actors::performance::PerformanceActor;
22use crate::actors::preference::PreferenceActor;
23use crate::actors::process::{ProcessActor, ProcessActorMsg};
24use crate::actors::tab::{TabDescriptorActor, TabDescriptorActorMsg};
25use crate::actors::worker::{WorkerActor, WorkerActorMsg};
26use crate::protocol::{ActorDescription, ClientRequest};
27use crate::{EmptyReplyMsg, StreamId};
28
29#[derive(Serialize)]
30#[serde(rename_all = "camelCase")]
31struct ServiceWorkerInfo {
32 actor: String,
33 url: String,
34 state: u32,
35 state_text: String,
36 id: String,
37 fetch: bool,
38 traits: HashMap<&'static str, bool>,
39}
40
41#[derive(Serialize)]
42#[serde(rename_all = "camelCase")]
43struct ServiceWorkerRegistrationMsg {
44 actor: String,
45 scope: String,
46 url: String,
47 registration_state: String,
48 last_update_time: u64,
49 traits: HashMap<&'static str, bool>,
50 evaluating_worker: Option<ServiceWorkerInfo>,
53 installing_worker: Option<ServiceWorkerInfo>,
54 waiting_worker: Option<ServiceWorkerInfo>,
55 active_worker: Option<ServiceWorkerInfo>,
56}
57
58#[derive(Serialize)]
59#[serde(rename_all = "camelCase")]
60struct RootTraits {
61 sources: bool,
62 highlightable: bool,
63 custom_highlighters: bool,
64 network_monitor: bool,
65 resources: HashMap<&'static str, bool>,
66}
67
68#[derive(Serialize)]
69struct ListAddonsReply {
70 from: String,
71 addons: Vec<AddonMsg>,
72}
73
74#[derive(Serialize)]
75enum AddonMsg {}
76
77#[derive(Clone, Default, Serialize, MallocSizeOf)]
78#[serde(rename_all = "camelCase")]
79struct GlobalActors {
80 device_actor: String,
81 perf_actor: String,
82 preference_actor: String,
83 }
89
90#[derive(Serialize)]
91struct GetRootReply {
92 from: String,
93 #[serde(flatten)]
94 global_actors: GlobalActors,
95}
96
97#[derive(Serialize)]
98struct ListTabsReply {
99 from: String,
100 tabs: Vec<TabDescriptorActorMsg>,
101}
102
103#[derive(Serialize)]
104struct GetTabReply {
105 from: String,
106 tab: TabDescriptorActorMsg,
107}
108
109#[derive(Serialize)]
110#[serde(rename_all = "camelCase")]
111pub(crate) struct RootActorMsg {
112 from: String,
113 application_type: String,
114 traits: RootTraits,
115}
116
117#[derive(Serialize)]
118pub(crate) struct ProtocolDescriptionReply {
119 from: String,
120 types: Types,
121}
122
123#[derive(Serialize)]
124struct ListWorkersReply {
125 from: String,
126 workers: Vec<WorkerActorMsg>,
127}
128
129#[derive(Serialize)]
130struct ListServiceWorkerRegistrationsReply {
131 from: String,
132 registrations: Vec<ServiceWorkerRegistrationMsg>,
133}
134
135#[derive(Serialize)]
136pub(crate) struct Types {
137 performance: ActorDescription,
138 device: ActorDescription,
139}
140
141#[derive(Serialize)]
142struct ListProcessesResponse {
143 from: String,
144 processes: Vec<ProcessActorMsg>,
145}
146
147#[derive(Default, Serialize)]
148#[serde(rename_all = "camelCase")]
149pub(crate) struct DescriptorTraits {
150 pub(crate) watcher: bool,
151 pub(crate) supports_reload_descriptor: bool,
152 pub(crate) supports_navigation: bool,
153}
154
155#[derive(Serialize)]
156#[serde(rename_all = "camelCase")]
157struct GetProcessResponse {
158 from: String,
159 process_descriptor: ProcessActorMsg,
160}
161
162#[derive(Default, MallocSizeOf)]
163pub(crate) struct RootActor {
164 active_tab: AtomicRefCell<Option<String>>,
165 global_actors: GlobalActors,
166 process_name: String,
167 pub tabs: AtomicRefCell<Vec<String>>,
168 pub workers: AtomicRefCell<Vec<String>>,
169 pub service_workers: AtomicRefCell<Vec<String>>,
170}
171
172impl Actor for RootActor {
173 fn name(&self) -> String {
174 "root".to_owned()
175 }
176
177 fn handle_message(
178 &self,
179 request: ClientRequest,
180 registry: &ActorRegistry,
181 msg_type: &str,
182 msg: &Map<String, Value>,
183 _id: StreamId,
184 ) -> Result<(), ActorError> {
185 match msg_type {
186 "connect" => {
187 let message = EmptyReplyMsg {
188 from: "root".into(),
189 };
190 request.reply_final(&message)?
191 },
192
193 "getProcess" => {
195 let process_descriptor = registry.encode::<ProcessActor, _>(&self.process_name);
196 let reply = GetProcessResponse {
197 from: self.name(),
198 process_descriptor,
199 };
200 request.reply_final(&reply)?
201 },
202
203 "getRoot" => {
204 let reply = GetRootReply {
205 from: "root".to_owned(),
206 global_actors: self.global_actors.clone(),
207 };
208 request.reply_final(&reply)?
209 },
210
211 "getTab" => {
212 let browser_id = msg
213 .get("browserId")
214 .ok_or(ActorError::MissingParameter)?
215 .as_u64()
216 .ok_or(ActorError::BadParameterType)?;
217 let Some(tab) = self.get_tab_msg_by_browser_id(registry, browser_id as u32) else {
218 return Err(ActorError::Internal);
219 };
220
221 let reply = GetTabReply {
222 from: self.name(),
223 tab,
224 };
225 request.reply_final(&reply)?
226 },
227
228 "listAddons" => {
229 let reply = ListAddonsReply {
230 from: "root".to_owned(),
231 addons: vec![],
232 };
233 request.reply_final(&reply)?
234 },
235
236 "listProcesses" => {
237 let process_descriptor = registry.encode::<ProcessActor, _>(&self.process_name);
238 let reply = ListProcessesResponse {
239 from: self.name(),
240 processes: vec![process_descriptor],
241 };
242 request.reply_final(&reply)?
243 },
244
245 "listServiceWorkerRegistrations" => {
246 let registrations = self
247 .service_workers
248 .borrow()
249 .iter()
250 .map(|worker_name| {
251 let worker = registry.find::<WorkerActor>(worker_name);
252 let url = worker.url.to_string();
253 let scope = url.clone();
255 ServiceWorkerRegistrationMsg {
256 actor: worker.name(),
257 scope,
258 url: url.clone(),
259 registration_state: "".to_string(),
260 last_update_time: 0,
261 traits: HashMap::new(),
262 evaluating_worker: None,
263 installing_worker: None,
264 waiting_worker: None,
265 active_worker: Some(ServiceWorkerInfo {
266 actor: worker.name(),
267 url,
268 state: 4, state_text: "activated".to_string(),
270 id: worker.worker_id.to_string(),
271 fetch: false,
272 traits: HashMap::new(),
273 }),
274 }
275 })
276 .collect();
277 let reply = ListServiceWorkerRegistrationsReply {
278 from: self.name(),
279 registrations,
280 };
281 request.reply_final(&reply)?
282 },
283
284 "listTabs" => {
285 let reply = ListTabsReply {
286 from: "root".to_owned(),
287 tabs: self
288 .tabs
289 .borrow()
290 .iter()
291 .filter_map(|tab_descriptor_name| {
292 let tab_descriptor_actor =
293 registry.find::<TabDescriptorActor>(tab_descriptor_name);
294 if tab_descriptor_actor.is_top_level_global() {
296 Some(tab_descriptor_actor.encode(registry))
297 } else {
298 None
299 }
300 })
301 .collect(),
302 };
303 request.reply_final(&reply)?
304 },
305
306 "listWorkers" => {
307 let reply = ListWorkersReply {
308 from: self.name(),
309 workers: self
310 .workers
311 .borrow()
312 .iter()
313 .map(|worker_name| registry.encode::<WorkerActor, _>(worker_name))
314 .collect(),
315 };
316 request.reply_final(&reply)?
317 },
318
319 "protocolDescription" => {
320 let msg = ProtocolDescriptionReply {
321 from: self.name(),
322 types: Types {
323 performance: PerformanceActor::description(),
324 device: DeviceActor::description(),
325 },
326 };
327 request.reply_final(&msg)?
328 },
329
330 "watchResources" => {
331 request.reply_final(&EmptyReplyMsg { from: self.name() })?
333 },
334
335 "unwatchResources" => {
336 request.reply_final(&EmptyReplyMsg { from: self.name() })?
338 },
339
340 _ => return Err(ActorError::UnrecognizedPacketType),
341 };
342 Ok(())
343 }
344}
345
346impl RootActor {
347 pub fn register(registry: &mut ActorRegistry) {
349 let device_name = DeviceActor::register(registry);
351 let performance_name = PerformanceActor::register(registry);
352 let preference_name = PreferenceActor::register(registry);
353
354 let process_name = ProcessActor::register(registry);
356
357 let root_actor = Self {
359 global_actors: GlobalActors {
360 device_actor: device_name,
361 perf_actor: performance_name,
362 preference_actor: preference_name,
363 },
364 process_name,
365 ..Default::default()
366 };
367
368 registry.register(root_actor);
369 }
370
371 fn get_tab_msg_by_browser_id(
372 &self,
373 registry: &ActorRegistry,
374 browser_id: u32,
375 ) -> Option<TabDescriptorActorMsg> {
376 let mut tab_msg = self
377 .tabs
378 .borrow()
379 .iter()
380 .map(|tab_descriptor_name| {
381 registry.encode::<TabDescriptorActor, _>(tab_descriptor_name)
382 })
383 .find(|tab_descriptor_actor| tab_descriptor_actor.browser_id() == browser_id);
384
385 if let Some(ref mut msg) = tab_msg {
386 msg.selected = true;
387 *self.active_tab.borrow_mut() = Some(msg.actor());
388 }
389 tab_msg
390 }
391
392 pub fn active_tab(&self) -> Option<String> {
393 self.active_tab.borrow().clone()
394 }
395}
396
397impl ActorEncode<RootActorMsg> for RootActor {
398 fn encode(&self, _: &ActorRegistry) -> RootActorMsg {
399 RootActorMsg {
400 from: "root".to_owned(),
401 application_type: "browser".to_owned(),
402 traits: RootTraits {
403 sources: false,
404 highlightable: true,
405 custom_highlighters: true,
406 network_monitor: true,
407 resources: HashMap::from([("extensions-backgroundscript-status", true)]),
408 },
409 }
410 }
411}