shuck_server/session/
client.rs1use 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}