add state saving and loading

This commit is contained in:
Slavasil 2024-11-17 16:53:18 +03:00
parent f7e6699fec
commit 28e662b393
4 changed files with 107 additions and 2 deletions

View File

@ -7,7 +7,7 @@ add_subdirectory(libuv)
add_subdirectory(spdlog) add_subdirectory(spdlog)
add_subdirectory(td) add_subdirectory(td)
add_executable(${PROJECT_NAME} main.cpp http.cpp vk.cpp) add_executable(${PROJECT_NAME} main.cpp http.cpp state.cpp vk.cpp)
target_compile_options(${PROJECT_NAME} PRIVATE -std=c++2b) target_compile_options(${PROJECT_NAME} PRIVATE -std=c++2b)

View File

@ -1,4 +1,6 @@
#include "http.h" #include "spdlog/spdlog.h"
#include "state.h"
#include <filesystem>
#include <uv.h> #include <uv.h>
#include <td/telegram/td_api.h> #include <td/telegram/td_api.h>
#include <td/telegram/td_api.hpp> #include <td/telegram/td_api.hpp>
@ -20,7 +22,17 @@ int main() {
uv_signal_t signalHandles[2] = {}; uv_signal_t signalHandles[2] = {};
create_signal_handles(loop, signalHandles); create_signal_handles(loop, signalHandles);
state::AppState state;
try {
state = state::AppState("bridge_state.json");
spdlog::info("state: {}", state.to_string());
} catch (state::InvalidSavedStateException &e) {
spdlog::error("invalid saved state: {}", e.message);
return 1;
}
uv_run(loop, UV_RUN_DEFAULT); uv_run(loop, UV_RUN_DEFAULT);
spdlog::info("event loop ended"); spdlog::info("event loop ended");
state.save();
return 0; return 0;
} }

67
state.cpp Normal file
View File

@ -0,0 +1,67 @@
#include "state.h"
#include "spdlog/spdlog.h"
#include <fstream>
#include <nlohmann/json.hpp>
#include <string>
using namespace state;
using namespace nlohmann;
AppState::AppState(std::string filename) : m_saveFilename(filename) {
std::ifstream f(filename);
if (f.fail()) {
spdlog::info("no state file");
return;
}
json state = json::parse(f);
if (state.type() != json::value_t::object) {
throw InvalidSavedStateException("JSON root must be an object");
}
if (state.contains("vk")) {
json vkState = state["vk"];
if (vkState.type() == json::value_t::object) {
if (vkState.contains("last_post_id")) {
json lastPostId = vkState["last_post_id"];
if (lastPostId.type() == json::value_t::number_integer || lastPostId.type() == json::value_t::number_unsigned) {
vkLastPostId = lastPostId;
} else {
throw InvalidSavedStateException("key vk.last_post_id must be an integer");
}
}
} else {
throw InvalidSavedStateException("key vk must be an object");
}
}
if (state.contains("tg")) {
json tgState = state["tg"];
if (tgState.type() == json::value_t::object) {
if (tgState.contains("last_post_id")) {
json lastPostId = tgState["last_post_id"];
if (lastPostId.type() == json::value_t::number_integer || lastPostId.type() == json::value_t::number_unsigned) {
tgLastPostId = lastPostId;
} else {
throw InvalidSavedStateException("key tg.last_post_id must be an integer");
}
}
} else {
throw InvalidSavedStateException("key tg must be an object");
}
}
}
void AppState::save() {
if (m_saveFilename.empty()) return;
spdlog::info("saving state");
json state = {{"vk", {{"last_post_id", vkLastPostId}}}, {"tg", {{"last_post_id", tgLastPostId}}}};
std::ofstream f(m_saveFilename.c_str());
if (f.fail()) {
spdlog::error("failed to open state file '{}'", m_saveFilename);
return;
}
f << state << std::endl;
}
std::string AppState::to_string() {
return std::format("AppState {{ tgLastPostId: {}, vkLastPostId: {} }}", tgLastPostId, vkLastPostId);
}

26
state.h Normal file
View File

@ -0,0 +1,26 @@
#pragma once
#include <cstdint>
#include <exception>
#include <string>
namespace state {
class InvalidSavedStateException : std::exception {
public:
inline InvalidSavedStateException(const char *message): message(message) {};
const char *message;
};
class AppState {
public:
inline AppState() {};
AppState(std::string filename);
std::string to_string();
void save();
int64_t tgLastPostId = 0;
int64_t vkLastPostId = 0;
private:
std::string m_saveFilename;
};
}