tldr_cli/commands/
daemon_router.rs1use std::path::{Path, PathBuf};
18
19use serde::de::DeserializeOwned;
20
21use crate::commands::daemon::error::DaemonError;
22use crate::commands::daemon::ipc::send_raw_command;
23
24pub fn try_daemon_route<T: DeserializeOwned>(
52 project: &Path,
53 endpoint: &str,
54 params: serde_json::Value,
55) -> Option<T> {
56 let runtime = match tokio::runtime::Runtime::new() {
58 Ok(rt) => rt,
59 Err(_) => return None,
60 };
61
62 runtime.block_on(try_daemon_route_async(project, endpoint, params))
63}
64
65pub async fn try_daemon_route_async<T: DeserializeOwned>(
69 project: &Path,
70 endpoint: &str,
71 params: serde_json::Value,
72) -> Option<T> {
73 let project = project.canonicalize().unwrap_or_else(|_| {
75 std::env::current_dir()
76 .unwrap_or_else(|_| PathBuf::from("."))
77 .join(project)
78 });
79
80 let mut cmd_obj = serde_json::json!({
82 "cmd": endpoint.to_lowercase()
83 });
84
85 if let serde_json::Value::Object(params_obj) = params {
87 if let serde_json::Value::Object(ref mut cmd_map) = cmd_obj {
88 for (key, value) in params_obj {
89 cmd_map.insert(key, value);
90 }
91 }
92 }
93
94 let command_json = match serde_json::to_string(&cmd_obj) {
95 Ok(json) => json,
96 Err(_) => return None,
97 };
98
99 let response = match send_raw_command(&project, &command_json).await {
101 Ok(resp) => resp,
102 Err(DaemonError::NotRunning) => return None,
103 Err(DaemonError::ConnectionRefused) => return None,
104 Err(_) => return None,
105 };
106
107 let response_value: serde_json::Value = match serde_json::from_str(&response) {
109 Ok(v) => v,
110 Err(_) => return None,
111 };
112
113 if let Some(status) = response_value.get("status") {
115 if status == "error" {
116 return None;
117 }
118 }
119
120 let result_value = if response_value.get("result").is_some() {
122 response_value
123 .get("result")
124 .cloned()
125 .unwrap_or(response_value)
126 } else {
127 response_value
128 };
129
130 serde_json::from_value(result_value).ok()
132}
133
134pub fn is_daemon_running(project: &Path) -> bool {
138 let runtime = match tokio::runtime::Runtime::new() {
139 Ok(rt) => rt,
140 Err(_) => return false,
141 };
142
143 runtime.block_on(is_daemon_running_async(project))
144}
145
146pub async fn is_daemon_running_async(project: &Path) -> bool {
148 use crate::commands::daemon::ipc::check_socket_alive;
149 check_socket_alive(project).await
150}
151
152pub fn params_with_path(path: Option<&Path>) -> serde_json::Value {
158 let mut obj = serde_json::Map::new();
159 if let Some(p) = path {
160 obj.insert("path".to_string(), serde_json::json!(p));
161 }
162 serde_json::Value::Object(obj)
163}
164
165pub fn params_with_file(file: &Path) -> serde_json::Value {
167 serde_json::json!({
168 "file": file
169 })
170}
171
172pub fn params_with_file_function(file: &Path, function: &str) -> serde_json::Value {
174 serde_json::json!({
175 "file": file,
176 "function": function
177 })
178}
179
180pub fn params_with_file_function_line(file: &Path, function: &str, line: u32) -> serde_json::Value {
182 serde_json::json!({
183 "file": file,
184 "function": function,
185 "line": line
186 })
187}
188
189pub fn params_with_func_depth(func: &str, depth: Option<usize>) -> serde_json::Value {
191 let mut obj = serde_json::Map::new();
192 obj.insert("func".to_string(), serde_json::json!(func));
193 if let Some(d) = depth {
194 obj.insert("depth".to_string(), serde_json::json!(d));
195 }
196 serde_json::Value::Object(obj)
197}
198
199pub fn params_with_module(module: &str, path: Option<&Path>) -> serde_json::Value {
201 let mut obj = serde_json::Map::new();
202 obj.insert("module".to_string(), serde_json::json!(module));
203 if let Some(p) = path {
204 obj.insert("path".to_string(), serde_json::json!(p));
205 }
206 serde_json::Value::Object(obj)
207}
208
209pub fn params_with_pattern(pattern: &str, max_results: Option<usize>) -> serde_json::Value {
211 let mut obj = serde_json::Map::new();
212 obj.insert("pattern".to_string(), serde_json::json!(pattern));
213 if let Some(m) = max_results {
214 obj.insert("max_results".to_string(), serde_json::json!(m));
215 }
216 serde_json::Value::Object(obj)
217}
218
219pub fn params_with_entry_depth(entry: &str, depth: Option<usize>) -> serde_json::Value {
221 let mut obj = serde_json::Map::new();
222 obj.insert("entry".to_string(), serde_json::json!(entry));
223 if let Some(d) = depth {
224 obj.insert("depth".to_string(), serde_json::json!(d));
225 }
226 serde_json::Value::Object(obj)
227}
228
229pub fn params_with_path_lang(path: &Path, lang: Option<&str>) -> serde_json::Value {
231 let mut obj = serde_json::Map::new();
232 obj.insert("path".to_string(), serde_json::json!(path));
233 if let Some(l) = lang {
234 obj.insert("lang".to_string(), serde_json::json!(l));
235 }
236 serde_json::Value::Object(obj)
237}
238
239pub fn params_for_dead(path: Option<&Path>, entry: Option<&[String]>) -> serde_json::Value {
241 let mut obj = serde_json::Map::new();
242 if let Some(p) = path {
243 obj.insert("path".to_string(), serde_json::json!(p));
244 }
245 if let Some(e) = entry {
246 obj.insert("entry".to_string(), serde_json::json!(e));
247 }
248 serde_json::Value::Object(obj)
249}
250
251#[cfg(test)]
256mod tests {
257 use super::*;
258 use tempfile::TempDir;
259
260 #[test]
261 fn test_params_with_path() {
262 let params = params_with_path(Some(Path::new("/test/path")));
263 assert_eq!(params.get("path").unwrap(), "/test/path");
264 }
265
266 #[test]
267 fn test_params_with_path_none() {
268 let params = params_with_path(None);
269 assert!(params.get("path").is_none());
270 }
271
272 #[test]
273 fn test_params_with_file_function() {
274 let params = params_with_file_function(Path::new("/test/file.py"), "my_func");
275 assert_eq!(params.get("file").unwrap(), "/test/file.py");
276 assert_eq!(params.get("function").unwrap(), "my_func");
277 }
278
279 #[test]
280 fn test_params_with_file_function_line() {
281 let params = params_with_file_function_line(Path::new("/test/file.py"), "my_func", 42);
282 assert_eq!(params.get("file").unwrap(), "/test/file.py");
283 assert_eq!(params.get("function").unwrap(), "my_func");
284 assert_eq!(params.get("line").unwrap(), 42);
285 }
286
287 #[test]
288 fn test_params_with_func_depth() {
289 let params = params_with_func_depth("process_data", Some(5));
290 assert_eq!(params.get("func").unwrap(), "process_data");
291 assert_eq!(params.get("depth").unwrap(), 5);
292 }
293
294 #[test]
295 fn test_params_with_pattern() {
296 let params = params_with_pattern("fn main", Some(100));
297 assert_eq!(params.get("pattern").unwrap(), "fn main");
298 assert_eq!(params.get("max_results").unwrap(), 100);
299 }
300
301 #[test]
302 fn test_is_daemon_running_no_daemon() {
303 let temp = TempDir::new().unwrap();
304 assert!(!is_daemon_running(temp.path()));
305 }
306
307 #[test]
308 fn test_try_daemon_route_no_daemon() {
309 let temp = TempDir::new().unwrap();
310 let result: Option<serde_json::Value> =
311 try_daemon_route(temp.path(), "ping", serde_json::json!({}));
312 assert!(result.is_none());
313 }
314}