Skip to main content

lsp_client/
transport.rs

1use jsonrpsee::core::client::{ReceivedMessage, TransportReceiverT, TransportSenderT};
2use tokio::io::{AsyncBufReadExt, AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, BufReader};
3
4/// Error that can occur when reading or sending messages on a transport.
5#[derive(thiserror::Error, Debug)]
6pub enum TransportError {
7    /// Error in I/O operation.
8    #[error("io error: {0}")]
9    Io(#[from] std::io::Error),
10    /// Error in parsing message.
11    #[error("parse error: {0}")]
12    Parse(String),
13}
14
15/// Sending end of I/O transport.
16pub struct Sender<T>(T)
17where
18    T: AsyncWrite + Send + Unpin + 'static;
19
20#[async_trait::async_trait]
21impl<T> TransportSenderT for Sender<T>
22where
23    T: AsyncWrite + Send + Unpin + 'static,
24{
25    type Error = TransportError;
26
27    async fn send(&mut self, msg: String) -> Result<(), Self::Error> {
28        let msg_with_header = format!("Content-Length: {}\r\n\r\n{}", msg.len(), msg);
29        self.0.write_all(msg_with_header.as_bytes()).await?;
30        Ok(())
31    }
32}
33
34/// Receiving end of I/O transport.
35pub struct Receiver<T>(BufReader<T>)
36where
37    T: AsyncRead + Send + Unpin + 'static;
38
39#[async_trait::async_trait]
40impl<T> TransportReceiverT for Receiver<T>
41where
42    T: AsyncRead + Send + Unpin + 'static,
43{
44    type Error = TransportError;
45
46    async fn receive(&mut self) -> Result<ReceivedMessage, Self::Error> {
47        let mut content_length: Option<usize> = None;
48
49        // Parse header part.
50        // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#baseProtocol
51        let mut line = String::new();
52        loop {
53            self.0.read_line(&mut line).await?;
54            match line.as_str() {
55                // End of header.
56                "\r\n" => break,
57                // Content-Length: the length of the content part in bytes.
58                line if line.starts_with("Content-Length: ") => {
59                    // "Content-Length: " is 16 chars long and the last 2 chars are \r\n.
60                    let len = &line[16..line.len() - 2];
61                    let len = len
62                        .parse::<usize>()
63                        .map_err(|e| TransportError::Parse(e.to_string()))?;
64                    content_length = Some(len);
65                }
66                _ => {}
67            }
68            line.clear();
69        }
70
71        let content_length = content_length.ok_or(TransportError::Parse(
72            "Content-Length header not found".to_string(),
73        ))?;
74        let mut buf = vec![0; content_length];
75        self.0.read_exact(&mut buf).await?;
76        Ok(ReceivedMessage::Bytes(buf))
77    }
78}
79
80/// Create a I/O transport `Sender` and `Receiver` pair.
81pub fn io_transport<I, O>(input: I, output: O) -> (Sender<I>, Receiver<O>)
82where
83    I: AsyncWrite + Send + Unpin + 'static,
84    O: AsyncRead + Send + Unpin + 'static,
85{
86    let sender = Sender(input);
87    let receiver = Receiver(BufReader::new(output));
88    (sender, receiver)
89}