Skip to main content

rust_analyzer_cli/daemon/
server.rs

1use crate::cargo::run_cargo_check;
2use crate::daemon::state::AppState;
3use crate::lsp::types::*;
4use axum::{
5    Json, Router,
6    extract::State,
7    http::StatusCode,
8    routing::{get, post},
9};
10use std::net::SocketAddr;
11use std::path::PathBuf;
12use std::sync::Arc;
13use tracing::info;
14
15pub async fn start_daemon_server(workspace_root: PathBuf, port: u16) -> anyhow::Result<()> {
16    let state = Arc::new(AppState::new(workspace_root));
17
18    let app = Router::new()
19        .route("/status", get(handle_status))
20        .route("/refresh", post(handle_refresh))
21        .route("/api/symbol", post(handle_symbol))
22        .route("/api/outline", post(handle_outline))
23        .route("/api/definition", post(handle_definition))
24        .route("/api/body", post(handle_body))
25        .route("/api/cursor", post(handle_cursor))
26        .route("/api/type-hierarchy", post(handle_type_hierarchy))
27        .route("/api/check", post(handle_check))
28        .with_state(state);
29
30    let addr = SocketAddr::from(([127, 0, 0, 1], port));
31    info!("rust-analyzer-cli daemon listening on http://{}", addr);
32    println!("rust-analyzer-cli daemon started on http://{}", addr);
33
34    let listener = tokio::net::TcpListener::bind(addr).await?;
35    axum::serve(listener, app).await?;
36    Ok(())
37}
38
39async fn handle_status(
40    State(state): State<Arc<AppState>>,
41) -> Result<Json<DaemonStatusResponse>, (StatusCode, String)> {
42    let client_opt = state.lsp_client.read().await;
43    let (ready, pid) = match client_opt.as_ref() {
44        Some(c) => (true, c.process_id),
45        None => (false, 0),
46    };
47
48    Ok(Json(DaemonStatusResponse {
49        ready,
50        indexed_at: Some(chrono_now_str()),
51        workspace_root: state.workspace_root.to_string_lossy().to_string(),
52        process_id: pid,
53    }))
54}
55
56async fn handle_refresh(
57    State(state): State<Arc<AppState>>,
58) -> Result<Json<serde_json::Value>, (StatusCode, String)> {
59    state
60        .refresh_lsp()
61        .await
62        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
63    Ok(Json(
64        serde_json::json!({ "success": true, "message": "LSP session refreshed" }),
65    ))
66}
67
68async fn handle_symbol(
69    State(state): State<Arc<AppState>>,
70    Json(req): Json<SymbolQueryRequest>,
71) -> Result<Json<Vec<SymbolItem>>, (StatusCode, String)> {
72    let client = state
73        .get_or_start_lsp()
74        .await
75        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
76
77    let items = client
78        .query_symbol(&req.name, &req.kind, req.exact, false, 100)
79        .await
80        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
81
82    Ok(Json(items))
83}
84
85async fn handle_outline(
86    State(state): State<Arc<AppState>>,
87    Json(req): Json<OutlineQueryRequest>,
88) -> Result<Json<Vec<OutlineItem>>, (StatusCode, String)> {
89    let client = state
90        .get_or_start_lsp()
91        .await
92        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
93
94    let items = client
95        .query_outline(&req.file, false, 100)
96        .await
97        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
98
99    Ok(Json(items))
100}
101
102async fn handle_definition(
103    State(state): State<Arc<AppState>>,
104    Json(req): Json<DefinitionQueryRequest>,
105) -> Result<Json<Vec<DefinitionItem>>, (StatusCode, String)> {
106    let client = state
107        .get_or_start_lsp()
108        .await
109        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
110
111    let items = client
112        .query_definition(&req.file, req.line, req.col, false, 100)
113        .await
114        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
115
116    Ok(Json(items))
117}
118
119async fn handle_body(
120    State(state): State<Arc<AppState>>,
121    Json(req): Json<BodyQueryRequest>,
122) -> Result<Json<BodyItem>, (StatusCode, String)> {
123    let client = state
124        .get_or_start_lsp()
125        .await
126        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
127
128    let item = client
129        .query_body(&req.file, req.line, req.col, req.max_lines)
130        .await
131        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
132
133    Ok(Json(item))
134}
135
136async fn handle_cursor(
137    State(state): State<Arc<AppState>>,
138    Json(req): Json<CursorQueryRequest>,
139) -> Result<Json<Vec<CursorItem>>, (StatusCode, String)> {
140    let client = state
141        .get_or_start_lsp()
142        .await
143        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
144
145    let items = client
146        .query_cursor(&req.file, req.line, req.col, &req.mode, req.depth)
147        .await
148        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
149
150    Ok(Json(items))
151}
152
153async fn handle_type_hierarchy(
154    State(state): State<Arc<AppState>>,
155    Json(req): Json<TypeHierarchyQueryRequest>,
156) -> Result<Json<Vec<TypeHierarchyItemResult>>, (StatusCode, String)> {
157    let client = state
158        .get_or_start_lsp()
159        .await
160        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
161
162    let items = client
163        .query_type_hierarchy(&req.file, req.line, req.col, &req.mode, req.depth)
164        .await
165        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
166
167    Ok(Json(items))
168}
169
170async fn handle_check(
171    State(state): State<Arc<AppState>>,
172    Json(req): Json<CheckQueryRequest>,
173) -> Result<Json<CheckResponse>, (StatusCode, String)> {
174    let res = run_cargo_check(&state.workspace_root, req.target.as_deref())
175        .await
176        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
177
178    Ok(Json(res))
179}
180
181fn chrono_now_str() -> String {
182    let now = std::time::SystemTime::now();
183    format!("{:?}", now)
184}