commits
tags
#include "torlinkc/engine/history.hpp"
#include <algorithm>
#include <fstream>
#include <optional>
#include <sstream>
#include <nlohmann/json.hpp>
#include "torlinkc/config/paths.hpp"
#include "torlinkc/util/atomic_write.hpp"
using nlohmann::json;
namespace torlinkc {
namespace {
json toJson(const HistoryItem& h) {
json j;
j["id"] = h.id;
j["name"] = h.name;
if (!h.source.empty()) j["source"] = h.source;
j["sizeBytes"] = h.sizeBytes;
j["magnet"] = h.magnet;
j["dir"] = h.dir;
j["completedAt"] = h.completedAt;
return j;
}
std::optional<HistoryItem> fromJson(const json& j) {
if (!j.is_object()) return std::nullopt;
auto idIt = j.find("id");
auto nameIt = j.find("name");
auto magnetIt = j.find("magnet");
if (idIt == j.end() || !idIt->is_string()) return std::nullopt;
if (nameIt == j.end() || !nameIt->is_string()) return std::nullopt;
if (magnetIt == j.end() || !magnetIt->is_string()) return std::nullopt;
HistoryItem h;
h.id = idIt->get<std::string>();
h.name = nameIt->get<std::string>();
h.magnet = magnetIt->get<std::string>();
if (auto v = j.find("source"); v != j.end() && v->is_string()) h.source = v->get<std::string>();
if (auto v = j.find("dir"); v != j.end() && v->is_string()) h.dir = v->get<std::string>();
if (auto v = j.find("sizeBytes"); v != j.end() && v->is_number()) h.sizeBytes = v->get<std::int64_t>();
if (auto v = j.find("completedAt"); v != j.end() && v->is_number()) h.completedAt = v->get<std::int64_t>();
return h;
}
} // namespace
void saveHistory(const std::vector<HistoryItem>& items) {
json arr = json::array();
std::size_t n = std::min<std::size_t>(items.size(), kHistoryCap);
for (std::size_t i = 0; i < n; ++i) arr.push_back(toJson(items[i]));
try {
writeJsonAtomic(paths::historyFile(), arr);
} catch (...) {
}
}
std::vector<HistoryItem> loadHistory() {
std::vector<HistoryItem> out;
std::ifstream in(paths::historyFile(), std::ios::binary);
if (!in) return out;
std::ostringstream ss;
ss << in.rdbuf();
json parsed;
try {
parsed = json::parse(ss.str());
} catch (...) {
return out;
}
if (!parsed.is_array()) return out;
for (const auto& el : parsed) {
if (out.size() >= static_cast<std::size_t>(kHistoryCap)) break;
if (auto h = fromJson(el)) out.push_back(std::move(*h));
}
return out;
}
} // namespace torlinkc