1use std::cell::RefCell;
13
14use serde::Serialize;
15use serde_json::{Map, Value, json};
16
17use crate::StreamId;
18use crate::actor::{Actor, ActorError, ActorRegistry};
19use crate::actors::device::DeviceActor;
20use crate::actors::performance::PerformanceActor;
21use crate::actors::process::{ProcessActor, ProcessActorMsg};
22use crate::actors::tab::{TabDescriptorActor, TabDescriptorActorMsg};
23use crate::actors::worker::{WorkerActor, WorkerMsg};
24use crate::protocol::{ActorDescription, ClientRequest};
25
26#[derive(Serialize)]
27#[serde(rename_all = "camelCase")]
28struct ActorTraits {
29 sources: bool,
30 highlightable: bool,
31 custom_highlighters: bool,
32 network_monitor: bool,
33}
34
35#[derive(Serialize)]
36struct ListAddonsReply {
37 from: String,
38 addons: Vec<AddonMsg>,
39}
40
41#[derive(Serialize)]
42enum AddonMsg {}
43
44#[derive(Serialize)]
45#[serde(rename_all = "camelCase")]
46struct GetRootReply {
47 from: String,
48 selected: u32,
49 performance_actor: String,
50 device_actor: String,
51 preference_actor: String,
52}
53
54#[derive(Serialize)]
55struct ListTabsReply {
56 from: String,
57 tabs: Vec<TabDescriptorActorMsg>,
58}
59
60#[derive(Serialize)]
61struct GetTabReply {
62 from: String,
63 tab: TabDescriptorActorMsg,
64}
65
66#[derive(Serialize)]
67#[serde(rename_all = "camelCase")]
68pub struct RootActorMsg {
69 from: String,
70 application_type: String,
71 traits: ActorTraits,
72}
73
74#[derive(Serialize)]
75pub struct ProtocolDescriptionReply {
76 from: String,
77 types: Types,
78}
79
80#[derive(Serialize)]
81struct ListWorkersReply {
82 from: String,
83 workers: Vec<WorkerMsg>,
84}
85
86#[derive(Serialize)]
87struct ListServiceWorkerRegistrationsReply {
88 from: String,
89 registrations: Vec<u32>, }
91
92#[derive(Serialize)]
93pub struct Types {
94 performance: ActorDescription,
95 device: ActorDescription,
96}
97
98#[derive(Serialize)]
99struct ListProcessesResponse {
100 from: String,
101 processes: Vec<ProcessActorMsg>,
102}
103
104#[derive(Default, Serialize)]
105#[serde(rename_all = "camelCase")]
106pub struct DescriptorTraits {
107 pub(crate) watcher: bool,
108 pub(crate) supports_reload_descriptor: bool,
109}
110
111#[derive(Serialize)]
112#[serde(rename_all = "camelCase")]
113struct GetProcessResponse {
114 from: String,
115 process_descriptor: ProcessActorMsg,
116}
117
118pub struct RootActor {
119 pub tabs: Vec<String>,
120 pub workers: Vec<String>,
121 pub performance: String,
122 pub device: String,
123 pub preference: String,
124 pub process: String,
125 pub active_tab: RefCell<Option<String>>,
126}
127
128impl Actor for RootActor {
129 fn name(&self) -> String {
130 "root".to_owned()
131 }
132
133 fn handle_message(
134 &self,
135 request: ClientRequest,
136 registry: &ActorRegistry,
137 msg_type: &str,
138 msg: &Map<String, Value>,
139 _id: StreamId,
140 ) -> Result<(), ActorError> {
141 match msg_type {
142 "connect" => {
143 let message = json!({
144 "from": "root",
145 });
146 request.reply_final(&message)?
147 },
148 "listAddons" => {
149 let actor = ListAddonsReply {
150 from: "root".to_owned(),
151 addons: vec![],
152 };
153 request.reply_final(&actor)?
154 },
155
156 "listProcesses" => {
157 let process = registry.find::<ProcessActor>(&self.process).encodable();
158 let reply = ListProcessesResponse {
159 from: self.name(),
160 processes: vec![process],
161 };
162 request.reply_final(&reply)?
163 },
164
165 "getProcess" => {
167 let process = registry.find::<ProcessActor>(&self.process).encodable();
168 let reply = GetProcessResponse {
169 from: self.name(),
170 process_descriptor: process,
171 };
172 request.reply_final(&reply)?
173 },
174
175 "getRoot" => {
176 let actor = GetRootReply {
177 from: "root".to_owned(),
178 selected: 0,
179 performance_actor: self.performance.clone(),
180 device_actor: self.device.clone(),
181 preference_actor: self.preference.clone(),
182 };
183 request.reply_final(&actor)?
184 },
185
186 "listTabs" => {
187 let actor = ListTabsReply {
188 from: "root".to_owned(),
189 tabs: self
190 .tabs
191 .iter()
192 .filter_map(|target| {
193 let tab_actor = registry.find::<TabDescriptorActor>(target);
194 if tab_actor.is_top_level_global() {
196 Some(tab_actor.encodable(registry, false))
197 } else {
198 None
199 }
200 })
201 .collect(),
202 };
203 request.reply_final(&actor)?
204 },
205
206 "listServiceWorkerRegistrations" => {
207 let reply = ListServiceWorkerRegistrationsReply {
208 from: self.name(),
209 registrations: vec![],
210 };
211 request.reply_final(&reply)?
212 },
213
214 "listWorkers" => {
215 let reply = ListWorkersReply {
216 from: self.name(),
217 workers: self
218 .workers
219 .iter()
220 .map(|name| registry.find::<WorkerActor>(name).encodable())
221 .collect(),
222 };
223 request.reply_final(&reply)?
224 },
225
226 "getTab" => {
227 let browser_id = msg
228 .get("browserId")
229 .ok_or(ActorError::MissingParameter)?
230 .as_u64()
231 .ok_or(ActorError::BadParameterType)?;
232 let Some(tab) = self.get_tab_msg_by_browser_id(registry, browser_id as u32) else {
233 return Err(ActorError::Internal);
234 };
235
236 let reply = GetTabReply {
237 from: self.name(),
238 tab,
239 };
240 request.reply_final(&reply)?
241 },
242
243 "protocolDescription" => {
244 let msg = ProtocolDescriptionReply {
245 from: self.name(),
246 types: Types {
247 performance: PerformanceActor::description(),
248 device: DeviceActor::description(),
249 },
250 };
251 request.reply_final(&msg)?
252 },
253
254 _ => return Err(ActorError::UnrecognizedPacketType),
255 };
256 Ok(())
257 }
258}
259
260impl RootActor {
261 pub fn encodable(&self) -> RootActorMsg {
262 RootActorMsg {
263 from: "root".to_owned(),
264 application_type: "browser".to_owned(),
265 traits: ActorTraits {
266 sources: false,
267 highlightable: true,
268 custom_highlighters: true,
269 network_monitor: true,
270 },
271 }
272 }
273
274 fn get_tab_msg_by_browser_id(
275 &self,
276 registry: &ActorRegistry,
277 browser_id: u32,
278 ) -> Option<TabDescriptorActorMsg> {
279 let tab_msg = self
280 .tabs
281 .iter()
282 .map(|target| {
283 registry
284 .find::<TabDescriptorActor>(target)
285 .encodable(registry, true)
286 })
287 .find(|tab| tab.browser_id() == browser_id);
288
289 if let Some(ref msg) = tab_msg {
290 *self.active_tab.borrow_mut() = Some(msg.actor());
291 }
292 tab_msg
293 }
294
295 #[allow(dead_code)]
296 pub fn active_tab(&self) -> Option<String> {
297 self.active_tab.borrow().clone()
298 }
299}