1#[cfg(feature = "system")]
2use std::sync::atomic::Ordering;
3
4use dapts::IRequest;
5
6use super::*;
7
8impl LspClient {
9 pub fn send_dap_event<E: dapts::IEvent>(&self, body: E::Body) {
11 let req_id = self.req_queue.lock().outgoing.alloc_request_id();
12
13 self.send_dap_event_(dap::Event::new(req_id as i64, E::EVENT.to_owned(), body));
14 }
15
16 pub fn send_dap_event_(&self, evt: dap::Event) {
18 self.sender.send_message(evt.into());
19 }
20}
21
22impl<Args: Initializer> LsBuilder<DapMessage, Args>
23where
24 Args::S: 'static,
25{
26 pub fn with_command<R: Serialize + 'static>(
28 mut self,
29 cmd: &'static str,
30 handler: AsyncHandler<Args::S, Vec<JsonValue>, R>,
31 ) -> Self {
32 self.command_handlers.insert(
33 cmd,
34 Box::new(move |s, _req_id, req| erased_response(handler(s, req))),
35 );
36 self
37 }
38
39 pub fn with_raw_request<R: IRequest>(
42 mut self,
43 handler: RawHandler<Args::S, JsonValue>,
44 ) -> Self {
45 self.req_handlers
46 .insert(R::COMMAND, Box::new(move |s, _req_id, req| handler(s, req)));
47 self
48 }
49
50 pub fn with_request_<R: IRequest>(
54 mut self,
55 handler: fn(&mut Args::S, RequestId, R::Arguments) -> ScheduledResult,
56 ) -> Self {
57 self.req_handlers.insert(
58 R::COMMAND,
59 Box::new(move |s, req_id, req| scheduled_response(handler(s, req_id, from_json(req)?))),
60 );
61 self
62 }
63
64 pub fn with_request<R: IRequest>(
66 mut self,
67 handler: AsyncHandler<Args::S, R::Arguments, R::Response>,
68 ) -> Self {
69 self.req_handlers.insert(
70 R::COMMAND,
71 Box::new(move |s, _req_id, req| erased_response(handler(s, from_json(req)?))),
72 );
73 self
74 }
75}
76
77#[cfg(feature = "system")]
78impl<Args: Initializer> LsDriver<DapMessage, Args>
79where
80 Args::S: 'static,
81{
82 pub fn start(
90 &mut self,
91 inbox: TConnectionRx<DapMessage>,
92 is_replay: bool,
93 ) -> anyhow::Result<()> {
94 let res = self.start_(inbox);
95
96 if is_replay {
97 let client = self.client.clone();
98 let _ = std::thread::spawn(move || {
99 let since = tinymist_std::time::Instant::now();
100 let timeout = std::env::var("REPLAY_TIMEOUT")
101 .ok()
102 .and_then(|s| s.parse().ok())
103 .unwrap_or(60);
104 client.handle.block_on(async {
105 while client.has_pending_requests() {
106 if since.elapsed().as_secs() > timeout {
107 log::error!("replay timeout reached, {timeout}s");
108 client.begin_panic();
109 }
110
111 tokio::time::sleep(tinymist_std::time::Duration::from_millis(10)).await;
112 }
113 })
114 })
115 .join();
116 }
117
118 res
119 }
120
121 pub fn start_(&mut self, inbox: TConnectionRx<DapMessage>) -> anyhow::Result<()> {
123 use EventOrMessage::*;
124
125 while let Ok(msg) = inbox.recv() {
126 let loop_start = tinymist_std::time::now();
127 match msg {
128 Evt(event) => {
129 let Some(event_handler) = self.events.get(&event.as_ref().type_id()) else {
130 log::warn!("unhandled event: {:?}", event.as_ref().type_id());
131 continue;
132 };
133
134 let s = match &mut self.state {
135 State::Uninitialized(u) => ServiceState::Uninitialized(u.as_deref_mut()),
136 State::Initializing(s) | State::Ready(s) => ServiceState::Ready(s),
137 State::ShuttingDown => {
138 log::warn!("server is shutting down");
139 continue;
140 }
141 };
142
143 event_handler(s, &self.client, event)?;
144 }
145 Msg(DapMessage::Request(req)) => {
146 let client = self.client.clone();
147 let req_id = (req.seq as i32).into();
148 client.register_request(&req.command, &req_id, loop_start);
149 let fut = client.schedule_tail(req_id.clone(), self.on_request(req_id, req));
150 self.client.handle.spawn(fut);
151 }
152 Msg(DapMessage::Event(not)) => {
153 self.on_event(loop_start, not)?;
154 }
155 Msg(
156 DapMessage::Response(resp)
157 | DapMessage::ResponseWithCommand(dap::ResponseWithCommand {
158 response: resp,
159 ..
160 }),
161 ) => {
162 let s = match &mut self.state {
163 State::Ready(s) => s,
164 _ => {
165 log::warn!("server is not ready yet");
166 continue;
167 }
168 };
169
170 self.client.clone().complete_dap_request(s, resp)
171 }
172 }
173 }
174
175 log::warn!("client exited without proper shutdown sequence");
176 Ok(())
177 }
178
179 fn on_request(&mut self, req_id: RequestId, req: dap::Request) -> ScheduleResult {
182 match (&mut self.state, &*req.command) {
183 (State::Uninitialized(args), dapts::request::Initialize::COMMAND) => {
184 let params = serde_json::from_value::<Args::I>(req.arguments);
186 match params {
187 Ok(params) => {
188 let args = args.take().expect("already initialized");
189 let (s, res) = args.initialize(params);
190 self.state = State::Ready(s);
191 res
192 }
193 Err(e) => just_result(Err(invalid_request(e))),
194 }
195 }
196 (State::Uninitialized(..) | State::Initializing(..), _) => {
218 just_result(Err(not_initialized()))
219 }
220 (_, dapts::request::Initialize::COMMAND) => {
221 just_result(Err(invalid_request("server is already initialized")))
222 }
223 (State::Ready(s), _) => 'serve_req: {
228 let method = req.command.as_str();
229
230 let is_disconnect = method == dapts::request::Disconnect::COMMAND;
231
232 let Some(handler) = self.requests.get(method) else {
233 log::warn!("unhandled dap request: {method}");
234 break 'serve_req just_result(Err(method_not_found()));
235 };
236
237 let resp = handler(s, req_id, req.arguments);
238
239 if is_disconnect {
240 self.state = State::ShuttingDown;
241 }
242
243 resp
244 }
245 (State::ShuttingDown, _) => {
246 just_result(Err(invalid_request("server is shutting down")))
247 }
248 }
249 }
250
251 fn on_event(&mut self, received_at: Time, not: dap::Event) -> anyhow::Result<()> {
253 let track_id = self.next_not_id.fetch_add(1, Ordering::Relaxed);
254 self.client.hook.start_notification(track_id, ¬.event);
255 let handle = |s,
256 dap::Event {
257 seq: _,
258 event,
259 body,
260 }: dap::Event| {
261 let Some(handler) = self.notifications.get(event.as_str()) else {
262 log::warn!("unhandled event: {event}");
263 return Ok(());
264 };
265
266 let result = handler(s, body);
267 self.client
268 .hook
269 .stop_notification(track_id, &event, received_at, result);
270
271 Ok(())
272 };
273
274 match (&mut self.state, &*not.event) {
275 (State::Ready(state), _) => handle(state, not),
276 (State::Uninitialized(..) | State::Initializing(..), method) => {
278 log::warn!("server is not ready yet, while received event {method}");
279 Ok(())
280 }
281 (State::ShuttingDown, method) => {
282 log::warn!("server is shutting down, while received event {method}");
283 Ok(())
284 }
285 }
286 }
287}