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#[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}