haystack_server/ops/
defs.rs1use actix_web::{HttpRequest, HttpResponse, web};
4
5use haystack_core::data::{HCol, HDict, HGrid};
6use haystack_core::kinds::Kind;
7
8use crate::content;
9use crate::error::HaystackError;
10use crate::state::AppState;
11
12pub async fn handle(
17 req: HttpRequest,
18 body: String,
19 state: web::Data<AppState>,
20) -> Result<HttpResponse, HaystackError> {
21 let content_type = req
22 .headers()
23 .get("Content-Type")
24 .and_then(|v| v.to_str().ok())
25 .unwrap_or("");
26 let accept = req
27 .headers()
28 .get("Accept")
29 .and_then(|v| v.to_str().ok())
30 .unwrap_or("");
31
32 let ns = state.namespace.read();
33
34 let filter: Option<String> = if body.trim().is_empty() {
36 None
37 } else {
38 let request_grid = content::decode_request_grid(&body, content_type)
39 .map_err(|e| HaystackError::bad_request(format!("failed to decode request: {e}")))?;
40
41 request_grid.row(0).and_then(|row| match row.get("filter") {
42 Some(Kind::Str(s)) if !s.is_empty() => Some(s.clone()),
43 _ => None,
44 })
45 };
46
47 let cols = vec![HCol::new("def"), HCol::new("lib"), HCol::new("doc")];
49
50 let defs = ns.defs();
51 let mut rows: Vec<HDict> = Vec::new();
52
53 for (symbol, def) in defs {
54 if let Some(ref f) = filter
56 && !symbol.contains(f.as_str())
57 {
58 continue;
59 }
60
61 let mut row = HDict::new();
62 row.set(
63 "def",
64 Kind::Symbol(haystack_core::kinds::Symbol::new(symbol)),
65 );
66 row.set(
67 "lib",
68 Kind::Symbol(haystack_core::kinds::Symbol::new(&def.lib)),
69 );
70 row.set("doc", Kind::Str(def.doc.clone()));
71 rows.push(row);
72 }
73
74 rows.sort_by(|a, b| {
76 let a_name = match a.get("def") {
77 Some(Kind::Symbol(s)) => s.val(),
78 _ => "",
79 };
80 let b_name = match b.get("def") {
81 Some(Kind::Symbol(s)) => s.val(),
82 _ => "",
83 };
84 a_name.cmp(b_name)
85 });
86
87 let grid = HGrid::from_parts(HDict::new(), cols, rows);
88 let (encoded, ct) = content::encode_response_grid(&grid, accept)
89 .map_err(|e| HaystackError::internal(format!("encoding error: {e}")))?;
90
91 Ok(HttpResponse::Ok().content_type(ct).body(encoded))
92}
93
94pub async fn handle_libs(
96 req: HttpRequest,
97 state: web::Data<AppState>,
98) -> Result<HttpResponse, HaystackError> {
99 let accept = req
100 .headers()
101 .get("Accept")
102 .and_then(|v| v.to_str().ok())
103 .unwrap_or("");
104
105 let ns = state.namespace.read();
106
107 let cols = vec![HCol::new("name"), HCol::new("version")];
108 let libs = ns.libs();
109 let mut rows: Vec<HDict> = libs
110 .values()
111 .map(|lib| {
112 let mut row = HDict::new();
113 row.set("name", Kind::Str(lib.name.clone()));
114 row.set("version", Kind::Str(lib.version.clone()));
115 row
116 })
117 .collect();
118
119 rows.sort_by(|a, b| {
121 let a_name = match a.get("name") {
122 Some(Kind::Str(s)) => s.as_str(),
123 _ => "",
124 };
125 let b_name = match b.get("name") {
126 Some(Kind::Str(s)) => s.as_str(),
127 _ => "",
128 };
129 a_name.cmp(b_name)
130 });
131
132 let grid = HGrid::from_parts(HDict::new(), cols, rows);
133 let (encoded, ct) = content::encode_response_grid(&grid, accept)
134 .map_err(|e| HaystackError::internal(format!("encoding error: {e}")))?;
135
136 Ok(HttpResponse::Ok().content_type(ct).body(encoded))
137}