async_lsp/
client_monitor.rs1use std::ops::ControlFlow;
21use std::task::{Context, Poll};
22
23use lsp_types::request::{self, Request};
24use tower_layer::Layer;
25use tower_service::Service;
26
27use crate::{AnyEvent, AnyNotification, AnyRequest, ClientSocket, Error, LspService, Result};
28
29struct ClientProcessExited;
30
31pub struct ClientProcessMonitor<S> {
35 service: S,
36 client: ClientSocket,
37}
38
39impl<S: LspService> Service<AnyRequest> for ClientProcessMonitor<S> {
40 type Response = S::Response;
41 type Error = S::Error;
42 type Future = S::Future;
43
44 fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
45 self.service.poll_ready(cx)
46 }
47
48 fn call(&mut self, req: AnyRequest) -> Self::Future {
49 if let Some(pid) = (|| -> Option<i32> {
50 (req.method == request::Initialize::METHOD)
51 .then_some(&req.params)?
52 .as_object()?
53 .get("processId")?
54 .as_i64()?
55 .try_into()
56 .ok()
57 })() {
58 match waitpid_any::WaitHandle::open(pid) {
59 Ok(mut handle) => {
60 let client = self.client.clone();
61 let spawn_ret = std::thread::Builder::new()
62 .name("client-process-monitor".into())
63 .spawn(move || {
64 match handle.wait() {
65 Ok(()) => {
66 let _: Result<_, _> = client.emit(ClientProcessExited);
68 }
69 #[allow(unused_variables)]
70 Err(err) => {
71 #[cfg(feature = "tracing")]
72 ::tracing::error!(
73 "Failed to monitor peer process ({pid}): {err:#}"
74 );
75 }
76 }
77 });
78 #[allow(unused_variables)]
79 if let Err(err) = spawn_ret {
80 #[cfg(feature = "tracing")]
81 ::tracing::error!("Failed to spawn client process monitor thread: {err:#}");
82 }
83 }
84 #[cfg(unix)]
86 Err(err) if err.raw_os_error() == Some(rustix::io::Errno::SRCH.raw_os_error()) => {
87 let _: Result<_, _> = self.client.emit(ClientProcessExited);
89 }
90 #[allow(unused_variables)]
91 Err(err) => {
92 #[cfg(feature = "tracing")]
93 ::tracing::error!("Failed to monitor peer process {pid}: {err:#}");
94 }
95 }
96 }
97
98 self.service.call(req)
99 }
100}
101
102impl<S: LspService> LspService for ClientProcessMonitor<S> {
103 fn notify(&mut self, notif: AnyNotification) -> ControlFlow<Result<()>> {
104 self.service.notify(notif)
105 }
106
107 fn emit(&mut self, event: AnyEvent) -> ControlFlow<Result<()>> {
108 match event.downcast::<ClientProcessExited>() {
109 Ok(ClientProcessExited) => {
110 ControlFlow::Break(Err(Error::Protocol("Client process exited".into())))
111 }
112 Err(event) => self.service.emit(event),
113 }
114 }
115}
116
117#[must_use]
119pub struct ClientProcessMonitorBuilder {
120 client: ClientSocket,
121}
122
123impl ClientProcessMonitorBuilder {
124 pub fn new(client: ClientSocket) -> Self {
126 Self { client }
127 }
128}
129
130pub type ClientProcessMonitorLayer = ClientProcessMonitorBuilder;
133
134impl<S> Layer<S> for ClientProcessMonitorBuilder {
135 type Service = ClientProcessMonitor<S>;
136
137 fn layer(&self, inner: S) -> Self::Service {
138 ClientProcessMonitor {
139 service: inner,
140 client: self.client.clone(),
141 }
142 }
143}