devtools/actors/
thread.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 serde::Serialize;
6use serde_json::{Map, Value};
7
8use super::source::{SourceManager, SourcesReply};
9use crate::actor::{Actor, ActorError, ActorRegistry};
10use crate::protocol::{ClientRequest, JsonPacketStream};
11use crate::{EmptyReplyMsg, StreamId};
12
13#[derive(Serialize)]
14#[serde(rename_all = "camelCase")]
15struct ThreadAttached {
16    from: String,
17    #[serde(rename = "type")]
18    type_: String,
19    actor: String,
20    frame: u32,
21    error: u32,
22    recording_endpoint: u32,
23    execution_point: u32,
24    popped_frames: Vec<PoppedFrameMsg>,
25    why: WhyMsg,
26}
27
28#[derive(Serialize)]
29enum PoppedFrameMsg {}
30
31#[derive(Serialize)]
32struct WhyMsg {
33    #[serde(rename = "type")]
34    type_: String,
35}
36
37#[derive(Serialize)]
38struct ThreadResumedReply {
39    from: String,
40    #[serde(rename = "type")]
41    type_: String,
42}
43
44#[derive(Serialize)]
45struct ThreadInterruptedReply {
46    from: String,
47    #[serde(rename = "type")]
48    type_: String,
49}
50
51pub struct ThreadActor {
52    pub name: String,
53    pub source_manager: SourceManager,
54}
55
56impl ThreadActor {
57    pub fn new(name: String) -> ThreadActor {
58        ThreadActor {
59            name: name.clone(),
60            source_manager: SourceManager::new(),
61        }
62    }
63}
64
65impl Actor for ThreadActor {
66    fn name(&self) -> String {
67        self.name.clone()
68    }
69
70    fn handle_message(
71        &self,
72        mut request: ClientRequest,
73        registry: &ActorRegistry,
74        msg_type: &str,
75        _msg: &Map<String, Value>,
76        _id: StreamId,
77    ) -> Result<(), ActorError> {
78        match msg_type {
79            "attach" => {
80                let msg = ThreadAttached {
81                    from: self.name(),
82                    type_: "paused".to_owned(),
83                    actor: registry.new_name("pause"),
84                    frame: 0,
85                    error: 0,
86                    recording_endpoint: 0,
87                    execution_point: 0,
88                    popped_frames: vec![],
89                    why: WhyMsg {
90                        type_: "attached".to_owned(),
91                    },
92                };
93                request.write_json_packet(&msg)?;
94                request.reply_final(&EmptyReplyMsg { from: self.name() })?
95            },
96
97            "resume" => {
98                let msg = ThreadResumedReply {
99                    from: self.name(),
100                    type_: "resumed".to_owned(),
101                };
102                request.write_json_packet(&msg)?;
103                request.reply_final(&EmptyReplyMsg { from: self.name() })?
104            },
105
106            "interrupt" => {
107                let msg = ThreadInterruptedReply {
108                    from: self.name(),
109                    type_: "interrupted".to_owned(),
110                };
111                request.write_json_packet(&msg)?;
112                request.reply_final(&EmptyReplyMsg { from: self.name() })?
113            },
114
115            "reconfigure" => request.reply_final(&EmptyReplyMsg { from: self.name() })?,
116
117            // Client has attached to the thread and wants to load script sources.
118            // <https://firefox-source-docs.mozilla.org/devtools/backend/protocol.html#loading-script-sources>
119            "sources" => {
120                let msg = SourcesReply {
121                    from: self.name(),
122                    sources: self.source_manager.source_forms(registry),
123                };
124                request.reply_final(&msg)?
125            },
126            _ => return Err(ActorError::UnrecognizedPacketType),
127        };
128        Ok(())
129    }
130}