1use std::panic::AssertUnwindSafe;
4use std::pin::Pin;
5use std::sync::Arc;
6
7use futures_util::FutureExt;
8use serde_json::Value;
9use tracing::{Instrument, error, info_span};
10
11use crate::builder::Router;
12use crate::sync::Semaphore;
13use crate::{Context, LspError, RequestId, TaskFuture, TaskSend};
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum CallKind {
18 Request,
20 Notification,
22}
23
24pub struct IncomingCall<S> {
33 kind: CallKind,
34 method: String,
35 request_id: Option<RequestId>,
36 params: Value,
37 context: Context,
38 state: Arc<S>,
39}
40
41impl<S> IncomingCall<S> {
42 pub(crate) fn request(
43 method: String,
44 request_id: RequestId,
45 params: Value,
46 context: Context,
47 state: Arc<S>,
48 ) -> Self {
49 Self {
50 kind: CallKind::Request,
51 method,
52 request_id: Some(request_id),
53 params,
54 context,
55 state,
56 }
57 }
58
59 pub(crate) fn notification(
60 method: String,
61 params: Value,
62 context: Context,
63 state: Arc<S>,
64 ) -> Self {
65 Self {
66 kind: CallKind::Notification,
67 method,
68 request_id: None,
69 params,
70 context,
71 state,
72 }
73 }
74
75 pub fn kind(&self) -> CallKind {
77 self.kind
78 }
79
80 pub fn method(&self) -> &str {
82 &self.method
83 }
84
85 pub fn request_id(&self) -> Option<&RequestId> {
87 self.request_id.as_ref()
88 }
89
90 pub fn params(&self) -> &Value {
92 &self.params
93 }
94
95 pub fn params_mut(&mut self) -> &mut Value {
97 &mut self.params
98 }
99
100 pub fn context(&self) -> &Context {
102 &self.context
103 }
104
105 pub fn state(&self) -> &Arc<S> {
107 &self.state
108 }
109}
110
111pub enum ServiceResult {
113 Response(Value),
115 Error(LspError),
117 NoResponse,
119}
120
121pub type ServiceFuture = Pin<Box<dyn TaskFuture<ServiceResult> + 'static>>;
123
124macro_rules! service_trait {
125 ($($native_bound:tt)*) => {
126 pub(crate) trait Service<S>: TaskSend $($native_bound)* {
127 fn call(&self, call: IncomingCall<S>) -> ServiceFuture;
128 }
129 };
130}
131
132#[cfg(not(target_arch = "wasm32"))]
133service_trait!(+ Sync);
134#[cfg(target_arch = "wasm32")]
135service_trait!();
136
137pub struct Next<S> {
139 inner: Arc<dyn Service<S>>,
140}
141
142impl<S> Clone for Next<S> {
143 fn clone(&self) -> Self {
144 Self {
145 inner: Arc::clone(&self.inner),
146 }
147 }
148}
149
150impl<S: Send + Sync + 'static> Next<S> {
151 pub fn call(&self, call: IncomingCall<S>) -> ServiceFuture {
153 self.inner.call(call)
154 }
155}
156
157macro_rules! layer_trait {
158 ($($native_bound:tt)*) => {
159 pub trait Layer<S>: TaskSend $($native_bound)* + 'static {
165 fn call(&self, call: IncomingCall<S>, next: Next<S>) -> ServiceFuture;
167 }
168 };
169}
170
171#[cfg(not(target_arch = "wasm32"))]
172layer_trait!(+ Sync);
173#[cfg(target_arch = "wasm32")]
174layer_trait!();
175
176pub(crate) type UserLayer<S> = Arc<dyn Layer<S>>;
177pub(crate) type UserService<S> = Arc<dyn Service<S>>;
178
179struct LayerService<S> {
180 layer: UserLayer<S>,
181 inner: UserService<S>,
182}
183
184impl<S: Send + Sync + 'static> Service<S> for LayerService<S> {
185 fn call(&self, call: IncomingCall<S>) -> ServiceFuture {
186 self.layer.call(
187 call,
188 Next {
189 inner: Arc::clone(&self.inner),
190 },
191 )
192 }
193}
194
195struct RouterService<S> {
196 router: Arc<Router<S>>,
197}
198
199impl<S: Send + Sync + 'static> Service<S> for RouterService<S> {
200 fn call(&self, call: IncomingCall<S>) -> ServiceFuture {
201 let router = Arc::clone(&self.router);
202 Box::pin(async move {
203 match call.kind {
204 CallKind::Request => {
205 let cancellation = call
206 .context
207 .cancellation()
208 .cloned()
209 .expect("request contexts carry cancellation");
210 let result = if call.method == "workspace/executeCommand"
211 && router.has_commands()
212 {
213 let params: lsp_types::ExecuteCommandParams =
214 match serde_json::from_value(call.params) {
215 Ok(params) => params,
216 Err(error) => {
217 return ServiceResult::Error(LspError::invalid_params(error));
218 }
219 };
220 match router.command(¶ms.command) {
221 Some(handler) => {
222 handler
223 .invoke((
224 call.state,
225 call.context,
226 params.arguments,
227 cancellation,
228 ))
229 .await
230 }
231 None => Err(LspError::invalid_params(format!(
232 "unknown command: {}",
233 params.command
234 ))),
235 }
236 } else {
237 match router.request(&call.method) {
238 Some(handler) => {
239 handler
240 .invoke((call.state, call.context, call.params, cancellation))
241 .await
242 }
243 None => Err(LspError::MethodNotFound(call.method)),
244 }
245 };
246 match result {
247 Ok(value) => ServiceResult::Response(value),
248 Err(error) => ServiceResult::Error(error),
249 }
250 }
251 CallKind::Notification => {
252 let handler = router
258 .notification(&call.method)
259 .or_else(|| router.built_in_hook(&call.method));
260 if let Some(handler) = handler {
261 handler
262 .invoke((call.state, call.context, call.params))
263 .await;
264 }
265 ServiceResult::NoResponse
266 }
267 }
268 })
269 }
270}
271
272struct ConcurrencyLimitService<S> {
273 inner: UserService<S>,
274 permits: Arc<Semaphore>,
275}
276
277impl<S: Send + Sync + 'static> Service<S> for ConcurrencyLimitService<S> {
278 fn call(&self, call: IncomingCall<S>) -> ServiceFuture {
279 let inner = Arc::clone(&self.inner);
280 let permits = Arc::clone(&self.permits);
281 Box::pin(async move {
282 let _permit = permits
283 .clone()
284 .acquire_owned()
285 .instrument(info_span!("handler.acquire_permit"))
286 .await;
287 inner.call(call).await
288 })
289 }
290}
291
292struct TracingService<S> {
293 inner: UserService<S>,
294}
295
296impl<S: Send + Sync + 'static> Service<S> for TracingService<S> {
297 fn call(&self, call: IncomingCall<S>) -> ServiceFuture {
298 let inner = Arc::clone(&self.inner);
299 let span = call.context.span().clone();
300 Box::pin(inner.call(call).instrument(span))
301 }
302}
303
304struct PanicIsolationService<S> {
305 inner: UserService<S>,
306}
307
308impl<S: Send + Sync + 'static> Service<S> for PanicIsolationService<S> {
309 fn call(&self, call: IncomingCall<S>) -> ServiceFuture {
310 let inner = Arc::clone(&self.inner);
311 let kind = call.kind;
312 Box::pin(async move {
313 match AssertUnwindSafe(async move { inner.call(call).await })
314 .catch_unwind()
315 .await
316 {
317 Ok(result) => result,
318 Err(_) if kind == CallKind::Request => {
319 error!("panic isolated while dispatching request");
320 ServiceResult::Error(LspError::internal("user dispatch panicked"))
321 }
322 Err(_) => {
323 error!("panic isolated while dispatching notification");
324 ServiceResult::NoResponse
325 }
326 }
327 })
328 }
329}
330
331pub(crate) fn build_service_stack<S>(
332 router: Arc<Router<S>>,
333 layers: Vec<UserLayer<S>>,
334 concurrency_limit: usize,
335) -> UserService<S>
336where
337 S: Send + Sync + 'static,
338{
339 let mut service: UserService<S> = Arc::new(RouterService { router });
340 for layer in layers {
341 service = Arc::new(LayerService {
342 layer,
343 inner: service,
344 });
345 }
346 service = Arc::new(ConcurrencyLimitService {
347 inner: service,
348 permits: Semaphore::shared(concurrency_limit),
349 });
350 service = Arc::new(TracingService { inner: service });
351 Arc::new(PanicIsolationService { inner: service })
352}