Files
fileserver/src/data/data_save.cxx

110 lines
3.2 KiB
C++

#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();
}