90 lines
3.4 KiB
C++
90 lines
3.4 KiB
C++
#pragma once
|
||
|
||
#include <QJsonObject>
|
||
#include <QJsonArray>
|
||
#include <QVector>
|
||
#include <QString>
|
||
#include <QHash>
|
||
#include <atomic>
|
||
#include <QMutex>
|
||
|
||
// 轻量级设备树模型:从 daemon_config.json 的 device_tree 字段加载
|
||
|
||
struct DeviceTreeNode
|
||
{
|
||
QString id;
|
||
QString name;
|
||
QString type;
|
||
QString endpoint;
|
||
QString driver;
|
||
QString capabilitiesRef;
|
||
QJsonObject params;
|
||
QVector<QString> childrenIds;
|
||
bool enabled{true};
|
||
};
|
||
|
||
class DeviceTreeModel
|
||
{
|
||
public:
|
||
// 从给定的 JSON 根对象(包含 device_tree 字段)加载
|
||
bool loadFromDaemonConfig(const QJsonObject& root, QString* errorMessage = nullptr);
|
||
|
||
const QVector<DeviceTreeNode>& nodes() const { return m_nodes; }
|
||
QVector<DeviceTreeNode>& nodesMutable() { return m_nodes; }
|
||
|
||
const DeviceTreeNode* findById(const QString& id) const;
|
||
int findIndexById(const QString& id) const;
|
||
int findIndexByEndpoint(const QString& endpoint) const;
|
||
int findIndexByStableKey(const QString& stableKey) const;
|
||
|
||
// Monitor/register path: upsert or mark online/offline
|
||
QString upsertNodeByStableKey(const QString& stableKey,
|
||
const QString& preferredId,
|
||
const QString& type,
|
||
const QString& endpoint,
|
||
const QString& name,
|
||
const QJsonObject& extraParams,
|
||
bool online,
|
||
const QString& lastSeenTs);
|
||
bool markOfflineByStableKey(const QString& stableKey, const QString& lastSeenTs);
|
||
|
||
// 序列化为 daemon_config.json 所需格式
|
||
QJsonArray toDeviceTreeJson() const;
|
||
QJsonObject toDaemonConfigRoot() const;
|
||
|
||
// 当外部直接修改 nodesMutable() 后,需要重建索引
|
||
void rebuildIndex();
|
||
|
||
// 与 D-Bus patch / 边缘 CTRL_TREE_PROPOSE 共用的写锁与 revision(见 docs/EDGE_UPLINK_PROTOCOL_v1.md)
|
||
QMutex& writeMutex() { return m_writeMutex; }
|
||
qint64 treeRevision() const { return m_treeRevision.load(std::memory_order_relaxed); }
|
||
void bumpTreeRevision();
|
||
bool applyPatchToNodeById(const QString& id, const QJsonObject& patch);
|
||
|
||
struct EdgeProposeResult
|
||
{
|
||
bool ok{false};
|
||
QString code; // OK, CONFLICT, FORBIDDEN_SCOPE, NODE_NOT_FOUND, INVALID_JSON
|
||
QString message;
|
||
qint64 newRevision{0};
|
||
qint64 currentRevision{0};
|
||
};
|
||
EdgeProposeResult applyEdgePropose(const QString& edgeId, qint64 baseRevision, const QJsonArray& entries);
|
||
|
||
/** 导出属于该 edge 的节点子集(与 applyEdgePropose 作用域规则一致),用于下行 TREE_FULL。
|
||
* 若传入 outRevisionAtExport,则写入导出时刻的 treeRevision(与 nodes 同一快照)。 */
|
||
QJsonArray exportSubtreeForEdge(const QString& edgeId, qint64* outRevisionAtExport = nullptr) const;
|
||
|
||
/** 节点若处于边缘作用域(params.edgeId 或 id 前缀 edges/<edgeId>/...),返回应尝试下行 TREE_FULL 的 edgeId(去重)。 */
|
||
QVector<QString> downlinkEdgeIdsForNode(const DeviceTreeNode& node) const;
|
||
|
||
private:
|
||
static bool nodeBelongsToEdge(const DeviceTreeNode& node, const QString& edgeId);
|
||
|
||
QVector<DeviceTreeNode> m_nodes;
|
||
QHash<QString, int> m_indexById;
|
||
mutable QMutex m_writeMutex;
|
||
std::atomic<qint64> m_treeRevision{1};
|
||
};
|
||
|