7#include "absl/strings/str_cat.h"
8#include "absl/strings/str_format.h"
14#include "nlohmann/json.hpp"
26 for (
size_t i = 0; i < data.size(); ++i) {
27 hash = hash * 31 + data[i];
29 return absl::StrFormat(
"%08x", hash);
34 auto now = std::chrono::system_clock::now();
35 auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
36 now.time_since_epoch())
38 return absl::StrFormat(
"snap_%lld", ms);
42 return std::chrono::duration_cast<std::chrono::milliseconds>(
43 std::chrono::system_clock::now().time_since_epoch())
54 : rom_(rom), last_backup_time_(0) {}
64 auto initial_result =
CreateSnapshot(
"Initial state",
"system",
true);
66 if (!initial_result.ok()) {
67 return initial_result.status();
75 const std::string& description,
const std::string& creator,
78 return absl::FailedPreconditionError(
"ROM not loaded");
82 std::vector<uint8_t> rom_data(
rom_->
size());
89 snapshot.
timestamp = GetCurrentTimestamp();
90 snapshot.
rom_hash = ComputeHash(rom_data);
100 snapshot.
rom_data = std::move(rom_data);
105 snapshot.metadata = nlohmann::json::object();
106 snapshot.metadata[
"size"] =
rom_->
size();
107 snapshot.metadata[
"auto_backup"] = !is_checkpoint;
123 const std::string& snapshot_id) {
126 return absl::NotFoundError(
127 absl::StrCat(
"Snapshot not found: ", snapshot_id));
131 return absl::FailedPreconditionError(
"ROM not loaded");
137 std::vector<uint8_t> rom_data;
145 if (rom_data.size() !=
rom_->
size()) {
146 return absl::DataLossError(
"Snapshot size mismatch");
150 auto backup_result =
CreateSnapshot(
"Pre-restore backup",
"system",
false);
152 if (!backup_result.ok()) {
153 return absl::InternalError(
"Failed to create pre-restore backup");
158 if (!restore_status.ok()) {
159 return restore_status;
164 return absl::OkStatus();
168 const std::string& snapshot_id) {
171 return absl::NotFoundError(
"Snapshot not found");
174 it->second.is_safe_point =
true;
175 return absl::OkStatus();
179 bool safe_points_only)
const {
180 std::vector<RomSnapshot> result;
182 for (
const auto& [
id, snapshot] :
snapshots_) {
183 if (!safe_points_only || snapshot.is_safe_point) {
184 result.push_back(snapshot);
189 std::sort(result.begin(), result.end(),
191 return a.timestamp > b.timestamp;
198 const std::string& snapshot_id)
const {
201 return absl::NotFoundError(
"Snapshot not found");
209 return absl::NotFoundError(
"Snapshot not found");
213 if (it->second.is_safe_point) {
214 return absl::FailedPreconditionError(
"Cannot delete safe point");
218 return absl::OkStatus();
227 return absl::FailedPreconditionError(
"ROM not loaded");
231 std::vector<uint8_t> current_data(
rom_->
size());
233 std::string current_hash = ComputeHash(current_data);
237 if (!integrity_status.ok()) {
254 if (snapshots.empty()) {
255 return absl::NotFoundError(
"No safe points available for recovery");
267 std::vector<uint8_t> data(
rom_->
size());
269 return ComputeHash(data);
276 std::vector<std::pair<int64_t, std::string>> auto_backups;
277 for (
const auto& [
id, snapshot] :
snapshots_) {
278 if (!snapshot.is_safe_point && !snapshot.is_checkpoint) {
279 auto_backups.push_back({snapshot.timestamp,
id});
284 std::sort(auto_backups.begin(), auto_backups.end());
288 snapshots_.erase(auto_backups.front().second);
289 auto_backups.erase(auto_backups.begin());
294 !auto_backups.empty()) {
295 snapshots_.erase(auto_backups.front().second);
296 auto_backups.erase(auto_backups.begin());
299 return absl::OkStatus();
306 for (
const auto& [
id, snapshot] :
snapshots_) {
307 if (snapshot.is_safe_point)
309 if (snapshot.is_checkpoint)
311 if (!snapshot.is_checkpoint)
335 std::vector<uint8_t> data(
rom_->
size());
337 return ComputeHash(data);
341 const std::vector<uint8_t>& data)
const {
348 const std::vector<uint8_t>& compressed)
const {
355 return absl::FailedPreconditionError(
"ROM not loaded");
360 return absl::DataLossError(
"ROM size is zero");
366 return absl::DataLossError(
"ROM too small to be valid");
369 return absl::OkStatus();
374 for (
const auto& [
id, snapshot] :
snapshots_) {
375 total += snapshot.compressed_size;
385 : version_mgr_(version_mgr), mode_(
ApprovalMode::kHostOnly) {}
396 const std::string& proposal_id,
const std::string& sender,
397 const std::string& description,
const nlohmann::json& proposal_data) {
400 status.
status =
"pending";
406 absl::StrCat(
"Before proposal: ", description), sender,
false);
408 if (!snapshot_result.ok()) {
409 return snapshot_result.status();
416 return absl::OkStatus();
420 const std::string& proposal_id,
const std::string& username,
424 return absl::NotFoundError(
"Proposal not found");
429 if (status.
status !=
"pending") {
430 return absl::FailedPreconditionError(
"Proposal already decided");
434 status.
votes[username] = approved;
438 status.
status =
"approved";
442 size_t rejection_count = 0;
443 for (
const auto& [user, vote] : status.
votes) {
451 status.
status =
"rejected";
456 return absl::OkStatus();
470 size_t approval_count = 0;
471 for (
const auto& [user, approved] : status.
votes) {
482 for (
const auto& [user, approved] : status.
votes) {
497 const std::string& proposal_id)
const {
502 return it->second.status ==
"approved";
505std::vector<ProposalApprovalManager::ApprovalStatus>
507 std::vector<ApprovalStatus> pending;
509 if (status.status ==
"pending") {
510 pending.push_back(status);
516absl::StatusOr<ProposalApprovalManager::ApprovalStatus>
518 const std::string& proposal_id)
const {
521 return absl::NotFoundError(
"Proposal not found");
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
absl::Status WriteVector(int addr, std::vector< uint8_t > data)
std::vector< std::string > participants_
void SetHost(const std::string &host_username)
absl::StatusOr< ApprovalStatus > GetProposalStatus(const std::string &proposal_id) const
absl::Status VoteOnProposal(const std::string &proposal_id, const std::string &username, bool approved)
std::string host_username_
void SetApprovalMode(ApprovalMode mode)
bool IsProposalApproved(const std::string &proposal_id) const
RomVersionManager * version_mgr_
absl::Status SubmitProposal(const std::string &proposal_id, const std::string &sender, const std::string &description, const nlohmann::json &proposal_data)
std::vector< ApprovalStatus > GetPendingProposals() const
bool CheckApprovalThreshold(const ApprovalStatus &status) const
ProposalApprovalManager(RomVersionManager *version_mgr)
std::map< std::string, ApprovalStatus > proposals_
Manages ROM versioning, snapshots, and rollback capabilities.
std::string ComputeRomHash() const
absl::Status CleanupOldSnapshots()
std::vector< uint8_t > DecompressData(const std::vector< uint8_t > &compressed) const
size_t GetTotalStorageUsed() const
absl::StatusOr< std::string > CreateSnapshot(const std::string &description, const std::string &creator, bool is_checkpoint=false)
absl::StatusOr< RomSnapshot > GetSnapshot(const std::string &snapshot_id) const
std::string GetCurrentHash() const
std::map< std::string, RomSnapshot > snapshots_
absl::Status ValidateRomIntegrity() const
std::string last_known_hash_
RomVersionManager(Rom *rom)
absl::Status Initialize(const Config &config)
absl::Status AutoRecover()
absl::StatusOr< bool > DetectCorruption()
absl::Status RestoreSnapshot(const std::string &snapshot_id)
absl::Status MarkAsSafePoint(const std::string &snapshot_id)
std::vector< uint8_t > CompressData(const std::vector< uint8_t > &data) const
absl::Status DeleteSnapshot(const std::string &snapshot_id)
std::vector< RomSnapshot > GetSnapshots(bool safe_points_only=false) const
std::string ComputeHash(const std::vector< uint8_t > &data)
int64_t GetCurrentTimestamp()
std::string snapshot_before
std::map< std::string, bool > votes
Represents a versioned snapshot of ROM state.
std::vector< uint8_t > rom_data
bool enable_corruption_detection
size_t total_storage_bytes
size_t manual_checkpoints
int64_t oldest_snapshot_timestamp
int64_t newest_snapshot_timestamp