Skip to main content

devtools/actors/
blackboxing.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use std::sync::Arc;
6
7use devtools_traits::{BlackboxCoverage, DevtoolScriptControlMsg};
8use malloc_size_of_derive::MallocSizeOf;
9use serde::Deserialize;
10
11use crate::actor::{Actor, ActorEncode, ActorError, ActorRegistry, new_actor_name};
12use crate::actors::browsing_context::BrowsingContextActor;
13use crate::actors::thread::ThreadActor;
14use crate::{ActorMsg, EmptyReplyMsg};
15
16/// Used for both 'blackbox' and 'unblackbox' requests
17#[derive(Deserialize)]
18struct BlackboxRequest {
19    range: Vec<BlackboxRange>,
20    url: String,
21}
22
23#[derive(Deserialize, Debug)]
24struct BlackboxRange {
25    start: BlackboxSourceLocation,
26    end: BlackboxSourceLocation,
27}
28
29#[derive(Deserialize, Debug)]
30struct BlackboxSourceLocation {
31    line: u32,
32    column: u32,
33}
34
35#[derive(MallocSizeOf)]
36pub(crate) struct BlackboxingActor {
37    name: String,
38    browsing_context_name: String,
39}
40
41impl Actor for BlackboxingActor {
42    fn name(&self) -> &str {
43        &self.name
44    }
45
46    fn handle_message(
47        &self,
48        request: crate::protocol::ClientRequest,
49        registry: &ActorRegistry,
50        msg_type: &str,
51        msg: &serde_json::Map<String, serde_json::Value>,
52        _: crate::StreamId,
53    ) -> Result<(), crate::actor::ActorError> {
54        if msg_type != "blackbox" && msg_type != "unblackbox" {
55            return Err(ActorError::UnrecognizedPacketType);
56        }
57
58        let blackbox_request: BlackboxRequest =
59            serde_json::from_value(msg.clone().into()).map_err(|_| ActorError::Internal)?;
60
61        let coverage = match &blackbox_request.range[..] {
62            [] => BlackboxCoverage::Full,
63            [range] => BlackboxCoverage::Partial(
64                (range.start.line, range.start.column),
65                (range.end.line, range.end.column),
66            ),
67            _ => {
68                log::warn!(
69                    "Expected 0 or 1 range elements, got {:?}",
70                    blackbox_request.range
71                );
72                return Err(ActorError::Internal);
73            },
74        };
75
76        let browsing_context_actor =
77            registry.find::<BrowsingContextActor>(&self.browsing_context_name);
78        let thread_actor = registry.find::<ThreadActor>(&browsing_context_actor.thread_name);
79        let source = thread_actor
80            .source_manager
81            .find_source(registry, &blackbox_request.url)
82            .ok_or(ActorError::Internal)?;
83
84        let control_msg = match msg_type {
85            "blackbox" => DevtoolScriptControlMsg::Blackbox(source.spidermonkey_id, coverage),
86            "unblackbox" => DevtoolScriptControlMsg::Unblackbox(source.spidermonkey_id, coverage),
87            _ => unreachable!(),
88        };
89        source
90            .script_sender
91            .send(control_msg)
92            .map_err(|_| ActorError::Internal)?;
93
94        request.reply_final(&EmptyReplyMsg {
95            from: self.name().into(),
96        })?;
97        Ok(())
98    }
99}
100
101impl BlackboxingActor {
102    pub fn register(registry: &ActorRegistry, browsing_context_name: String) -> Arc<Self> {
103        let name = new_actor_name::<Self>();
104        let actor = Self {
105            name,
106            browsing_context_name,
107        };
108        registry.register::<Self>(actor)
109    }
110}
111
112impl ActorEncode<ActorMsg> for BlackboxingActor {
113    fn encode(&self, _: &ActorRegistry) -> ActorMsg {
114        ActorMsg {
115            actor: self.name().into(),
116        }
117    }
118}