159 lines
5.3 KiB
C
159 lines
5.3 KiB
C
|
|
#pragma once
|
|||
|
|
#include <chrono>
|
|||
|
|
#include <memory>
|
|||
|
|
#include <mutex>
|
|||
|
|
#include <string>
|
|||
|
|
#include <string_view>
|
|||
|
|
|
|||
|
|
#include "TboxConfigClient.h"
|
|||
|
|
#include "TboxConfigSemantic.h"
|
|||
|
|
|
|||
|
|
// =======================================================
|
|||
|
|
// TboxConfigManager
|
|||
|
|
// - 表驱动生成 getter / setter
|
|||
|
|
// - 支持多项修改 + commit
|
|||
|
|
// - 自动 version 检测 + reload
|
|||
|
|
// =======================================================
|
|||
|
|
class TboxConfigManager
|
|||
|
|
{
|
|||
|
|
public:
|
|||
|
|
static TboxConfigManager& instance()
|
|||
|
|
{
|
|||
|
|
static TboxConfigManager inst;
|
|||
|
|
return inst;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ================= 初始化 =================
|
|||
|
|
bool init(const std::string& server = "127.0.0.1", int port = 18080)
|
|||
|
|
{
|
|||
|
|
std::lock_guard<std::mutex> lock(mtx_);
|
|||
|
|
client_ = std::make_unique<TboxConfigClient>(server, port);
|
|||
|
|
bool ok = client_->fetch();
|
|||
|
|
last_check_ = std::chrono::steady_clock::now();
|
|||
|
|
return ok;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
uint64_t version()
|
|||
|
|
{
|
|||
|
|
ensure();
|
|||
|
|
return client_ ? client_->version() : 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ===================================================
|
|||
|
|
// 🔑 配置字段定义表(唯一维护点)
|
|||
|
|
// type, Name, semantic, default
|
|||
|
|
// ===================================================
|
|||
|
|
#define TBOX_CONFIG_FIELDS(X) \
|
|||
|
|
/* -------- 基础身份 -------- */ \
|
|||
|
|
X(std::string, DeviceNo, tbox::semantic::DEVICE_NO, "KL001") \
|
|||
|
|
X(std::string, VehicleId, tbox::semantic::VEHICLE_ID, "V010001") \
|
|||
|
|
X(std::string, Vin, tbox::semantic::VIN, "") \
|
|||
|
|
\
|
|||
|
|
/* -------- 云平台 -------- */ \
|
|||
|
|
X(std::string, PlatformIp, tbox::semantic::PLATFORM_IP, "") \
|
|||
|
|
X(int, PlatformPort, tbox::semantic::PLATFORM_PORT, 0) \
|
|||
|
|
X(std::string, MqttIp, tbox::semantic::MQTT_IP, "") \
|
|||
|
|
X(int, MqttPort, tbox::semantic::MQTT_PORT, 1883) \
|
|||
|
|
X(std::string, MqttUsername, tbox::semantic::MQTT_USERNAME, "") \
|
|||
|
|
X(std::string, MqttPassword, tbox::semantic::MQTT_PASSWORD, "") \
|
|||
|
|
\
|
|||
|
|
/* -------- 驾驶舱 -------- */ \
|
|||
|
|
X(std::string, CockpitMqttIp, tbox::semantic::COCKPIT_MQTT_IP, "") \
|
|||
|
|
X(int, CockpitMqttPort, tbox::semantic::COCKPIT_MQTT_PORT, 1883) \
|
|||
|
|
\
|
|||
|
|
/* -------- 协议相关 -------- */ \
|
|||
|
|
X(int, LoginSeq, tbox::semantic::LOGIN_SEQ, 1) \
|
|||
|
|
X(std::string, LoginSeqDate, tbox::semantic::LOGIN_SEQ_DATE, "000000") \
|
|||
|
|
X(int, HeartbeatInterval, tbox::semantic::HEARTBEAT_INTERVAL, 60)
|
|||
|
|
|
|||
|
|
// ================= Getter 自动生成 =================
|
|||
|
|
#define GEN_GET(type, name, semantic, def) \
|
|||
|
|
type get##name() { return getValue<type>(semantic, def); }
|
|||
|
|
|
|||
|
|
TBOX_CONFIG_FIELDS(GEN_GET)
|
|||
|
|
#undef GEN_GET
|
|||
|
|
|
|||
|
|
// ================= Setter(写入缓存,不立即提交) =================
|
|||
|
|
#define GEN_SET(type, name, semantic, def) \
|
|||
|
|
void set##name(const type& v) { setValue<type>(semantic, v); }
|
|||
|
|
|
|||
|
|
TBOX_CONFIG_FIELDS(GEN_SET)
|
|||
|
|
#undef GEN_SET
|
|||
|
|
|
|||
|
|
// ================= 统一提交 =================
|
|||
|
|
bool commit()
|
|||
|
|
{
|
|||
|
|
ensure();
|
|||
|
|
return client_->commitAndFetch();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
TboxConfigManager() = default;
|
|||
|
|
~TboxConfigManager() = default;
|
|||
|
|
TboxConfigManager(const TboxConfigManager&) = delete;
|
|||
|
|
TboxConfigManager& operator=(const TboxConfigManager&) = delete;
|
|||
|
|
|
|||
|
|
// ================= 自动刷新机制 =================
|
|||
|
|
void ensureFresh()
|
|||
|
|
{
|
|||
|
|
auto now = std::chrono::steady_clock::now();
|
|||
|
|
if (now - last_check_ < check_interval_) return;
|
|||
|
|
|
|||
|
|
last_check_ = now;
|
|||
|
|
|
|||
|
|
// 简单粗暴,但稳定:直接 fetch
|
|||
|
|
client_->fetch();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void ensure()
|
|||
|
|
{
|
|||
|
|
if (!client_)
|
|||
|
|
{
|
|||
|
|
client_ = std::make_unique<TboxConfigClient>();
|
|||
|
|
client_->fetch();
|
|||
|
|
}
|
|||
|
|
ensureFresh();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ================= 泛型访问 =================
|
|||
|
|
template <typename T>
|
|||
|
|
T getValue(std::string_view semantic, const T& def)
|
|||
|
|
{
|
|||
|
|
ensure();
|
|||
|
|
if constexpr (std::is_same_v<T, int>)
|
|||
|
|
{
|
|||
|
|
auto v = client_->getInt(semantic);
|
|||
|
|
return v ? *v : def;
|
|||
|
|
}
|
|||
|
|
else if constexpr (std::is_same_v<T, bool>)
|
|||
|
|
{
|
|||
|
|
auto v = client_->getBool(semantic);
|
|||
|
|
return v ? *v : def;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
auto v = client_->getString(semantic);
|
|||
|
|
return v ? *v : def;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
template <typename T>
|
|||
|
|
void setValue(std::string_view semantic, const T& v)
|
|||
|
|
{
|
|||
|
|
ensure();
|
|||
|
|
if constexpr (std::is_same_v<T, int>)
|
|||
|
|
client_->setInt(semantic, v);
|
|||
|
|
else if constexpr (std::is_same_v<T, bool>)
|
|||
|
|
client_->setBool(semantic, v);
|
|||
|
|
else
|
|||
|
|
client_->setString(semantic, v);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
std::mutex mtx_;
|
|||
|
|
std::unique_ptr<TboxConfigClient> client_;
|
|||
|
|
|
|||
|
|
std::chrono::steady_clock::time_point last_check_{};
|
|||
|
|
const std::chrono::seconds check_interval_{30};
|
|||
|
|
};
|