59 lines
2.8 KiB
C++
59 lines
2.8 KiB
C++
#pragma once
|
|
#include <chrono>
|
|
#include <filesystem>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace utils::afk
|
|
{
|
|
struct request { std::string id, action, body; };
|
|
struct session
|
|
{
|
|
std::string body, phase;
|
|
int authorized_seconds = 0, consumed_seconds = 0;
|
|
};
|
|
struct acknowledgement
|
|
{
|
|
bool valid = false;
|
|
std::string reason = "schema", state, code, id, session_id;
|
|
int free_seconds = 0, saved_seconds = 0, available_seconds = 0,
|
|
reserved_seconds = 0, capacity_seconds = 0, authorized_seconds = 0,
|
|
bank_balance = 0, purchase_points = 0, purchase_seconds = 0,
|
|
max_purchase_packs = 0, awarded_seconds = 0, consumed_seconds = -1;
|
|
};
|
|
acknowledgement parse_acknowledgement(const std::string& response);
|
|
// Single game-thread writer. Active clocks are process-local, so recovery
|
|
// can never accidentally replay protection after a process restart.
|
|
class journal
|
|
{
|
|
public:
|
|
using clock = std::chrono::steady_clock;
|
|
journal(std::filesystem::path root, std::string server, std::string endpoint);
|
|
std::vector<request> load() const;
|
|
void store(const std::string& body) const;
|
|
void erase(const std::string& id) const;
|
|
void prepare(const std::string& reserve_body) const;
|
|
void authorize(const std::string& id, int seconds) const;
|
|
void begin(const std::string& id, clock::time_point now = clock::time_point{}) const;
|
|
int checkpoint(const std::string& id, clock::time_point now = clock::now()) const;
|
|
// Hot path for the damage hook/countdown: no disk I/O or clock reset.
|
|
// Missing/restarted clocks return -1; stopped/expired clocks return 0.
|
|
int remaining(const std::string& id, clock::time_point now = clock::now()) const;
|
|
void stop(const std::string& id, const std::string& reason, clock::time_point now = clock::now()) const;
|
|
// Call only at map initialization, with its new persistent match ID.
|
|
// Active current-map sessions are rejected. Unknown crash intervals
|
|
// remain unresolved at EC, rather than refunding spendable authority.
|
|
void recover(const std::string& current_match) const;
|
|
private:
|
|
struct snapshot { std::vector<request> requests; std::vector<session> sessions; };
|
|
std::filesystem::path file_;
|
|
std::string server_, endpoint_, scope_;
|
|
request decode(const std::string& body) const;
|
|
snapshot read() const;
|
|
void save(const snapshot& value) const;
|
|
std::string key(const std::string& id) const;
|
|
int elapsed(const session& value, clock::time_point now, bool round_up = false) const;
|
|
request settlement(const session& value, const std::string& reason, int consumed) const;
|
|
};
|
|
}
|