context bind
This commit is contained in:
@@ -78,7 +78,57 @@
|
||||
| `GET` | `/v1/status` | 透传 `get_status` 的状态响应 |
|
||||
| `POST` | `/v1/command` | 统一命令入口(请求体为 executeCommand JSON) |
|
||||
|
||||
### 5.2 Discovery 路由
|
||||
### 5.2 设备树 / 设备路由
|
||||
|
||||
| 方法 | 路径 | 请求参数 | 说明 |
|
||||
|---|---|---|---|
|
||||
| `GET` | `/api/v1/device-tree` | 无 | 返回当前设备树快照 |
|
||||
| `GET` | `/api/v1/devices` | 无 | 返回当前运行态设备列表 |
|
||||
| `GET` | `/api/v1/devices/{id}` | path: `id(int)` | 返回指定运行态设备详情 |
|
||||
| `PATCH` | `/api/v1/device-tree/nodes/{id}` | body: 任意可变节点字段子集 | 部分更新设备树节点;当前至少保护 `id`、`params.stableKey`、`params.online`、`params.lastSeenTs` |
|
||||
|
||||
### 5.3 规则管理路由
|
||||
|
||||
| 方法 | 路径 | 请求参数 | 说明 |
|
||||
|---|---|---|---|
|
||||
| `GET` | `/api/v1/rules/status` | 无 | 返回动态规则计数状态 |
|
||||
| `POST` | `/api/v1/rules/filter` | body: `id`, `endpointHash?`, `deviceId?`, `stableKey?`, `condition?` | 新增过滤规则 |
|
||||
| `DELETE` | `/api/v1/rules/filter/{id}` | path: `id` | 删除过滤规则 |
|
||||
| `POST` | `/api/v1/rules/transform` | body: `id`, `endpointHash?`, `deviceId?`, `stableKey?`, `scale?`, `offset?`, `unit?` | 新增转换规则 |
|
||||
| `DELETE` | `/api/v1/rules/transform/{id}` | path: `id` | 删除转换规则 |
|
||||
|
||||
- 说明:
|
||||
- `transform` 规则已经在 `PipelineEngine::applyTransformAndEnrich(...)` 中生效。
|
||||
- `filter` 路由当前主要提供“注册表管理”能力;动态 filter 规则尚未真正接入 `PipelineEngine::stage3Filter(...)` 的执行链路。
|
||||
|
||||
### 5.4 Pipeline 路由
|
||||
|
||||
| 方法 | 路径 | 请求参数 | 说明 |
|
||||
|---|---|---|---|
|
||||
| `GET` | `/api/v1/pipeline/status` | 无 | 返回 pipeline 运行状态、session 数量、队列容量、插件摘要与 counters |
|
||||
| `GET` | `/api/v1/pipeline/counters` | 无 | 返回 `in/out/drop/error/mergeDrop` 计数器快照 |
|
||||
| `GET` | `/api/v1/pipeline/config` | 无 | 返回当前运行时配置快照 |
|
||||
|
||||
- 说明:`/v1/status` 仍然是 control-plane 摘要(规则 + discovery + mapping),不等同于 `/api/v1/pipeline/status`。
|
||||
|
||||
### 5.5 插件 / 协议能力路由
|
||||
|
||||
| 方法 | 路径 | 请求参数 | 说明 |
|
||||
|---|---|---|---|
|
||||
| `GET` | `/api/v1/plugins` | 无 | 返回 parser / framer / mapper 三类逻辑插件的统一列表 |
|
||||
| `GET` | `/api/v1/plugins/protocols` | 无 | 返回按协议聚合后的能力快照(parser/framer/mapper pluginId) |
|
||||
| `GET` | `/api/v1/plugins/mappers` | 无 | 返回 mapper 插件列表 |
|
||||
|
||||
### 5.6 Metadata / Profile 路由
|
||||
|
||||
| 方法 | 路径 | 请求参数 | 说明 |
|
||||
|---|---|---|---|
|
||||
| `GET` | `/api/v1/metadata` | 无 | 返回 metadata 字典全量快照 |
|
||||
| `GET` | `/api/v1/metadata/{metadataId}` | path: `metadataId` | 返回指定 metadata 详情 |
|
||||
| `GET` | `/api/v1/profiles` | 无 | 返回全部设备 profile 快照 |
|
||||
| `GET` | `/api/v1/profiles/{deviceId}` | path: `deviceId` | 返回指定 `deviceId` 关联的全部 profile |
|
||||
|
||||
### 5.7 Discovery 路由
|
||||
|
||||
| 方法 | 路径 | 请求参数 | 说明 |
|
||||
|---|---|---|---|
|
||||
@@ -88,7 +138,7 @@
|
||||
| `POST` | `/api/v1/discovery/clear` | 无 | 清空发现池样本 |
|
||||
| `GET` | `/api/v1/discovery/samples` | query: `offset?`, `limit?`, `endpointHash?`, `protocol?` | 拉取样本(按更新时间倒序,且过滤已映射 key) |
|
||||
|
||||
### 5.3 Mapping 路由
|
||||
### 5.8 Mapping 路由
|
||||
|
||||
| 方法 | 路径 | 请求参数 | 说明 |
|
||||
|---|---|---|---|
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
#include "api/http/RestApiRoutes.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <mutex>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QHttpServer>
|
||||
#include <QHttpHeaders>
|
||||
#include <QHttpServerRequest>
|
||||
#include <QHttpServerResponse>
|
||||
#include <QHttpServerResponder>
|
||||
@@ -9,13 +14,20 @@
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonParseError>
|
||||
#include <QJsonValue>
|
||||
#include <QUrlQuery>
|
||||
#include <utility>
|
||||
|
||||
#include "api/http/RestApiCommandHttp.h"
|
||||
#include "api/ipc_dbus/CommandDispatcher.h"
|
||||
#include "core/metadata/MetadataRegistry.h"
|
||||
#include "core/metadata/ProfileRegistry.h"
|
||||
#include "core/plugin_system/PluginManager.h"
|
||||
#include "device_bus/DeviceBus.h"
|
||||
#include "message_bus/pipeline/discovery/DiscoveryPool.h"
|
||||
#include "message_bus/pipeline/mapping/MappingRegistry.h"
|
||||
#include "message_bus/pipeline/PipelineEngine.h"
|
||||
#include "message_bus/pipeline/rules/DynamicRuleRegistry.h"
|
||||
|
||||
namespace softbus::api::http
|
||||
{
|
||||
@@ -23,6 +35,97 @@ namespace softbus::api::http
|
||||
namespace
|
||||
{
|
||||
|
||||
QHttpServerResponse withCorsHeaders(QHttpServerResponse response)
|
||||
{
|
||||
QHttpHeaders headers = response.headers();
|
||||
headers.append(QHttpHeaders::WellKnownHeader::AccessControlAllowOrigin, QByteArrayView("*"));
|
||||
headers.append(QHttpHeaders::WellKnownHeader::AccessControlAllowMethods,
|
||||
QByteArrayView("GET, POST, PATCH, DELETE, OPTIONS"));
|
||||
headers.append(QHttpHeaders::WellKnownHeader::AccessControlAllowHeaders,
|
||||
QByteArrayView("Content-Type, Authorization, X-Requested-With"));
|
||||
headers.append(QHttpHeaders::WellKnownHeader::AccessControlMaxAge, QByteArrayView("86400"));
|
||||
response.setHeaders(std::move(headers));
|
||||
return response;
|
||||
}
|
||||
|
||||
QHttpServerResponse corsPreflightResponse()
|
||||
{
|
||||
return withCorsHeaders(QHttpServerResponse(QHttpServerResponse::StatusCode::NoContent));
|
||||
}
|
||||
|
||||
void registerCorsPreflightRoutes(QHttpServer* server, QObject* routeContext)
|
||||
{
|
||||
server->route(QStringLiteral("/health"), QHttpServerRequest::Method::Options, routeContext,
|
||||
[]() { return corsPreflightResponse(); });
|
||||
server->route(QStringLiteral("/v1/status"), QHttpServerRequest::Method::Options, routeContext,
|
||||
[]() { return corsPreflightResponse(); });
|
||||
server->route(QStringLiteral("/v1/command"), QHttpServerRequest::Method::Options, routeContext,
|
||||
[]() { return corsPreflightResponse(); });
|
||||
server->route(QStringLiteral("/api/v1/discovery/start"), QHttpServerRequest::Method::Options, routeContext,
|
||||
[]() { return corsPreflightResponse(); });
|
||||
server->route(QStringLiteral("/api/v1/discovery/stop"), QHttpServerRequest::Method::Options, routeContext,
|
||||
[]() { return corsPreflightResponse(); });
|
||||
server->route(QStringLiteral("/api/v1/discovery/status"), QHttpServerRequest::Method::Options, routeContext,
|
||||
[]() { return corsPreflightResponse(); });
|
||||
server->route(QStringLiteral("/api/v1/discovery/clear"), QHttpServerRequest::Method::Options, routeContext,
|
||||
[]() { return corsPreflightResponse(); });
|
||||
server->route(QStringLiteral("/api/v1/discovery/samples"), QHttpServerRequest::Method::Options, routeContext,
|
||||
[]() { return corsPreflightResponse(); });
|
||||
server->route(QStringLiteral("/api/v1/mapping/bind"), QHttpServerRequest::Method::Options, routeContext,
|
||||
[]() { return corsPreflightResponse(); });
|
||||
server->route(QStringLiteral("/api/v1/mapping/unbind"), QHttpServerRequest::Method::Options, routeContext,
|
||||
[]() { return corsPreflightResponse(); });
|
||||
server->route(QStringLiteral("/api/v1/mapping/list"), QHttpServerRequest::Method::Options, routeContext,
|
||||
[]() { return corsPreflightResponse(); });
|
||||
server->route(QStringLiteral("/api/v1/device-tree"), QHttpServerRequest::Method::Options, routeContext,
|
||||
[]() { return corsPreflightResponse(); });
|
||||
server->route(QStringLiteral("/api/v1/devices"), QHttpServerRequest::Method::Options, routeContext,
|
||||
[]() { return corsPreflightResponse(); });
|
||||
server->route(QStringLiteral("/api/v1/devices/<arg>"), QHttpServerRequest::Method::Options, routeContext,
|
||||
[](const QString&) { return corsPreflightResponse(); });
|
||||
server->route(QStringLiteral("/api/v1/device-tree/nodes/<arg>"), QHttpServerRequest::Method::Options, routeContext,
|
||||
[](const QString&) { return corsPreflightResponse(); });
|
||||
server->route(QStringLiteral("/api/v1/rules/status"), QHttpServerRequest::Method::Options, routeContext,
|
||||
[]() { return corsPreflightResponse(); });
|
||||
server->route(QStringLiteral("/api/v1/rules/filter"), QHttpServerRequest::Method::Options, routeContext,
|
||||
[]() { return corsPreflightResponse(); });
|
||||
server->route(QStringLiteral("/api/v1/rules/filter/<arg>"), QHttpServerRequest::Method::Options, routeContext,
|
||||
[](const QString&) { return corsPreflightResponse(); });
|
||||
server->route(QStringLiteral("/api/v1/rules/transform"), QHttpServerRequest::Method::Options, routeContext,
|
||||
[]() { return corsPreflightResponse(); });
|
||||
server->route(QStringLiteral("/api/v1/rules/transform/<arg>"), QHttpServerRequest::Method::Options, routeContext,
|
||||
[](const QString&) { return corsPreflightResponse(); });
|
||||
server->route(QStringLiteral("/api/v1/pipeline/status"), QHttpServerRequest::Method::Options, routeContext,
|
||||
[]() { return corsPreflightResponse(); });
|
||||
server->route(QStringLiteral("/api/v1/pipeline/counters"), QHttpServerRequest::Method::Options, routeContext,
|
||||
[]() { return corsPreflightResponse(); });
|
||||
server->route(QStringLiteral("/api/v1/pipeline/counters/clear"), QHttpServerRequest::Method::Options, routeContext,
|
||||
[]() { return corsPreflightResponse(); });
|
||||
server->route(QStringLiteral("/api/v1/pipeline/config"), QHttpServerRequest::Method::Options, routeContext,
|
||||
[]() { return corsPreflightResponse(); });
|
||||
server->route(QStringLiteral("/api/v1/plugins"), QHttpServerRequest::Method::Options, routeContext,
|
||||
[]() { return corsPreflightResponse(); });
|
||||
server->route(QStringLiteral("/api/v1/plugins/protocols"), QHttpServerRequest::Method::Options, routeContext,
|
||||
[]() { return corsPreflightResponse(); });
|
||||
server->route(QStringLiteral("/api/v1/plugins/mappers"), QHttpServerRequest::Method::Options, routeContext,
|
||||
[]() { return corsPreflightResponse(); });
|
||||
server->route(QStringLiteral("/api/v1/metadata"), QHttpServerRequest::Method::Options, routeContext,
|
||||
[]() { return corsPreflightResponse(); });
|
||||
server->route(QStringLiteral("/api/v1/metadata/<arg>"), QHttpServerRequest::Method::Options, routeContext,
|
||||
[](const QString&) { return corsPreflightResponse(); });
|
||||
server->route(QStringLiteral("/api/v1/profiles"), QHttpServerRequest::Method::Options, routeContext,
|
||||
[]() { return corsPreflightResponse(); });
|
||||
server->route(QStringLiteral("/api/v1/profiles/<arg>"), QHttpServerRequest::Method::Options, routeContext,
|
||||
[](const QString&) { return corsPreflightResponse(); });
|
||||
}
|
||||
|
||||
constexpr auto kProtectedNodeKeys = std::array{
|
||||
"id",
|
||||
"stableKey",
|
||||
"online",
|
||||
"lastSeenTs",
|
||||
};
|
||||
|
||||
softbus::core::models::ProtocolType protocolFromString(const QString& s)
|
||||
{
|
||||
const QString x = s.trimmed().toUpper();
|
||||
@@ -47,16 +150,190 @@ softbus::core::models::ProtocolType protocolFromString(const QString& s)
|
||||
return softbus::core::models::ProtocolType::UNKNOWN;
|
||||
}
|
||||
|
||||
QJsonObject parseJsonBody(const QHttpServerRequest& request)
|
||||
QJsonObject parseJsonBody(const QHttpServerRequest& request, bool* ok = nullptr)
|
||||
{
|
||||
QJsonParseError err;
|
||||
const auto doc = QJsonDocument::fromJson(request.body(), &err);
|
||||
if (err.error != QJsonParseError::NoError || !doc.isObject()) {
|
||||
const bool parsed = err.error == QJsonParseError::NoError && doc.isObject();
|
||||
if (ok) {
|
||||
*ok = parsed;
|
||||
}
|
||||
if (!parsed) {
|
||||
return {};
|
||||
}
|
||||
return doc.object();
|
||||
}
|
||||
|
||||
QHttpServerResponse jsonResponse(const QJsonObject& obj,
|
||||
QHttpServerResponse::StatusCode code = QHttpServerResponse::StatusCode::Ok)
|
||||
{
|
||||
return withCorsHeaders(QHttpServerResponse(obj, code));
|
||||
}
|
||||
|
||||
QHttpServerResponse okDataResponse(const QJsonValue& data,
|
||||
QHttpServerResponse::StatusCode code = QHttpServerResponse::StatusCode::Ok)
|
||||
{
|
||||
return jsonResponse(QJsonObject{{QStringLiteral("ok"), true}, {QStringLiteral("data"), data}}, code);
|
||||
}
|
||||
|
||||
QHttpServerResponse errorResponse(const QString& error,
|
||||
QHttpServerResponse::StatusCode code = QHttpServerResponse::StatusCode::BadRequest)
|
||||
{
|
||||
return jsonResponse(QJsonObject{{QStringLiteral("ok"), false}, {QStringLiteral("error"), error}}, code);
|
||||
}
|
||||
|
||||
QJsonObject deviceTreeNodeToJson(const DeviceTreeNode& node)
|
||||
{
|
||||
QJsonObject obj;
|
||||
obj.insert(QStringLiteral("id"), node.id);
|
||||
obj.insert(QStringLiteral("name"), node.name);
|
||||
obj.insert(QStringLiteral("type"), node.type);
|
||||
obj.insert(QStringLiteral("endpoint"), node.endpoint);
|
||||
obj.insert(QStringLiteral("driver"), node.driver);
|
||||
obj.insert(QStringLiteral("capabilitiesRef"), node.capabilitiesRef);
|
||||
obj.insert(QStringLiteral("params"), node.params);
|
||||
obj.insert(QStringLiteral("enabled"), node.enabled);
|
||||
QJsonArray children;
|
||||
for (const auto& child : node.childrenIds) {
|
||||
children.push_back(child);
|
||||
}
|
||||
obj.insert(QStringLiteral("children"), children);
|
||||
return obj;
|
||||
}
|
||||
|
||||
QJsonArray devicesToJson(const std::vector<softbus::devices::DeviceInfo>& devices)
|
||||
{
|
||||
QJsonArray out;
|
||||
for (const auto& device : devices) {
|
||||
out.push_back(device.toJsonObject());
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
QString resolveConfigBaseDir()
|
||||
{
|
||||
QString configBase = qEnvironmentVariable("SOFTBUS_CONFIG_DIR");
|
||||
if (!configBase.isEmpty()) {
|
||||
return configBase.endsWith(QChar('/')) ? configBase : configBase + QChar('/');
|
||||
}
|
||||
return QDir::homePath() + QStringLiteral("/softbus/config/");
|
||||
}
|
||||
|
||||
QString resolveConfigFile(const QString& fileName, const QString& fallbackRelative)
|
||||
{
|
||||
const QString homePath = resolveConfigBaseDir() + fileName;
|
||||
return QFileInfo::exists(homePath) ? homePath : fallbackRelative;
|
||||
}
|
||||
|
||||
bool ensureMetadataLoaded(softbus::core::metadata::MetadataRegistry& registry, QString* error)
|
||||
{
|
||||
static std::mutex mtx;
|
||||
static bool attempted = false;
|
||||
static bool loaded = false;
|
||||
std::lock_guard<std::mutex> lk(mtx);
|
||||
if (!attempted) {
|
||||
attempted = true;
|
||||
loaded = registry.loadFromFile(
|
||||
resolveConfigFile(QStringLiteral("metadata_dictionary.json"),
|
||||
QStringLiteral("config/metadata_dictionary.json")));
|
||||
}
|
||||
if (!loaded && error) {
|
||||
*error = registry.lastError();
|
||||
}
|
||||
return loaded;
|
||||
}
|
||||
|
||||
softbus::core::metadata::MetadataRegistry& metadataRegistry()
|
||||
{
|
||||
static softbus::core::metadata::MetadataRegistry registry;
|
||||
return registry;
|
||||
}
|
||||
|
||||
bool ensureProfileLoaded(softbus::core::metadata::ProfileRegistry& registry, QString* error)
|
||||
{
|
||||
static std::mutex mtx;
|
||||
static bool attempted = false;
|
||||
static bool loaded = false;
|
||||
std::lock_guard<std::mutex> lk(mtx);
|
||||
if (!attempted) {
|
||||
attempted = true;
|
||||
loaded = registry.loadFromFile(
|
||||
resolveConfigFile(QStringLiteral("device_profiles.json"),
|
||||
QStringLiteral("config/device_profiles.json")));
|
||||
}
|
||||
if (!loaded && error) {
|
||||
*error = registry.lastError();
|
||||
}
|
||||
return loaded;
|
||||
}
|
||||
|
||||
softbus::core::metadata::ProfileRegistry& profileRegistry()
|
||||
{
|
||||
static softbus::core::metadata::ProfileRegistry registry;
|
||||
return registry;
|
||||
}
|
||||
|
||||
bool isProtectedNodeKey(const QString& key)
|
||||
{
|
||||
for (const auto* value : kProtectedNodeKeys) {
|
||||
if (key == QLatin1String(value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool applyNodePatch(DeviceTreeNode& node, const QJsonObject& patch)
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
if (patch.contains(QStringLiteral("name")) && patch.value(QStringLiteral("name")).isString()) {
|
||||
node.name = patch.value(QStringLiteral("name")).toString();
|
||||
changed = true;
|
||||
}
|
||||
if (patch.contains(QStringLiteral("type")) && patch.value(QStringLiteral("type")).isString()) {
|
||||
node.type = patch.value(QStringLiteral("type")).toString();
|
||||
changed = true;
|
||||
}
|
||||
if (patch.contains(QStringLiteral("endpoint")) && patch.value(QStringLiteral("endpoint")).isString()) {
|
||||
node.endpoint = patch.value(QStringLiteral("endpoint")).toString();
|
||||
changed = true;
|
||||
}
|
||||
if (patch.contains(QStringLiteral("driver")) && patch.value(QStringLiteral("driver")).isString()) {
|
||||
node.driver = patch.value(QStringLiteral("driver")).toString();
|
||||
changed = true;
|
||||
}
|
||||
if (patch.contains(QStringLiteral("capabilitiesRef")) && patch.value(QStringLiteral("capabilitiesRef")).isString()) {
|
||||
node.capabilitiesRef = patch.value(QStringLiteral("capabilitiesRef")).toString();
|
||||
changed = true;
|
||||
}
|
||||
if (patch.contains(QStringLiteral("enabled")) && patch.value(QStringLiteral("enabled")).isBool()) {
|
||||
node.enabled = patch.value(QStringLiteral("enabled")).toBool();
|
||||
changed = true;
|
||||
}
|
||||
if (patch.contains(QStringLiteral("children")) && patch.value(QStringLiteral("children")).isArray()) {
|
||||
QVector<QString> children;
|
||||
for (const auto& child : patch.value(QStringLiteral("children")).toArray()) {
|
||||
if (child.isString()) {
|
||||
children.push_back(child.toString());
|
||||
}
|
||||
}
|
||||
node.childrenIds = children;
|
||||
changed = true;
|
||||
}
|
||||
if (patch.contains(QStringLiteral("params")) && patch.value(QStringLiteral("params")).isObject()) {
|
||||
const auto paramsPatch = patch.value(QStringLiteral("params")).toObject();
|
||||
for (auto it = paramsPatch.begin(); it != paramsPatch.end(); ++it) {
|
||||
if (isProtectedNodeKey(it.key())) {
|
||||
continue;
|
||||
}
|
||||
node.params.insert(it.key(), it.value());
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
void registerDiscoveryRoutes(QHttpServer* server, QObject* routeContext)
|
||||
{
|
||||
server->route(QStringLiteral("/api/v1/discovery/start"), QHttpServerRequest::Method::Post, routeContext,
|
||||
@@ -65,25 +342,25 @@ void registerDiscoveryRoutes(QHttpServer* server, QObject* routeContext)
|
||||
const auto payload = parseJsonBody(request);
|
||||
const std::int64_t ttlMs = payload.value(QStringLiteral("ttlMs")).toInteger(0);
|
||||
pool.startSniffing(ttlMs);
|
||||
return QHttpServerResponse(pool.status(), QHttpServerResponse::StatusCode::Ok);
|
||||
return withCorsHeaders(QHttpServerResponse(pool.status(), QHttpServerResponse::StatusCode::Ok));
|
||||
});
|
||||
|
||||
server->route(QStringLiteral("/api/v1/discovery/stop"), QHttpServerRequest::Method::Post, routeContext, []() {
|
||||
auto& pool = softbus::message_bus::pipeline::DiscoveryPool::instance();
|
||||
pool.stopSniffing();
|
||||
return QHttpServerResponse(pool.status(), QHttpServerResponse::StatusCode::Ok);
|
||||
return withCorsHeaders(QHttpServerResponse(pool.status(), QHttpServerResponse::StatusCode::Ok));
|
||||
});
|
||||
|
||||
server->route(QStringLiteral("/api/v1/discovery/status"), QHttpServerRequest::Method::Get, routeContext, []() {
|
||||
auto& pool = softbus::message_bus::pipeline::DiscoveryPool::instance();
|
||||
pool.tick();
|
||||
return QHttpServerResponse(pool.status(), QHttpServerResponse::StatusCode::Ok);
|
||||
return withCorsHeaders(QHttpServerResponse(pool.status(), QHttpServerResponse::StatusCode::Ok));
|
||||
});
|
||||
|
||||
server->route(QStringLiteral("/api/v1/discovery/clear"), QHttpServerRequest::Method::Post, routeContext, []() {
|
||||
auto& pool = softbus::message_bus::pipeline::DiscoveryPool::instance();
|
||||
pool.clear();
|
||||
return QHttpServerResponse(pool.status(), QHttpServerResponse::StatusCode::Ok);
|
||||
return withCorsHeaders(QHttpServerResponse(pool.status(), QHttpServerResponse::StatusCode::Ok));
|
||||
});
|
||||
|
||||
server->route(QStringLiteral("/api/v1/discovery/samples"), QHttpServerRequest::Method::Get, routeContext,
|
||||
@@ -108,7 +385,7 @@ void registerDiscoveryRoutes(QHttpServer* server, QObject* routeContext)
|
||||
o.insert(QStringLiteral("offset"), static_cast<qint64>(offset));
|
||||
o.insert(QStringLiteral("limit"), static_cast<qint64>(limit));
|
||||
o.insert(QStringLiteral("status"), pool.status());
|
||||
return QHttpServerResponse(o, QHttpServerResponse::StatusCode::Ok);
|
||||
return withCorsHeaders(QHttpServerResponse(o, QHttpServerResponse::StatusCode::Ok));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -126,14 +403,14 @@ void registerMappingRoutes(QHttpServer* server, QObject* routeContext)
|
||||
|
||||
auto& mappingReg = softbus::message_bus::pipeline::MappingRegistry::instance();
|
||||
if (!mappingReg.upsert(rule)) {
|
||||
return QHttpServerResponse(
|
||||
return withCorsHeaders(QHttpServerResponse(
|
||||
QJsonObject{{QStringLiteral("error"), QStringLiteral("invalid_mapping_rule")}},
|
||||
QHttpServerResponse::StatusCode::BadRequest);
|
||||
QHttpServerResponse::StatusCode::BadRequest));
|
||||
}
|
||||
return QHttpServerResponse(QJsonObject{{QStringLiteral("ok"), true},
|
||||
return withCorsHeaders(QHttpServerResponse(QJsonObject{{QStringLiteral("ok"), true},
|
||||
{QStringLiteral("compositeKey"),
|
||||
QString::number(rule.compositeKey)}},
|
||||
QHttpServerResponse::StatusCode::Ok);
|
||||
QHttpServerResponse::StatusCode::Ok));
|
||||
});
|
||||
|
||||
server->route(QStringLiteral("/api/v1/mapping/unbind"), QHttpServerRequest::Method::Post, routeContext,
|
||||
@@ -143,20 +420,264 @@ void registerMappingRoutes(QHttpServer* server, QObject* routeContext)
|
||||
payload.value(QStringLiteral("compositeKey")).toString().toULongLong();
|
||||
auto& mappingReg = softbus::message_bus::pipeline::MappingRegistry::instance();
|
||||
const bool ok = mappingReg.remove(compositeKey);
|
||||
return QHttpServerResponse(QJsonObject{{QStringLiteral("ok"), ok},
|
||||
return withCorsHeaders(QHttpServerResponse(QJsonObject{{QStringLiteral("ok"), ok},
|
||||
{QStringLiteral("compositeKey"),
|
||||
QString::number(compositeKey)}},
|
||||
ok ? QHttpServerResponse::StatusCode::Ok
|
||||
: QHttpServerResponse::StatusCode::NotFound);
|
||||
: QHttpServerResponse::StatusCode::NotFound));
|
||||
});
|
||||
|
||||
server->route(QStringLiteral("/api/v1/mapping/list"), QHttpServerRequest::Method::Get, routeContext, []() {
|
||||
auto& mappingReg = softbus::message_bus::pipeline::MappingRegistry::instance();
|
||||
return QHttpServerResponse(QJsonObject{{QStringLiteral("items"), mappingReg.list()}},
|
||||
QHttpServerResponse::StatusCode::Ok);
|
||||
return withCorsHeaders(
|
||||
QHttpServerResponse(QJsonObject{{QStringLiteral("items"), mappingReg.list()}},
|
||||
QHttpServerResponse::StatusCode::Ok));
|
||||
});
|
||||
}
|
||||
|
||||
void registerDeviceRoutes(QHttpServer* server, QObject* routeContext)
|
||||
{
|
||||
server->route(QStringLiteral("/api/v1/device-tree"), QHttpServerRequest::Method::Get, routeContext, []() {
|
||||
auto model = softbus::device_bus::DeviceBus::instance().deviceTreeModel();
|
||||
if (!model) {
|
||||
return errorResponse(QStringLiteral("device_tree_unavailable"),
|
||||
QHttpServerResponse::StatusCode::ServiceUnavailable);
|
||||
}
|
||||
return okDataResponse(model->toDeviceTreeJson());
|
||||
});
|
||||
|
||||
server->route(QStringLiteral("/api/v1/devices"), QHttpServerRequest::Method::Get, routeContext, []() {
|
||||
return okDataResponse(devicesToJson(softbus::device_bus::DeviceBus::instance().listDevices()));
|
||||
});
|
||||
|
||||
server->route(QStringLiteral("/api/v1/devices/<arg>"), QHttpServerRequest::Method::Get, routeContext,
|
||||
[](int id) {
|
||||
const auto device = softbus::device_bus::DeviceBus::instance().findDeviceById(id);
|
||||
if (!device.has_value()) {
|
||||
return errorResponse(QStringLiteral("device_not_found"),
|
||||
QHttpServerResponse::StatusCode::NotFound);
|
||||
}
|
||||
return okDataResponse(device->toJsonObject());
|
||||
});
|
||||
|
||||
server->route(QStringLiteral("/api/v1/device-tree/nodes/<arg>"), QHttpServerRequest::Method::Patch, routeContext,
|
||||
[](const QString& id, const QHttpServerRequest& request) {
|
||||
bool bodyOk = false;
|
||||
const auto patch = parseJsonBody(request, &bodyOk);
|
||||
if (!bodyOk) {
|
||||
return errorResponse(QStringLiteral("invalid_json"),
|
||||
QHttpServerResponse::StatusCode::BadRequest);
|
||||
}
|
||||
|
||||
auto model = softbus::device_bus::DeviceBus::instance().deviceTreeModel();
|
||||
if (!model) {
|
||||
return errorResponse(QStringLiteral("device_tree_unavailable"),
|
||||
QHttpServerResponse::StatusCode::ServiceUnavailable);
|
||||
}
|
||||
const int index = model->findIndexById(id);
|
||||
if (index < 0) {
|
||||
return errorResponse(QStringLiteral("device_tree_node_not_found"),
|
||||
QHttpServerResponse::StatusCode::NotFound);
|
||||
}
|
||||
|
||||
auto& node = model->nodesMutable()[index];
|
||||
const bool changed = applyNodePatch(node, patch);
|
||||
if (!changed) {
|
||||
return errorResponse(QStringLiteral("no_mutable_fields_provided"),
|
||||
QHttpServerResponse::StatusCode::BadRequest);
|
||||
}
|
||||
|
||||
model->rebuildIndex();
|
||||
auto& bus = softbus::device_bus::DeviceBus::instance();
|
||||
bus.markDeviceTreeDirty();
|
||||
(void)bus.reconcileFromTreeModel();
|
||||
return okDataResponse(deviceTreeNodeToJson(model->nodes().at(index)));
|
||||
});
|
||||
}
|
||||
|
||||
void registerRuleRoutes(QHttpServer* server,
|
||||
QObject* routeContext,
|
||||
softbus::api::ipc::CommandDispatcher* dispatcher)
|
||||
{
|
||||
server->route(QStringLiteral("/api/v1/rules/status"), QHttpServerRequest::Method::Get, routeContext, []() {
|
||||
return okDataResponse(softbus::message_bus::pipeline::DynamicRuleRegistry::instance().status());
|
||||
});
|
||||
|
||||
server->route(QStringLiteral("/api/v1/rules/filter"), QHttpServerRequest::Method::Post, routeContext,
|
||||
[dispatcher](const QHttpServerRequest& request) {
|
||||
bool bodyOk = false;
|
||||
const auto payload = parseJsonBody(request, &bodyOk);
|
||||
if (!bodyOk) {
|
||||
return errorResponse(QStringLiteral("invalid_json"),
|
||||
QHttpServerResponse::StatusCode::BadRequest);
|
||||
}
|
||||
const auto result = dispatcher->dispatch(QStringLiteral("add_filter"), payload);
|
||||
return withCorsHeaders(makeCommandHttpResponse(QString(), result));
|
||||
});
|
||||
|
||||
server->route(QStringLiteral("/api/v1/rules/filter/<arg>"), QHttpServerRequest::Method::Delete, routeContext,
|
||||
[dispatcher](const QString& id) {
|
||||
const auto result = dispatcher->dispatch(QStringLiteral("remove_filter"),
|
||||
QJsonObject{{QStringLiteral("id"), id}});
|
||||
return withCorsHeaders(makeCommandHttpResponse(QString(), result));
|
||||
});
|
||||
|
||||
server->route(QStringLiteral("/api/v1/rules/transform"), QHttpServerRequest::Method::Post, routeContext,
|
||||
[dispatcher](const QHttpServerRequest& request) {
|
||||
bool bodyOk = false;
|
||||
const auto payload = parseJsonBody(request, &bodyOk);
|
||||
if (!bodyOk) {
|
||||
return errorResponse(QStringLiteral("invalid_json"),
|
||||
QHttpServerResponse::StatusCode::BadRequest);
|
||||
}
|
||||
const auto result = dispatcher->dispatch(QStringLiteral("add_transform_rule"), payload);
|
||||
return withCorsHeaders(makeCommandHttpResponse(QString(), result));
|
||||
});
|
||||
|
||||
server->route(QStringLiteral("/api/v1/rules/transform/<arg>"), QHttpServerRequest::Method::Delete, routeContext,
|
||||
[dispatcher](const QString& id) {
|
||||
const auto result = dispatcher->dispatch(QStringLiteral("remove_transform_rule"),
|
||||
QJsonObject{{QStringLiteral("id"), id}});
|
||||
return withCorsHeaders(makeCommandHttpResponse(QString(), result));
|
||||
});
|
||||
}
|
||||
|
||||
void registerPipelineRoutes(QHttpServer* server, QObject* routeContext)
|
||||
{
|
||||
server->route(QStringLiteral("/api/v1/pipeline/status"), QHttpServerRequest::Method::Get, routeContext, []() {
|
||||
auto* pipeline = softbus::device_bus::DeviceBus::instance().pipelineEngine();
|
||||
if (!pipeline) {
|
||||
return errorResponse(QStringLiteral("pipeline_unavailable"),
|
||||
QHttpServerResponse::StatusCode::ServiceUnavailable);
|
||||
}
|
||||
return okDataResponse(pipeline->status());
|
||||
});
|
||||
|
||||
server->route(QStringLiteral("/api/v1/pipeline/counters"), QHttpServerRequest::Method::Get, routeContext, []() {
|
||||
auto* pipeline = softbus::device_bus::DeviceBus::instance().pipelineEngine();
|
||||
if (!pipeline) {
|
||||
return errorResponse(QStringLiteral("pipeline_unavailable"),
|
||||
QHttpServerResponse::StatusCode::ServiceUnavailable);
|
||||
}
|
||||
return okDataResponse(pipeline->countersJson());
|
||||
});
|
||||
|
||||
server->route(QStringLiteral("/api/v1/pipeline/counters/clear"), QHttpServerRequest::Method::Post, routeContext, []() {
|
||||
auto* pipeline = softbus::device_bus::DeviceBus::instance().pipelineEngine();
|
||||
if (!pipeline) {
|
||||
return errorResponse(QStringLiteral("pipeline_unavailable"),
|
||||
QHttpServerResponse::StatusCode::ServiceUnavailable);
|
||||
}
|
||||
pipeline->resetCounters();
|
||||
return okDataResponse(pipeline->countersJson());
|
||||
});
|
||||
|
||||
server->route(QStringLiteral("/api/v1/pipeline/config"), QHttpServerRequest::Method::Get, routeContext, []() {
|
||||
auto* pipeline = softbus::device_bus::DeviceBus::instance().pipelineEngine();
|
||||
if (!pipeline) {
|
||||
return errorResponse(QStringLiteral("pipeline_unavailable"),
|
||||
QHttpServerResponse::StatusCode::ServiceUnavailable);
|
||||
}
|
||||
return okDataResponse(pipeline->runtimeConfigJson());
|
||||
});
|
||||
}
|
||||
|
||||
void registerPluginRoutes(QHttpServer* server, QObject* routeContext)
|
||||
{
|
||||
server->route(QStringLiteral("/api/v1/plugins"), QHttpServerRequest::Method::Get, routeContext, []() {
|
||||
auto pluginManager = softbus::device_bus::DeviceBus::instance().pluginManager();
|
||||
if (!pluginManager) {
|
||||
return errorResponse(QStringLiteral("plugin_manager_unavailable"),
|
||||
QHttpServerResponse::StatusCode::ServiceUnavailable);
|
||||
}
|
||||
QJsonArray items;
|
||||
for (const auto& entry : pluginManager->protocolPluginsSnapshot()) {
|
||||
items.push_back(entry);
|
||||
}
|
||||
for (const auto& entry : pluginManager->protocolFramerPluginsSnapshot()) {
|
||||
items.push_back(entry);
|
||||
}
|
||||
for (const auto& entry : pluginManager->protocolMapperPluginsSnapshot()) {
|
||||
items.push_back(entry);
|
||||
}
|
||||
return okDataResponse(items);
|
||||
});
|
||||
|
||||
server->route(QStringLiteral("/api/v1/plugins/protocols"), QHttpServerRequest::Method::Get, routeContext, []() {
|
||||
auto pluginManager = softbus::device_bus::DeviceBus::instance().pluginManager();
|
||||
if (!pluginManager) {
|
||||
return errorResponse(QStringLiteral("plugin_manager_unavailable"),
|
||||
QHttpServerResponse::StatusCode::ServiceUnavailable);
|
||||
}
|
||||
return okDataResponse(pluginManager->protocolCapabilitiesSnapshot());
|
||||
});
|
||||
|
||||
server->route(QStringLiteral("/api/v1/plugins/mappers"), QHttpServerRequest::Method::Get, routeContext, []() {
|
||||
auto pluginManager = softbus::device_bus::DeviceBus::instance().pluginManager();
|
||||
if (!pluginManager) {
|
||||
return errorResponse(QStringLiteral("plugin_manager_unavailable"),
|
||||
QHttpServerResponse::StatusCode::ServiceUnavailable);
|
||||
}
|
||||
return okDataResponse(pluginManager->protocolMapperPluginsSnapshot());
|
||||
});
|
||||
}
|
||||
|
||||
void registerMetadataRoutes(QHttpServer* server, QObject* routeContext)
|
||||
{
|
||||
server->route(QStringLiteral("/api/v1/metadata"), QHttpServerRequest::Method::Get, routeContext, []() {
|
||||
auto& registry = metadataRegistry();
|
||||
QString error;
|
||||
if (!ensureMetadataLoaded(registry, &error)) {
|
||||
return errorResponse(error.isEmpty() ? QStringLiteral("metadata_unavailable") : error,
|
||||
QHttpServerResponse::StatusCode::ServiceUnavailable);
|
||||
}
|
||||
return okDataResponse(registry.list());
|
||||
});
|
||||
|
||||
server->route(QStringLiteral("/api/v1/metadata/<arg>"), QHttpServerRequest::Method::Get, routeContext,
|
||||
[](const QString& metadataId) {
|
||||
auto& registry = metadataRegistry();
|
||||
QString error;
|
||||
if (!ensureMetadataLoaded(registry, &error)) {
|
||||
return errorResponse(error.isEmpty() ? QStringLiteral("metadata_unavailable") : error,
|
||||
QHttpServerResponse::StatusCode::ServiceUnavailable);
|
||||
}
|
||||
const auto items = registry.list();
|
||||
for (const auto& item : items) {
|
||||
const auto obj = item.toObject();
|
||||
if (obj.value(QStringLiteral("metadataId")).toString() == metadataId) {
|
||||
return okDataResponse(obj);
|
||||
}
|
||||
}
|
||||
return errorResponse(QStringLiteral("metadata_not_found"),
|
||||
QHttpServerResponse::StatusCode::NotFound);
|
||||
});
|
||||
}
|
||||
|
||||
void registerProfileRoutes(QHttpServer* server, QObject* routeContext)
|
||||
{
|
||||
server->route(QStringLiteral("/api/v1/profiles"), QHttpServerRequest::Method::Get, routeContext, []() {
|
||||
auto& registry = profileRegistry();
|
||||
QString error;
|
||||
if (!ensureProfileLoaded(registry, &error)) {
|
||||
return errorResponse(error.isEmpty() ? QStringLiteral("profiles_unavailable") : error,
|
||||
QHttpServerResponse::StatusCode::ServiceUnavailable);
|
||||
}
|
||||
return okDataResponse(registry.list());
|
||||
});
|
||||
|
||||
server->route(QStringLiteral("/api/v1/profiles/<arg>"), QHttpServerRequest::Method::Get, routeContext,
|
||||
[](const QString& deviceId) {
|
||||
auto& registry = profileRegistry();
|
||||
QString error;
|
||||
if (!ensureProfileLoaded(registry, &error)) {
|
||||
return errorResponse(error.isEmpty() ? QStringLiteral("profiles_unavailable") : error,
|
||||
QHttpServerResponse::StatusCode::ServiceUnavailable);
|
||||
}
|
||||
return okDataResponse(registry.listByDeviceId(deviceId));
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void registerSoftbusRestApiRoutes(QHttpServer* server,
|
||||
@@ -168,24 +689,33 @@ void registerSoftbusRestApiRoutes(QHttpServer* server,
|
||||
}
|
||||
|
||||
server->route(QStringLiteral("/health"), QHttpServerRequest::Method::Get, routeContext, []() {
|
||||
return QHttpServerResponse(QJsonObject{{QStringLiteral("ok"), true}}, QHttpServerResponse::StatusCode::Ok);
|
||||
return withCorsHeaders(
|
||||
QHttpServerResponse(QJsonObject{{QStringLiteral("ok"), true}}, QHttpServerResponse::StatusCode::Ok));
|
||||
});
|
||||
|
||||
server->route(QStringLiteral("/v1/status"), QHttpServerRequest::Method::Get, routeContext, [dispatcher]() {
|
||||
return makeCommandHttpResponse(QString(), dispatcher->dispatch(QStringLiteral("get_status"), {}));
|
||||
return withCorsHeaders(makeCommandHttpResponse(QString(), dispatcher->dispatch(QStringLiteral("get_status"), {})));
|
||||
});
|
||||
|
||||
server->route(QStringLiteral("/v1/command"), QHttpServerRequest::Method::Post, routeContext,
|
||||
[dispatcher](const QHttpServerRequest& request) {
|
||||
return handleExecuteCommandHttpBody(request.body(), *dispatcher);
|
||||
return withCorsHeaders(handleExecuteCommandHttpBody(request.body(), *dispatcher));
|
||||
});
|
||||
|
||||
registerCorsPreflightRoutes(server, routeContext);
|
||||
registerDiscoveryRoutes(server, routeContext);
|
||||
registerMappingRoutes(server, routeContext);
|
||||
registerDeviceRoutes(server, routeContext);
|
||||
registerRuleRoutes(server, routeContext, dispatcher);
|
||||
registerPipelineRoutes(server, routeContext);
|
||||
registerPluginRoutes(server, routeContext);
|
||||
registerMetadataRoutes(server, routeContext);
|
||||
registerProfileRoutes(server, routeContext);
|
||||
|
||||
server->setMissingHandler(routeContext, [](const QHttpServerRequest&, QHttpServerResponder& responder) {
|
||||
QHttpServerResponse resp(QJsonObject{{QStringLiteral("error"), QStringLiteral("not_found")}},
|
||||
QHttpServerResponse::StatusCode::NotFound);
|
||||
responder.sendResponse(std::move(resp));
|
||||
responder.sendResponse(withCorsHeaders(std::move(resp)));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,17 @@
|
||||
#include "api/ipc_dbus/CommandDispatcher.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QSaveFile>
|
||||
|
||||
#include "device_bus/DeviceBus.h"
|
||||
#include "message_bus/pipeline/rules/DynamicRuleRegistry.h"
|
||||
#include "message_bus/pipeline/discovery/DiscoveryPool.h"
|
||||
#include "message_bus/pipeline/mapping/MappingRegistry.h"
|
||||
#include "utils/logs/logging.h"
|
||||
|
||||
namespace softbus::api::ipc
|
||||
{
|
||||
@@ -10,6 +19,16 @@ namespace softbus::api::ipc
|
||||
namespace
|
||||
{
|
||||
|
||||
QString rulesConfigPath()
|
||||
{
|
||||
const QString daemonConfigPath = softbus::device_bus::DeviceBus::instance().configPath();
|
||||
if (!daemonConfigPath.isEmpty()) {
|
||||
const QFileInfo fi(daemonConfigPath);
|
||||
return fi.dir().filePath(QStringLiteral("runtime_rules.json"));
|
||||
}
|
||||
return QDir::homePath() + QStringLiteral("/softbus/config/runtime_rules.json");
|
||||
}
|
||||
|
||||
softbus::message_bus::pipeline::RuleScope parseScope(const QJsonObject& params)
|
||||
{
|
||||
softbus::message_bus::pipeline::RuleScope scope;
|
||||
@@ -19,6 +38,89 @@ softbus::message_bus::pipeline::RuleScope parseScope(const QJsonObject& params)
|
||||
return scope;
|
||||
}
|
||||
|
||||
QJsonObject scopeToJson(const softbus::message_bus::pipeline::RuleScope& scope)
|
||||
{
|
||||
QJsonObject out;
|
||||
if (scope.endpointHash != 0) {
|
||||
out.insert(QStringLiteral("endpointHash"), static_cast<qint64>(scope.endpointHash));
|
||||
}
|
||||
if (scope.deviceId >= 0) {
|
||||
out.insert(QStringLiteral("deviceId"), scope.deviceId);
|
||||
}
|
||||
if (!scope.stableKey.isEmpty()) {
|
||||
out.insert(QStringLiteral("stableKey"), scope.stableKey);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
QJsonObject filterRuleToJson(const softbus::message_bus::pipeline::FilterRule& rule)
|
||||
{
|
||||
QJsonObject out;
|
||||
out.insert(QStringLiteral("id"), rule.id);
|
||||
out.insert(QStringLiteral("scope"), scopeToJson(rule.scope));
|
||||
out.insert(QStringLiteral("condition"), rule.condition);
|
||||
return out;
|
||||
}
|
||||
|
||||
QJsonObject transformRuleToJson(const softbus::message_bus::pipeline::TransformRule& rule)
|
||||
{
|
||||
QJsonObject out;
|
||||
out.insert(QStringLiteral("id"), rule.id);
|
||||
out.insert(QStringLiteral("scope"), scopeToJson(rule.scope));
|
||||
out.insert(QStringLiteral("scale"), rule.scale);
|
||||
out.insert(QStringLiteral("offset"), rule.offset);
|
||||
if (!rule.unit.isEmpty()) {
|
||||
out.insert(QStringLiteral("unit"), rule.unit);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
bool persistRulesToDedicatedConfig(const softbus::message_bus::pipeline::DynamicRuleRegistry& reg)
|
||||
{
|
||||
const QString configPath = rulesConfigPath();
|
||||
if (configPath.isEmpty()) {
|
||||
LOG_ERROR() << "CommandDispatcher: rules config path is empty, cannot persist rules";
|
||||
return false;
|
||||
}
|
||||
|
||||
const QFileInfo fi(configPath);
|
||||
QJsonArray filtersJson;
|
||||
for (const auto& rule : reg.snapshotAllFilterRules()) {
|
||||
filtersJson.push_back(filterRuleToJson(rule));
|
||||
}
|
||||
QJsonArray transformsJson;
|
||||
for (const auto& rule : reg.snapshotAllTransformRules()) {
|
||||
transformsJson.push_back(transformRuleToJson(rule));
|
||||
}
|
||||
|
||||
QJsonObject root;
|
||||
root.insert(QStringLiteral("filter"), filtersJson);
|
||||
root.insert(QStringLiteral("transform"), transformsJson);
|
||||
|
||||
if (!QDir().mkpath(fi.dir().absolutePath())) {
|
||||
LOG_ERROR() << "CommandDispatcher: failed to create rules config directory:" << fi.dir().absolutePath();
|
||||
return false;
|
||||
}
|
||||
|
||||
const QByteArray bytes = QJsonDocument(root).toJson(QJsonDocument::Indented);
|
||||
QSaveFile out(configPath);
|
||||
if (!out.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
LOG_ERROR() << "CommandDispatcher: failed to open rules config for write:" << configPath;
|
||||
return false;
|
||||
}
|
||||
if (out.write(bytes) != bytes.size()) {
|
||||
LOG_ERROR() << "CommandDispatcher: failed to write rules config:" << configPath;
|
||||
out.cancelWriting();
|
||||
return false;
|
||||
}
|
||||
if (!out.commit()) {
|
||||
LOG_ERROR() << "CommandDispatcher: failed to commit rules config:" << configPath;
|
||||
return false;
|
||||
}
|
||||
LOG_INFO() << "CommandDispatcher: rules persisted to" << configPath;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
DispatchResult CommandDispatcher::dispatch(const QString& action, const QJsonObject& params) const
|
||||
@@ -34,11 +136,17 @@ DispatchResult CommandDispatcher::dispatch(const QString& action, const QJsonObj
|
||||
if (!reg.addFilterRule(rule)) {
|
||||
return {4001, QStringLiteral("invalid_filter_rule"), {}};
|
||||
}
|
||||
if (!persistRulesToDedicatedConfig(reg)) {
|
||||
return {5001, QStringLiteral("persist_rules_failed"), {}};
|
||||
}
|
||||
return {0, QStringLiteral("ok"), QJsonObject{{QStringLiteral("id"), rule.id}}};
|
||||
}
|
||||
if (action == QStringLiteral("remove_filter")) {
|
||||
const QString id = params.value(QStringLiteral("id")).toString();
|
||||
const bool ok = reg.removeFilterRule(id);
|
||||
if (ok && !persistRulesToDedicatedConfig(reg)) {
|
||||
return {5001, QStringLiteral("persist_rules_failed"), {}};
|
||||
}
|
||||
return {ok ? 0 : 4041, ok ? QStringLiteral("ok") : QStringLiteral("filter_not_found"),
|
||||
QJsonObject{{QStringLiteral("id"), id}}};
|
||||
}
|
||||
@@ -52,11 +160,17 @@ DispatchResult CommandDispatcher::dispatch(const QString& action, const QJsonObj
|
||||
if (!reg.addTransformRule(rule)) {
|
||||
return {4002, QStringLiteral("invalid_transform_rule"), {}};
|
||||
}
|
||||
if (!persistRulesToDedicatedConfig(reg)) {
|
||||
return {5001, QStringLiteral("persist_rules_failed"), {}};
|
||||
}
|
||||
return {0, QStringLiteral("ok"), QJsonObject{{QStringLiteral("id"), rule.id}}};
|
||||
}
|
||||
if (action == QStringLiteral("remove_transform_rule")) {
|
||||
const QString id = params.value(QStringLiteral("id")).toString();
|
||||
const bool ok = reg.removeTransformRule(id);
|
||||
if (ok && !persistRulesToDedicatedConfig(reg)) {
|
||||
return {5001, QStringLiteral("persist_rules_failed"), {}};
|
||||
}
|
||||
return {ok ? 0 : 4042, ok ? QStringLiteral("ok") : QStringLiteral("transform_rule_not_found"),
|
||||
QJsonObject{{QStringLiteral("id"), id}}};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user