Rewrote the server in cpp with the frontend in svelte
This commit is contained in:
109
src/data/data_save.cxx
Normal file
109
src/data/data_save.cxx
Normal file
@@ -0,0 +1,109 @@
|
||||
#define RAPIDJSON_HAS_STDSTRING 1
|
||||
#include <rapidjson/filewritestream.h>
|
||||
#include <rapidjson/writer.h>
|
||||
#include "data_internal.hxx"
|
||||
|
||||
#define KEY(x) writer.Key(#x, sizeof(#x)-1)
|
||||
|
||||
using Writer = rapidjson::Writer<rapidjson::FileWriteStream>;
|
||||
|
||||
void save_node(Writer &writer, Node *node) {
|
||||
writer.StartObject();
|
||||
|
||||
KEY(id); writer.Uint64(node->id);
|
||||
KEY(name); writer.String(node->name);
|
||||
KEY(file); writer.Bool(node->file);
|
||||
KEY(preview); writer.Bool(node->preview);
|
||||
KEY(size); writer.Uint64(node->size);
|
||||
KEY(parent); writer.Uint64(node->parent == nullptr ? 0 : node->parent->id);
|
||||
|
||||
KEY(children);
|
||||
writer.StartArray();
|
||||
for (const auto &child : node->children)
|
||||
writer.Uint64(child->id);
|
||||
writer.EndArray();
|
||||
|
||||
writer.EndObject();
|
||||
}
|
||||
|
||||
void save_user(Writer &writer, User *user) {
|
||||
std::shared_lock lock{user->node_lock};
|
||||
writer.StartObject();
|
||||
|
||||
KEY(id); writer.Uint64(user->id);
|
||||
KEY(name); writer.String(user->name);
|
||||
KEY(password); writer.String(user->password);
|
||||
KEY(tfa_secret); writer.String(user->tfa_secret);
|
||||
KEY(enabled); writer.Bool(user->enabled);
|
||||
KEY(admin); writer.Bool(user->admin);
|
||||
KEY(tfa_enabled); writer.Bool(user->tfa_enabled);
|
||||
KEY(tfa_mail); writer.Bool(user->tfa_mail);
|
||||
KEY(next_node_id); writer.Uint64(user->next_node_id);
|
||||
|
||||
KEY(nodes);
|
||||
writer.StartArray();
|
||||
for (const auto &node : user->nodes)
|
||||
save_node(writer, node.second.get());
|
||||
writer.EndArray();
|
||||
|
||||
writer.EndObject();
|
||||
}
|
||||
|
||||
char save_buf[65536];
|
||||
void save(Data* data) {
|
||||
data_logger->info("Saving data");
|
||||
try {
|
||||
{
|
||||
FileWrapper f{data_new_file.c_str(), "w"};
|
||||
rapidjson::FileWriteStream stream{f.f, save_buf, sizeof(save_buf)};
|
||||
Writer writer{stream};
|
||||
|
||||
std::shared_lock lock{data->user_lock};
|
||||
|
||||
writer.StartObject();
|
||||
|
||||
KEY(version); writer.Uint64(data->version);
|
||||
KEY(next_user_id); writer.Uint64(data->next_user_id);
|
||||
|
||||
KEY(users);
|
||||
writer.StartArray();
|
||||
for (const auto &user : data->users)
|
||||
save_user(writer, user.second.get());
|
||||
writer.EndArray();
|
||||
|
||||
writer.EndObject();
|
||||
}
|
||||
data_logger->info("Finished writing data");
|
||||
if (std::filesystem::exists(data_cur_file))
|
||||
std::filesystem::copy_file(data_cur_file, data_old_file, std::filesystem::copy_options::overwrite_existing);
|
||||
std::filesystem::rename(data_new_file, data_cur_file);
|
||||
data_logger->info("Save done");
|
||||
} catch (std::exception &e) {
|
||||
data_logger->error("Error while saving: {}, retrying...", e.what());
|
||||
data->save_flag.test_and_set();
|
||||
}
|
||||
}
|
||||
|
||||
void save_worker(Data *data) {
|
||||
while (!data->shutdown_flag.test()) {
|
||||
data->save_flag.wait(false);
|
||||
do {
|
||||
data->save_flag.clear();
|
||||
std::this_thread::sleep_for(std::chrono::seconds{2});
|
||||
} while (data->save_flag.test());
|
||||
save(data);
|
||||
}
|
||||
data_logger->info("Data saver stopping");
|
||||
save(data);
|
||||
}
|
||||
|
||||
void Data::start_save_thread() {
|
||||
save();
|
||||
shutdown_flag.clear();
|
||||
this->save_thread = std::thread{save_worker, this};
|
||||
}
|
||||
|
||||
void Data::save() {
|
||||
save_flag.test_and_set();
|
||||
save_flag.notify_all();
|
||||
}
|
||||
Reference in New Issue
Block a user