Skip to content
EN

后端开发

后端基于 C++17 和 CMake 构建,提供运行时服务、媒体处理、NN 推理、API 路由、事件输出和场景任务编排,最终链接为单一可执行文件 cosmo-engine

架构概览

CMake 构建以对象库形式按分层组织,各层之间单向依赖(上层依赖下层,反之不可):

Layer 0 (基础层)         cosmo_util  cosmo_db  cosmo_platform  cosmo_mem
Layer 1 (基础设施层)     cosmo_media  cosmo_infer  cosmo_network  cosmo_nn
Layer 2 (业务层)         cosmo_flow  cosmo_service  cosmo_linkage
Layer 3 (接口层)         cosmo_api

每个对象库对应 src/ 下的一个源码目录。

构建系统

构建入口

文件 / 脚本用途
scripts/build_cpu.shx86 CPU 后端构建
scripts/build_cpu_test.shCPU 测试构建(cosmo-tests
scripts/build.shSophon / aarch64 构建
CMakeLists.txt顶层构建和打包入口

CMake 选项

选项默认值说明
COSMO_TARGET_ARCHaarch64目标架构:aarch64x86_64
COSMO_NN_USE_SOPHON_BACKENDON启用 Sophon TPU 后端
COSMO_NN_USE_CPU_BACKENDOFF启用 CPU / ONNX Runtime 后端
COSMO_ENABLE_OPENH264自动启用 OpenH264(CPU 后端时自动开启)
COSMO_DEV_MODEOFF开发模式,跳过看门狗等生产校验
COSMO_MODEL_GUARD自动链接 libcosmo_model_guard.so(Sophon 默认开启)
BUILD_TESTSOFF构建 cosmo-tests,含 Catch2 + gcov

COSMO_NN_USE_SOPHON_BACKENDCOSMO_NN_USE_CPU_BACKEND 互斥。选择 CPU 后端时会自动启用 COSMO_ENABLE_OPENH264 并禁用 COSMO_MODEL_GUARD

服务层与依赖注入

ServiceRegistry

所有后端服务通过 cosmo::service::ServiceRegistry 装配。它是一个以 std::type_index 为 key 的线程安全 DI 容器。

cpp
// 生产环境注册(持有所有权,ShutdownAll 时按注册逆序销毁)
ServiceRegistry::Instance().Register<IFooService>(std::make_unique<FooServiceImpl>());

// 测试 / Mock 注入(不持有所有权)
ServiceRegistry::Instance().Set<IFooService>(&mockFoo);

// 获取服务
auto& foo = ServiceRegistry::Instance().Get<IFooService>();

启动流程

服务初始化在 src/app/app_init.cc 中完成,由 SwDeviceInit() 按四阶段调用:

阶段一 — RegisterInfrastructureServices() 注册基础设施服务:IFileServiceIEventNotifier(WebSocket 推送)、IMemoryPoolServiceIStorageCleanServiceIWatchDogServiceIDbService(SQLite)、IOsdTextRendererIVideoFrameServiceITaskServiceIInferPoolServiceILlmInferServiceINetworkServiceIDeviceDiscoveryServiceIHttpClient

阶段二 — RegisterBusinessServices() 注册业务服务:音频、联动、摄像头、图片任务、算法、设备信息、时间(NTP)、系统配置、模型管理、告警记录/推送、认证、计划任务、人脸/人体/物品底库、直播流、动作、客户端消息、应用信息、定时重启。

阶段三 — InitializeServices() 按依赖顺序调用各服务的 Init():OSD 字体加载 → 算法服务 → 网络服务 → 数据库 → 告警推送 → 模型 → 设备信息 → 定时重启 → 人脸数据加载 → 摄像头实体初始化 → 应用信息 → MQTT 启动。

阶段四 — InitializeExternalComponents() 启动 HTTP 服务器、WebSocket 服务器、设备发现多播、存储清理定时器、硬件看门狗(COSMO_DEV_MODE 下跳过)。

新增服务

  1. src/service/<domain>/ 下定义接口(如有对应基础接口则继承)。
  2. 在同一目录下编写实现类。
  3. src/app/app_init.cc 的对应阶段中注册:
    cpp
    ServiceRegistry::Instance().Register<IMyService>(std::make_unique<MyServiceImpl>());
    如果一个实现类同时对外暴露多个窄接口,通过 Set<>() 添加别名:
    cpp
    ServiceRegistry::Instance().Set<IMyQuery>(&ServiceRegistry::Instance().Get<IMyService>());
  4. 将实现文件加入 src/service/CMakeLists.txt

销毁由 SwDeviceDestroy() 自动处理:调用 ServiceRegistry::ShutdownAll() 按注册逆序销毁所有持有所有权的服务。

API 路由

路由注册

API 路由定义在 src/api/ApiRouter.ccsrc/api/ApiRouterRoutes.cc 中。系统创建两个 ApiRouter 实例:一个处理 HTTP 请求(MessageFromHttp),一个处理 MQTT 下发请求(MessageFromMqtt),两者共享同一份路由表。

路由注册使用宏模式(定义在 ApiRouterInternal.h):

cpp
ROUTE("/gtw/cwai/System/", kAuth, system_handler_, System, QueryDeviceInfo);

宏把路径前缀和最后一个参数 X 拼接为完整 URL;上例注册 /gtw/cwai/System/QueryDeviceInfo。不要把完整端点作为第一个参数,否则会再次拼接 QueryDeviceInfo

展开后完成以下流程:

  1. 通过 util::ToLower 注册并匹配大小写不敏感的完整 URL。
  2. kAuth 校验 HTTP mtkkNoAuth 允许匿名访问。
  3. 将请求 JSON 反序列化为 NS::MsgQueryDeviceInfoSend
  4. 调用对应的 handler 方法。
  5. 将响应 NS::MsgQueryDeviceInfoRecv 序列化为 JSON 返回。

需要上传会话主体、已认证 principal 等请求上下文时使用 ROUTE_CONTEXT;Core DTO 使用 ROUTE_COREROUTE_CORE_CONTEXT。这些宏仍要求传入路径前缀,而不是完整端点。

标准响应信封

大多数管理端响应继承 MsgSendHead

字段类型说明
resCodenumber1 成功,0 失败
resMsgobject[]错误或提示信息列表
resultCodestringChinaMobile 兼容响应码
resultMsgstringChinaMobile 兼容响应文本

MsgSendHead 本身不声明 resData;具体响应 DTO 在公共响应头之外定义自己的业务数据字段。

新增路由组

  1. src/api/ 下创建 handler 类(如 MessageMyHandler.h/.cc)。
  2. 定义 Send/Recv 结构体和 handler 方法。
  3. 编写 RegisterMyRoutes() 函数,为每个端点调用 ROUTEROUTE_CORE
  4. ApiRouter 构造函数中调用 RegisterMyRoutes()

路由组一览

注册函数URL 前缀领域
RegisterCoreRoutes()/v1/cwai/aihost//gtw/cwai/aihost//gtw/cwai/login/核心、兼容入口、登录
RegisterNetworkRoutes()/gtw/cwai/network/网络、DNS、NTP
RegisterAlgorithmRoutes()/gtw/cwai/Algorithm//gtw/cwai/algorithm/layout/算法管理、编排
RegisterModelRoutes()/gtw/cwai/atomic/Model/模型仓库
RegisterScheduleRoutes()/gtw/cwai/schedule/时间模板
RegisterEventRoutes()/gtw/cwai/Event/事件、告警
RegisterCameraRoutes()/gtw/cwai/Camera/摄像头、USB
RegisterTaskRoutes()/gtw/cwai/Task/场景任务
RegisterSystemRoutes()/gtw/cwai/System/设备、升级、调试
RegisterLibraryRoutes()/gtw/cwai/Library//BodyLibrary//ThingsLibrary/人脸、人体、物品底库
RegisterFileRoutes()/gtw/cwai/File/文件导入
RegisterAudioRoutes()/gtw/cwai/Audio/音频文件、设备
RegisterLinkageRoutes()/gtw/cwai/AlarmStrage/告警联动
RegisterLiveStreamRoutes()/gtw/cwai/LiveStream/直播流生命周期
RegisterOnboardingRoutes()/gtw/cwai/Onboarding/首次使用引导

测试

框架

测试使用 Catch2 + Trompeloeil mock 框架。测试文件放在 test/,可复用的服务 mock 位于 test/mock/

构建和运行

bash
bash scripts/build_cpu_test.sh
./build_cpu/cosmo-tests

Mock

ServiceRegistry::Set<T>(ptr) 不持有所有权的注入方式是测试中替换真实服务的主要手段。 每个常用接口在 test/mock/Mock*Service.h 中维护独立 mock; test/mock/MockServiceRegistry.h.cc 负责把常用 mock 注册到测试用 ServiceRegistry

cpp
#include "mock/MockServiceRegistry.h"

cosmo::test::MockServiceRegistry mocks;

新增服务时,为接口增加对应的窄 mock;只有多个测试都需要统一依赖装配时,才把它加入 MockServiceRegistry 聚合器。

测试文件命名

测试文件遵循 test_<component>.cc 的命名规范,如:

  • test_service_registry.cc → 测试 ServiceRegistry
  • test_video_frame_service_impl.cc → 测试 VideoFrameServiceImpl
  • test_api_router.cc → 测试 ApiRouter

新增服务时,应增加覆盖其行为的测试文件,并为需要隔离的依赖提供 Trompeloeil mock。

代码风格

项目遵循 Google C++ Style Guide 并适配 C++17。完整规范见仓库根目录的 CODING_STYLE.md。核心约定速查:

类别约定示例
文件命名PascalCase,.h / .ccVideoFrameService.h
头文件保护#pragma once
命名空间cosmo:: 顶层;子模块按领域划分cosmo::mediacosmo::flow
类名PascalCaseVideoFrameServiceImpl
成员变量snake_case_(末尾下划线)video_width_
结构体成员snake_case(无末尾下划线)max_retries
函数名PascalCaseGetVideoFrame()
常量/constexprk + PascalCasekDefaultHttpPort
枚举值enum class + k + PascalCasekAlarmkInfo
布尔值is_ / has_ / should_ 前缀is_running_

严格规则:

  • 头文件中禁止 using namespace
  • 禁止裸 new / delete,统一使用 RAII 和智能指针。
  • 禁止 C 风格类型转换,使用 static_castconst_cast 等。
  • 禁止 #define 定义常量,使用 constexpr
  • 禁止魔数。
  • 全量要求 const 正确性。
  • 线程安全:共享标志位用 std::atomic,共享数据用锁守卫。

格式化和静态分析

bash
# 格式检查
bash scripts/format_check.sh --check          # 检查全部 src/ 和 test/
bash scripts/format_check.sh --staged --check # 仅检查暂存区
bash scripts/format_check.sh --fix            # 自动格式化

# 静态分析
bash scripts/static_analysis.sh --cppcheck
bash scripts/static_analysis.sh --clang-tidy  # 需要 compile_commands.json

配置文件位于仓库根目录:.clang-format.clang-tidy.cppcheck-suppressions

核心模块参考

Flow(src/flow/)— 算法流水线节点

flow 层实现场景任务流水线中的可组合节点:

子目录用途
action/动作实例、分支、动作管理器
alarm/区域告警、任务告警、告警抑制
channel/算法通道解码、解复用、MP4 录像、缓冲池
classify/AI 分类器(属性、分组、区域)
detect/AI 检测器(YOLO)、DINO 开放词表检测器、SAM2 分割器
logical/逻辑判断、人脸逻辑、灵敏度计算
qwen3vl/Qwen3 VL 推理 worker 和管理器
recognizer/AI 识别器(人脸/人体 re-id)
stream/RTMP 推流、编码器、概览渲染器
common/共享类型:AlgDataUnitAlgDataQueueAlgCommonType

每个领域通常包含:

  • Ai* 类(如 AiDetector)—— 实现实际算法逻辑。
  • P* 类(如 PDetector)—— 封装为流水线算子节点,构成 AlgActionBase 派生 action 的一部分。

NN(src/nn/)— 后端抽象

神经网络层使用抽象设备模式:

  • src/nn/core/ — 与设备无关的图、Blob 和 Node 基类。
  • src/nn/device/sophon/ — Sophon BM1688 TPU 后端(BMRT)。
  • src/nn/device/cpu/ — x86 ONNX Runtime 后端。
  • src/nn/device/naive/ — 内存计算兜底实现。
  • src/nn/pipeline/ — 高层流水线:detectionclassifyfeaturekeypointsadvanced

新增 NN 算子时需要为每个活跃后端提供对应的节点实现。

Inference(src/infer/)— 后端无关推理

使用 "Unify" 模式:每种任务类型定义一个接口 + 一个统一实现,将调用委托给当前活跃的 NN 后端:

任务
AiDetectorUnify目标检测
AiClassifierUnify图像分类
AiRecognizerUnify特征提取 / re-id
AiLandmarkerUnify关键点 / 姿态估计
AiTrackerUnify目标跟踪(ByteTrack)
DinoDetectorUnify开放词表检测
Sam2SegmenterUnifySAM2 分割
Qwen3VLUnify视觉语言模型

Media(src/media/)— 视频 / 音频 / OSD

负责视频编解码(FFmpeg)、硬件编解码(Sophon VPP/VPU)、OSD 渲染(位图文字 + 图形)、帧变换和流输出。

Network(src/network/)— HTTP / MQTT

子目录底层库用途
http/uWebSocketsHTTP 服务器、线程池、multipart 解析
mqtt/Paho MQTT CMQTT 客户端、topic、心跳
msg/内部消息分发

Database(src/db/)— SQLite

DaoBase 类封装 SQLite::Database,提供 SetCondition()SetLimit()Begin()Commit()Rollback()。具体 DAO(如 PersonDaoTaskEventDaoPassengerFlowDao)继承该类。TransactionGuard 提供 RAII 事务管理。

第三方依赖

主要第三方库(位于 3rd/ 并通过 CMake ExternalProject 链接):

用途许可证
SQLiteCppSQLite C++ 封装MIT
fmt字符串格式化MIT
nlohmann-jsonJSON 解析MIT
uWebSocketsHTTP / WebSocket 服务器Apache 2.0
Paho MQTT CMQTT 客户端EPL 2.0
ONNX Runtimex86 CPU 推理MIT
Sophon BMRTaarch64 TPU 推理专有
FFmpeg视频编解码LGPL 2.1+
OpenH264H.264 编码(CPU 后端)BSD 2-Clause
Catch2测试框架Boost
TrompeloeilMock 框架Boost

Released under the Apache 2.0 License.