设备监控-回写
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
.cache/clangd/index/DeviceRegistry.cpp.D6392F292F1C203D.idx
Normal file
BIN
.cache/clangd/index/DeviceRegistry.cpp.D6392F292F1C203D.idx
Normal file
Binary file not shown.
BIN
.cache/clangd/index/DeviceRegistry.h.97F54B624D840DC0.idx
Normal file
BIN
.cache/clangd/index/DeviceRegistry.h.97F54B624D840DC0.idx
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -100,6 +100,8 @@ qt_add_executable(softbus_daemon
|
||||
|
||||
# device bus: registry skeleton
|
||||
src/device_bus/registry/IDeviceRegistry.h
|
||||
src/device_bus/registry/DeviceRegistry.h
|
||||
src/device_bus/registry/DeviceRegistry.cpp
|
||||
|
||||
# devices: base skeleton
|
||||
src/devices/base/IDevice.h
|
||||
|
||||
Binary file not shown.
7
main.cpp
7
main.cpp
@@ -10,6 +10,11 @@
|
||||
void signalHandler(int signal)
|
||||
{
|
||||
LOG_INFO() << "Received signal:" << signal;
|
||||
CoreService* coreService = CoreService::instance();
|
||||
if (coreService) {
|
||||
coreService->shutdown();
|
||||
}
|
||||
|
||||
QCoreApplication::quit();
|
||||
}
|
||||
|
||||
@@ -68,7 +73,7 @@ int main(int argc, char *argv[])
|
||||
LOG_ERROR() << "CoreService initialize failed";
|
||||
return 1;
|
||||
}
|
||||
QObject::connect(&app, &QCoreApplication::aboutToQuit, coreService, &CoreService::shutdown);
|
||||
// QObject::connect(&app, &QCoreApplication::aboutToQuit, coreService, &CoreService::shutdown);
|
||||
|
||||
// ========================================================================
|
||||
// 创建并注册 D-Bus 服务(仅在 CoreRouter 角色中启用)
|
||||
|
||||
@@ -24,7 +24,7 @@ CoreService::CoreService(QObject* parent)
|
||||
|
||||
CoreService::~CoreService()
|
||||
{
|
||||
shutdown();
|
||||
|
||||
}
|
||||
|
||||
bool CoreService::initialize()
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "device_bus/manager/DeviceBusManager.h"
|
||||
#include "device_bus/monitor/DeviceMonitorService.h"
|
||||
#include "device_bus/registry/DeviceRegistry.h"
|
||||
#include "device_bus/tree/DeviceTreeModel.h"
|
||||
#include "utils/logs/logging.h"
|
||||
|
||||
@@ -14,11 +15,12 @@ namespace softbus::device_bus {
|
||||
|
||||
class DeviceBus::Impl {
|
||||
public:
|
||||
DeviceBusManager manager;
|
||||
std::unique_ptr<DeviceBusManager> manager;
|
||||
std::unique_ptr<monitor::DeviceMonitorService> monitorService;
|
||||
std::unique_ptr<registry::DeviceRegistry> registry;
|
||||
std::shared_ptr<DeviceTreeModel> treeModel;
|
||||
QString configPath;
|
||||
bool deviceTreeDirty{false};
|
||||
bool deviceTreeDirty{false}; // 设备树是否脏了
|
||||
};
|
||||
|
||||
DeviceBus &DeviceBus::instance() {
|
||||
@@ -34,37 +36,61 @@ DeviceBus::~DeviceBus() {
|
||||
}
|
||||
|
||||
bool DeviceBus::initialize(const QJsonObject &rootConfig) {
|
||||
if (!d->monitorService) {
|
||||
d->monitorService = std::make_unique<monitor::DeviceMonitorService>(nullptr);
|
||||
if (!d->monitorService->start()) {
|
||||
LOG_WARNING() << "DeviceBus: device monitor service start failed";
|
||||
}
|
||||
if (!d) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!d->treeModel) {
|
||||
d->treeModel = std::make_shared<DeviceTreeModel>();
|
||||
}
|
||||
d->manager.setDeviceTreeModel(d->treeModel);
|
||||
return d->manager.initialize(rootConfig);
|
||||
if (!d->manager) {
|
||||
d->manager = std::make_unique<DeviceBusManager>();
|
||||
}
|
||||
if (!d->registry) {
|
||||
d->registry = std::make_unique<registry::DeviceRegistry>(d->treeModel);
|
||||
}
|
||||
d->manager->setDeviceTreeModel(d->treeModel);
|
||||
d->manager->setRegistry(d->registry.get());
|
||||
|
||||
if (!d->monitorService) {
|
||||
d->monitorService = std::make_unique<monitor::DeviceMonitorService>(nullptr);
|
||||
d->monitorService->setRegistry(d->registry.get());
|
||||
d->monitorService->setDirtyCallback([this]() { this->markDeviceTreeDirty(); });
|
||||
if (!d->monitorService->start()) {
|
||||
LOG_WARNING() << "DeviceBus: device monitor service start failed";
|
||||
}
|
||||
}
|
||||
return d->manager->initialize(rootConfig);
|
||||
}
|
||||
|
||||
void DeviceBus::shutdown() {
|
||||
if (!d) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (d->monitorService) {
|
||||
LOG_INFO() << "DeviceBus shutting down monitor service";
|
||||
d->monitorService->stop();
|
||||
d->monitorService.reset();
|
||||
}
|
||||
|
||||
d->manager.shutdown();
|
||||
if (d->manager) {
|
||||
LOG_INFO() << "DeviceBus shutting down manager";
|
||||
d->manager->shutdown();
|
||||
}
|
||||
|
||||
if (!d->deviceTreeDirty) {
|
||||
LOG_INFO() << "DeviceBus device tree dirty is false";
|
||||
return;
|
||||
}
|
||||
|
||||
if (d->configPath.isEmpty() || !d->treeModel) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QFileInfo fi(d->configPath);
|
||||
const QString dirPath = fi.dir().absolutePath();
|
||||
LOG_INFO() << "DeviceBus: saving config to" << dirPath;
|
||||
if (!QDir().mkpath(dirPath)) {
|
||||
LOG_ERROR() << "DeviceBus: failed to create config dir" << dirPath;
|
||||
return;
|
||||
@@ -92,18 +118,22 @@ void DeviceBus::shutdown() {
|
||||
}
|
||||
|
||||
void DeviceBus::setConfigPath(const QString& path) {
|
||||
if (!d) return;
|
||||
d->configPath = path;
|
||||
}
|
||||
|
||||
QString DeviceBus::configPath() const {
|
||||
if (!d) return {};
|
||||
return d->configPath;
|
||||
}
|
||||
|
||||
std::shared_ptr<DeviceTreeModel> DeviceBus::deviceTreeModel() const {
|
||||
if (!d) return {};
|
||||
return d->treeModel;
|
||||
}
|
||||
|
||||
void DeviceBus::markDeviceTreeDirty() {
|
||||
if (!d) return;
|
||||
d->deviceTreeDirty = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QSerialPort>
|
||||
#include <algorithm>
|
||||
// #include <algorithm>
|
||||
|
||||
#include "hardware/drivers/serial/SerialQtDriver.h"
|
||||
#include "hardware/drivers/serial/SerialCapabilities.h"
|
||||
@@ -19,6 +19,11 @@ void DeviceBusManager::setDeviceTreeModel(std::shared_ptr<DeviceTreeModel> model
|
||||
m_treeModel = std::move(model);
|
||||
}
|
||||
|
||||
void DeviceBusManager::setRegistry(softbus::device_bus::registry::IDeviceRegistry* registry)
|
||||
{
|
||||
m_registry = registry;
|
||||
}
|
||||
|
||||
bool DeviceBusManager::initialize(const QJsonObject& rootConfig)
|
||||
{
|
||||
if (!m_treeModel) {
|
||||
@@ -167,4 +172,4 @@ void DeviceBusManager::shutdownSerialDevice(const QString& endpoint)
|
||||
}
|
||||
|
||||
m_serialDevicesByEndpoint.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ class DeviceBusManager
|
||||
{
|
||||
public:
|
||||
void setDeviceTreeModel(std::shared_ptr<DeviceTreeModel> model);
|
||||
void setRegistry(softbus::device_bus::registry::IDeviceRegistry* registry);
|
||||
|
||||
bool initialize(const QJsonObject& rootConfig);
|
||||
void shutdown();
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <QJsonDocument>
|
||||
|
||||
#include "device_bus/registry/IDeviceRegistry.h"
|
||||
#include "utils/logs/logging.h"
|
||||
|
||||
#if defined(__linux__)
|
||||
@@ -57,6 +58,16 @@ void DeviceMonitorService::stop()
|
||||
m_started = false;
|
||||
}
|
||||
|
||||
void DeviceMonitorService::setRegistry(softbus::device_bus::registry::IDeviceRegistry* registry)
|
||||
{
|
||||
m_registry = registry;
|
||||
}
|
||||
|
||||
void DeviceMonitorService::setDirtyCallback(std::function<void()> cb)
|
||||
{
|
||||
m_dirtyCb = std::move(cb);
|
||||
}
|
||||
|
||||
void DeviceMonitorService::onEvent(const DeviceEvent& ev)
|
||||
{
|
||||
// De-dup (short window): suppress identical events bursts
|
||||
@@ -78,6 +89,18 @@ void DeviceMonitorService::onEvent(const DeviceEvent& ev)
|
||||
}
|
||||
m_lastEventMsByKey.insert(key, nowMs);
|
||||
|
||||
if (m_registry) {
|
||||
bool changed = false;
|
||||
if (ev.action == DeviceEventAction::Add || ev.action == DeviceEventAction::Change) {
|
||||
changed = m_registry->upsertFromMonitorEvent(ev);
|
||||
} else if (ev.action == DeviceEventAction::Remove) {
|
||||
changed = m_registry->markOfflineFromMonitorEvent(ev);
|
||||
}
|
||||
if (changed && m_dirtyCb) {
|
||||
m_dirtyCb();
|
||||
}
|
||||
}
|
||||
|
||||
// 第一版:仅日志
|
||||
LOG_INFO() << "DeviceMonitor event"
|
||||
<< "type=" << toString(ev.type)
|
||||
|
||||
@@ -5,9 +5,12 @@
|
||||
#include <vector>
|
||||
#include <QHash>
|
||||
#include <QDateTime>
|
||||
#include <functional>
|
||||
|
||||
#include "device_bus/monitor/IDeviceMonitor.h"
|
||||
|
||||
namespace softbus::device_bus::registry { class IDeviceRegistry; }
|
||||
|
||||
namespace softbus::device_bus::monitor
|
||||
{
|
||||
|
||||
@@ -20,6 +23,8 @@ public:
|
||||
|
||||
bool start();
|
||||
void stop();
|
||||
void setRegistry(softbus::device_bus::registry::IDeviceRegistry* registry);
|
||||
void setDirtyCallback(std::function<void()> cb);
|
||||
|
||||
private:
|
||||
void onEvent(const DeviceEvent& ev);
|
||||
@@ -27,6 +32,8 @@ private:
|
||||
private:
|
||||
std::vector<std::unique_ptr<IDeviceMonitor>> m_monitors;
|
||||
bool m_started{false};
|
||||
softbus::device_bus::registry::IDeviceRegistry* m_registry{nullptr};
|
||||
std::function<void()> m_dirtyCb;
|
||||
|
||||
// Lightweight de-dup: key -> last timestamp (ms)
|
||||
QHash<QString, qint64> m_lastEventMsByKey;
|
||||
|
||||
166
src/device_bus/registry/DeviceRegistry.cpp
Normal file
166
src/device_bus/registry/DeviceRegistry.cpp
Normal file
@@ -0,0 +1,166 @@
|
||||
#include "device_bus/registry/DeviceRegistry.h"
|
||||
|
||||
#include <QCryptographicHash>
|
||||
#include <QDateTime>
|
||||
|
||||
#include "utils/logs/logging.h"
|
||||
|
||||
namespace softbus::device_bus::registry
|
||||
{
|
||||
|
||||
DeviceRegistry::DeviceRegistry(std::shared_ptr<DeviceTreeModel> treeModel)
|
||||
: m_treeModel(std::move(treeModel))
|
||||
{
|
||||
}
|
||||
|
||||
void DeviceRegistry::registerDevice(const softbus::devices::DeviceInfo& info)
|
||||
{
|
||||
m_devicesById.insert(info.id, info);
|
||||
}
|
||||
|
||||
void DeviceRegistry::unregisterDevice(int id)
|
||||
{
|
||||
m_devicesById.remove(id);
|
||||
}
|
||||
|
||||
std::optional<softbus::devices::DeviceInfo> DeviceRegistry::findById(int id) const
|
||||
{
|
||||
auto it = m_devicesById.constFind(id);
|
||||
if (it == m_devicesById.constEnd()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return it.value();
|
||||
}
|
||||
|
||||
std::vector<softbus::devices::DeviceInfo> DeviceRegistry::listDevices() const
|
||||
{
|
||||
std::vector<softbus::devices::DeviceInfo> out;
|
||||
out.reserve(m_devicesById.size());
|
||||
for (auto it = m_devicesById.cbegin(); it != m_devicesById.cend(); ++it) {
|
||||
out.push_back(it.value());
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
bool DeviceRegistry::upsertFromMonitorEvent(const softbus::device_bus::monitor::DeviceEvent& ev)
|
||||
{
|
||||
if (!m_treeModel) return false;
|
||||
|
||||
const QString stableKey = buildStableKey(ev);
|
||||
if (stableKey.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
const QString preferredId = buildPreferredNodeId(ev, stableKey);
|
||||
const QString now = QDateTime::currentDateTimeUtc().toString(Qt::ISODate);
|
||||
|
||||
const QString nodeId = m_treeModel->upsertNodeByStableKey(
|
||||
stableKey,
|
||||
preferredId,
|
||||
inferType(ev),
|
||||
inferEndpoint(ev),
|
||||
inferName(ev),
|
||||
buildParams(ev),
|
||||
true,
|
||||
now);
|
||||
|
||||
if (!nodeId.isEmpty()) {
|
||||
m_stableKeyToNodeId.insert(stableKey, nodeId);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DeviceRegistry::markOfflineFromMonitorEvent(const softbus::device_bus::monitor::DeviceEvent& ev)
|
||||
{
|
||||
if (!m_treeModel) return false;
|
||||
const QString stableKey = buildStableKey(ev);
|
||||
if (stableKey.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
const QString now = QDateTime::currentDateTimeUtc().toString(Qt::ISODate);
|
||||
return m_treeModel->markOfflineByStableKey(stableKey, now);
|
||||
}
|
||||
|
||||
QString DeviceRegistry::buildStableKey(const softbus::device_bus::monitor::DeviceEvent& ev)
|
||||
{
|
||||
const QString type = inferType(ev);
|
||||
|
||||
if (!ev.serial.isEmpty()) {
|
||||
return type + QStringLiteral("|serial|") + ev.serial;
|
||||
}
|
||||
|
||||
if (ev.type == softbus::device_bus::monitor::DeviceEventType::NetInterface) {
|
||||
if (!ev.ifname.isEmpty()) return type + QStringLiteral("|ifname|") + ev.ifname;
|
||||
if (ev.ifindex >= 0) return type + QStringLiteral("|ifindex|") + QString::number(ev.ifindex);
|
||||
}
|
||||
|
||||
const QString path = !ev.props.value(QStringLiteral("SYSPATH")).isEmpty()
|
||||
? ev.props.value(QStringLiteral("SYSPATH"))
|
||||
: (!ev.devicePath.isEmpty() ? ev.devicePath : ev.devnode);
|
||||
if (!ev.vid.isEmpty() || !ev.pid.isEmpty() || !path.isEmpty()) {
|
||||
return type + QStringLiteral("|vpidpath|") + ev.vid + QStringLiteral(":") + ev.pid + QStringLiteral("|") + path;
|
||||
}
|
||||
|
||||
if (!ev.devnode.isEmpty()) {
|
||||
return type + QStringLiteral("|devnode|") + ev.devnode;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
QString DeviceRegistry::buildPreferredNodeId(const softbus::device_bus::monitor::DeviceEvent& ev, const QString& stableKey)
|
||||
{
|
||||
if (!ev.serial.isEmpty()) {
|
||||
return QStringLiteral("dev_serial_") + ev.serial;
|
||||
}
|
||||
|
||||
const QByteArray hash = QCryptographicHash::hash(stableKey.toUtf8(), QCryptographicHash::Sha1).toHex();
|
||||
return QStringLiteral("dev_") + QString::fromUtf8(hash.left(12));
|
||||
}
|
||||
|
||||
QString DeviceRegistry::inferType(const softbus::device_bus::monitor::DeviceEvent& ev)
|
||||
{
|
||||
using softbus::device_bus::monitor::DeviceEventType;
|
||||
switch (ev.type) {
|
||||
case DeviceEventType::Serial: return QStringLiteral("serial");
|
||||
case DeviceEventType::NetInterface: return QStringLiteral("network");
|
||||
case DeviceEventType::Storage: return QStringLiteral("storage");
|
||||
case DeviceEventType::Usb: return QStringLiteral("usb");
|
||||
default: return QStringLiteral("unknown");
|
||||
}
|
||||
}
|
||||
|
||||
QString DeviceRegistry::inferEndpoint(const softbus::device_bus::monitor::DeviceEvent& ev)
|
||||
{
|
||||
if (!ev.devnode.isEmpty()) return ev.devnode;
|
||||
if (!ev.ifname.isEmpty()) return ev.ifname;
|
||||
if (!ev.devicePath.isEmpty()) return ev.devicePath;
|
||||
return ev.props.value(QStringLiteral("SYSPATH"));
|
||||
}
|
||||
|
||||
QString DeviceRegistry::inferName(const softbus::device_bus::monitor::DeviceEvent& ev)
|
||||
{
|
||||
if (!ev.model.isEmpty()) return ev.model;
|
||||
if (!ev.ifname.isEmpty()) return ev.ifname;
|
||||
if (!ev.devnode.isEmpty()) return ev.devnode;
|
||||
return inferType(ev);
|
||||
}
|
||||
|
||||
QJsonObject DeviceRegistry::buildParams(const softbus::device_bus::monitor::DeviceEvent& ev)
|
||||
{
|
||||
QJsonObject p;
|
||||
p.insert(QStringLiteral("online"), true);
|
||||
if (!ev.vid.isEmpty()) p.insert(QStringLiteral("vid"), ev.vid);
|
||||
if (!ev.pid.isEmpty()) p.insert(QStringLiteral("pid"), ev.pid);
|
||||
if (!ev.serial.isEmpty()) p.insert(QStringLiteral("serial"), ev.serial);
|
||||
if (!ev.vendor.isEmpty()) p.insert(QStringLiteral("vendor"), ev.vendor);
|
||||
if (!ev.model.isEmpty()) p.insert(QStringLiteral("model"), ev.model);
|
||||
if (!ev.ifname.isEmpty()) p.insert(QStringLiteral("ifname"), ev.ifname);
|
||||
if (ev.ifindex >= 0) p.insert(QStringLiteral("ifindex"), ev.ifindex);
|
||||
if (!ev.subsystem.isEmpty()) p.insert(QStringLiteral("subsystem"), ev.subsystem);
|
||||
if (!ev.devicePath.isEmpty()) p.insert(QStringLiteral("devicePath"), ev.devicePath);
|
||||
if (!ev.devnode.isEmpty()) p.insert(QStringLiteral("devnode"), ev.devnode);
|
||||
return p;
|
||||
}
|
||||
|
||||
} // namespace softbus::device_bus::registry
|
||||
|
||||
44
src/device_bus/registry/DeviceRegistry.h
Normal file
44
src/device_bus/registry/DeviceRegistry.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include <QHash>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include "device_bus/registry/IDeviceRegistry.h"
|
||||
#include "device_bus/tree/DeviceTreeModel.h"
|
||||
|
||||
namespace softbus::device_bus::registry
|
||||
{
|
||||
|
||||
class DeviceRegistry : public IDeviceRegistry
|
||||
{
|
||||
public:
|
||||
explicit DeviceRegistry(std::shared_ptr<DeviceTreeModel> treeModel);
|
||||
~DeviceRegistry() override = default;
|
||||
|
||||
void registerDevice(const softbus::devices::DeviceInfo& info) override;
|
||||
void unregisterDevice(int id) override;
|
||||
|
||||
std::optional<softbus::devices::DeviceInfo> findById(int id) const override;
|
||||
std::vector<softbus::devices::DeviceInfo> listDevices() const override;
|
||||
|
||||
bool upsertFromMonitorEvent(const softbus::device_bus::monitor::DeviceEvent& ev) override;
|
||||
bool markOfflineFromMonitorEvent(const softbus::device_bus::monitor::DeviceEvent& ev) override;
|
||||
|
||||
private:
|
||||
static QString buildStableKey(const softbus::device_bus::monitor::DeviceEvent& ev);
|
||||
static QString buildPreferredNodeId(const softbus::device_bus::monitor::DeviceEvent& ev, const QString& stableKey);
|
||||
static QString inferType(const softbus::device_bus::monitor::DeviceEvent& ev);
|
||||
static QString inferEndpoint(const softbus::device_bus::monitor::DeviceEvent& ev);
|
||||
static QString inferName(const softbus::device_bus::monitor::DeviceEvent& ev);
|
||||
static QJsonObject buildParams(const softbus::device_bus::monitor::DeviceEvent& ev);
|
||||
|
||||
private:
|
||||
std::shared_ptr<DeviceTreeModel> m_treeModel;
|
||||
QHash<int, softbus::devices::DeviceInfo> m_devicesById;
|
||||
QHash<QString, QString> m_stableKeyToNodeId;
|
||||
};
|
||||
|
||||
} // namespace softbus::device_bus::registry
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "devices/DeviceTypes.h"
|
||||
#include "device_bus/monitor/DeviceEvent.h"
|
||||
|
||||
namespace softbus::device_bus::registry
|
||||
{
|
||||
@@ -18,6 +19,10 @@ public:
|
||||
|
||||
virtual std::optional<softbus::devices::DeviceInfo> findById(int id) const = 0;
|
||||
virtual std::vector<softbus::devices::DeviceInfo> listDevices() const = 0;
|
||||
|
||||
// Monitor-driven registry APIs
|
||||
virtual bool upsertFromMonitorEvent(const softbus::device_bus::monitor::DeviceEvent& ev) = 0;
|
||||
virtual bool markOfflineFromMonitorEvent(const softbus::device_bus::monitor::DeviceEvent& ev) = 0;
|
||||
};
|
||||
|
||||
} // namespace softbus::device_bus::registry
|
||||
|
||||
@@ -118,14 +118,96 @@ QJsonObject DeviceTreeModel::toDaemonConfigRoot() const
|
||||
|
||||
const DeviceTreeNode* DeviceTreeModel::findById(const QString& id) const
|
||||
{
|
||||
const auto it = m_indexById.constFind(id);
|
||||
if (it == m_indexById.constEnd()) {
|
||||
return nullptr;
|
||||
}
|
||||
const int index = it.value();
|
||||
const int index = findIndexById(id);
|
||||
if (index < 0 || index >= m_nodes.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
return &m_nodes.at(index);
|
||||
}
|
||||
|
||||
int DeviceTreeModel::findIndexById(const QString& id) const
|
||||
{
|
||||
const auto it = m_indexById.constFind(id);
|
||||
if (it == m_indexById.constEnd()) {
|
||||
return -1;
|
||||
}
|
||||
return it.value();
|
||||
}
|
||||
|
||||
int DeviceTreeModel::findIndexByStableKey(const QString& stableKey) const
|
||||
{
|
||||
if (stableKey.isEmpty()) {
|
||||
return -1;
|
||||
}
|
||||
for (int i = 0; i < m_nodes.size(); ++i) {
|
||||
const auto& n = m_nodes.at(i);
|
||||
if (n.params.value(QStringLiteral("stableKey")).toString() == stableKey) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
QString DeviceTreeModel::upsertNodeByStableKey(const QString& stableKey,
|
||||
const QString& preferredId,
|
||||
const QString& type,
|
||||
const QString& endpoint,
|
||||
const QString& name,
|
||||
const QJsonObject& extraParams,
|
||||
bool online,
|
||||
const QString& lastSeenTs)
|
||||
{
|
||||
int idx = findIndexByStableKey(stableKey);
|
||||
if (idx < 0 && !preferredId.isEmpty()) {
|
||||
idx = findIndexById(preferredId);
|
||||
}
|
||||
|
||||
if (idx < 0) {
|
||||
DeviceTreeNode node;
|
||||
node.id = preferredId;
|
||||
node.type = type;
|
||||
node.endpoint = endpoint;
|
||||
node.name = name;
|
||||
node.enabled = true;
|
||||
node.params = extraParams;
|
||||
node.params.insert(QStringLiteral("stableKey"), stableKey);
|
||||
node.params.insert(QStringLiteral("online"), online);
|
||||
if (!lastSeenTs.isEmpty()) {
|
||||
node.params.insert(QStringLiteral("lastSeenTs"), lastSeenTs);
|
||||
}
|
||||
m_nodes.push_back(node);
|
||||
rebuildIndex();
|
||||
return node.id;
|
||||
}
|
||||
|
||||
auto& node = m_nodes[idx];
|
||||
if (!type.isEmpty()) node.type = type;
|
||||
if (!endpoint.isEmpty()) node.endpoint = endpoint;
|
||||
if (!name.isEmpty()) node.name = name;
|
||||
node.enabled = true;
|
||||
|
||||
for (auto it = extraParams.begin(); it != extraParams.end(); ++it) {
|
||||
node.params.insert(it.key(), it.value());
|
||||
}
|
||||
node.params.insert(QStringLiteral("stableKey"), stableKey);
|
||||
node.params.insert(QStringLiteral("online"), online);
|
||||
if (!lastSeenTs.isEmpty()) {
|
||||
node.params.insert(QStringLiteral("lastSeenTs"), lastSeenTs);
|
||||
}
|
||||
return node.id;
|
||||
}
|
||||
|
||||
bool DeviceTreeModel::markOfflineByStableKey(const QString& stableKey, const QString& lastSeenTs)
|
||||
{
|
||||
const int idx = findIndexByStableKey(stableKey);
|
||||
if (idx < 0) {
|
||||
return false;
|
||||
}
|
||||
auto& node = m_nodes[idx];
|
||||
node.params.insert(QStringLiteral("online"), false);
|
||||
if (!lastSeenTs.isEmpty()) {
|
||||
node.params.insert(QStringLiteral("lastSeenTs"), lastSeenTs);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,19 @@ public:
|
||||
QVector<DeviceTreeNode>& nodesMutable() { return m_nodes; }
|
||||
|
||||
const DeviceTreeNode* findById(const QString& id) const;
|
||||
int findIndexById(const QString& id) 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;
|
||||
|
||||
Reference in New Issue
Block a user