1use crossbeam_channel::{Receiver, Sender, bounded};
10use lsp_types::SetTraceParams;
11use serde_json::from_value;
12use std::{
13 io,
14 sync::{Arc, RwLock},
15 thread::{Builder, JoinHandle},
16};
17use tracing::{debug, level_filters::LevelFilter, trace, warn};
18
19use crate::{Client, Notification, ParseError, TracingLayer};
20
21use super::Message;
22
23mod handler;
24
25pub use handler::Handler;
26
27pub struct ThreadConnection {
28 pub sender: JoinHandle<io::Result<()>>,
29 pub receiver: JoinHandle<io::Result<()>>,
30}
31
32impl ThreadConnection {
33 pub fn is_finished(&self) -> bool {
34 self.sender.is_finished() || self.receiver.is_finished()
35 }
36}
37
38pub struct Server {
40 write_sender: Sender<Message>,
41 write_receiver: Receiver<Message>,
42 read_sender: Sender<Message>,
43 #[allow(dead_code)]
44 request_handler: JoinHandle<Result<(), io::Error>>,
45 #[allow(dead_code)]
46 read_receiver: Receiver<Message>,
47 trace_level: Arc<RwLock<LevelFilter>>,
48}
49
50impl Server {
51 pub fn new<T: Handler>(make_handler: impl FnOnce(Client) -> T) -> Self {
53 let (write_sender, write_receiver) = bounded::<Message>(0);
54 let (read_sender, read_receiver) = bounded::<Message>(0);
55 let handler = make_handler(Client::new(write_sender.clone()));
56
57 let handler_receiver = read_receiver.clone();
58 let handler_sender = write_sender.clone();
59 let trace_level = Arc::new(RwLock::new(LevelFilter::OFF));
60 let level_set = trace_level.clone();
61 let request_handler = Builder::new()
62 .name("LspMessageHandler".into())
63 .spawn(move || {
64 while let Ok(message) = handler_receiver.recv() {
65 trace!("LspMessageHandler -> {:#?}", &message);
66 if let Message::Notification(Notification { method, params }) = &message {
67 if method == "exit" {
68 break;
69 }
70 if method == "$/setTrace" {
71 let level = from_value::<SetTraceParams>(params.clone())
72 .map(|p| match p.value {
73 lsp_types::TraceValue::Off => LevelFilter::OFF,
74 lsp_types::TraceValue::Messages => LevelFilter::WARN,
75 lsp_types::TraceValue::Verbose => LevelFilter::TRACE,
76 })
77 .unwrap_or(LevelFilter::OFF);
78 trace!("Changing level to {:?}", level);
79 let mut level_set = level_set.write().unwrap();
80 *level_set = level;
81 }
82 }
83 let response = handler.handle(message);
84 if let Some(response) = response
85 && let Err(e) = handler_sender.send(response)
86 {
87 warn!("Handler failed to send response {:?}", &e);
88 return Err(io::Error::other(e));
89 }
90 }
91 debug!("LspMessageHandler closing");
92 Ok(())
93 })
94 .expect("Failed to create Reader");
95 Server { write_sender, write_receiver, read_sender, read_receiver, request_handler, trace_level }
96 }
97
98 pub fn tracer(&self) -> TracingLayer {
99 TracingLayer::new(self.trace_level.clone(), self.write_sender.clone())
100 }
101
102 pub fn listen_stdio(&self) -> Result<ThreadConnection, io::Error> {
103 let write_receiver = self.write_receiver.clone();
104 let writer = Builder::new().name("LspWriter".into()).spawn(move || {
105 let mut stdout = io::stdout().lock();
106 while let Ok(message) = write_receiver.recv() {
107 trace!("{:#?}", message);
108 message.write(&mut stdout)?;
109 }
110 Ok(())
111 })?;
112 let read_sender = self.read_sender.clone();
113 let reader = Builder::new()
114 .name("LspReader".into())
115 .spawn(move || read_messages(&mut io::stdin().lock(), &read_sender))?;
116 Ok(ThreadConnection { sender: reader, receiver: writer })
117 }
118
119 pub fn raw_channels(&self) -> (Sender<Message>, Receiver<Message>) {
122 (self.read_sender.clone(), self.write_receiver.clone())
123 }
124}
125
126fn read_messages(reader: &mut impl io::BufRead, sender: &Sender<Message>) -> io::Result<()> {
129 loop {
130 match Message::read(reader) {
131 Ok(Some(message)) => {
132 let exit = message.is_exit_notification();
133 sender.send(message).map_err(io::Error::other)?;
134 if exit {
135 return Ok(());
136 }
137 }
138 Ok(None) => return Ok(()),
139 Err(ParseError::Body(error)) => warn!("Skipping unparseable message: {error}"),
140 Err(error) => return Err(error.into()),
141 }
142 }
143}
144
145#[cfg(test)]
146mod tests {
147 use std::sync::atomic::{AtomicBool, Ordering};
148
149 use crate::{ErrorCode, Notification, Request, Response, ResponseError};
150
151 use super::*;
152 use lsp_types::{
153 InitializeParams, InitializeResult,
154 request::{GotoDeclaration, Initialize, Request as RequestTrait},
155 };
156 use serde_json::{Value, json, to_value};
157 use tracing::level_filters::LevelFilter;
158 use tracing_subscriber::{Layer, fmt, layer::SubscriberExt, registry, util::SubscriberInitExt};
159
160 #[test]
161 fn smoke_test() {
162 let stderr_log = fmt::layer().with_writer(io::stderr).with_filter(LevelFilter::TRACE);
163 struct TestHandler {
164 initialized: AtomicBool,
165 }
166 impl Handler for TestHandler {
167 fn initialized(&self) -> bool {
168 self.initialized.load(Ordering::SeqCst)
169 }
170 fn initialize(&self, _req: InitializeParams) -> Result<InitializeResult, ResponseError> {
171 self.initialized.swap(true, Ordering::SeqCst);
172 Ok(InitializeResult { ..Default::default() })
173 }
174 }
175
176 let server = Server::new(|_| TestHandler { initialized: AtomicBool::new(false) });
177 registry().with(stderr_log).with(server.tracer()).init();
178 let (sender, receiver) = server.raw_channels();
179 sender
180 .send(Message::Request(Request {
181 id: 1.into(),
182 method: Initialize::METHOD.into(),
183 params: to_value(InitializeParams { ..Default::default() }).unwrap(),
184 }))
185 .unwrap();
186 assert_eq!(receiver.recv(), Ok(Message::Response(Response::Ok(1.into(), json!({"capabilities": {}})))));
187 sender
188 .send(Message::Request(Request {
189 id: 1.into(),
190 method: GotoDeclaration::METHOD.into(),
191 params: json!({
192 "textDocument": {
193 "uri": "foo/bar",
194 },
195 "position": {
196 "line": 1,
197 "character": 1
198 }
199 }),
200 }))
201 .unwrap();
202 assert!(matches!(
203 receiver.recv(),
204 Ok(Message::Response(Response::Err(id, ErrorCode::MethodNotFound, _, Value::Null))) if id == 1.into()
205 ));
206 sender.send(Message::Notification(Notification { method: "exit".into(), params: Value::Null })).unwrap();
207 }
208
209 #[test]
210 fn reader_skips_unparseable_bodies_and_stops_at_exit() {
211 let input = concat!(
212 "Content-Length: 11\r\n\r\n{\"foo\":\"x\"}",
213 "Content-Length: 29\r\n\r\n{\"method\":\"exit\",\"params\":[]}",
214 "Content-Length: 29\r\n\r\n{\"method\":\"next\",\"params\":[]}",
215 );
216 let (sender, receiver) = crossbeam_channel::unbounded();
217 read_messages(&mut input.as_bytes(), &sender).unwrap();
218 assert_eq!(
219 receiver.try_iter().collect::<Vec<_>>(),
220 vec![Message::Notification(Notification { method: "exit".into(), params: json!([]) })]
221 );
222 }
223}