194 lines
5.7 KiB
C++
194 lines
5.7 KiB
C++
#include "problems.h"
|
|
|
|
#include <print>
|
|
|
|
#include <leveldb/db.h>
|
|
#include <leveldb/write_batch.h>
|
|
|
|
#include <nlohmann/json.hpp>
|
|
#include <string>
|
|
|
|
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<int>{};
|
|
|
|
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;
|
|
}
|
|
} |