142 lines
4.8 KiB
C++
142 lines
4.8 KiB
C++
#include "state.h"
|
|
#include "spdlog/spdlog.h"
|
|
#include <exception>
|
|
#include <fstream>
|
|
#include <nlohmann/json.hpp>
|
|
#include <sstream>
|
|
#include <string>
|
|
|
|
using namespace state;
|
|
using namespace nlohmann;
|
|
|
|
AppState::AppState(std::string filename, config::AppConfig *cfg) : m_saveFilename(filename), m_config(cfg) {
|
|
for (int i = 0; i < cfg->vkSources.size(); ++i) {
|
|
vkRepostState.emplace_back();
|
|
}
|
|
for (int i = 0; i < cfg->tgSources.size(); ++i) {
|
|
tgRepostState.emplace_back();
|
|
}
|
|
|
|
std::ifstream f(filename);
|
|
if (f.fail()) {
|
|
spdlog::error("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 vkStates_ = state["vk"];
|
|
if (vkStates_.type() == json::value_t::object) {
|
|
for (auto& [key, vkState_] : vkStates_.items()) {
|
|
if (key.empty()) continue;
|
|
int sourceIndex;
|
|
RepostState &&s {};
|
|
if (key[0] >= '0' && key[0] <= '9') {
|
|
long keyNum;
|
|
try {
|
|
keyNum = std::stol(key);
|
|
} catch (std::exception &e) {
|
|
throw InvalidSavedStateException("invalid number in vk source id");
|
|
}
|
|
sourceIndex = std::distance(
|
|
m_config->vkSources.begin(),
|
|
std::find_if(m_config->vkSources.begin(), m_config->vkSources.end(),
|
|
[=](auto &src){ return src.id.index() == 0 && std::get<long>(src.id) == std::stoi(key); }
|
|
)
|
|
);
|
|
} else {
|
|
sourceIndex = std::distance(
|
|
m_config->vkSources.begin(),
|
|
std::find_if(m_config->vkSources.begin(), m_config->vkSources.end(),
|
|
[=](auto &src){ return src.id.index() == 1 && std::get<std::string>(src.id) == key; }
|
|
)
|
|
);
|
|
}
|
|
if (vkState_.contains("last_post_date")) {
|
|
json lastPostDate_ = vkState_["last_post_date"];
|
|
if (lastPostDate_.type() == json::value_t::number_integer ||
|
|
lastPostDate_.type() == json::value_t::number_unsigned) {
|
|
s.lastForwardedPostDate = vkState_["last_post_date"];
|
|
} else {
|
|
throw InvalidSavedStateException("key vk.last_post_date must be an integer");
|
|
}
|
|
}
|
|
if (sourceIndex < m_config->vkSources.size())
|
|
vkRepostState[sourceIndex] = s;
|
|
}
|
|
} else {
|
|
throw InvalidSavedStateException("key vk must be an object");
|
|
}
|
|
}
|
|
|
|
if (state.contains("tg")) {
|
|
json tgStates_ = state["tg"];
|
|
if (tgStates_.type() == json::value_t::object) {
|
|
for (auto& [key, tgState_] : tgStates_.items()) {
|
|
if (key.empty()) continue;
|
|
int sourceIndex;
|
|
RepostState &&s {};
|
|
long keyNum;
|
|
try {
|
|
keyNum = std::stol(key);
|
|
} catch (std::exception &e) {
|
|
throw InvalidSavedStateException("invalid number in tg source id");
|
|
}
|
|
sourceIndex = std::distance(
|
|
m_config->tgSources.begin(),
|
|
std::find_if(m_config->tgSources.begin(), m_config->tgSources.end(),
|
|
[=](auto &src){ return src.id == keyNum; }
|
|
)
|
|
);
|
|
if (tgState_.contains("last_post_date")) {
|
|
json lastPostDate_ = tgState_["last_post_date"];
|
|
if (lastPostDate_.type() == json::value_t::number_integer ||
|
|
lastPostDate_.type() == json::value_t::number_unsigned) {
|
|
s.lastForwardedPostDate = tgState_["last_post_date"];
|
|
} else {
|
|
throw InvalidSavedStateException("key tg.last_post_date must be an integer");
|
|
}
|
|
}
|
|
if (sourceIndex < m_config->tgSources.size())
|
|
tgRepostState[sourceIndex] = s;
|
|
}
|
|
} else {
|
|
throw InvalidSavedStateException("key tg must be an object");
|
|
}
|
|
}
|
|
}
|
|
|
|
void AppState::save() {
|
|
if (m_saveFilename.empty()) return;
|
|
spdlog::info("saving state");
|
|
json state = {{"vk", json::object()}, {"tg", json::object()}};
|
|
for (int i = 0; i < m_config->vkSources.size(); ++i) {
|
|
auto &s = vkRepostState[i];
|
|
json st = {{"last_post_date", s.lastForwardedPostDate}};
|
|
auto &vkId = m_config->vkSources[i].id;
|
|
std::string vkIdStr;
|
|
if (vkId.index() == 0) vkIdStr = std::to_string(std::get<long>(vkId));
|
|
else vkIdStr = std::get<std::string>(vkId);
|
|
state["vk"].emplace(vkIdStr, st);
|
|
}
|
|
for (int i = 0; i < m_config->tgSources.size(); ++i) {
|
|
auto &s = tgRepostState[i];
|
|
json st = {{"last_post_date", s.lastForwardedPostDate}};
|
|
state["tg"].emplace(std::to_string(m_config->tgSources[i].id), st);
|
|
}
|
|
std::ofstream f(m_saveFilename.c_str());
|
|
if (f.fail()) {
|
|
spdlog::error("failed to open state file '{}'", m_saveFilename);
|
|
return;
|
|
}
|
|
f << state;
|
|
}
|
|
|
|
std::string AppState::to_string() {
|
|
std::stringstream output;
|
|
output << "<not implemented>";
|
|
return output.str();
|
|
} |