1use std::collections::HashSet;
6use std::sync::Arc;
7
8use atomic_refcell::AtomicRefCell;
9use devtools_traits::{DevtoolScriptControlMsg, PauseReason};
10use malloc_size_of_derive::MallocSizeOf;
11use serde::{Deserialize, Serialize};
12use serde_json::{Map, Value};
13use servo_base::generic_channel::GenericSender;
14
15use super::source::{SourceManager, SourcesReply};
16use crate::actor::{Actor, ActorError, ActorRegistry, new_actor_name};
17use crate::actors::browsing_context::BrowsingContextActor;
18use crate::actors::frame::{FrameActor, FrameActorMsg};
19use crate::actors::pause::PauseActor;
20use crate::generic_channel::channel;
21use crate::protocol::{ClientRequest, JsonPacketStream};
22use crate::{EmptyReplyMsg, StreamId};
23
24#[derive(Serialize)]
25#[serde(rename_all = "camelCase")]
26struct ThreadAttached {
27 from: String,
28 #[serde(rename = "type")]
29 type_: String,
30 actor: String,
31 frame: u32,
32 error: u32,
33 recording_endpoint: u32,
34 execution_point: u32,
35 popped_frames: Vec<PoppedFrameMsg>,
36 why: PauseReason,
37}
38
39#[derive(Serialize)]
40enum PoppedFrameMsg {}
41
42#[derive(Serialize)]
43struct ThreadResumedReply {
44 from: String,
45 #[serde(rename = "type")]
46 type_: String,
47}
48
49#[derive(Serialize)]
50pub(crate) struct ThreadInterruptedReply {
51 pub from: String,
52 #[serde(rename = "type")]
53 pub type_: String,
54 pub actor: String,
55 pub frame: FrameActorMsg,
56 pub why: PauseReason,
57}
58
59#[derive(Serialize)]
60struct GetAvailableEventBreakpointsReply {
61 from: String,
62 value: Vec<()>,
63}
64
65#[derive(Serialize)]
66struct FramesReply {
67 from: String,
68 frames: Vec<FrameActorMsg>,
69}
70
71#[derive(Debug, Deserialize, Serialize)]
72#[serde(rename_all = "lowercase")]
73enum ResumeLimitType {
74 Break,
75 Finish,
76 Next,
77 Restart,
78 Step,
79}
80
81#[derive(Debug, Deserialize, Serialize)]
82struct ResumeLimit {
83 #[serde(rename = "type")]
84 type_: ResumeLimitType,
85}
86
87#[derive(Deserialize, Debug)]
88#[serde(rename_all = "camelCase")]
89struct ResumeRequest {
90 resume_limit: Option<ResumeLimit>,
91 #[serde(rename = "frameActorID")]
92 #[serde(skip_serializing_if = "Option::is_none")]
93 frame_actor_id: Option<String>,
94}
95
96#[derive(Deserialize, Debug)]
97struct FramesRequest {
98 start: u32,
99 count: u32,
100}
101
102impl ResumeRequest {
103 fn get_type(&self) -> Option<String> {
104 let resume_limit = self.resume_limit.as_ref()?;
105 serde_json::to_string(&resume_limit.type_)
106 .ok()
107 .map(|s| s.trim_matches('"').into())
108 }
109}
110
111#[derive(MallocSizeOf)]
112pub(crate) struct ThreadActor {
113 name: String,
114 pub source_manager: SourceManager,
115 script_sender: GenericSender<DevtoolScriptControlMsg>,
116 pub frames: AtomicRefCell<HashSet<String>>,
117 browsing_context_name: Option<String>,
118}
119
120impl ThreadActor {
121 pub fn register(
122 registry: &ActorRegistry,
123 script_sender: GenericSender<DevtoolScriptControlMsg>,
124 browsing_context_name: Option<String>,
125 ) -> Arc<Self> {
126 let name = new_actor_name::<Self>();
127 let actor = ThreadActor {
128 name,
129 source_manager: SourceManager::new(),
130 script_sender,
131 frames: Default::default(),
132 browsing_context_name,
133 };
134 registry.register::<Self>(actor)
135 }
136}
137
138impl Actor for ThreadActor {
139 fn name(&self) -> &str {
140 &self.name
141 }
142
143 fn handle_message(
144 &self,
145 mut request: ClientRequest,
146 registry: &ActorRegistry,
147 msg_type: &str,
148 msg: &Map<String, Value>,
149 _id: StreamId,
150 ) -> Result<(), ActorError> {
151 match msg_type {
152 "attach" => {
153 let pause_actor = PauseActor::register(registry);
154 let msg = ThreadAttached {
155 from: self.name().into(),
156 type_: "paused".to_owned(),
157 actor: pause_actor.name().into(),
158 frame: 0,
159 error: 0,
160 recording_endpoint: 0,
161 execution_point: 0,
162 popped_frames: vec![],
163 why: PauseReason {
164 type_: "attached".to_owned(),
165 on_next: None,
166 },
167 };
168 request.write_json_packet(&msg)?;
169 request.reply_final(&EmptyReplyMsg {
170 from: self.name().into(),
171 })?
172 },
173
174 "resume" => {
175 let resume: ResumeRequest =
176 serde_json::from_value(msg.clone().into()).map_err(|_| ActorError::Internal)?;
177
178 let _ = self.script_sender.send(DevtoolScriptControlMsg::Resume(
179 resume.get_type(),
180 resume.frame_actor_id,
181 ));
182
183 let msg = ThreadResumedReply {
184 from: self.name().into(),
185 type_: "resumed".to_owned(),
186 };
187 request.write_json_packet(&msg)?;
188 request.reply_final(&EmptyReplyMsg {
189 from: self.name().into(),
190 })?
191 },
192
193 "interrupt" => {
194 self.script_sender
195 .send(DevtoolScriptControlMsg::Interrupt)
196 .map_err(|_| ActorError::Internal)?;
197
198 request.reply_final(&EmptyReplyMsg {
199 from: self.name().into(),
200 })?
201 },
202
203 "reconfigure" => request.reply_final(&EmptyReplyMsg {
204 from: self.name().into(),
205 })?,
206
207 "getAvailableEventBreakpoints" => {
208 let msg = GetAvailableEventBreakpointsReply {
210 from: self.name().into(),
211 value: vec![],
212 };
213 request.reply_final(&msg)?
214 },
215
216 "sources" => {
219 let msg = SourcesReply {
220 from: self.name().into(),
221 sources: self.source_manager.source_forms(registry),
222 };
223 request.reply_final(&msg)?
224 },
225
226 "frames" => {
227 let Some(ref browsing_context_name) = self.browsing_context_name else {
228 return Err(ActorError::Internal);
229 };
230 let browsing_context_actor =
231 registry.find::<BrowsingContextActor>(browsing_context_name);
232
233 let frames: FramesRequest =
234 serde_json::from_value(msg.clone().into()).map_err(|_| ActorError::Internal)?;
235
236 let Some((tx, rx)) = channel() else {
237 return Err(ActorError::Internal);
238 };
239 self.script_sender
240 .send(DevtoolScriptControlMsg::ListFrames(
241 browsing_context_actor.pipeline_id(),
242 frames.start,
243 frames.count,
244 tx,
245 ))
246 .map_err(|_| ActorError::Internal)?;
247
248 let result = rx.recv().map_err(|_| ActorError::Internal)?;
249 let msg = FramesReply {
252 from: self.name().into(),
253 frames: result
254 .iter()
255 .map(|frame_name| registry.encode::<FrameActor, _>(frame_name))
256 .collect(),
257 };
258 request.reply_final(&msg)?
259 },
260
261 _ => return Err(ActorError::UnrecognizedPacketType),
262 };
263 Ok(())
264 }
265}