rune/languageserver/
connection.rs

1use core::fmt;
2
3use ::rust_alloc::sync::Arc;
4
5use anyhow::{anyhow, bail, Result};
6use tokio::io;
7use tokio::io::{
8    AsyncBufRead, AsyncBufReadExt as _, AsyncReadExt as _, AsyncWriteExt as _, BufReader,
9};
10use tokio::sync::Mutex;
11
12use crate::alloc::prelude::*;
13use crate::languageserver::envelope;
14
15/// An input frame.
16#[derive(Debug)]
17pub(super) struct Frame<'a> {
18    pub(super) content: &'a [u8],
19}
20
21/// Input connection.
22pub(super) struct Input {
23    buf: ::rust_alloc::vec::Vec<u8>,
24    stdin: BufReader<io::Stdin>,
25}
26
27impl Input {
28    /// Get the next input frame.
29    pub(super) async fn next(&mut self) -> Result<Option<Frame<'_>>> {
30        let headers = match Headers::read(&mut self.buf, &mut self.stdin).await? {
31            Some(headers) => headers,
32            None => return Ok(None),
33        };
34
35        tracing::trace!("headers: {:?}", headers);
36
37        let length = match headers.content_length {
38            Some(length) => length as usize,
39            None => bail!("missing content-length"),
40        };
41
42        self.buf.resize(length, 0u8);
43        self.stdin.read_exact(&mut self.buf[..]).await?;
44        Ok(Some(Frame { content: &self.buf }))
45    }
46}
47
48/// Output connection.
49#[derive(Clone)]
50pub(super) struct Output {
51    stdout: Arc<Mutex<io::Stdout>>,
52}
53
54impl Output {
55    /// Send the given response.
56    pub(super) async fn response<R>(&self, id: Option<envelope::RequestId>, result: R) -> Result<()>
57    where
58        R: serde::Serialize,
59    {
60        let response = envelope::ResponseMessage {
61            jsonrpc: envelope::V2,
62            id,
63            result: Some(result),
64            error: None::<envelope::ResponseError<()>>,
65        };
66
67        let mut bytes = serde_json::to_vec(&response)?;
68        self.write_response(&mut bytes).await?;
69        Ok(())
70    }
71
72    /// Respond that the given method is not supported.
73    pub(super) async fn method_not_found(&self, id: Option<envelope::RequestId>) -> Result<()> {
74        self.error(
75            id,
76            envelope::Code::MethodNotFound,
77            "Method not found",
78            None::<()>,
79        )
80        .await?;
81        Ok(())
82    }
83
84    /// Send the given error as response.
85    pub(super) async fn error<D>(
86        &self,
87        id: Option<envelope::RequestId>,
88        code: envelope::Code,
89        message: &'static str,
90        data: Option<D>,
91    ) -> Result<()>
92    where
93        D: serde::Serialize,
94    {
95        let response = envelope::ResponseMessage {
96            jsonrpc: envelope::V2,
97            id,
98            result: None::<()>,
99            error: Some(envelope::ResponseError {
100                code,
101                message,
102                data,
103            }),
104        };
105
106        let mut bytes = serde_json::to_vec(&response)?;
107        self.write_response(&mut bytes).await?;
108        Ok(())
109    }
110
111    /// Send the given notification
112    pub(super) async fn notification<N>(&self, notification: N::Params) -> Result<()>
113    where
114        N: lsp::notification::Notification,
115    {
116        let notification = envelope::NotificationMessage {
117            jsonrpc: envelope::V2,
118            method: N::METHOD,
119            params: notification,
120        };
121
122        let mut bytes = serde_json::to_vec(&notification)?;
123        self.write_response(&mut bytes).await?;
124        Ok(())
125    }
126
127    /// Send a log message.
128    pub(super) async fn log<M>(&self, typ: lsp::MessageType, message: M) -> Result<()>
129    where
130        M: fmt::Display,
131    {
132        self.notification::<lsp::notification::LogMessage>(lsp::LogMessageParams {
133            typ,
134            message: message.try_to_string()?.into_std(),
135        })
136        .await?;
137
138        Ok(())
139    }
140
141    /// Write the given response body.
142    async fn write_response(&self, bytes: &mut ::rust_alloc::vec::Vec<u8>) -> Result<()> {
143        use std::io::Write as _;
144
145        let mut m = ::rust_alloc::vec::Vec::new();
146
147        write!(m, "Content-Length: {}\r\n", bytes.len())?;
148        write!(m, "\r\n")?;
149        m.append(bytes);
150
151        let mut stdout = self.stdout.lock().await;
152        stdout.write_all(&m).await?;
153        stdout.flush().await?;
154        Ok(())
155    }
156}
157
158/// Setup a stdin/stdout connection.
159pub(super) fn stdio() -> Result<(Input, Output)> {
160    let stdin = io::stdin();
161    let stdout = io::stdout();
162
163    let input = Input {
164        buf: ::rust_alloc::vec::Vec::new(),
165        stdin: BufReader::new(stdin),
166    };
167
168    let output = Output {
169        stdout: Arc::new(Mutex::new(stdout)),
170    };
171
172    Ok((input, output))
173}
174
175#[derive(Debug)]
176pub(super) enum ContentType {
177    JsonRPC,
178}
179
180#[derive(Default, Debug)]
181pub(super) struct Headers {
182    pub(super) content_length: Option<u32>,
183    pub(super) content_type: Option<ContentType>,
184}
185
186impl Headers {
187    /// Read headers from the given line stream.
188    pub(super) async fn read<S>(
189        buf: &mut ::rust_alloc::vec::Vec<u8>,
190        reader: &mut S,
191    ) -> anyhow::Result<Option<Self>>
192    where
193        S: Unpin + AsyncBufRead,
194    {
195        let mut headers = Headers::default();
196
197        loop {
198            buf.clear();
199
200            let len = match reader.read_until(b'\n', buf).await {
201                Ok(len) => len,
202                Err(error) => return Err(error.into()),
203            };
204
205            if len == 0 {
206                return Ok(None);
207            }
208
209            debug_assert!(len == buf.len());
210            let buf = &buf[..len];
211
212            let buf = std::str::from_utf8(buf)?;
213            let line = buf.trim();
214
215            if line.is_empty() {
216                break;
217            }
218
219            let Some((key, value)) = line.split_once(':') else {
220                return Err(anyhow!("bad header"));
221            };
222
223            let key = key.trim();
224            let value = value.trim();
225            let key = key.to_lowercase();
226
227            match key.as_str() {
228                "content-type" => match value {
229                    "application/vscode-jsonrpc; charset=utf-8" => {
230                        headers.content_type = Some(ContentType::JsonRPC);
231                    }
232                    value => {
233                        return Err(anyhow!("bad value: {:?}", value));
234                    }
235                },
236                "content-length" => {
237                    let value = value
238                        .parse::<u32>()
239                        .map_err(|e| anyhow!("bad content-length: {}: {}", value, e))?;
240
241                    headers.content_length = Some(value);
242                }
243                key => {
244                    return Err(anyhow!("header not supported: {:?}", key));
245                }
246            }
247        }
248
249        Ok(Some(headers))
250    }
251}