Skip to main content

shuck_server/session/
client.rs

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