#include #include #include #include #include #include #include #include "utils.hpp" #include "crow/http_response.h" #include #include #include using namespace std; namespace utils { map parseBody(const string& body) { size_t pos = 0; size_t start = 0; map data; while (true) { pos = body.find('=', start); const string key = body.substr(start, pos - start); size_t nextPos = body.find('&', pos + 1); string value = body.substr(pos + 1, nextPos - (pos + 1)); data[key] = value; if (nextPos == std::string::npos) { break; } start = nextPos + 1; } return data; } optional getBodyName(const string& body) { const auto pos = body.find('='); if (pos == std::string::npos) return {}; const string key = body.substr(0, pos); string value = body.substr(pos + 1); if (key != "name") return {}; return value; } expected isLocalPortOpen(uint16_t portno) { const char *hostname = "localhost"; int sockfd; bool ret; struct sockaddr_in serv_addr; struct hostent *server; sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { close(sockfd); return unexpected("ERROR opening socket"); } server = gethostbyname(hostname); if (server == NULL) { close(sockfd); return unexpected("ERROR, no such host"); } bzero((char *) &serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length); serv_addr.sin_port = htons(portno); if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) { ret = false; } else { ret = true; } close(sockfd); return ret; } string to_id_format(const string& s){ string new_s = s; // transform(new_s.begin(), new_s.end(), new_s.begin(), // [](unsigned char c){ return std::tolower(c); }); replace( new_s.begin(), new_s.end(), ' ', '-'); return new_s; } string loadFile(const string& path) { ifstream f(path); stringstream buffer; buffer << f.rdbuf(); return buffer.str(); } std::filesystem::path getDataDir(){ return std::getenv("XDG_DATA_HOME") ? std::filesystem::path(std::getenv("XDG_DATA_HOME")) / APPLICATION_NAME : std::filesystem::path(std::getenv("HOME")) / ".local" / "share" / APPLICATION_NAME; } std::string urlDecode(const std::string& str) { std::ostringstream decoded; for (size_t i = 0; i < str.length(); ++i) { if (str[i] == '%' && i + 2 < str.length()) { std::istringstream hex_stream(str.substr(i + 1, 2)); int hex = 0; if (hex_stream >> std::hex >> hex) { decoded << static_cast(hex); i += 2; } else { decoded << '%'; // malformed encoding, keep as-is } } else if (str[i] == '+') { decoded << ' '; // '+' is often used for spaces in form-encoding } else { decoded << str[i]; } } return decoded.str(); } string currentTime(){ auto now = std::chrono::system_clock::now(); std::time_t t = std::chrono::system_clock::to_time_t(now); std::stringstream ss; ss << std::put_time(std::gmtime(&t), "%Y-%m-%d %H:%M:%S"); return ss.str(); } std::string read_file(const std::string& path) { std::ifstream file(path, std::ios::binary); if (!file) { throw std::runtime_error("Cannot open file: " + path); } std::ostringstream ss; ss << file.rdbuf(); return ss.str(); } // Simple MIME type detection std::string get_mime_type(const std::string& path) { if (path.ends_with(".html")) return "text/html"; if (path.ends_with(".js")) return "text/javascript"; if (path.ends_with(".css")) return "text/css"; if (path.ends_with(".json")) return "application/json"; if (path.ends_with(".svg")) return "image/svg+xml"; if (path.ends_with(".png")) return "image/png"; if (path.ends_with(".jpg") || path.ends_with(".jpeg")) return "image/jpeg"; if (path.ends_with(".woff")) return "font/woff"; if (path.ends_with(".woff2")) return "font/woff2"; if (path.ends_with(".pdf")) return "application/pdf"; return "application/octet-stream"; } crow::response getFile(const filesystem::path& file_path){ // If file exists, serve it if (filesystem::exists(file_path)) { auto data = read_file(file_path); auto mime = get_mime_type(file_path.string()); return crow::response(200, mime.c_str(), data); } // SPA fallback: serve root index.html for unknown routes filesystem::path fallback = build_dir / "index.html"; auto data = read_file(fallback); return crow::response(404, "text/html", data); } std::expected parseJson(const std::string& input) { try { return nlohmann::json::parse(input); } catch (const nlohmann::json::exception& e) { return std::unexpected(e.what()); } } }