1use serde::Serialize;
13use serde_json::{Map, Value};
14
15use crate::StreamId;
16use crate::actor::{Actor, ActorError, ActorRegistry};
17use crate::actors::browsing_context::{BrowsingContextActor, BrowsingContextActorMsg};
18use crate::actors::root::{DescriptorTraits, RootActor};
19use crate::actors::watcher::{WatcherActor, WatcherActorMsg};
20use crate::protocol::ClientRequest;
21
22#[derive(Serialize)]
23#[serde(rename_all = "camelCase")]
24pub struct TabDescriptorActorMsg {
25 actor: String,
26 #[serde(rename = "browserId")]
28 browser_id: u32,
29 #[serde(rename = "browsingContextID")]
30 browsing_context_id: u32,
31 is_zombie_tab: bool,
32 #[serde(rename = "outerWindowID")]
33 outer_window_id: u32,
34 selected: bool,
35 title: String,
36 traits: DescriptorTraits,
37 url: String,
38}
39
40impl TabDescriptorActorMsg {
41 pub fn browser_id(&self) -> u32 {
42 self.browser_id
43 }
44
45 pub fn actor(&self) -> String {
46 self.actor.clone()
47 }
48}
49
50#[derive(Serialize)]
51struct GetTargetReply {
52 from: String,
53 frame: BrowsingContextActorMsg,
54}
55
56#[derive(Serialize)]
57struct GetFaviconReply {
58 from: String,
59 favicon: String,
60}
61
62#[derive(Serialize)]
63struct GetWatcherReply {
64 from: String,
65 #[serde(flatten)]
66 watcher: WatcherActorMsg,
67}
68
69pub struct TabDescriptorActor {
70 name: String,
71 browsing_context_actor: String,
72 is_top_level_global: bool,
73}
74
75impl Actor for TabDescriptorActor {
76 fn name(&self) -> String {
77 self.name.clone()
78 }
79
80 fn handle_message(
89 &self,
90 request: ClientRequest,
91 registry: &ActorRegistry,
92 msg_type: &str,
93 _msg: &Map<String, Value>,
94 _id: StreamId,
95 ) -> Result<(), ActorError> {
96 match msg_type {
97 "getTarget" => {
98 let frame = registry
99 .find::<BrowsingContextActor>(&self.browsing_context_actor)
100 .encodable();
101 request.reply_final(&GetTargetReply {
102 from: self.name(),
103 frame,
104 })?
105 },
106 "getFavicon" => {
107 request.reply_final(&GetFaviconReply {
109 from: self.name(),
110 favicon: String::new(),
111 })?
112 },
113 "getWatcher" => {
114 let ctx_actor = registry.find::<BrowsingContextActor>(&self.browsing_context_actor);
115 let watcher = registry.find::<WatcherActor>(&ctx_actor.watcher);
116 request.reply_final(&GetWatcherReply {
117 from: self.name(),
118 watcher: watcher.encodable(),
119 })?
120 },
121 _ => return Err(ActorError::UnrecognizedPacketType),
122 };
123 Ok(())
124 }
125}
126
127impl TabDescriptorActor {
128 pub(crate) fn new(
129 actors: &mut ActorRegistry,
130 browsing_context_actor: String,
131 is_top_level_global: bool,
132 ) -> TabDescriptorActor {
133 let name = actors.new_name("tab-description");
134 let root = actors.find_mut::<RootActor>("root");
135 root.tabs.push(name.clone());
136 TabDescriptorActor {
137 name,
138 browsing_context_actor,
139 is_top_level_global,
140 }
141 }
142
143 pub fn encodable(&self, registry: &ActorRegistry, selected: bool) -> TabDescriptorActorMsg {
144 let ctx_actor = registry.find::<BrowsingContextActor>(&self.browsing_context_actor);
145 let title = ctx_actor.title.borrow().clone();
146 let url = ctx_actor.url.borrow().clone();
147
148 TabDescriptorActorMsg {
149 actor: self.name(),
150 browser_id: ctx_actor.browser_id.value(),
151 browsing_context_id: ctx_actor.browsing_context_id.value(),
152 is_zombie_tab: false,
153 outer_window_id: ctx_actor.active_outer_window_id.get().value(),
154 selected,
155 title,
156 traits: DescriptorTraits {
157 watcher: true,
158 supports_reload_descriptor: true,
159 },
160 url,
161 }
162 }
163
164 pub(crate) fn is_top_level_global(&self) -> bool {
165 self.is_top_level_global
166 }
167
168 #[allow(dead_code)]
169 pub fn browsing_context(&self) -> String {
170 self.browsing_context_actor.clone()
171 }
172}