Adds local System Name persistence (trimmed, 1-40) in system_kv, an
injectable sync module with conflict/invalid revert and a pending-sync
flag, a background SystemNameSync worker (retries on boot and on a timer),
and api_client support for PUT /licenses/{key}/system-name plus the
additive systemName field/systemNameStatus on license validation. The
license service sends the stored name and applies the status. Covers
validation, pending retry, and conflict revert with a faked HTTP layer.
124 lines
3.7 KiB
C++
124 lines
3.7 KiB
C++
#include "network/system_name.h"
|
|
#include "db/db_keys.h"
|
|
#include "validation.h"
|
|
|
|
namespace radiantwave::systemname {
|
|
|
|
namespace {
|
|
|
|
void revertToSynced(db::DatabaseManager& db) {
|
|
const std::string synced = db.getKV(db::KV_SYSTEM_NAME_SYNCED);
|
|
if (synced.empty()) {
|
|
db.deleteKV(db::KV_SYSTEM_NAME);
|
|
} else {
|
|
db.setKV(db::KV_SYSTEM_NAME, synced);
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
Status parseStatus(const std::string& status) {
|
|
if (status == "ok") return Status::Ok;
|
|
if (status == "conflict") return Status::Conflict;
|
|
if (status == "invalid") return Status::Invalid;
|
|
return Status::Unchanged;
|
|
}
|
|
|
|
std::string storedName(const db::DatabaseManager& db) {
|
|
return db.getKV(db::KV_SYSTEM_NAME);
|
|
}
|
|
|
|
bool pendingSync(const db::DatabaseManager& db) {
|
|
return db.getKV(db::KV_SYSTEM_NAME_PENDING) == "1";
|
|
}
|
|
|
|
bool storeLocalName(db::DatabaseManager& db, const std::string& raw,
|
|
std::string* error) {
|
|
const std::string trimmed = validation::trim(raw);
|
|
if (!validation::isValidSystemName(trimmed)) {
|
|
if (error) *error = INVALID_MESSAGE;
|
|
return false;
|
|
}
|
|
|
|
db.setKV(db::KV_SYSTEM_NAME, trimmed);
|
|
db.setKV(db::KV_SYSTEM_NAME_PENDING, "1");
|
|
db.setKV(db::KV_SYSTEM_NAME_MESSAGE, "");
|
|
return true;
|
|
}
|
|
|
|
Status applyServerStatus(db::DatabaseManager& db, const std::string& serverStatus) {
|
|
const Status status = parseStatus(serverStatus);
|
|
switch (status) {
|
|
case Status::Ok:
|
|
db.setKV(db::KV_SYSTEM_NAME_SYNCED, db.getKV(db::KV_SYSTEM_NAME));
|
|
db.setKV(db::KV_SYSTEM_NAME_PENDING, "0");
|
|
db.setKV(db::KV_SYSTEM_NAME_MESSAGE, "");
|
|
return Status::Ok;
|
|
case Status::Unchanged:
|
|
if (!db.getKV(db::KV_SYSTEM_NAME).empty()) {
|
|
db.setKV(db::KV_SYSTEM_NAME_SYNCED, db.getKV(db::KV_SYSTEM_NAME));
|
|
}
|
|
db.setKV(db::KV_SYSTEM_NAME_PENDING, "0");
|
|
db.setKV(db::KV_SYSTEM_NAME_MESSAGE, "");
|
|
return Status::Unchanged;
|
|
case Status::Conflict:
|
|
revertToSynced(db);
|
|
db.setKV(db::KV_SYSTEM_NAME_PENDING, "0");
|
|
db.setKV(db::KV_SYSTEM_NAME_MESSAGE, CONFLICT_MESSAGE);
|
|
return Status::Conflict;
|
|
case Status::Invalid:
|
|
revertToSynced(db);
|
|
db.setKV(db::KV_SYSTEM_NAME_PENDING, "0");
|
|
db.setKV(db::KV_SYSTEM_NAME_MESSAGE, INVALID_MESSAGE);
|
|
return Status::Invalid;
|
|
default:
|
|
return Status::Unchanged;
|
|
}
|
|
}
|
|
|
|
Status syncWithServer(db::DatabaseManager& db, const PutFn& put) {
|
|
const std::string key = db.getKV(db::KV_LICENSE_KEY);
|
|
if (key.empty()) {
|
|
return Status::NotConfigured;
|
|
}
|
|
|
|
const std::string name = db.getKV(db::KV_SYSTEM_NAME);
|
|
if (name.empty()) {
|
|
// Nothing to sync; a cleared/empty name is never sent.
|
|
db.setKV(db::KV_SYSTEM_NAME_PENDING, "0");
|
|
return Status::Unchanged;
|
|
}
|
|
|
|
if (!pendingSync(db)) {
|
|
return Status::Unchanged;
|
|
}
|
|
|
|
const api::PutNameResult result = put(key, name);
|
|
if (!result.transport_ok) {
|
|
return Status::NetworkError; // keep pending for a later retry
|
|
}
|
|
|
|
switch (result.status) {
|
|
case 200:
|
|
return applyServerStatus(db, "ok");
|
|
case 400:
|
|
return applyServerStatus(db, "invalid");
|
|
case 409:
|
|
return applyServerStatus(db, "conflict");
|
|
case 404:
|
|
return Status::UnknownLicense; // keep pending; license not validated
|
|
default:
|
|
return Status::NetworkError; // 5xx etc: keep pending
|
|
}
|
|
}
|
|
|
|
std::string consumeMessage(db::DatabaseManager& db) {
|
|
const std::string message = db.getKV(db::KV_SYSTEM_NAME_MESSAGE);
|
|
if (!message.empty()) {
|
|
db.setKV(db::KV_SYSTEM_NAME_MESSAGE, "");
|
|
}
|
|
return message;
|
|
}
|
|
|
|
} // namespace radiantwave::systemname
|