1use std::collections::HashMap;
4use std::sync::Arc;
5
6use lsp_types_max::Diagnostic;
7use serde_json::{json, Value};
8use tokio::sync::{broadcast, Mutex};
9
10use crate::jsonrpc::{Error, Request, Result};
11use crate::Client;
12
13use super::capability_tracker::CapabilityTracker;
14use super::edit_gate::TransactionEditGate;
15use super::strategy::method_strategy;
16use super::upstream::PersistentUpstream;
17use super::version_tracker::DocumentVersionTracker;
18
19#[derive(Debug)]
21pub struct CompositionState {
22 pub capability_tracker: CapabilityTracker,
24 pub doc_tracker: DocumentVersionTracker,
26 pub edit_gate: TransactionEditGate,
28 pub upstream_timeout_ms: u64,
30 pub diagnostics: HashMap<String, HashMap<String, Value>>,
32 pub request_counter: u64,
34 pub request_traces: Arc<std::sync::Mutex<Vec<Value>>>,
36}
37
38impl CompositionState {
39 pub fn new(upstream_addresses: Vec<(String, String)>) -> Self {
41 use super::strategy::UpstreamSource;
42 let mut tracker = CapabilityTracker::new();
43 for (id, addr) in upstream_addresses {
44 tracker.add_source(UpstreamSource::new(id, addr));
45 }
46 let upstream_timeout_ms = std::env::var("LSP_MAX_TIMEOUT")
47 .ok()
48 .and_then(|v| v.parse::<u64>().ok())
49 .unwrap_or(150);
50 Self {
51 capability_tracker: tracker,
52 doc_tracker: DocumentVersionTracker::new(),
53 edit_gate: TransactionEditGate::new(),
54 upstream_timeout_ms,
55 diagnostics: HashMap::new(),
56 request_counter: 0,
57 request_traces: Arc::new(std::sync::Mutex::new(Vec::new())),
58 }
59 }
60}
61
62pub type SharedCompositionState = Arc<Mutex<CompositionState>>;
64
65#[derive(Debug)]
67pub struct ComposedServer {
68 pub(super) _client: Client,
69 pub(super) state: SharedCompositionState,
70 pub(super) upstreams: Arc<dashmap::DashMap<String, PersistentUpstream>>,
71}
72
73impl ComposedServer {
74 pub fn state(&self) -> &SharedCompositionState {
76 &self.state
77 }
78
79 pub fn new(client: Client, upstream_addresses: Vec<(String, String)>) -> Self {
81 let state = Arc::new(Mutex::new(CompositionState::new(
82 upstream_addresses.clone(),
83 )));
84 let upstreams = Arc::new(dashmap::DashMap::new());
85 let (unsolicited_tx, mut unsolicited_rx) = broadcast::channel(128);
86
87 let _upstreams_clone = upstreams.clone();
88 for (id, addr) in upstream_addresses {
89 let id_clone = id.clone();
90 let addr_clone = addr.clone();
91 let unsolicited_tx = unsolicited_tx.clone();
92 let upstreams_connections = upstreams.clone();
93 tokio::spawn(async move {
94 if let Some(conn) =
95 PersistentUpstream::connect(id_clone.clone(), addr_clone, 1000, unsolicited_tx)
96 .await
97 {
98 upstreams_connections.insert(id_clone, conn);
99 }
100 });
101 }
102
103 let client_clone = client.clone();
104 let state_clone = state.clone();
105 let upstreams_connections_clone = upstreams.clone();
106 tokio::spawn(async move {
107 loop {
108 match unsolicited_rx.recv().await {
109 Ok(notification) => {
110 let msg = notification.message;
111 let source_id = notification.source_id;
112
113 let method = match msg.get("method").and_then(|v| v.as_str()) {
114 Some(m) => m,
115 None => continue,
116 };
117
118 if method == "client/registerCapability" {
119 let mut valid_registrations = Vec::new();
120 if let Some(params) = msg.get("params") {
121 if let Some(registrations) =
122 params.get("registrations").and_then(|v| v.as_array())
123 {
124 let mut s = state_clone.lock().await;
125 for reg in registrations {
126 if let (Some(id), Some(m)) = (
127 reg.get("id").and_then(|v| v.as_str()),
128 reg.get("method").and_then(|v| v.as_str()),
129 ) {
130 let options = reg
131 .get("registerOptions")
132 .cloned()
133 .unwrap_or(Value::Null);
134 if s.capability_tracker
135 .register_dynamic(id, m, &source_id, options)
136 {
137 valid_registrations.push(reg.clone());
138 }
139 }
140 }
141 }
142 }
143 let msg_id_opt = msg.get("id").cloned();
144 let client = client_clone.clone();
145 let upstreams_connections = upstreams_connections_clone.clone();
146 let source_id = source_id.clone();
147 if valid_registrations.is_empty() {
148 if let Some(msg_id) = msg_id_opt {
149 tokio::spawn(async move {
150 let resp = json!({ "jsonrpc": "2.0", "id": msg_id, "result": null });
151 if let Some(conn) = upstreams_connections.get(&source_id) {
152 let _ = conn.send_raw(resp).await;
153 }
154 });
155 }
156 } else {
157 let params = json!({ "registrations": valid_registrations });
158 tokio::spawn(async move {
159 let req_id = client.next_request_id();
160 let request =
161 Request::build("client/registerCapability".to_string())
162 .id(req_id.clone())
163 .params(params)
164 .finish();
165 let mut client_clone = client.clone();
166 use tower::Service;
167 let resp_res = client_clone.call(request).await;
168 if let Some(msg_id) = msg_id_opt {
169 let resp = match resp_res {
170 Ok(Some(response)) => {
171 let (_, result) = response.into_parts();
172 match result {
173 Ok(res) => {
174 json!({ "jsonrpc": "2.0", "id": msg_id, "result": res })
175 }
176 Err(err) => {
177 json!({ "jsonrpc": "2.0", "id": msg_id, "error": err })
178 }
179 }
180 }
181 _ => {
182 json!({ "jsonrpc": "2.0", "id": msg_id, "error": { "code": -32603, "message": "Internal error" } })
183 }
184 };
185 if let Some(conn) = upstreams_connections.get(&source_id) {
186 let _ = conn.send_raw(resp).await;
187 }
188 }
189 });
190 }
191 } else if method == "client/unregisterCapability" {
192 let mut valid_unregistrations = Vec::new();
193 if let Some(params) = msg.get("params") {
194 let unregs_opt = params
195 .get("unregisterations")
196 .and_then(|v| v.as_array())
197 .or_else(|| {
198 params.get("unregistrations").and_then(|v| v.as_array())
199 });
200 if let Some(unregistrations) = unregs_opt {
201 let mut s = state_clone.lock().await;
202 for unreg in unregistrations {
203 if let Some(id) = unreg.get("id").and_then(|v| v.as_str()) {
204 if s.capability_tracker.unregister_dynamic(id) {
205 valid_unregistrations.push(unreg.clone());
206 }
207 }
208 }
209 }
210 }
211 let msg_id_opt = msg.get("id").cloned();
212 let client = client_clone.clone();
213 let upstreams_connections = upstreams_connections_clone.clone();
214 let source_id = source_id.clone();
215 if valid_unregistrations.is_empty() {
216 if let Some(msg_id) = msg_id_opt {
217 tokio::spawn(async move {
218 let resp = json!({ "jsonrpc": "2.0", "id": msg_id, "result": null });
219 if let Some(conn) = upstreams_connections.get(&source_id) {
220 let _ = conn.send_raw(resp).await;
221 }
222 });
223 }
224 } else {
225 let params = json!({ "unregistrations": valid_unregistrations });
226 tokio::spawn(async move {
227 let req_id = client.next_request_id();
228 let request =
229 Request::build("client/unregisterCapability".to_string())
230 .id(req_id.clone())
231 .params(params)
232 .finish();
233 let mut client_clone = client.clone();
234 use tower::Service;
235 let resp_res = client_clone.call(request).await;
236 if let Some(msg_id) = msg_id_opt {
237 let resp = match resp_res {
238 Ok(Some(response)) => {
239 let (_, result) = response.into_parts();
240 match result {
241 Ok(res) => {
242 json!({ "jsonrpc": "2.0", "id": msg_id, "result": res })
243 }
244 Err(err) => {
245 json!({ "jsonrpc": "2.0", "id": msg_id, "error": err })
246 }
247 }
248 }
249 _ => {
250 json!({ "jsonrpc": "2.0", "id": msg_id, "error": { "code": -32603, "message": "Internal error" } })
251 }
252 };
253 if let Some(conn) = upstreams_connections.get(&source_id) {
254 let _ = conn.send_raw(resp).await;
255 }
256 }
257 });
258 }
259 } else if method == "textDocument/publishDiagnostics" {
260 if let Some(params) = msg.get("params") {
261 if let Some(uri) = params.get("uri").and_then(|v| v.as_str()) {
262 let diagnostics_val =
263 params.get("diagnostics").cloned().unwrap_or(json!([]));
264 let (merged_diags, version) = {
265 let mut s = state_clone.lock().await;
266 s.diagnostics
267 .entry(uri.to_string())
268 .or_default()
269 .insert(source_id.clone(), diagnostics_val);
270 let mut flat_diags = Vec::new();
271 if let Some(uri_diags) = s.diagnostics.get(uri) {
272 for (src_id, diags_value) in uri_diags {
273 if let Some(src) =
274 s.capability_tracker.sources.get(src_id)
275 {
276 if src.is_routable() {
277 if let Some(diags_arr) =
278 diags_value.as_array()
279 {
280 for diag in diags_arr {
281 if src_id == "ggen-lsp" {
282 let has_source_id = diag
283 .get("data")
284 .and_then(|data| {
285 data.get("source_id")
286 })
287 .is_some();
288 if !has_source_id {
289 continue;
290 }
291 }
292 let mut diag_clone = diag.clone();
293 if let Some(obj) =
294 diag_clone.as_object_mut()
295 {
296 obj.insert(
297 "source".to_string(),
298 Value::String(
299 src_id.clone(),
300 ),
301 );
302 }
303 flat_diags.push(diag_clone);
304 }
305 }
306 }
307 }
308 }
309 }
310 let version = s.doc_tracker.current_version(uri);
311 (flat_diags, version)
312 };
313 if let Ok(diag_list) = serde_json::from_value::<Vec<Diagnostic>>(
314 Value::Array(merged_diags),
315 ) {
316 if let Ok(parsed_uri) =
317 <lsp_types_max::Uri as std::str::FromStr>::from_str(uri)
318 {
319 client_clone
320 .publish_diagnostics(parsed_uri, diag_list, version)
321 .await;
322 }
323 }
324 }
325 }
326 }
327 }
328 Err(broadcast::error::RecvError::Lagged(n)) => {
329 tracing::warn!("Unsolicited message channel lagged by {} messages", n);
330 }
331 Err(broadcast::error::RecvError::Closed) => {
332 break;
333 }
334 }
335 }
336 });
337
338 Self {
339 _client: client,
340 state,
341 upstreams,
342 }
343 }
344
345 pub(super) async fn route_request<P, R>(&self, method: &str, params: P) -> Result<Option<R>>
346 where
347 P: serde::Serialize,
348 R: serde::de::DeserializeOwned,
349 {
350 tracing::trace!("--- route_request [{}] start", method);
351 let params_val = serde_json::to_value(params).unwrap_or(Value::Null);
352
353 tracing::trace!("--- route_request [{}] locking state at start", method);
354 let (request_id, strategy_str, uri_opt, doc_version) = {
355 let mut s = self.state.lock().await;
356 tracing::trace!(
357 "--- route_request [{}] locked state at start inside block",
358 method
359 );
360 s.request_counter += 1;
361 let counter = s.request_counter;
362 let strategy = method_strategy(method);
363 let uri = params_val
364 .get("textDocument")
365 .and_then(|td| td.get("uri"))
366 .and_then(|u| u.as_str())
367 .map(|s| s.to_string())
368 .or_else(|| {
369 params_val
370 .get("uri")
371 .and_then(|u| u.as_str())
372 .map(|s| s.to_string())
373 });
374 let ver = uri.as_ref().and_then(|u| s.doc_tracker.current_version(u));
375 (
376 format!("req_{}", counter),
377 format!("{:?}", strategy),
378 uri,
379 ver,
380 )
381 };
382 tracing::trace!("--- route_request [{}] strategy: {}", method, strategy_str);
383
384 let sources_contacted = Arc::new(std::sync::Mutex::new(Vec::<String>::new()));
385 let sources_returned = Arc::new(std::sync::Mutex::new(Vec::<String>::new()));
386 let source_health = Arc::new(std::sync::Mutex::new(std::collections::HashMap::<
387 String,
388 String,
389 >::new()));
390 let gate_outcome = Arc::new(std::sync::Mutex::new(None::<String>));
391 let staleness_outcome = Arc::new(std::sync::Mutex::new(None::<String>));
392
393 let res = self
394 .route_request_internal(
395 method,
396 params_val,
397 sources_contacted.clone(),
398 sources_returned.clone(),
399 source_health.clone(),
400 gate_outcome.clone(),
401 staleness_outcome.clone(),
402 )
403 .await;
404
405 let final_response_val = match &res {
406 Ok(Some(v)) => v.clone(),
407 _ => Value::Null,
408 };
409
410 {
412 let s = self.state.lock().await;
413 let trace = json!({
414 "request_id": request_id,
415 "method": method,
416 "document_uri": uri_opt,
417 "document_version": doc_version,
418 "strategy": strategy_str,
419 "sources_contacted": *sources_contacted.lock().unwrap(),
420 "sources_returned": *sources_returned.lock().unwrap(),
421 "source_health": *source_health.lock().unwrap(),
422 "gate_outcome": *gate_outcome.lock().unwrap(),
423 "staleness_outcome": *staleness_outcome.lock().unwrap(),
424 "final_response": final_response_val,
425 });
426 s.request_traces.lock().unwrap().push(trace);
427 }
428
429 match res {
430 Ok(Some(v)) => match serde_json::from_value::<R>(v) {
431 Ok(r) => Ok(Some(r)),
432 Err(e) => Err(Error::invalid_params(format!(
433 "Failed to deserialize response: {}",
434 e
435 ))),
436 },
437 Ok(None) => Ok(None),
438 Err(e) => Err(e),
439 }
440 }
441}