1use std::any::TypeId;
2use std::fmt::Display;
3
4use anyhow::{Context, anyhow};
5use lsp_server::{ErrorCode, Message, Notification, RequestId, ResponseError};
6use serde_json::Value;
7
8use crate::Session;
9use crate::server::{ConnectionSender, Event, MainLoopSender};
10
11pub(crate) type ClientResponseHandler =
12 Box<dyn FnOnce(&Client, &mut Session, lsp_server::Response) + Send>;
13
14#[derive(Clone, Debug)]
15pub struct Client {
16 main_loop_sender: MainLoopSender,
17 client_sender: ConnectionSender,
18}
19
20impl Client {
21 pub fn new(main_loop_sender: MainLoopSender, client_sender: ConnectionSender) -> Self {
22 Self {
23 main_loop_sender,
24 client_sender,
25 }
26 }
27
28 pub(crate) fn send_request<R>(
29 &self,
30 session: &Session,
31 params: R::Params,
32 response_handler: impl FnOnce(&Client, &mut Session, R::Result) + Send + 'static,
33 ) -> crate::Result<()>
34 where
35 R: lsp_types::request::Request,
36 {
37 let response_handler = Box::new(
38 move |client: &Client, session: &mut Session, response: lsp_server::Response| match (
39 response.error,
40 response.result,
41 ) {
42 (Some(err), _) => {
43 tracing::error!(
44 "Client request failed (method={} code={}): {}",
45 R::METHOD,
46 err.code,
47 err.message
48 );
49 }
50 (None, Some(response)) => match serde_json::from_value(response) {
51 Ok(response) => response_handler(client, session, response),
52 Err(error) => {
53 tracing::error!(
54 "Failed to deserialize client response for {}: {error}",
55 R::METHOD
56 );
57 }
58 },
59 (None, None) => {
60 if TypeId::of::<R::Result>() == TypeId::of::<()>() {
61 match serde_json::from_value(Value::Null) {
62 Ok(response) => response_handler(client, session, response),
63 Err(error) => {
64 tracing::error!(
65 "Failed to deserialize unit client response for {}: {error}",
66 R::METHOD
67 );
68 }
69 }
70 } else {
71 tracing::error!(
72 "Client response missing result and error for {}",
73 R::METHOD
74 );
75 }
76 }
77 },
78 );
79
80 let id = session
81 .request_queue()
82 .outgoing()
83 .register(response_handler);
84 self.client_sender
85 .send(Message::Request(lsp_server::Request {
86 id,
87 method: R::METHOD.to_string(),
88 params: serde_json::to_value(params).context("Failed to serialize params")?,
89 }))
90 .with_context(|| format!("Failed to send request {}", R::METHOD))?;
91 Ok(())
92 }
93
94 pub(crate) fn send_notification<N>(&self, params: N::Params) -> crate::Result<()>
95 where
96 N: lsp_types::notification::Notification,
97 {
98 self.client_sender
99 .send(Message::Notification(Notification::new(
100 N::METHOD.to_string(),
101 params,
102 )))
103 .map_err(|error| anyhow!("Failed to send notification {}: {error}", N::METHOD))
104 }
105
106 pub(crate) fn respond<R>(
107 &self,
108 id: &RequestId,
109 result: crate::server::Result<R>,
110 ) -> crate::Result<()>
111 where
112 R: serde::Serialize,
113 {
114 let response = match result {
115 Ok(value) => lsp_server::Response::new_ok(id.clone(), value),
116 Err(crate::server::Error { code, error }) => {
117 lsp_server::Response::new_err(id.clone(), code as i32, error.to_string())
118 }
119 };
120
121 self.main_loop_sender
122 .send(Event::SendResponse(response))
123 .map_err(|error| anyhow!("Failed to queue response {id}: {error}"))
124 }
125
126 pub(crate) fn respond_err(&self, id: RequestId, error: ResponseError) -> crate::Result<()> {
127 self.main_loop_sender
128 .send(Event::SendResponse(lsp_server::Response {
129 id,
130 result: None,
131 error: Some(error),
132 }))
133 .map_err(|send_error| anyhow!("Failed to queue error response: {send_error}"))
134 }
135
136 pub(crate) fn show_message(
137 &self,
138 message: impl Display,
139 message_type: lsp_types::MessageType,
140 ) -> crate::Result<()> {
141 self.send_notification::<lsp_types::notification::ShowMessage>(
142 lsp_types::ShowMessageParams {
143 typ: message_type,
144 message: message.to_string(),
145 },
146 )
147 }
148
149 pub(crate) fn log_message(
150 &self,
151 message: impl Display,
152 message_type: lsp_types::MessageType,
153 ) -> crate::Result<()> {
154 self.send_notification::<lsp_types::notification::LogMessage>(lsp_types::LogMessageParams {
155 typ: message_type,
156 message: message.to_string(),
157 })
158 }
159
160 pub(crate) fn show_error_message(&self, message: impl Display) {
161 if let Err(err) = self.show_message(message, lsp_types::MessageType::ERROR) {
162 tracing::error!("Failed to send error message to client: {err}");
163 }
164 }
165
166 pub(crate) fn cancel(&self, session: &mut Session, id: RequestId) -> crate::Result<()> {
167 let method_name = session.request_queue_mut().incoming_mut().cancel(&id);
168 if let Some(method_name) = method_name {
169 tracing::debug!("Cancelled request id={id} method={method_name}");
170 self.client_sender
171 .send(Message::Response(lsp_server::Response {
172 id,
173 result: None,
174 error: Some(ResponseError {
175 code: ErrorCode::RequestCanceled as i32,
176 message: "request was cancelled by client".to_owned(),
177 data: None,
178 }),
179 }))?;
180 }
181 Ok(())
182 }
183}