Skip to main content

atomcode_core/lsp/
jsonrpc.rs

1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3use tokio::io::{AsyncBufReadExt, AsyncReadExt, BufReader};
4
5#[derive(Debug, Serialize, Deserialize)]
6pub struct Request {
7    pub jsonrpc: String,
8    pub id: u64,
9    pub method: String,
10    #[serde(skip_serializing_if = "Option::is_none")]
11    pub params: Option<Value>,
12}
13
14#[derive(Debug, Serialize, Deserialize)]
15pub struct Notification {
16    pub jsonrpc: String,
17    pub method: String,
18    #[serde(skip_serializing_if = "Option::is_none")]
19    pub params: Option<Value>,
20}
21
22pub fn encode(body: &[u8]) -> Vec<u8> {
23    let header = format!("Content-Length: {}\r\n\r\n", body.len());
24    let mut msg = header.into_bytes();
25    msg.extend_from_slice(body);
26    msg
27}
28
29pub async fn read_message<R: tokio::io::AsyncRead + Unpin>(
30    reader: &mut BufReader<R>,
31) -> anyhow::Result<Value> {
32    let mut content_length: usize = 0;
33    let mut line = String::new();
34    loop {
35        line.clear();
36        let n = reader.read_line(&mut line).await?;
37        if n == 0 {
38            anyhow::bail!("EOF while reading LSP header");
39        }
40        let trimmed = line.trim();
41        if trimmed.is_empty() {
42            break;
43        }
44        if let Some(len_str) = trimmed.strip_prefix("Content-Length:") {
45            content_length = len_str.trim().parse()?;
46        }
47    }
48    if content_length == 0 {
49        anyhow::bail!("No Content-Length in LSP message");
50    }
51    let mut body = vec![0u8; content_length];
52    reader.read_exact(&mut body).await?;
53    Ok(serde_json::from_slice(&body)?)
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59
60    #[test]
61    fn encode_format() {
62        let body = b"{\"jsonrpc\":\"2.0\"}";
63        let encoded = encode(body);
64        let expected = format!("Content-Length: {}\r\n\r\n{}", body.len(), "{\"jsonrpc\":\"2.0\"}");
65        assert_eq!(encoded, expected.as_bytes());
66    }
67
68    #[tokio::test]
69    async fn read_message_parses() {
70        let body = b"{\"jsonrpc\":\"2.0\",\"id\":1}";
71        let raw = format!("Content-Length: {}\r\n\r\n{}", body.len(), std::str::from_utf8(body).unwrap());
72        let cursor = std::io::Cursor::new(raw.into_bytes());
73        let mut reader = BufReader::new(cursor);
74        let msg = read_message(&mut reader).await.unwrap();
75        assert_eq!(msg["jsonrpc"], "2.0");
76        assert_eq!(msg["id"], 1);
77    }
78
79    #[tokio::test]
80    async fn read_message_eof_error() {
81        let cursor = std::io::Cursor::new(Vec::<u8>::new());
82        let mut reader = BufReader::new(cursor);
83        let result = read_message(&mut reader).await;
84        assert!(result.is_err());
85        assert!(result.unwrap_err().to_string().contains("EOF"));
86    }
87}