#include "problems.h" #include #include #include #include #include using leveldb_ptr = leveldb::DB*; auto problems_db = leveldb_ptr{nullptr}; auto max_problem_id = 0; extern "C" { int open_problems_db() { auto opts = leveldb::Options{}; opts.create_if_missing = true; auto status = leveldb::DB::Open(opts, "db/problems", &problems_db); if (!status.ok()) { std::println(stderr, "Failed to open problems database: {}", status.ToString()); return 0; } auto value = std::string{}; status = problems_db->Get(leveldb::ReadOptions{}, "@", &value); if (status.ok()) { auto json = nlohmann::json::parse(value); json["max_problem_id"].get_to(max_problem_id); } else if (status.IsNotFound()) { auto json = nlohmann::json{ {"max_problem_id", 0} }; status = problems_db->Put(leveldb::WriteOptions{}, "@", json.dump()); return 1; } else { std::println(stderr, "Failed to get max problem id: {}", status.ToString()); delete problems_db; return 0; } return 1; } void close_problems_db() { delete problems_db; } int add_problem(const char* problem, const char* answer, const char* check_error, int* result) { auto batch = leveldb::WriteBatch{}; ++max_problem_id; auto json = nlohmann::json{ {"max_problem_id", max_problem_id} }; batch.Put("@", json.dump()); json = nlohmann::json{ {"content", problem }, {"answer", answer }, {"error", check_error} }; batch.Put(std::to_string(max_problem_id), json.dump()); auto status = problems_db->Write(leveldb::WriteOptions{}, &batch); if (!status.ok()) { std::println(stderr, "Failed to add a problem: {}", status.ToString()); return 0; } *result = max_problem_id; return 1; } int delete_problems(int problems_id) { auto batch = leveldb::WriteBatch{}; auto status = problems_db->Delete(leveldb::WriteOptions{}, std::to_string(problems_id)); if (!status.ok()) { std::println(stderr, "Failed to delete a problem: {}", status.ToString()); return 0; } return 1; } int get_problem(int id, char** result1, char** result2, char** result3) { auto value = std::string{}; auto status = problems_db->Get(leveldb::ReadOptions{}, std::to_string(id), &value); if (!status.ok()) { std::println(stderr, "Failed to get a problem: {}", status.ToString()); return 0; } auto json = nlohmann::json::parse(value); if (result1) { json["content"].get_to(value); *result1 = strdup(value.data()); } if (result2) { json["answer"].get_to(value); *result2 = strdup(value.data()); } if (result3) { json["error"].get_to(value); *result3 = strdup(value.data()); } return 1; } int modify_problem(int problems_id, const char* problem, const char* answer, const char* check_error) { auto json = nlohmann::json{ {"content", problem }, {"answer", answer }, {"error", check_error} }; auto status = problems_db->Put(leveldb::WriteOptions{}, std::to_string(problems_id), json.dump()); if (!status.ok()) { std::println(stderr, "Failed to modify a problem: {}", status.ToString()); return 0; } return 1; } int check_answer(int problems_id, const char* answer, int* result) { auto value = std::string{}; auto status = problems_db->Get(leveldb::ReadOptions{}, std::to_string(problems_id), &value); if (!status.ok()) { std::println(stderr, "Failed to check the answer: {}", status.ToString()); return 0; } auto value2 = std::string{}; auto json = nlohmann::json::parse(value); json["answer"].get_to(value); json["error"].get_to(value2); if (value2.empty()) { *result = value == answer; } else { auto error = std::stod(value2); auto std_answer = std::stod(value); auto user_answer = std::stod(answer); *result = std::fabs(std_answer - user_answer) <= error; } return 1; } int has_problem(int problems_id, int* result) { auto value = std::string{}; auto status = problems_db->Get(leveldb::ReadOptions{}, std::to_string(problems_id), &value); if (status.ok()) { *result = 1; } else if (status.IsNotFound()) { *result = 0; } else { std::println(stderr, "Failed to check problem existence: {}", status.ToString()); return 0; } return 1; } int all_problems(char** result) { auto problems = std::vector{}; leveldb::Iterator* it = problems_db->NewIterator(leveldb::ReadOptions()); for (it->SeekToFirst(); it->Valid(); it->Next()) { if (!it->key().compare("@")) continue; problems.emplace_back(std::stoi(it->key().ToString())); } if (!it->status().ok()) { std::println(stderr, "Failed to get all problems: {}", it->status().ToString()); return 0; } auto json = nlohmann::json(problems); *result = strdup(json.dump().c_str()); return 1; } }