1#[cfg(all(feature = "runtime-agnostic", not(feature = "runtime-tokio")))]
4use async_codec_lite::{FramedRead, FramedWrite};
5#[cfg(all(feature = "runtime-agnostic", not(feature = "runtime-tokio")))]
6use futures::io::{AsyncRead, AsyncWrite};
7
8#[cfg(feature = "runtime-tokio")]
9use tokio::io::{AsyncRead, AsyncWrite};
10#[cfg(feature = "runtime-tokio")]
11use tokio_util::codec::{FramedRead, FramedWrite};
12
13use std::task::Poll;
14
15use futures::channel::mpsc;
16use futures::{future, join, stream, FutureExt, Sink, SinkExt, Stream, StreamExt, TryFutureExt};
17use tower::Service;
18use tracing::error;
19
20async fn await_ready<S>(service: &mut S) -> Result<(), S::Error>
22where
23 S: Service<Request>,
24{
25 future::poll_fn(|cx| service.poll_ready(cx)).await
26}
27
28async fn probe_exited<S>(service: &mut S) -> Option<S::Error>
31where
32 S: Service<Request>,
33{
34 future::poll_fn(|cx| match service.poll_ready(cx) {
35 Poll::Ready(Err(err)) => Poll::Ready(Some(err)),
36 _ => Poll::Ready(None),
37 })
38 .await
39}
40
41use crate::codec::{LanguageServerCodec, ParseError};
42use crate::jsonrpc::{Error, Id, Message, Request, Response};
43use crate::service::{ClientSocket, ExitedError, RequestStream, ResponseSink};
44
45const DEFAULT_MAX_CONCURRENCY: usize = 4;
46const MESSAGE_QUEUE_SIZE: usize = 100;
47const MAX_EXIT_OBSERVE_POLLS: usize = 16;
51
52pub trait Loopback {
59 type RequestStream: Stream<Item = Request>;
61 type ResponseSink: Sink<Response> + Unpin;
63
64 fn split(self) -> (Self::RequestStream, Self::ResponseSink);
68}
69
70impl Loopback for ClientSocket {
71 type RequestStream = RequestStream;
72 type ResponseSink = ResponseSink;
73
74 #[inline]
75 fn split(self) -> (Self::RequestStream, Self::ResponseSink) {
76 self.split()
77 }
78}
79
80#[derive(Debug)]
82pub struct Server<I, O, L = ClientSocket> {
83 stdin: I,
84 stdout: O,
85 loopback: L,
86 max_concurrency: usize,
87}
88
89impl<I, O, L> Server<I, O, L>
90where
91 I: AsyncRead + Unpin,
92 O: AsyncWrite,
93 L: Loopback,
94 <L::ResponseSink as Sink<Response>>::Error: std::error::Error,
95{
96 pub fn new(stdin: I, stdout: O, socket: L) -> Self {
98 Server {
99 stdin,
100 stdout,
101 loopback: socket,
102 max_concurrency: DEFAULT_MAX_CONCURRENCY,
103 }
104 }
105
106 pub fn concurrency_level(mut self, max: usize) -> Self {
127 self.max_concurrency = max;
128 self
129 }
130
131 pub async fn serve<T>(self, mut service: T) -> Result<(), T::Error>
133 where
134 T: Service<Request, Response = Option<Response>> + Send + 'static,
135 T::Error: std::error::Error + Send + Sync + 'static + From<ExitedError>,
136 T::Future: Send,
137 {
138 let (client_requests, mut client_responses) = self.loopback.split();
139 let (client_requests, client_abort) = stream::abortable(client_requests);
140 let (mut responses_tx, responses_rx) = mpsc::channel(MESSAGE_QUEUE_SIZE);
141 let (mut server_tasks_tx, server_tasks_rx) = mpsc::channel(MESSAGE_QUEUE_SIZE);
142
143 let mut framed_stdin = FramedRead::new(self.stdin, LanguageServerCodec::default());
144 let framed_stdout = FramedWrite::new(self.stdout, LanguageServerCodec::default());
145
146 let process_server_tasks = server_tasks_rx
147 .buffer_unordered(self.max_concurrency)
148 .filter_map(future::ready)
149 .map(|res| Ok(Message::Response(res)))
150 .forward(responses_tx.clone().sink_map_err(|_| unreachable!()))
151 .map(|_| ());
152
153 let print_output = stream::select(responses_rx, client_requests.map(Message::Request))
154 .map(Ok)
155 .forward(framed_stdout.sink_map_err(|e| error!("failed to encode message: {}", e)))
156 .map(|_| ());
157
158 let read_input = async {
159 while let Some(msg) = framed_stdin.next().await {
160 if let Ok(ref m) = msg {
161 match m {
162 Message::Request(req) => tracing::trace!(
163 "--- Server::serve read_input got Request: method={}, id={:?}",
164 req.method(),
165 req.id()
166 ),
167 Message::Response(res) => tracing::trace!(
168 "--- Server::serve read_input got Response: id={:?}",
169 res.id()
170 ),
171 }
172 }
173 match msg {
174 Ok(Message::Request(req)) => {
175 if let Err(err) = await_ready(&mut service).await {
176 error!("{}", display_sources(&err));
177 return Err(err);
178 }
179
180 let fut = service.call(req).unwrap_or_else(|err| {
181 error!("{}", display_sources(&err));
182 None
183 });
184
185 if let Err(e) = server_tasks_tx.send(fut).await {
186 error!("transport send failed: {}", e);
187 return Ok(());
188 }
189 }
190 Ok(Message::Response(res)) => {
191 if let Err(err) = client_responses.send(res).await {
192 error!("{}", display_sources(&err));
193 return Ok(());
194 }
195 }
196 Err(err) => {
197 error!("failed to decode message: {}", err);
198 let res = Response::from_error(Id::Null, to_jsonrpc_error(err));
199 if let Err(e) = responses_tx.send(Message::Response(res)).await {
200 error!("transport send failed: {}", e);
201 return Ok(());
202 }
203 }
204 }
205 }
206
207 server_tasks_tx.disconnect();
208 responses_tx.disconnect();
209 client_abort.abort();
210
211 for _ in 0..MAX_EXIT_OBSERVE_POLLS {
223 if let Some(err) = probe_exited(&mut service).await {
224 return Err(err);
225 }
226
227 tokio::task::yield_now().await;
230 }
231
232 Err(T::Error::from(ExitedError(1)))
235 };
236
237 let (_, res, _) = join!(print_output, read_input, process_server_tasks);
238 res
239 }
240}
241
242fn display_sources(error: &dyn std::error::Error) -> String {
243 if let Some(source) = error.source() {
244 format!("{}: {}", error, display_sources(source))
245 } else {
246 error.to_string()
247 }
248}
249
250#[cfg(feature = "runtime-tokio")]
251fn to_jsonrpc_error(err: ParseError) -> Error {
252 match err {
253 ParseError::Body(err) if err.is_data() => Error::invalid_request(),
254 _ => Error::parse_error(),
255 }
256}
257
258#[cfg(all(feature = "runtime-agnostic", not(feature = "runtime-tokio")))]
259fn to_jsonrpc_error(err: impl std::error::Error) -> Error {
260 match err.source().and_then(|e| e.downcast_ref()) {
261 Some(ParseError::Body(err)) if err.is_data() => Error::invalid_request(),
262 _ => Error::parse_error(),
263 }
264}
265
266#[cfg(test)]
267mod tests {
268 use std::task::{Context, Poll};
269
270 #[cfg(all(feature = "runtime-agnostic", not(feature = "runtime-tokio")))]
271 use futures::io::Cursor;
272 #[cfg(feature = "runtime-tokio")]
273 use std::io::Cursor;
274
275 use futures::future::Ready;
276 use futures::{future, sink, stream};
277
278 use super::*;
279
280 const REQUEST: &str = r#"{"jsonrpc":"2.0","method":"initialize","params":{},"id":1}"#;
281 const RESPONSE: &str = r#"{"jsonrpc":"2.0","result":{"capabilities":{}},"id":1}"#;
282
283 #[derive(Debug)]
284 struct MockService;
285
286 impl Service<Request> for MockService {
287 type Response = Option<Response>;
288 type Error = ExitedError;
289 type Future = Ready<Result<Self::Response, Self::Error>>;
290
291 fn poll_ready(&mut self, _: &mut Context) -> Poll<Result<(), Self::Error>> {
292 Poll::Ready(Ok(()))
293 }
294
295 fn call(&mut self, _: Request) -> Self::Future {
296 let response = serde_json::from_str(RESPONSE).unwrap();
297 future::ok(Some(response))
298 }
299 }
300
301 struct MockLoopback(Vec<Request>);
302
303 impl Loopback for MockLoopback {
304 type RequestStream = stream::Iter<std::vec::IntoIter<Request>>;
305 type ResponseSink = sink::Drain<Response>;
306
307 fn split(self) -> (Self::RequestStream, Self::ResponseSink) {
308 (stream::iter(self.0), sink::drain())
309 }
310 }
311
312 fn mock_request() -> Vec<u8> {
313 format!("Content-Length: {}\r\n\r\n{}", REQUEST.len(), REQUEST).into_bytes()
314 }
315
316 fn mock_response() -> Vec<u8> {
317 format!("Content-Length: {}\r\n\r\n{}", RESPONSE.len(), RESPONSE).into_bytes()
318 }
319
320 fn mock_stdio() -> (Cursor<Vec<u8>>, Vec<u8>) {
321 (Cursor::new(mock_request()), Vec::new())
322 }
323
324 #[tokio::test(flavor = "current_thread")]
325 async fn serves_on_stdio() {
326 let (mut stdin, mut stdout) = mock_stdio();
327 let res = Server::new(&mut stdin, &mut stdout, MockLoopback(vec![]))
328 .serve(MockService)
329 .await;
330
331 assert_eq!(res, Err(ExitedError(1)));
332 assert_eq!(stdin.position(), 80);
333 assert_eq!(stdout, mock_response());
334 }
335
336 #[tokio::test(flavor = "current_thread")]
337 async fn interleaves_messages() {
338 let socket = MockLoopback(vec![serde_json::from_str(REQUEST).unwrap()]);
339
340 let (mut stdin, mut stdout) = mock_stdio();
341 let res = Server::new(&mut stdin, &mut stdout, socket)
342 .serve(MockService)
343 .await;
344
345 assert_eq!(res, Err(ExitedError(1)));
346 assert_eq!(stdin.position(), 80);
347 let output: Vec<_> = mock_request().into_iter().chain(mock_response()).collect();
348 assert_eq!(stdout, output);
349 }
350
351 #[tokio::test(flavor = "current_thread")]
352 async fn handles_invalid_json() {
353 let invalid = r#"{"jsonrpc":"2.0","method":"#;
354 let message = format!("Content-Length: {}\r\n\r\n{}", invalid.len(), invalid).into_bytes();
355 let (mut stdin, mut stdout) = (Cursor::new(message), Vec::new());
356
357 let res = Server::new(&mut stdin, &mut stdout, MockLoopback(vec![]))
358 .serve(MockService)
359 .await;
360
361 assert_eq!(res, Err(ExitedError(1)));
362 assert_eq!(stdin.position(), 48);
363 let err = r#"{"jsonrpc":"2.0","error":{"code":-32700,"message":"Parse error"},"id":null}"#;
364 let output = format!("Content-Length: {}\r\n\r\n{}", err.len(), err).into_bytes();
365 assert_eq!(stdout, output);
366 }
367
368 #[derive(Debug)]
371 struct NoneService;
372
373 impl Service<Request> for NoneService {
374 type Response = Option<Response>;
375 type Error = ExitedError;
376 type Future = Ready<Result<Self::Response, Self::Error>>;
377
378 fn poll_ready(&mut self, _: &mut Context) -> Poll<Result<(), Self::Error>> {
379 Poll::Ready(Ok(()))
380 }
381
382 fn call(&mut self, _: Request) -> Self::Future {
383 future::ok(None)
384 }
385 }
386
387 #[tokio::test(flavor = "current_thread")]
392 async fn no_panic_on_server_tasks_channel_send() {
393 let mut input = Vec::new();
394 for _ in 0..5 {
395 input.extend_from_slice(&mock_request());
396 }
397 let (mut stdin, mut stdout) = (Cursor::new(input), Vec::new());
398
399 let res = Server::new(&mut stdin, &mut stdout, MockLoopback(vec![]))
401 .serve(NoneService)
402 .await;
403
404 assert_eq!(res, Err(ExitedError(1)));
406 }
407
408 #[tokio::test(flavor = "current_thread")]
412 async fn no_panic_on_responses_tx_send_two_invalid_messages() {
413 let invalid = r#"{"jsonrpc":"2.0","method":"#;
414 let framed = format!("Content-Length: {}\r\n\r\n{}", invalid.len(), invalid).into_bytes();
415 let mut input = framed.clone();
416 input.extend_from_slice(&framed);
417
418 let (mut stdin, mut stdout) = (Cursor::new(input), Vec::new());
419
420 let res = Server::new(&mut stdin, &mut stdout, MockLoopback(vec![]))
421 .serve(MockService)
422 .await;
423
424 assert!(res == Ok(()) || res == Err(ExitedError(1)));
426 }
427}