use devtools_traits::DevtoolScriptControlMsg;
use malloc_size_of_derive::MallocSizeOf;
use serde::Deserialize;
use serde_json::Map;
use crate::actor::{Actor, ActorEncode, ActorError, ActorRegistry};
use crate::actors::browsing_context::BrowsingContextActor;
use crate::actors::thread::ThreadActor;
use crate::protocol::ClientRequest;
use crate::{ActorMsg, EmptyReplyMsg};
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BreakpointRequestLocation {
pub line: u32,
pub column: u32,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_url: Option<String>,
}
#[derive(Deserialize)]
struct BreakpointRequest {
location: BreakpointRequestLocation,
}
#[derive(MallocSizeOf)]
pub(crate) struct BreakpointListActor {
name: String,
browsing_context_name: String,
}
impl Actor for BreakpointListActor {
fn name(&self) -> String {
self.name.clone()
}
fn handle_message(
&self,
request: ClientRequest,
registry: &crate::actor::ActorRegistry,
msg_type: &str,
msg: &Map<String, serde_json::Value>,
_stream_id: crate::StreamId,
) -> Result<(), ActorError> {
match msg_type {
"setBreakpoint" => {
let msg: BreakpointRequest =
serde_json::from_value(msg.clone().into()).map_err(|_| ActorError::Internal)?;
let BreakpointRequestLocation {
line,
column,
source_url,
} = msg.location;
let source_url = source_url.ok_or(ActorError::Internal)?;
let browsing_context_actor =
registry.find::<BrowsingContextActor>(&self.browsing_context_name);
let thread_actor =
registry.find::<ThreadActor>(&browsing_context_actor.thread_name);
let source = thread_actor
.source_manager
.find_source(registry, &source_url)
.ok_or(ActorError::Internal)?;
if let Some((script_id, offset)) = source.find_offset(line, column) {
source
.script_sender
.send(DevtoolScriptControlMsg::SetBreakpoint(
source.spidermonkey_id,
script_id,
offset,
))
.map_err(|_| ActorError::Internal)?;
}
let msg = EmptyReplyMsg { from: self.name() };
request.reply_final(&msg)?
},
"setActiveEventBreakpoints" => {
let msg = EmptyReplyMsg { from: self.name() };
request.reply_final(&msg)?
},
"removeBreakpoint" => {
let msg: BreakpointRequest =
serde_json::from_value(msg.clone().into()).map_err(|_| ActorError::Internal)?;
let BreakpointRequestLocation {
line,
column,
source_url,
} = msg.location;
let source_url = source_url.ok_or(ActorError::Internal)?;
let browsing_context_actor =
registry.find::<BrowsingContextActor>(&self.browsing_context_name);
let thread_actor =
registry.find::<ThreadActor>(&browsing_context_actor.thread_name);
let source = thread_actor
.source_manager
.find_source(registry, &source_url)
.ok_or(ActorError::Internal)?;
if let Some((script_id, offset)) = source.find_offset(line, column) {
source
.script_sender
.send(DevtoolScriptControlMsg::ClearBreakpoint(
source.spidermonkey_id,
script_id,
offset,
))
.map_err(|_| ActorError::Internal)?;
}
let msg = EmptyReplyMsg { from: self.name() };
request.reply_final(&msg)?
},
_ => return Err(ActorError::UnrecognizedPacketType),
};
Ok(())
}
}
impl BreakpointListActor {
pub fn new(name: String, browsing_context_name: String) -> Self {
Self {
name,
browsing_context_name,
}
}
}
impl ActorEncode<ActorMsg> for BreakpointListActor {
fn encode(&self, _: &ActorRegistry) -> ActorMsg {
ActorMsg { actor: self.name() }
}
}