#include "data_http.h" #include "http_client.h" #include "vendor/nlohmann/json.hpp" #include #include using json = nlohmann::json; // Parse host and port from URL like "http://127.0.0.1:8484" static bool parse_url(const std::string& url, std::string& host, int& port) { auto pos = url.find("://"); std::string rest = (pos != std::string::npos) ? url.substr(pos + 3) : url; auto colon = rest.find(':'); if (colon == std::string::npos) { host = rest; port = 80; } else { host = rest.substr(0, colon); port = std::atoi(rest.substr(colon + 1).c_str()); } return !host.empty() && port > 0; } // POST a SQL query to the API and return parsed JSON, or null on failure. static json api_query(HttpClient& cli, const char* sql) { json body; body["sql"] = sql; auto res = cli.post("/api/databases/registry/query", body.dump(), "application/json"); if (!res.ok()) { if (res.status > 0) fprintf(stderr, "[http] query error %d: %s\n", res.status, res.body.c_str()); else fprintf(stderr, "[http] connection failed for query: %s\n", sql); return nullptr; } return json::parse(res.body, nullptr, false); } static int extract_int(const json& j) { if (j.is_null() || !j.contains("rows") || j["rows"].empty()) return 0; auto& val = j["rows"][0][0]; if (val.is_number()) return val.get(); if (val.is_string()) return std::atoi(val.get().c_str()); return 0; } static std::string extract_str(const json& row, size_t idx) { if (idx >= row.size() || row[idx].is_null()) return ""; if (row[idx].is_string()) return row[idx].get(); return row[idx].dump(); } static int extract_row_int(const json& row, size_t idx) { if (idx >= row.size() || row[idx].is_null()) return 0; if (row[idx].is_number()) return row[idx].get(); if (row[idx].is_string()) return std::atoi(row[idx].get().c_str()); return 0; } bool load_registry_data_http(const std::string& api_url, RegistryData& out) { std::string host; int port; if (!parse_url(api_url, host, port)) { fprintf(stderr, "[http] invalid URL: %s\n", api_url.c_str()); return false; } HttpClient cli(host, port); // Health check auto health = cli.get("/health"); if (!health.ok()) { fprintf(stderr, "[http] sqlite_api not reachable at %s\n", api_url.c_str()); return false; } fprintf(stdout, "[http] Connected to sqlite_api at %s\n", api_url.c_str()); // --- Counts --- out.stats.total_functions = extract_int(api_query(cli, "SELECT COUNT(*) FROM functions")); out.stats.total_types = extract_int(api_query(cli, "SELECT COUNT(*) FROM types")); out.stats.total_apps = extract_int(api_query(cli, "SELECT COUNT(*) FROM apps")); out.stats.total_analysis = extract_int(api_query(cli, "SELECT COUNT(*) FROM analysis")); out.stats.total_unit_tests = extract_int(api_query(cli, "SELECT COUNT(*) FROM unit_tests")); out.stats.total_proposals = extract_int(api_query(cli, "SELECT COUNT(*) FROM proposals")); out.stats.tested_functions = extract_int(api_query(cli, "SELECT COUNT(*) FROM functions WHERE tested = 1")); out.stats.pure_functions = extract_int(api_query(cli, "SELECT COUNT(*) FROM functions WHERE purity = 'pure'")); out.stats.impure_functions = extract_int(api_query(cli, "SELECT COUNT(*) FROM functions WHERE purity = 'impure'")); // --- By language --- out.by_lang.clear(); auto j = api_query(cli, "SELECT lang, COUNT(*) as cnt FROM functions GROUP BY lang ORDER BY cnt DESC"); if (!j.is_null() && j.contains("rows")) for (auto& row : j["rows"]) out.by_lang.push_back({extract_str(row, 0), extract_row_int(row, 1)}); // --- By domain --- out.by_domain.clear(); j = api_query(cli, "SELECT domain, COUNT(*) as cnt FROM functions GROUP BY domain ORDER BY cnt DESC"); if (!j.is_null() && j.contains("rows")) for (auto& row : j["rows"]) out.by_domain.push_back({extract_str(row, 0), extract_row_int(row, 1)}); // --- By kind --- out.by_kind.clear(); j = api_query(cli, "SELECT kind, COUNT(*) as cnt FROM functions GROUP BY kind ORDER BY cnt DESC"); if (!j.is_null() && j.contains("rows")) for (auto& row : j["rows"]) out.by_kind.push_back({extract_str(row, 0), extract_row_int(row, 1)}); // --- By date (last 30 days) --- out.by_date.clear(); j = api_query(cli, "SELECT date(created_at) as d, COUNT(*) as cnt FROM functions " "WHERE created_at >= date('now', '-30 days') GROUP BY d ORDER BY d"); if (!j.is_null() && j.contains("rows")) for (auto& row : j["rows"]) out.by_date.push_back({extract_str(row, 0), extract_row_int(row, 1)}); // --- Recent functions --- out.recent_funcs.clear(); j = api_query(cli, "SELECT id, name, lang, domain, kind, purity, description, created_at, tested " "FROM functions ORDER BY created_at DESC LIMIT 20"); if (!j.is_null() && j.contains("rows")) { for (auto& row : j["rows"]) { FunctionRow r; r.id = extract_str(row, 0); r.name = extract_str(row, 1); r.lang = extract_str(row, 2); r.domain = extract_str(row, 3); r.kind = extract_str(row, 4); r.purity = extract_str(row, 5); r.description = extract_str(row, 6); r.created_at = extract_str(row, 7); r.tested = extract_row_int(row, 8) != 0; out.recent_funcs.push_back(std::move(r)); } } // --- Apps --- out.apps.clear(); j = api_query(cli, "SELECT id, name, lang, domain, description, framework FROM apps ORDER BY name"); if (!j.is_null() && j.contains("rows")) { for (auto& row : j["rows"]) { AppRow r; r.id = extract_str(row, 0); r.name = extract_str(row, 1); r.lang = extract_str(row, 2); r.domain = extract_str(row, 3); r.description = extract_str(row, 4); r.framework = extract_str(row, 5); out.apps.push_back(std::move(r)); } } // --- Analysis --- out.analyses.clear(); j = api_query(cli, "SELECT id, name, domain, description FROM analysis ORDER BY name"); if (!j.is_null() && j.contains("rows")) { for (auto& row : j["rows"]) { AnalysisRow r; r.id = extract_str(row, 0); r.name = extract_str(row, 1); r.domain = extract_str(row, 2); r.description = extract_str(row, 3); out.analyses.push_back(std::move(r)); } } // --- Types --- out.types.clear(); j = api_query(cli, "SELECT id, name, lang, domain, algebraic, description FROM types ORDER BY name"); if (!j.is_null() && j.contains("rows")) { for (auto& row : j["rows"]) { TypeRow r; r.id = extract_str(row, 0); r.name = extract_str(row, 1); r.lang = extract_str(row, 2); r.domain = extract_str(row, 3); r.algebraic = extract_str(row, 4); r.description = extract_str(row, 5); out.types.push_back(std::move(r)); } } out.prepare_chart_data(); return true; }