devtools/actors/
breakpoint.rs1use devtools_traits::DevtoolScriptControlMsg;
6use malloc_size_of_derive::MallocSizeOf;
7use serde::Deserialize;
8use serde_json::Map;
9
10use crate::actor::{Actor, ActorEncode, ActorError, ActorRegistry};
11use crate::actors::browsing_context::BrowsingContextActor;
12use crate::actors::thread::ThreadActor;
13use crate::protocol::ClientRequest;
14use crate::{ActorMsg, EmptyReplyMsg};
15
16#[derive(Deserialize)]
17#[serde(rename_all = "camelCase")]
18pub struct BreakpointRequestLocation {
19 pub line: u32,
20 pub column: u32,
21 #[serde(skip_serializing_if = "Option::is_none")]
22 pub source_url: Option<String>,
23}
24
25#[derive(Deserialize)]
26struct BreakpointRequest {
27 location: BreakpointRequestLocation,
28}
29
30#[derive(MallocSizeOf)]
31pub(crate) struct BreakpointListActor {
32 name: String,
33 browsing_context_name: String,
34}
35
36impl Actor for BreakpointListActor {
37 fn name(&self) -> String {
38 self.name.clone()
39 }
40
41 fn handle_message(
42 &self,
43 request: ClientRequest,
44 registry: &crate::actor::ActorRegistry,
45 msg_type: &str,
46 msg: &Map<String, serde_json::Value>,
47 _stream_id: crate::StreamId,
48 ) -> Result<(), ActorError> {
49 match msg_type {
50 "setBreakpoint" => {
54 let msg: BreakpointRequest =
55 serde_json::from_value(msg.clone().into()).map_err(|_| ActorError::Internal)?;
56 let BreakpointRequestLocation {
57 line,
58 column,
59 source_url,
60 } = msg.location;
61 let source_url = source_url.ok_or(ActorError::Internal)?;
62
63 let browsing_context_actor =
64 registry.find::<BrowsingContextActor>(&self.browsing_context_name);
65 let thread_actor =
66 registry.find::<ThreadActor>(&browsing_context_actor.thread_name);
67 let source = thread_actor
68 .source_manager
69 .find_source(registry, &source_url)
70 .ok_or(ActorError::Internal)?;
71
72 if let Some((script_id, offset)) = source.find_offset(line, column) {
73 source
74 .script_sender
75 .send(DevtoolScriptControlMsg::SetBreakpoint(
76 source.spidermonkey_id,
77 script_id,
78 offset,
79 ))
80 .map_err(|_| ActorError::Internal)?;
81 }
82
83 let msg = EmptyReplyMsg { from: self.name() };
84 request.reply_final(&msg)?
85 },
86 "setActiveEventBreakpoints" => {
87 let msg = EmptyReplyMsg { from: self.name() };
88 request.reply_final(&msg)?
89 },
90 "removeBreakpoint" => {
91 let msg: BreakpointRequest =
92 serde_json::from_value(msg.clone().into()).map_err(|_| ActorError::Internal)?;
93 let BreakpointRequestLocation {
94 line,
95 column,
96 source_url,
97 } = msg.location;
98 let source_url = source_url.ok_or(ActorError::Internal)?;
99
100 let browsing_context_actor =
101 registry.find::<BrowsingContextActor>(&self.browsing_context_name);
102 let thread_actor =
103 registry.find::<ThreadActor>(&browsing_context_actor.thread_name);
104 let source = thread_actor
105 .source_manager
106 .find_source(registry, &source_url)
107 .ok_or(ActorError::Internal)?;
108 if let Some((script_id, offset)) = source.find_offset(line, column) {
109 source
110 .script_sender
111 .send(DevtoolScriptControlMsg::ClearBreakpoint(
112 source.spidermonkey_id,
113 script_id,
114 offset,
115 ))
116 .map_err(|_| ActorError::Internal)?;
117 }
118
119 let msg = EmptyReplyMsg { from: self.name() };
120 request.reply_final(&msg)?
121 },
122 _ => return Err(ActorError::UnrecognizedPacketType),
123 };
124 Ok(())
125 }
126}
127
128impl BreakpointListActor {
129 pub fn register(registry: &ActorRegistry, browsing_context_name: String) -> String {
130 let name = registry.new_name::<Self>();
131 let actor = Self {
132 name: name.clone(),
133 browsing_context_name,
134 };
135 registry.register::<Self>(actor);
136 name
137 }
138}
139
140impl ActorEncode<ActorMsg> for BreakpointListActor {
141 fn encode(&self, _: &ActorRegistry) -> ActorMsg {
142 ActorMsg { actor: self.name() }
143 }
144}