char/avril

(wip) why'd you have to go and make things so complicaaaaated?

git clone https://git.t4t.associates/char/avril

Charlotte Somchore: use lowercase avril branding consistentlyb862289

main
3.4 KiB111 linesraw
1use std::cell::RefCell;
2use std::collections::HashMap;
3use std::rc::Rc;
4
5use serde_json::Value;
6use v8::inspector::{
7    Channel, ChannelImpl, StringBuffer, StringView, V8Inspector, V8InspectorClient,
8    V8InspectorClientImpl, V8InspectorClientTrustLevel, V8InspectorSession,
9};
10
11pub(super) struct Inspector {
12    pub(super) session: V8InspectorSession,
13    pub(super) _inspector: V8Inspector,
14    responses: Rc<RefCell<Responses>>,
15    pub(super) next_id: i32,
16    pub(super) context_id: i32,
17}
18
19#[derive(Default)]
20struct Responses {
21    messages: HashMap<i32, String>,
22    context_id: Option<i32>,
23}
24
25struct ReplChannel(Rc<RefCell<Responses>>);
26
27struct ReplInspectorClient;
28
29impl V8InspectorClientImpl for ReplInspectorClient {}
30
31impl ChannelImpl for ReplChannel {
32    fn send_response(&self, call_id: i32, mut message: v8::UniquePtr<StringBuffer>) {
33        if let Some(message) = message.as_mut() {
34            self.0
35                .borrow_mut()
36                .messages
37                .insert(call_id, message.string().to_string());
38        }
39    }
40
41    fn send_notification(&self, mut message: v8::UniquePtr<StringBuffer>) {
42        let Some(message) = message.as_mut() else {
43            return;
44        };
45        let Ok(value) = serde_json::from_str::<Value>(&message.string().to_string()) else {
46            return;
47        };
48        if value.get("method").and_then(Value::as_str) != Some("Runtime.executionContextCreated") {
49            return;
50        }
51        let context_id = value
52            .get("params")
53            .and_then(|params| params.get("context"))
54            .and_then(|context| context.get("id"))
55            .and_then(Value::as_i64)
56            .and_then(|id| i32::try_from(id).ok());
57        if let Some(context_id) = context_id {
58            self.0.borrow_mut().context_id = Some(context_id);
59        }
60    }
61
62    fn flush_protocol_notifications(&self) {}
63}
64
65impl Inspector {
66    pub(super) fn new(isolate: &mut v8::OwnedIsolate, context: &v8::Global<v8::Context>) -> Self {
67        let client = V8InspectorClient::new(Box::new(ReplInspectorClient));
68        let inspector = V8Inspector::create(isolate, client);
69        {
70            v8::scope!(let scope, isolate);
71            let context = v8::Local::new(scope, context);
72            inspector.context_created(
73                context,
74                1,
75                StringView::from(b"avril REPL" as &[u8]),
76                StringView::from(b"{\"isDefault\":true}" as &[u8]),
77            );
78        }
79        let responses = Rc::new(RefCell::new(Responses::default()));
80        let channel = Channel::new(Box::new(ReplChannel(Rc::clone(&responses))));
81        let session = inspector.connect(
82            1,
83            channel,
84            StringView::from(b"" as &[u8]),
85            V8InspectorClientTrustLevel::Untrusted,
86        );
87        Self {
88            session,
89            _inspector: inspector,
90            responses,
91            next_id: 1,
92            context_id: 0,
93        }
94    }
95
96    pub(super) fn take_response(&mut self, id: i32) -> Option<String> {
97        let mut responses = self.responses.borrow_mut();
98        responses
99            .messages
100            .retain(|response_id, _| *response_id >= id);
101        responses.messages.remove(&id)
102    }
103
104    pub(super) fn has_response(&self, id: i32) -> bool {
105        self.responses.borrow().messages.contains_key(&id)
106    }
107
108    pub(super) fn context_id(&self) -> Option<i32> {
109        self.responses.borrow().context_id
110    }
111}