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