haystack_server/ops/
defs.rs1use actix_web::{HttpRequest, HttpResponse, web};
45
46use haystack_core::data::{HCol, HDict, HGrid};
47use haystack_core::kinds::Kind;
48
49use crate::content;
50use crate::error::HaystackError;
51use crate::state::AppState;
52
53pub async fn handle(
58 req: HttpRequest,
59 body: String,
60 state: web::Data<AppState>,
61) -> Result<HttpResponse, HaystackError> {
62 let content_type = req
63 .headers()
64 .get("Content-Type")
65 .and_then(|v| v.to_str().ok())
66 .unwrap_or("");
67 let accept = req
68 .headers()
69 .get("Accept")
70 .and_then(|v| v.to_str().ok())
71 .unwrap_or("");
72
73 let ns = state.namespace.read();
74
75 let filter: Option<String> = if body.trim().is_empty() {
77 None
78 } else {
79 let request_grid = content::decode_request_grid(&body, content_type)
80 .map_err(|e| HaystackError::bad_request(format!("failed to decode request: {e}")))?;
81
82 request_grid.row(0).and_then(|row| match row.get("filter") {
83 Some(Kind::Str(s)) if !s.is_empty() => Some(s.clone()),
84 _ => None,
85 })
86 };
87
88 let cols = vec![HCol::new("def"), HCol::new("lib"), HCol::new("doc")];
90
91 let defs = ns.defs();
92 let mut rows: Vec<HDict> = Vec::new();
93
94 for (symbol, def) in defs {
95 if let Some(ref f) = filter
97 && !symbol.contains(f.as_str())
98 {
99 continue;
100 }
101
102 let mut row = HDict::new();
103 row.set(
104 "def",
105 Kind::Symbol(haystack_core::kinds::Symbol::new(symbol)),
106 );
107 row.set(
108 "lib",
109 Kind::Symbol(haystack_core::kinds::Symbol::new(&def.lib)),
110 );
111 row.set("doc", Kind::Str(def.doc.clone()));
112 rows.push(row);
113 }
114
115 rows.sort_by(|a, b| {
117 let a_name = match a.get("def") {
118 Some(Kind::Symbol(s)) => s.val(),
119 _ => "",
120 };
121 let b_name = match b.get("def") {
122 Some(Kind::Symbol(s)) => s.val(),
123 _ => "",
124 };
125 a_name.cmp(b_name)
126 });
127
128 let grid = HGrid::from_parts(HDict::new(), cols, rows);
129 let (encoded, ct) = content::encode_response_grid(&grid, accept)
130 .map_err(|e| HaystackError::internal(format!("encoding error: {e}")))?;
131
132 Ok(HttpResponse::Ok().content_type(ct).body(encoded))
133}
134
135pub async fn handle_libs(
137 req: HttpRequest,
138 state: web::Data<AppState>,
139) -> Result<HttpResponse, HaystackError> {
140 let accept = req
141 .headers()
142 .get("Accept")
143 .and_then(|v| v.to_str().ok())
144 .unwrap_or("");
145
146 let ns = state.namespace.read();
147
148 let cols = vec![HCol::new("name"), HCol::new("version")];
149 let libs = ns.libs();
150 let mut rows: Vec<HDict> = libs
151 .values()
152 .map(|lib| {
153 let mut row = HDict::new();
154 row.set("name", Kind::Str(lib.name.clone()));
155 row.set("version", Kind::Str(lib.version.clone()));
156 row
157 })
158 .collect();
159
160 rows.sort_by(|a, b| {
162 let a_name = match a.get("name") {
163 Some(Kind::Str(s)) => s.as_str(),
164 _ => "",
165 };
166 let b_name = match b.get("name") {
167 Some(Kind::Str(s)) => s.as_str(),
168 _ => "",
169 };
170 a_name.cmp(b_name)
171 });
172
173 let grid = HGrid::from_parts(HDict::new(), cols, rows);
174 let (encoded, ct) = content::encode_response_grid(&grid, accept)
175 .map_err(|e| HaystackError::internal(format!("encoding error: {e}")))?;
176
177 Ok(HttpResponse::Ok().content_type(ct).body(encoded))
178}