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