#include "Scratchpad.h" #include #include #include #include #include // Helper: Execute shell command and capture output std::string exec(const char* cmd) { std::array buffer; std::string result; std::unique_ptr pipe(popen(cmd, "r"), pclose); if (!pipe) { throw std::runtime_error("popen() failed!"); } while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) { result += buffer.data(); } return result; } void Scratchpad::runCode(const HttpRequestPtr& req, std::function &&callback) { // 1. Auth Check auto authHeader = req->getHeader("X-API-Key"); if (authHeader != API_KEY) { Json::Value error; error["error"] = "Unauthorized. Invalid API Key."; auto resp = HttpResponse::newHttpJsonResponse(error); resp->setStatusCode(k401Unauthorized); callback(resp); return; } // 2. Get Code from Body auto json = req->getJsonObject(); if (!json || !(*json)["code"].isString()) { Json::Value error; error["error"] = "Invalid JSON. 'code' field required."; auto resp = HttpResponse::newHttpJsonResponse(error); resp->setStatusCode(k400BadRequest); callback(resp); return; } std::string userCode = (*json)["code"].asString(); // 3. Compile and Run Json::Value ret; try { std::string output = compileAndRun(userCode); ret["status"] = "success"; ret["output"] = output; } catch (const std::exception& e) { ret["status"] = "error"; ret["error"] = e.what(); } auto resp = HttpResponse::newHttpJsonResponse(ret); callback(resp); } std::string Scratchpad::compileAndRun(const std::string& code) { // A. Write to temp file std::string filename = "temp_scratchpad.cpp"; std::string binary = "./temp_scratchpad"; std::ofstream out(filename); out << code; out.close(); // B. Compile (Clang++) // Using -std=c++20 and linking nothing extra for now std::string compileCmd = "clang++ -std=c++20 " + filename + " -o " + binary + " 2>&1"; std::string compileOut = exec(compileCmd.c_str()); // Check if compilation failed (binary doesn't exist) if (!std::filesystem::exists(binary)) { return "Compilation Error:\n" + compileOut; } // C. Execute // Timeout logic should be added here later (e.g., using 'timeout' cmd) std::string runCmd = binary + " 2>&1"; std::string runOut = exec(runCmd.c_str()); // Cleanup std::filesystem::remove(filename); std::filesystem::remove(binary); return runOut; } void Scratchpad::status(const HttpRequestPtr& req, std::function &&callback) { Json::Value ret; ret["status"] = "online"; ret["version"] = "2.1 (Execution Engine)"; ret["compiler"] = "Clang 19.1.7"; ret["note"] = "Send POST to /scratchpad/run with header 'X-API-Key'"; auto resp = HttpResponse::newHttpJsonResponse(ret); callback(resp); }