Skip to content

Commit be601ad

Browse files
committed
Propagate connection errors from handlers and recover gracefully
1 parent 97c832e commit be601ad

File tree

1 file changed

+87
-75
lines changed

1 file changed

+87
-75
lines changed

crates/ark/src/dap/dap_server.rs

Lines changed: 87 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use crossbeam::channel::unbounded;
2222
use crossbeam::channel::Receiver;
2323
use crossbeam::channel::Sender;
2424
use crossbeam::select;
25+
use dap::errors::ServerError;
2526
use dap::events::*;
2627
use dap::prelude::*;
2728
use dap::requests::*;
@@ -253,83 +254,71 @@ impl<R: Read, W: Write> DapServer<R, W> {
253254

254255
let cmd = req.command.clone();
255256

256-
match cmd {
257-
Command::Initialize(args) => {
258-
self.handle_initialize(req, args);
259-
},
260-
Command::Attach(args) => {
261-
self.handle_attach(req, args);
262-
},
263-
Command::Disconnect(args) => {
264-
self.handle_disconnect(req, args);
265-
},
266-
Command::Restart(args) => {
267-
self.handle_restart(req, args);
268-
},
269-
Command::Threads => {
270-
self.handle_threads(req);
271-
},
272-
Command::SetBreakpoints(args) => {
273-
self.handle_set_breakpoints(req, args);
274-
},
257+
let result = match cmd {
258+
Command::Initialize(args) => self.handle_initialize(req, args),
259+
Command::Attach(args) => self.handle_attach(req, args),
260+
Command::Disconnect(args) => self.handle_disconnect(req, args),
261+
Command::Restart(args) => self.handle_restart(req, args),
262+
Command::Threads => self.handle_threads(req),
263+
Command::SetBreakpoints(args) => self.handle_set_breakpoints(req, args),
275264
Command::SetExceptionBreakpoints(args) => {
276-
self.handle_set_exception_breakpoints(req, args);
277-
},
278-
Command::StackTrace(args) => {
279-
self.handle_stacktrace(req, args);
280-
},
281-
Command::Source(args) => {
282-
self.handle_source(req, args);
283-
},
284-
Command::Scopes(args) => {
285-
self.handle_scopes(req, args);
286-
},
287-
Command::Variables(args) => {
288-
self.handle_variables(req, args);
265+
self.handle_set_exception_breakpoints(req, args)
289266
},
267+
Command::StackTrace(args) => self.handle_stacktrace(req, args),
268+
Command::Source(args) => self.handle_source(req, args),
269+
Command::Scopes(args) => self.handle_scopes(req, args),
270+
Command::Variables(args) => self.handle_variables(req, args),
290271
Command::Continue(args) => {
291272
let resp = ResponseBody::Continue(ContinueResponse {
292273
all_threads_continued: Some(true),
293274
});
294-
self.handle_step(req, args, DebugRequest::Continue, resp);
275+
self.handle_step(req, args, DebugRequest::Continue, resp)
295276
},
296277
Command::Next(args) => {
297-
self.handle_step(req, args, DebugRequest::Next, ResponseBody::Next);
278+
self.handle_step(req, args, DebugRequest::Next, ResponseBody::Next)
298279
},
299280
Command::StepIn(args) => {
300-
self.handle_step(req, args, DebugRequest::StepIn, ResponseBody::StepIn);
281+
self.handle_step(req, args, DebugRequest::StepIn, ResponseBody::StepIn)
301282
},
302283
Command::StepOut(args) => {
303-
self.handle_step(req, args, DebugRequest::StepOut, ResponseBody::StepOut);
284+
self.handle_step(req, args, DebugRequest::StepOut, ResponseBody::StepOut)
304285
},
305286
_ => {
306287
log::warn!("DAP: Unknown request");
307288
let rsp = req.error("Ark DAP: Unknown request");
308-
self.server.respond(rsp).unwrap();
289+
self.respond(rsp)
309290
},
291+
};
292+
293+
if let Err(err) = result {
294+
log::warn!("DAP: Handler failed, closing connection: {err}");
295+
return false;
310296
}
311297

312298
true
313299
}
314300

315-
fn respond(&mut self, rsp: Response) {
301+
fn respond(&mut self, rsp: Response) -> Result<(), ServerError> {
316302
log::trace!("DAP: Responding to request: {rsp:#?}");
317-
self.server.respond(rsp).unwrap();
303+
self.server.respond(rsp)
318304
}
319305

320-
fn send_event(&mut self, event: Event) {
306+
fn send_event(&mut self, event: Event) -> Result<(), ServerError> {
321307
log::trace!("DAP: Sending event: {event:#?}");
322-
self.server.send_event(event).unwrap();
308+
self.server.send_event(event)
323309
}
324310

325-
fn handle_initialize(&mut self, req: Request, _args: InitializeArguments) {
311+
fn handle_initialize(
312+
&mut self,
313+
req: Request,
314+
_args: InitializeArguments,
315+
) -> Result<(), ServerError> {
326316
let rsp = req.success(ResponseBody::Initialize(types::Capabilities {
327317
supports_restart_request: Some(true),
328318
..Default::default()
329319
}));
330-
self.respond(rsp);
331-
332-
self.send_event(Event::Initialized);
320+
self.respond(rsp)?;
321+
self.send_event(Event::Initialized)
333322
}
334323

335324
// Handle SetBreakpoints requests from the frontend.
@@ -347,12 +336,15 @@ impl<R: Read, W: Write> DapServer<R, W> {
347336
// - When a user unchecks a breakpoint, it appears as a deletion (omitted
348337
// from the request). We preserve verified breakpoints as Disabled so we
349338
// can restore their state when re-enabled without requiring re-sourcing.
350-
fn handle_set_breakpoints(&mut self, req: Request, args: SetBreakpointsArguments) {
339+
fn handle_set_breakpoints(
340+
&mut self,
341+
req: Request,
342+
args: SetBreakpointsArguments,
343+
) -> Result<(), ServerError> {
351344
let Some(path) = args.source.path.as_ref() else {
352345
// We don't currently have virtual documents managed via source references
353346
log::warn!("Missing a path to set breakpoints for.");
354-
self.respond(req.error("Missing a path to set breakpoints for"));
355-
return;
347+
return self.respond(req.error("Missing a path to set breakpoints for"));
356348
};
357349

358350
// We currently only support "path" URIs as Positron never sends URIs.
@@ -365,8 +357,7 @@ impl<R: Read, W: Write> DapServer<R, W> {
365357
let rsp = req.success(ResponseBody::SetBreakpoints(SetBreakpointsResponse {
366358
breakpoints: vec![],
367359
}));
368-
self.respond(rsp);
369-
return;
360+
return self.respond(rsp);
370361
},
371362
};
372363

@@ -377,10 +368,9 @@ impl<R: Read, W: Write> DapServer<R, W> {
377368
Ok(content) => content,
378369
Err(err) => {
379370
// TODO: What do we do with breakpoints in virtual documents?
380-
log::error!("Failed to read file '{path}': {err}");
371+
log::warn!("Failed to read file '{path}': {err}");
381372
let rsp = req.error(&format!("Failed to read file: {path}"));
382-
self.respond(rsp);
383-
return;
373+
return self.respond(rsp);
384374
},
385375
};
386376

@@ -518,31 +508,39 @@ impl<R: Read, W: Write> DapServer<R, W> {
518508
breakpoints: response_breakpoints,
519509
}));
520510

521-
self.respond(rsp);
511+
self.respond(rsp)
522512
}
523513

524-
fn handle_attach(&mut self, req: Request, _args: AttachRequestArguments) {
514+
fn handle_attach(
515+
&mut self,
516+
req: Request,
517+
_args: AttachRequestArguments,
518+
) -> Result<(), ServerError> {
525519
let rsp = req.success(ResponseBody::Attach);
526-
self.respond(rsp);
520+
self.respond(rsp)?;
527521

528522
self.send_event(Event::Thread(ThreadEventBody {
529523
reason: ThreadEventReason::Started,
530524
thread_id: THREAD_ID,
531-
}));
525+
}))
532526
}
533527

534-
fn handle_disconnect(&mut self, req: Request, _args: DisconnectArguments) {
528+
fn handle_disconnect(
529+
&mut self,
530+
req: Request,
531+
_args: DisconnectArguments,
532+
) -> Result<(), ServerError> {
535533
// Only send `Q` if currently in a debugging session.
536534
let is_debugging = { self.state.lock().unwrap().is_debugging };
537535
if is_debugging {
538536
self.send_command(DebugRequest::Quit);
539537
}
540538

541539
let rsp = req.success(ResponseBody::Disconnect);
542-
self.respond(rsp);
540+
self.respond(rsp)
543541
}
544542

545-
fn handle_restart<T>(&mut self, req: Request, _args: T) {
543+
fn handle_restart<T>(&mut self, req: Request, _args: T) -> Result<(), ServerError> {
546544
// If connected to Positron, forward the restart command to the
547545
// frontend. Otherwise ignore it.
548546
if let Some(tx) = &self.comm_tx {
@@ -551,35 +549,39 @@ impl<R: Read, W: Write> DapServer<R, W> {
551549
}
552550

553551
let rsp = req.success(ResponseBody::Restart);
554-
self.respond(rsp);
552+
self.respond(rsp)
555553
}
556554

557555
// All servers must respond to `Threads` requests, possibly with
558556
// a dummy thread as is the case here
559-
fn handle_threads(&mut self, req: Request) {
557+
fn handle_threads(&mut self, req: Request) -> Result<(), ServerError> {
560558
let rsp = req.success(ResponseBody::Threads(ThreadsResponse {
561559
threads: vec![Thread {
562560
id: THREAD_ID,
563561
name: String::from("R console"),
564562
}],
565563
}));
566-
self.respond(rsp);
564+
self.respond(rsp)
567565
}
568566

569567
fn handle_set_exception_breakpoints(
570568
&mut self,
571569
req: Request,
572570
_args: SetExceptionBreakpointsArguments,
573-
) {
571+
) -> Result<(), ServerError> {
574572
let rsp = req.success(ResponseBody::SetExceptionBreakpoints(
575573
SetExceptionBreakpointsResponse {
576574
breakpoints: None, // TODO
577575
},
578576
));
579-
self.respond(rsp);
577+
self.respond(rsp)
580578
}
581579

582-
fn handle_stacktrace(&mut self, req: Request, args: StackTraceArguments) {
580+
fn handle_stacktrace(
581+
&mut self,
582+
req: Request,
583+
args: StackTraceArguments,
584+
) -> Result<(), ServerError> {
583585
let state = self.state.lock().unwrap();
584586
let stack = &state.stack;
585587
let fallback_sources = &state.fallback_sources;
@@ -613,17 +615,17 @@ impl<R: Read, W: Write> DapServer<R, W> {
613615
}));
614616

615617
drop(state);
616-
self.respond(rsp);
618+
self.respond(rsp)
617619
}
618620

619-
fn handle_source(&mut self, req: Request, _args: SourceArguments) {
621+
fn handle_source(&mut self, req: Request, _args: SourceArguments) -> Result<(), ServerError> {
620622
let message = "Unsupported `source` request: {req:?}";
621623
log::error!("{message}");
622624
let rsp = req.error(message);
623-
self.respond(rsp);
625+
self.respond(rsp)
624626
}
625627

626-
fn handle_scopes(&mut self, req: Request, args: ScopesArguments) {
628+
fn handle_scopes(&mut self, req: Request, args: ScopesArguments) -> Result<(), ServerError> {
627629
let state = self.state.lock().unwrap();
628630
let frame_id_to_variables_reference = &state.frame_id_to_variables_reference;
629631

@@ -653,15 +655,19 @@ impl<R: Read, W: Write> DapServer<R, W> {
653655
let rsp = req.success(ResponseBody::Scopes(ScopesResponse { scopes }));
654656

655657
drop(state);
656-
self.respond(rsp);
658+
self.respond(rsp)
657659
}
658660

659-
fn handle_variables(&mut self, req: Request, args: VariablesArguments) {
661+
fn handle_variables(
662+
&mut self,
663+
req: Request,
664+
args: VariablesArguments,
665+
) -> Result<(), ServerError> {
660666
let variables_reference = args.variables_reference;
661667
let variables = self.collect_r_variables(variables_reference);
662668
let variables = self.into_variables(variables);
663669
let rsp = req.success(ResponseBody::Variables(VariablesResponse { variables }));
664-
self.respond(rsp);
670+
self.respond(rsp)
665671
}
666672

667673
fn collect_r_variables(&self, variables_reference: i64) -> Vec<RVariable> {
@@ -724,10 +730,16 @@ impl<R: Read, W: Write> DapServer<R, W> {
724730
out
725731
}
726732

727-
fn handle_step<A>(&mut self, req: Request, _args: A, cmd: DebugRequest, resp: ResponseBody) {
733+
fn handle_step<A>(
734+
&mut self,
735+
req: Request,
736+
_args: A,
737+
cmd: DebugRequest,
738+
resp: ResponseBody,
739+
) -> Result<(), ServerError> {
728740
self.send_command(cmd);
729741
let rsp = req.success(resp);
730-
self.respond(rsp);
742+
self.respond(rsp)
731743
}
732744

733745
fn send_command(&mut self, cmd: DebugRequest) {

0 commit comments

Comments
 (0)