更新 wiki
This commit is contained in:
@@ -8,35 +8,47 @@
|
||||
- [internal/handler/device.go](file://internal/handler/device.go)
|
||||
- [internal/handler/health.go](file://internal/handler/health.go)
|
||||
- [internal/handler/ota.go](file://internal/handler/ota.go)
|
||||
- [internal/handler/curve.go](file://internal/handler/curve.go)
|
||||
- [internal/handler/share_code.go](file://internal/handler/share_code.go)
|
||||
- [internal/repository/brand.go](file://internal/repository/brand.go)
|
||||
- [internal/repository/model.go](file://internal/repository/model.go)
|
||||
- [internal/repository/ota.go](file://internal/repository/ota.go)
|
||||
- [internal/repository/curve.go](file://internal/repository/curve.go)
|
||||
- [internal/repository/share_code.go](file://internal/repository/share_code.go)
|
||||
- [internal/response/response.go](file://internal/response/response.go)
|
||||
- [pkg/encode/base64.go](file://pkg/encode/base64.go)
|
||||
- [internal/search/meilisearch.go](file://internal/search/meilisearch.go)
|
||||
- [internal/router/router.go](file://internal/router/router.go)
|
||||
- [cmd/server/main.go](file://cmd/server/main.go)
|
||||
- [internal/config/config.go](file://internal/config/config.go)
|
||||
- [internal/config/equalize.go](file://internal/config/equalize.go)
|
||||
- [internal/config/share_code_ttl.go](file://internal/config/share_code_ttl.go)
|
||||
- [internal/middleware/logger.go](file://internal/middleware/logger.go)
|
||||
- [internal/middleware/cors.go](file://internal/middleware/cors.go)
|
||||
- [internal/middleware/request_id.go](file://internal/middleware/request_id.go)
|
||||
- [internal/model/brand.go](file://internal/model/brand.go)
|
||||
- [internal/model/model.go](file://internal/model/model.go)
|
||||
- [internal/model/ota.go](file://internal/model/ota.go)
|
||||
- [internal/model/share_code.go](file://internal/model/share_code.go)
|
||||
- [internal/model/target.go](file://internal/model/target.go)
|
||||
- [internal/cache/brand_cache.go](file://internal/cache/brand_cache.go)
|
||||
- [internal/cache/model_cache.go](file://internal/cache/model_cache.go)
|
||||
- [internal/cache/curve_cache.go](file://internal/cache/curve_cache.go)
|
||||
- [internal/cache/share_code_cache.go](file://internal/cache/share_code_cache.go)
|
||||
- [internal/task/share_code_persist.go](file://internal/task/share_code_persist.go)
|
||||
- [sql/ota.sql](file://sql/ota.sql)
|
||||
- [sql/black_list.sql](file://sql/black_list.sql)
|
||||
- [sql/ota_target_device.sql](file://sql/ota_target_device.sql)
|
||||
- [sql/share_code_log.sql](file://sql/share_code_log.sql)
|
||||
</cite>
|
||||
|
||||
## 更新摘要
|
||||
**变更内容**
|
||||
- 新增OTA固件升级处理功能:引入OTAHandler组件,支持固件升级请求处理、黑名单过滤、目标设备分布和版本选择等OTA固件升级能力
|
||||
- 新增OTA仓储层:OTARepository提供完整的OTA数据访问能力,包括最新版本查询、黑名单检查、定向设备匹配等功能
|
||||
- 新增OTA数据模型:包含OTA、BlackList、OTATargetDevice三种数据结构,支持完整的OTA升级流程
|
||||
- 新增数据库表结构:ota、black_list、ota_target_device三张表,支撑OTA功能的数据存储需求
|
||||
- 更新路由集成:OTA功能已集成到/audio路由组中,提供/api/v1/audio/ota端点
|
||||
- 新增分享代码处理器(ShareCodeHandler):实现EQ数据分享功能,支持创建、查询、导入、删除分享码,包含Redis缓存、分布式锁和异步持久化
|
||||
- 新增等化曲线处理器(CurveHandler):实现频响曲线计算和参数化EQ生成功能,支持多种目标曲线和设备源
|
||||
- 新增分享码持久化任务:定时将Redis中的分享码操作记录刷入MySQL数据库
|
||||
- 新增分享码配置:支持灵活的TTL配置格式(分钟、小时、天)
|
||||
- 更新路由集成:分享码和等化曲线功能已集成到/audio路由组中
|
||||
|
||||
## 目录
|
||||
1. [简介](#简介)
|
||||
@@ -52,10 +64,10 @@
|
||||
11. [附录](#附录)
|
||||
|
||||
## 简介
|
||||
本文件面向 Luxsin 应用 API 的业务处理器模块,系统性梳理各处理器的职责、接口设计与实现细节,覆盖 BrandHandler、ModelHandler、ModelListHandler、DeviceHandler、HealthHandler 和新增的 OTAHandler。文档重点阐述新的依赖注入模式、错误处理机制、响应格式化策略,以及与 Gin 框架的集成方式;并通过流程图与类图展示处理器间的协作关系与数据流转过程,帮助初学者快速上手,同时为高级开发者提供深入的技术参考。
|
||||
本文件面向 Luxsin 应用 API 的业务处理器模块,系统性梳理各处理器的职责、接口设计与实现细节,覆盖 BrandHandler、ModelHandler、ModelListHandler、DeviceHandler、HealthHandler、OTAHandler、CurveHandler 和新增的 ShareCodeHandler。文档重点阐述新的依赖注入模式、错误处理机制、响应格式化策略,以及与 Gin 框架的集成方式;并通过流程图与类图展示处理器间的协作关系与数据流转过程,帮助初学者快速上手,同时为高级开发者提供深入的技术参考。
|
||||
|
||||
## 项目结构
|
||||
业务处理器位于 internal/handler 目录,采用依赖注入模式,围绕"控制器-仓储-搜索-缓存-响应"的分层组织,配合中间件与路由装配,形成清晰的控制流与依赖注入入口。新增的OTA功能通过独立的处理器、仓储层和数据模型实现完整的固件升级能力。
|
||||
业务处理器位于 internal/handler 目录,采用依赖注入模式,围绕"控制器-仓储-搜索-缓存-响应"的分层组织,配合中间件与路由装配,形成清晰的控制流与依赖注入入口。新增的分享码和等化曲线功能通过独立的处理器、仓储层和数据模型实现完整的业务能力。
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
@@ -75,18 +87,24 @@ MODEL["internal/handler/model.go<br/>NewModelHandler(modelRepo, log)"]
|
||||
MODELLIST["internal/handler/model_list.go<br/>NewModelListHandler(searchClient, log)"]
|
||||
DEVICE["internal/handler/device.go<br/>NewDeviceHandler(redis, log)"]
|
||||
OTA["internal/handler/ota.go<br/>NewOTAHandler(otaRepo, log)"]
|
||||
CURVE["internal/handler/curve.go<br/>NewCurveHandler(curveRepo, curveCache, eqCfg, s3, log)"]
|
||||
SHARECODE["internal/handler/share_code.go<br/>NewShareCodeHandler(shareCache, log, maxPerMac)"]
|
||||
end
|
||||
subgraph "仓储层"
|
||||
BRANDREPO["internal/repository/brand.go<br/>BrandRepository"]
|
||||
MODELREPO["internal/repository/model.go<br/>ModelRepository"]
|
||||
OTAREPO["internal/repository/ota.go<br/>OTARepository"]
|
||||
CURVEREPO["internal/repository/curve.go<br/>CurveRepository"]
|
||||
SHARECODEREPO["internal/repository/share_code.go<br/>ShareCodeRepository"]
|
||||
end
|
||||
subgraph "基础设施"
|
||||
RESP["internal/response/response.go<br/>统一响应体"]
|
||||
ENCODE["pkg/encode/base64.go<br/>自定义Base64编码"]
|
||||
SEARCH["internal/search/meilisearch.go<br/>Meilisearch客户端"]
|
||||
CACHE["internal/cache/*<br/>Redis缓存"]
|
||||
DB["MySQL 数据库<br/>ota, black_list, ota_target_device 表"]
|
||||
S3["S3存储<br/>CSV文件"]
|
||||
DB["MySQL 数据库<br/>ota, black_list, ota_target_device, share_code_log 表"]
|
||||
TASK["internal/task/share_code_persist.go<br/>分享码持久化任务"]
|
||||
end
|
||||
MAIN --> ROUTER
|
||||
ROUTER --> CORS
|
||||
@@ -98,17 +116,28 @@ ROUTER --> MODEL
|
||||
ROUTER --> MODELLIST
|
||||
ROUTER --> DEVICE
|
||||
ROUTER --> OTA
|
||||
ROUTER --> CURVE
|
||||
ROUTER --> SHARECODE
|
||||
BRAND --> BRANDREPO
|
||||
MODEL --> MODELREPO
|
||||
OTA --> OTAREPO
|
||||
CURVE --> CURVEREPO
|
||||
SHARECODE --> SHARECODEREPO
|
||||
BRANDREPO --> DB
|
||||
MODELREPO --> DB
|
||||
OTAREPO --> DB
|
||||
CURVEREPO --> DB
|
||||
SHARECODEREPO --> DB
|
||||
CURVE --> S3
|
||||
SHARECODE --> CACHE
|
||||
CURVE --> CACHE
|
||||
BRAND --> RESP
|
||||
MODEL --> RESP
|
||||
MODELLIST --> RESP
|
||||
DEVICE --> RESP
|
||||
OTA --> RESP
|
||||
CURVE --> RESP
|
||||
SHARECODE --> RESP
|
||||
MODELLIST --> SEARCH
|
||||
BRAND --> CACHE
|
||||
MODEL --> CACHE
|
||||
@@ -119,16 +148,18 @@ MODELLIST --> ENCODE
|
||||
|
||||
**图表来源**
|
||||
- [cmd/server/main.go:27-108](file://cmd/server/main.go#L27-L108)
|
||||
- [internal/router/router.go:16-56](file://internal/router/router.go#L16-L56)
|
||||
- [internal/router/router.go:16-82](file://internal/router/router.go#L16-L82)
|
||||
- [internal/handler/health.go:10](file://internal/handler/health.go#L10)
|
||||
- [internal/handler/brand.go:18](file://internal/handler/brand.go#L18)
|
||||
- [internal/handler/model.go:18](file://internal/handler/model.go#L18)
|
||||
- [internal/handler/model_list.go:19](file://internal/handler/model_list.go#L19)
|
||||
- [internal/handler/device.go:19](file://internal/handler/device.go#L19)
|
||||
- [internal/handler/ota.go:19](file://internal/handler/ota.go#L19)
|
||||
- [internal/handler/curve.go:37](file://internal/handler/curve.go#L37)
|
||||
- [internal/handler/share_code.go:21](file://internal/handler/share_code.go#L21)
|
||||
|
||||
**章节来源**
|
||||
- [internal/router/router.go:16-56](file://internal/router/router.go#L16-L56)
|
||||
- [internal/router/router.go:16-82](file://internal/router/router.go#L16-L82)
|
||||
- [cmd/server/main.go:27-108](file://cmd/server/main.go#L27-L108)
|
||||
|
||||
## 核心组件
|
||||
@@ -138,6 +169,8 @@ MODELLIST --> ENCODE
|
||||
- **型号检索处理器**:基于 Meilisearch 执行全文检索,依赖搜索客户端实例。
|
||||
- **设备上报处理器**:接收设备信息(MAC、型号、版本、来源 IP),依赖 Redis 客户端。
|
||||
- **OTA固件升级处理器**:处理固件升级请求,支持黑名单过滤、目标设备分布和版本选择等OTA固件升级能力。
|
||||
- **等化曲线处理器**:处理频响曲线计算和参数化EQ生成,支持多种目标曲线和设备源。
|
||||
- **分享代码处理器**:处理EQ数据分享功能,支持创建、查询、导入、删除分享码。
|
||||
|
||||
**章节来源**
|
||||
- [internal/handler/health.go:8-19](file://internal/handler/health.go#L8-L19)
|
||||
@@ -146,9 +179,11 @@ MODELLIST --> ENCODE
|
||||
- [internal/handler/model_list.go:14-24](file://internal/handler/model_list.go#L14-L24)
|
||||
- [internal/handler/device.go:14-24](file://internal/handler/device.go#L14-L24)
|
||||
- [internal/handler/ota.go:14-21](file://internal/handler/ota.go#L14-L21)
|
||||
- [internal/handler/curve.go:27-39](file://internal/handler/curve.go#L27-L39)
|
||||
- [internal/handler/share_code.go:15-23](file://internal/handler/share_code.go#L15-L23)
|
||||
|
||||
## 架构总览
|
||||
下图展示从请求进入至响应返回的关键路径,以及处理器与仓储、搜索、缓存、日志等组件的交互,体现了完整的依赖注入架构。新增的OTA功能通过独立的处理流程支持复杂的固件升级场景。
|
||||
下图展示从请求进入至响应返回的关键路径,以及处理器与仓储、搜索、缓存、日志等组件的交互,体现了完整的依赖注入架构。新增的分享码和等化曲线功能通过独立的处理流程支持复杂的业务场景。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
@@ -180,21 +215,40 @@ DB-->>REPO : "命中/未命中"
|
||||
H->>REPO : "FindTargetDevice(ctx, otaID, mac)"
|
||||
REPO->>DB : "检查定向设备"
|
||||
DB-->>REPO : "匹配/不匹配"
|
||||
else "等化曲线"
|
||||
H->>REPO : "GetModelByBrandAndName(ctx, brand, name)"
|
||||
REPO->>DB : "查询型号信息"
|
||||
DB-->>REPO : "型号记录"
|
||||
H->>REPO : "GetTargetByLabel(ctx, target)"
|
||||
REPO->>DB : "查询目标曲线"
|
||||
DB-->>REPO : "目标记录"
|
||||
H->>DB : "调用外部EQ接口"
|
||||
DB-->>H : "参数化EQ数据"
|
||||
else "分享代码"
|
||||
H->>DB : "Redis 操作:创建/查询/删除"
|
||||
DB-->>H : "分享码数据"
|
||||
H->>REPO : "插入分享码日志"
|
||||
REPO->>DB : "写入数据库"
|
||||
DB-->>REPO : "OK"
|
||||
end
|
||||
H->>L : "记录日志/错误"
|
||||
H-->>C : "JSON 响应"
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
- [internal/router/router.go:45-52](file://internal/router/router.go#L45-L52)
|
||||
- [internal/router/router.go:63-78](file://internal/router/router.go#L63-L78)
|
||||
- [internal/handler/brand.go:29](file://internal/handler/brand.go#L29)
|
||||
- [internal/handler/model.go:30](file://internal/handler/model.go#L30)
|
||||
- [internal/handler/model_list.go:37](file://internal/handler/model_list.go#L37)
|
||||
- [internal/handler/device.go:71](file://internal/handler/device.go#L71)
|
||||
- [internal/handler/ota.go:57-131](file://internal/handler/ota.go#L57-L131)
|
||||
- [internal/handler/curve.go:302-489](file://internal/handler/curve.go#L302-L489)
|
||||
- [internal/handler/share_code.go:40-382](file://internal/handler/share_code.go#L40-382)
|
||||
- [internal/repository/brand.go:23-52](file://internal/repository/brand.go#L23-L52)
|
||||
- [internal/repository/model.go:23-79](file://internal/repository/model.go#L23-L79)
|
||||
- [internal/repository/ota.go:20-158](file://internal/repository/ota.go#L20-L158)
|
||||
- [internal/repository/curve.go:19-65](file://internal/repository/curve.go#L19-L65)
|
||||
- [internal/repository/share_code.go:20-58](file://internal/repository/share_code.go#L20-L58)
|
||||
- [internal/search/meilisearch.go:22-45](file://internal/search/meilisearch.go#L22-L45)
|
||||
|
||||
## 详细组件分析
|
||||
@@ -210,7 +264,7 @@ H-->>C : "JSON 响应"
|
||||
**章节来源**
|
||||
- [internal/handler/health.go:8-19](file://internal/handler/health.go#L8-L19)
|
||||
- [internal/response/response.go:15-21](file://internal/response/response.go#L15-L21)
|
||||
- [internal/router/router.go:42](file://internal/router/router.go#L42)
|
||||
- [internal/router/router.go:55](file://internal/router/router.go#L55)
|
||||
|
||||
### 品牌处理器(BrandHandler)
|
||||
- **职责**:根据品牌名称模糊查询品牌列表。
|
||||
@@ -458,6 +512,126 @@ RespInternal --> End
|
||||
- [internal/repository/ota.go:20-158](file://internal/repository/ota.go#L20-L158)
|
||||
- [internal/model/ota.go:6-42](file://internal/model/ota.go#L6-L42)
|
||||
|
||||
### 等化曲线处理器(CurveHandler)
|
||||
- **职责**:处理频响曲线计算和参数化EQ生成,支持多种目标曲线和设备源。
|
||||
- **输入参数**:
|
||||
- 查询字符串:brand(必填)
|
||||
- 查询字符串:name(必填)
|
||||
- 查询字符串:target(可选,modelCurve接口固定为Harman over-ear 2018)
|
||||
- 查询字符串:base64Resp(可选,默认关闭)
|
||||
- **处理流程**:
|
||||
1. 参数校验:验证brand、name和target参数
|
||||
2. 缓存查询:优先查询Redis缓存,包含独立存储的fr数据优化
|
||||
3. 分布式锁:缓存未命中时获取分布式锁避免并发重复请求
|
||||
4. 外部API调用:调用EQ计算接口获取参数化EQ数据
|
||||
5. 缓存写入:将结果写入Redis缓存,分离存储fr数据
|
||||
6. 响应返回:根据base64Resp参数决定响应格式
|
||||
- **错误处理**:
|
||||
- 参数校验失败返回统一错误
|
||||
- 缓存操作失败记录警告并继续处理
|
||||
- 外部API调用失败返回统一内部错误
|
||||
- 分布式锁获取失败返回统一内部错误
|
||||
- **数据模型**:Model、Target
|
||||
- **依赖注入**:通过 NewCurveHandler 构造函数注入 CurveRepository、CurveCache、EqualizeConfig、S3Storage 和 zap.Logger
|
||||
- **S3集成**:支持从S3读取CSV文件作为测量数据
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start(["进入 CurveHandler"]) --> ParseParams["解析参数 brand/name/target/base64Resp"]
|
||||
ParseParams --> Validate{"参数校验通过?"}
|
||||
Validate -- 否 --> BadReq["返回BadRequest错误"]
|
||||
Validate -- 是 --> CacheQuery["查询Redis缓存"]
|
||||
CacheQuery --> CacheHit{"缓存命中?"}
|
||||
CacheHit -- 是 --> ReturnCached["返回缓存数据"]
|
||||
CacheHit -- 否 --> AcquireLock["获取分布式锁"]
|
||||
AcquireLock --> LockOK{"获取成功?"}
|
||||
LockOK -- 否 --> WaitRetry["等待后重试"]
|
||||
WaitRetry --> CacheQuery
|
||||
LockOK -- 是 --> DoubleCheck["双重检查缓存"]
|
||||
DoubleCheck --> CacheHit2{"缓存已存在?"}
|
||||
CacheHit2 -- 是 --> ReleaseLock["释放锁"]
|
||||
ReleaseLock --> ReturnCached
|
||||
CacheHit2 -- 否 --> CallEQ["调用外部EQ接口"]
|
||||
CallEQ --> ProcessResult["处理返回结果"]
|
||||
ProcessResult --> SplitFR["分离fr数据"]
|
||||
SplitFR --> WriteCache["写入Redis缓存"]
|
||||
WriteCache --> ReleaseLock2["释放锁"]
|
||||
ReleaseLock2 --> ReturnResult["返回结果"]
|
||||
BadReq --> End(["结束"])
|
||||
ReturnCached --> End
|
||||
ReturnResult --> End
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
- [internal/handler/curve.go:214-292](file://internal/handler/curve.go#L214-L292)
|
||||
- [internal/handler/curve.go:301-368](file://internal/handler/curve.go#L301-L368)
|
||||
|
||||
**章节来源**
|
||||
- [internal/handler/curve.go:27-582](file://internal/handler/curve.go#L27-L582)
|
||||
- [internal/repository/curve.go:19-65](file://internal/repository/curve.go#L19-L65)
|
||||
- [internal/model/model.go:5-15](file://internal/model/model.go#L5-L15)
|
||||
- [internal/model/target.go:5-14](file://internal/model/target.go#L5-L14)
|
||||
|
||||
### 分享代码处理器(ShareCodeHandler)
|
||||
- **职责**:处理EQ数据分享功能,支持创建、查询、导入、删除分享码,包含Redis缓存、分布式锁和异步持久化。
|
||||
- **输入参数**:
|
||||
- POST /audio/shareCreate:mac(必填)、model(必填)、eq_data(必填)
|
||||
- GET /audio/shareList:mac(必填)
|
||||
- GET /audio/shareQuery:shareCode(必填)
|
||||
- GET /audio/shareAccept:mac(必填)、model(必填)、shareCode(必填)
|
||||
- GET /audio/shareDelete:mac(必填)、shareCode(必填)
|
||||
- **处理流程**:
|
||||
1. 参数校验:验证所有必需参数,检查设备型号有效性
|
||||
2. 分布式锁:创建分享码时获取分布式锁避免重复
|
||||
3. Redis操作:使用Lua脚本原子性写入多个键值对
|
||||
4. 缓存查询:查询MAC地址对应的未过期分享码数量
|
||||
5. 异步持久化:将操作记录放入队列,由后台任务刷入数据库
|
||||
6. 响应返回:根据base64Resp参数决定响应格式
|
||||
- **错误处理**:
|
||||
- 参数校验失败返回统一错误
|
||||
- Redis操作失败记录错误并返回统一内部错误
|
||||
- 分布式锁获取失败返回统一内部错误
|
||||
- 设备型号无效返回统一错误
|
||||
- **数据模型**:ShareCodeData、ShareCodeLog
|
||||
- **依赖注入**:通过 NewShareCodeHandler 构造函数注入 ShareCodeCache、zap.Logger 和 maxPerMac
|
||||
- **Redis结构**:share:{code}、share:mac:{mac}、share:pending、share:import:pending等
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start(["进入 ShareCodeHandler"]) --> ParseAction["解析具体操作"]
|
||||
ParseAction --> CreateShare["创建分享码"]
|
||||
CreateShare --> ValidateParams["参数校验"]
|
||||
ValidateParams --> CheckCount["检查MAC分享码数量"]
|
||||
CheckCount --> AcquireLock["获取分布式锁"]
|
||||
AcquireLock --> AtomicWrite["Lua原子写入Redis"]
|
||||
AtomicWrite --> EnqueuePending["加入待持久化队列"]
|
||||
EnqueuePending --> ReturnResult["返回分享码"]
|
||||
Start --> QueryShare["查询分享码"]
|
||||
QueryShare --> ValidateQuery["参数校验"]
|
||||
ValidateQuery --> ListByMAC["按MAC查询未过期分享码"]
|
||||
ListByMAC --> ReturnList["返回分享码列表"]
|
||||
Start --> AcceptShare["接受分享码"]
|
||||
AcceptShare --> ValidateAccept["参数校验"]
|
||||
ValidateAccept --> LookupCode["查找分享码"]
|
||||
LookupCode --> EnqueueImport["加入导入持久化队列"]
|
||||
EnqueueImport --> ReturnData["返回EQ数据"]
|
||||
Start --> DeleteShare["删除分享码"]
|
||||
DeleteShare --> ValidateDelete["参数校验"]
|
||||
ValidateDelete --> CheckOwnership["校验所有权"]
|
||||
CheckOwnership --> DeleteRedis["删除Redis数据"]
|
||||
DeleteRedis --> ReturnDelete["返回删除结果"]
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
- [internal/handler/share_code.go:40-382](file://internal/handler/share_code.go#L40-382)
|
||||
- [internal/cache/share_code_cache.go:142-331](file://internal/cache/share_code_cache.go#L142-331)
|
||||
|
||||
**章节来源**
|
||||
- [internal/handler/share_code.go:15-383](file://internal/handler/share_code.go#L15-L383)
|
||||
- [internal/cache/share_code_cache.go:33-353](file://internal/cache/share_code_cache.go#L33-L353)
|
||||
- [internal/repository/share_code.go:12-59](file://internal/repository/share_code.go#L12-L59)
|
||||
- [internal/model/share_code.go:5-25](file://internal/model/share_code.go#L5-L25)
|
||||
|
||||
## 依赖注入模式详解
|
||||
|
||||
### 依赖注入架构
|
||||
@@ -469,23 +643,33 @@ MAIN["main.go<br/>应用启动"] --> ROUTER["router.New()<br/>集中装配依赖
|
||||
ROUTER --> DB["sql.DB<br/>数据库连接"]
|
||||
ROUTER --> RDB["redis.Client<br/>Redis客户端"]
|
||||
ROUTER --> SEARCH["search.Client<br/>Meilisearch客户端"]
|
||||
ROUTER --> S3["storage.S3Storage<br/>S3存储"]
|
||||
ROUTER --> LOG["zap.Logger<br/>日志器"]
|
||||
ROUTER --> EQCFG["config.EqualizeConfig<br/>等化配置"]
|
||||
ROUTER --> SHAREMAX["int<br/>分享码数量限制"]
|
||||
ROUTER --> SHARETTL["time.Duration<br/>分享码TTL"]
|
||||
ROUTER --> BRANCACHE["cache.BrandCache<br/>品牌缓存"]
|
||||
ROUTER --> MODELCACHE["cache.ModelCache<br/>型号缓存"]
|
||||
ROUTER --> CURVECACHE["cache.CurveCache<br/>曲线缓存"]
|
||||
ROUTER --> SHARECODECACHE["cache.ShareCodeCache<br/>分享码缓存"]
|
||||
ROUTER --> BRANDREPO["repository.NewBrandRepository()<br/>品牌仓储"]
|
||||
ROUTER --> MODELREPO["repository.NewModelRepository()<br/>型号仓储"]
|
||||
ROUTER --> OTAREPO["repository.NewOTARepository()<br/>OTA仓储"]
|
||||
ROUTER --> CURVEREPO["repository.NewCurveRepository()<br/>曲线仓储"]
|
||||
ROUTER --> SHARECODEREPO["repository.NewShareCodeRepository()<br/>分享码仓储"]
|
||||
ROUTER --> HEALTH["handler.NewHealthHandler()<br/>健康检查处理器"]
|
||||
ROUTER --> BRAND["handler.NewBrandHandler()<br/>品牌处理器"]
|
||||
ROUTER --> MODEL["handler.NewModelHandler()<br/>型号处理器"]
|
||||
ROUTER --> MODELLIST["handler.NewModelListHandler()<br/>型号检索处理器"]
|
||||
ROUTER --> DEVICE["handler.NewDeviceHandler()<br/>设备上报处理器"]
|
||||
ROUTER --> OTA["handler.NewOTAHandler()<br/>OTA固件升级处理器"]
|
||||
ROUTER --> CURVE["handler.NewCurveHandler()<br/>等化曲线处理器"]
|
||||
ROUTER --> SHARECODE["handler.NewShareCodeHandler()<br/>分享代码处理器"]
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
- [cmd/server/main.go:77](file://cmd/server/main.go#L77)
|
||||
- [internal/router/router.go:16-56](file://internal/router/router.go#L16-L56)
|
||||
- [internal/router/router.go:22-82](file://internal/router/router.go#L22-L82)
|
||||
|
||||
### 依赖注入优势
|
||||
- **测试友好**:可以轻松注入模拟对象进行单元测试
|
||||
@@ -494,7 +678,7 @@ ROUTER --> OTA["handler.NewOTAHandler()<br/>OTA固件升级处理器"]
|
||||
- **生命周期管理**:依赖项的创建和销毁由路由集中管理
|
||||
|
||||
### 仓储层依赖
|
||||
BrandRepository、ModelRepository 和 OTARepository 现在接收相应的依赖:
|
||||
BrandRepository、ModelRepository、OTARepository、CurveRepository 和 ShareCodeRepository 现在接收相应的依赖:
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
@@ -523,6 +707,18 @@ class OTARepository {
|
||||
+ IsInBlackList(ctx, otaID, mac) : "bool,error"
|
||||
+ FindTargetDevice(ctx, otaID, mac) : "OTATargetDevice,error"
|
||||
}
|
||||
class CurveRepository {
|
||||
- db : "sql.DB"
|
||||
+ NewCurveRepository(db) : "CurveRepository"
|
||||
+ GetModelByBrandAndName(ctx, brandName, name) : "Model,error"
|
||||
+ GetTargetByLabel(ctx, label) : "Target,error"
|
||||
}
|
||||
class ShareCodeRepository {
|
||||
- db : "sql.DB"
|
||||
+ NewShareCodeRepository(db) : "ShareCodeRepository"
|
||||
+ InsertLog(ctx, log) : "error"
|
||||
+ HasExportLog(ctx, shareCode) : "bool,error"
|
||||
}
|
||||
class BrandCache {
|
||||
- rdb : "redis.Client"
|
||||
+ NewBrandCache(rdb) : "BrandCache"
|
||||
@@ -537,30 +733,62 @@ class ModelCache {
|
||||
+ GetAll(ctx) : "[]Model,error"
|
||||
+ SetAll(ctx, list) : "error"
|
||||
}
|
||||
class CurveCache {
|
||||
- rdb : "redis.Client"
|
||||
+ NewCurveCache(rdb) : "CurveCache"
|
||||
+ Get(ctx, brand, name, target) : "string,error"
|
||||
+ Set(ctx, brand, name, target, data) : "error"
|
||||
+ GetFR(ctx, brand, name) : "string,error"
|
||||
+ GetWithFR(ctx, brand, name, target) : "string,error"
|
||||
+ AcquireLock(ctx, brand, name, target) : "bool,error"
|
||||
+ ReleaseLock(ctx, brand, name, target) : "error"
|
||||
}
|
||||
class ShareCodeCache {
|
||||
- rdb : "redis.Client"
|
||||
- codeTTL : "time.Duration"
|
||||
+ NewShareCodeCache(rdb, codeTTL) : "ShareCodeCache"
|
||||
+ Create(ctx, macAddr, ipAddr, model, eqData) : "ShareCodeData,error"
|
||||
+ Get(ctx, shareCode) : "ShareCodeData,error"
|
||||
+ ListByMac(ctx, macAddr) : "[]ShareCodeData,error"
|
||||
+ Delete(ctx, macAddr, shareCode) : "ShareDeleteResult,error"
|
||||
+ EnqueueImportLog(ctx, macAddr, shareCode, model, ipAddr, eqData, expireAt) : "error"
|
||||
+ AcquireFlushLock(ctx, shareCode) : "bool,error"
|
||||
+ ReleaseFlushLock(ctx, shareCode) : "error"
|
||||
}
|
||||
BrandRepository --> BrandCache : "依赖注入"
|
||||
ModelRepository --> ModelCache : "依赖注入"
|
||||
OTARepository --> DB : "依赖注入"
|
||||
CurveRepository --> DB : "依赖注入"
|
||||
ShareCodeRepository --> DB : "依赖注入"
|
||||
CurveCache --> RDB : "依赖注入"
|
||||
ShareCodeCache --> RDB : "依赖注入"
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
- [internal/repository/brand.go:14-21](file://internal/repository/brand.go#L14-L21)
|
||||
- [internal/repository/model.go:14-21](file://internal/repository/model.go#L14-L21)
|
||||
- [internal/repository/ota.go:11-17](file://internal/repository/ota.go#L11-L17)
|
||||
- [internal/repository/curve.go:11-17](file://internal/repository/curve.go#L11-L17)
|
||||
- [internal/repository/share_code.go:12-18](file://internal/repository/share_code.go#L12-L18)
|
||||
- [internal/cache/brand_cache.go:18-24](file://internal/cache/brand_cache.go#L18-L24)
|
||||
- [internal/cache/model_cache.go:19-25](file://internal/cache/model_cache.go#L19-L25)
|
||||
- [internal/cache/curve_cache.go:18-25](file://internal/cache/curve_cache.go#L18-L25)
|
||||
- [internal/cache/share_code_cache.go:128-135](file://internal/cache/share_code_cache.go#L128-L135)
|
||||
|
||||
**章节来源**
|
||||
- [internal/router/router.go:16-56](file://internal/router/router.go#L16-L56)
|
||||
- [internal/router/router.go:22-82](file://internal/router/router.go#L22-L82)
|
||||
- [cmd/server/main.go:77](file://cmd/server/main.go#L77)
|
||||
|
||||
## 依赖分析
|
||||
- **依赖注入模式**:
|
||||
- 所有处理器通过构造函数注入依赖项,包括仓储、搜索客户端、Redis 客户端与日志器。
|
||||
- 所有处理器通过构造函数注入依赖项,包括仓储、搜索客户端、Redis 客户端、S3存储与日志器。
|
||||
- 路由在应用启动时集中装配,保证依赖一次性构建与共享。
|
||||
- **组件耦合**:
|
||||
- 处理器与仓储之间为单向依赖,职责清晰。
|
||||
- 搜索与缓存作为外部服务,通过客户端封装接入。
|
||||
- OTA处理器与数据库直接交互,提供完整的OTA数据访问能力。
|
||||
- CurveHandler与外部EQ接口和S3存储集成,支持复杂的音频处理。
|
||||
- ShareCodeHandler与Redis缓存深度集成,实现高性能的分享码管理。
|
||||
- **可能的循环依赖**:
|
||||
- 当前结构未见循环导入,符合 Go 包管理最佳实践。
|
||||
|
||||
@@ -573,40 +801,49 @@ ROUTER --> MODEL["model.go"]
|
||||
ROUTER --> MODELLIST["model_list.go"]
|
||||
ROUTER --> DEVICE["device.go"]
|
||||
ROUTER --> OTA["ota.go"]
|
||||
ROUTER --> CURVE["curve.go"]
|
||||
ROUTER --> SHARECODE["share_code.go"]
|
||||
BRAND --> BREPO["repository/brand.go"]
|
||||
MODEL --> MREPO["repository/model.go"]
|
||||
OTA --> OTAREPO["repository/ota.go"]
|
||||
CURVE --> CURVEREPO["repository/curve.go"]
|
||||
SHARECODE --> SHARECODEREPO["repository/share_code.go"]
|
||||
BRAND --> BREPO
|
||||
BREPO --> BCACHE["cache/brand_cache.go"]
|
||||
MODEL --> MREPO
|
||||
MREPO --> MCACHE["cache/model_cache.go"]
|
||||
OTA --> OTAREPO
|
||||
OTAREPO --> DB["MySQL数据库"]
|
||||
BRAND --> ENCODE["pkg/encode/base64.go"]
|
||||
MODEL --> ENCODE
|
||||
MODELLIST --> ENCODE
|
||||
OTA --> ENCODE
|
||||
CURVE --> CURVEREPO
|
||||
CURVEREPO --> DB["MySQL数据库"]
|
||||
SHARECODE --> SHARECODEREPO
|
||||
SHARECODEREPO --> DB
|
||||
CURVE --> S3["S3存储"]
|
||||
CURVE --> ENCODE["pkg/encode/base64.go"]
|
||||
SHARECODE --> ENCODE
|
||||
ALL["各处理器"] --> RESP["internal/response/response.go"]
|
||||
ALL --> LOG["zap.Logger"]
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
- [cmd/server/main.go:77](file://cmd/server/main.go#L77)
|
||||
- [internal/router/router.go:16-56](file://internal/router/router.go#L16-L56)
|
||||
- [internal/router/router.go:22-82](file://internal/router/router.go#L22-L82)
|
||||
- [internal/handler/brand.go:18](file://internal/handler/brand.go#L18)
|
||||
- [internal/handler/model.go:18](file://internal/handler/model.go#L18)
|
||||
- [internal/handler/model_list.go:19](file://internal/handler/model_list.go#L19)
|
||||
- [internal/handler/device.go:19](file://internal/handler/device.go#L19)
|
||||
- [internal/handler/ota.go:19](file://internal/handler/ota.go#L19)
|
||||
- [internal/handler/curve.go:37](file://internal/handler/curve.go#L37)
|
||||
- [internal/handler/share_code.go:21](file://internal/handler/share_code.go#L21)
|
||||
- [internal/repository/brand.go:19](file://internal/repository/brand.go#L19)
|
||||
- [internal/repository/model.go:19](file://internal/repository/model.go#L19)
|
||||
- [internal/repository/ota.go:15](file://internal/repository/ota.go#L15)
|
||||
- [internal/repository/curve.go:15](file://internal/repository/curve.go#L15)
|
||||
- [internal/repository/share_code.go:16](file://internal/repository/share_code.go#L16)
|
||||
- [internal/search/meilisearch.go:17](file://internal/search/meilisearch.go#L17)
|
||||
- [pkg/encode/base64.go:8](file://pkg/encode/base64.go#L8)
|
||||
- [internal/response/response.go:9](file://internal/response/response.go#L9)
|
||||
|
||||
**章节来源**
|
||||
- [internal/router/router.go:16-56](file://internal/router/router.go#L16-L56)
|
||||
- [internal/router/router.go:22-82](file://internal/router/router.go#L22-L82)
|
||||
- [cmd/server/main.go:27-108](file://cmd/server/main.go#L27-L108)
|
||||
|
||||
## 性能考虑
|
||||
@@ -617,23 +854,34 @@ ALL --> LOG["zap.Logger"]
|
||||
- 品牌与型号查询均使用 ORDER BY 与 LIKE,建议在数据库侧建立合适索引以提升模糊查询性能。
|
||||
- OTA查询涉及多表关联,建议在ota表的model、hw、beta、status字段建立复合索引。
|
||||
- 仓储层现在支持缓存降级,当缓存不可用时自动回退到数据库查询。
|
||||
- 分享码持久化查询优化,使用索引加速查询。
|
||||
- **搜索与缓存**
|
||||
- Meilisearch 适合全文检索,建议合理设置属性检索范围与分页大小。
|
||||
- Redis 写入为单键 HSet,具备良好吞吐能力;建议评估内存占用与持久化策略。
|
||||
- 缓存层现在支持全量缓存和按品牌缓存两种策略,提升查询性能。
|
||||
- **OTA查询优化**
|
||||
- OTA查询流程涉及多次数据库查询,建议在黑名单表和定向设备表建立适当的索引。
|
||||
- 可以考虑缓存常用的OTA查询结果,减少数据库压力。
|
||||
- **新增**:CurveHandler的fr数据独立存储优化,避免每个target重复存储fr数据。
|
||||
- **新增**:ShareCodeCache使用Lua脚本原子性操作,减少网络往返。
|
||||
- **外部服务集成**
|
||||
- EQ接口调用设置10秒超时,避免阻塞请求。
|
||||
- S3读取CSV文件时进行错误处理和缓存优化。
|
||||
- 分布式锁避免并发重复请求EQ接口。
|
||||
- **分享码性能优化**
|
||||
- Redis ZSET存储MAC到分享码的映射,支持快速查询未过期分享码。
|
||||
- 分布式锁防止重复创建分享码。
|
||||
- 异步持久化任务批量刷入数据库,减少实时写入压力。
|
||||
- 分享码TTL配置支持灵活的时间单位(分钟、小时、天)。
|
||||
- **中间件与日志**
|
||||
- 开启 Recovery、CORS、Logger、RequestID 中间件,有助于可观测性与稳定性;注意日志级别与输出频率对性能的影响。
|
||||
- **并发安全**
|
||||
- Redis HSet 为线程安全操作;处理器方法本身无共享可变状态,天然并发安全。
|
||||
- 分布式锁确保同一资源的串行访问。
|
||||
- 依赖注入模式减少了全局状态,提升了并发安全性。
|
||||
- **最佳实践**
|
||||
- 在生产环境启用 Release 模式,降低框架开销。
|
||||
- 对外部依赖(数据库、搜索、缓存)增加超时与重试策略,提升鲁棒性。
|
||||
- 对外部依赖(数据库、搜索、缓存、S3)增加超时与重试策略,提升鲁棒性。
|
||||
- 利用缓存预热机制,在应用启动时加载常用数据到缓存。
|
||||
- OTA查询流程复杂,建议添加适当的超时控制和错误重试机制。
|
||||
- **新增**:分享码持久化任务建议设置合理的间隔时间,平衡实时性和性能。
|
||||
|
||||
## 故障排查指南
|
||||
- **健康检查失败**
|
||||
@@ -654,6 +902,19 @@ ALL --> LOG["zap.Logger"]
|
||||
- 关注"query ota failed"、"check black list failed"、"check target device failed"等错误日志。
|
||||
- 检查数据库连接,确认ota、black_list、ota_target_device表存在且结构正确。
|
||||
- 验证OTA状态、硬件版本号、灰度标识等字段是否符合预期。
|
||||
- **等化曲线异常**
|
||||
- 校验必填参数 brand、name 是否传入且格式正确。
|
||||
- 关注"get curve point failed"、"get model curve failed"等错误日志。
|
||||
- 检查外部EQ接口连通性和响应格式。
|
||||
- 验证S3存储权限和CSV文件是否存在。
|
||||
- 关注分布式锁获取失败的情况。
|
||||
- **分享代码异常**
|
||||
- 校验必填参数是否完整,特别是POST请求的JSON格式。
|
||||
- 关注"参数校验失败"、"系统错误"等错误信息。
|
||||
- 检查Redis连接状态和Lua脚本执行情况。
|
||||
- 验证分享码TTL配置是否正确。
|
||||
- 关注分布式锁获取失败和权限验证失败的情况。
|
||||
- 检查异步持久化任务是否正常运行。
|
||||
- **依赖注入相关问题**
|
||||
- 确认所有处理器都通过构造函数正确注入了依赖项。
|
||||
- 检查路由装配顺序,确保依赖项在处理器之前创建。
|
||||
@@ -669,12 +930,14 @@ ALL --> LOG["zap.Logger"]
|
||||
- [internal/handler/model_list.go:38-42](file://internal/handler/model_list.go#L38-L42)
|
||||
- [internal/handler/device.go:61-78](file://internal/handler/device.go#L61-L78)
|
||||
- [internal/handler/ota.go:58-94](file://internal/handler/ota.go#L58-L94)
|
||||
- [internal/handler/curve.go:93-95](file://internal/handler/curve.go#L93-L95)
|
||||
- [internal/handler/share_code.go:87-111](file://internal/handler/share_code.go#L87-L111)
|
||||
- [internal/response/response.go:15-36](file://internal/response/response.go#L15-L36)
|
||||
- [internal/middleware/logger.go:10-45](file://internal/middleware/logger.go#L10-L45)
|
||||
- [internal/middleware/request_id.go:20-31](file://internal/middleware/request_id.go#L20-L31)
|
||||
|
||||
## 结论
|
||||
本处理器模块采用全新的依赖注入模式,通过构造函数注入依赖项,实现了更好的解耦和可测试性。通过统一响应体与自定义 Base64 编码实现灵活的输出策略,结合 Gin 中间件与外部服务(数据库、Meilisearch、Redis)形成稳定高效的业务处理链路。新增的OTA固件升级功能提供了完整的固件升级能力,包括黑名单过滤、目标设备分布和版本选择等特性。新的架构模式简化了处理器实现,提升了代码质量,建议在生产环境中进一步完善超时与重试、索引优化与缓存策略,持续提升性能与可靠性。
|
||||
本处理器模块采用全新的依赖注入模式,通过构造函数注入依赖项,实现了更好的解耦和可测试性。通过统一响应体与自定义 Base64 编码实现灵活的输出策略,结合 Gin 中间件与外部服务(数据库、Meilisearch、Redis、S3)形成稳定高效的业务处理链路。新增的分享码和等化曲线功能提供了完整的业务能力,包括高性能的Redis缓存、分布式锁、异步持久化和复杂的音频处理流程。新的架构模式简化了处理器实现,提升了代码质量,建议在生产环境中进一步完善超时与重试、索引优化与缓存策略,持续提升性能与可靠性。
|
||||
|
||||
## 附录
|
||||
- **路由与处理器映射**
|
||||
@@ -684,35 +947,57 @@ ALL --> LOG["zap.Logger"]
|
||||
- /audio/modelList -> ModelListHandler.ModelList
|
||||
- /audio/reportDevInfo -> DeviceHandler.ReportDevInfo
|
||||
- /audio/ota -> OTAHandler.GetOTA
|
||||
- /audio/getCurve -> CurveHandler.GetCurve
|
||||
- /audio/modelCurve -> CurveHandler.ModelCurve
|
||||
- /audio/shareCreate -> ShareCodeHandler.ExportShareCode
|
||||
- /audio/shareList -> ShareCodeHandler.ListShareCodesByMac
|
||||
- /audio/shareQuery -> ShareCodeHandler.QueryShareCode
|
||||
- /audio/shareAccept -> ShareCodeHandler.ImportShareCode
|
||||
- /audio/shareDelete -> ShareCodeHandler.DeleteShareCode
|
||||
- **依赖注入示例**
|
||||
- 品牌处理器:BrandHandler.NewBrandHandler(brandRepo, log)
|
||||
- 型号处理器:ModelHandler.NewModelHandler(modelRepo, log)
|
||||
- 型号检索处理器:ModelListHandler.NewModelListHandler(searchClient, log)
|
||||
- 设备上报处理器:DeviceHandler.NewDeviceHandler(redis, log)
|
||||
- OTA固件升级处理器:OTAHandler.NewOTAHandler(otaRepo, log)
|
||||
- **OTA查询参数说明**
|
||||
- model:设备型号(必填)
|
||||
- hw:硬件版本号(必填)
|
||||
- mac:设备MAC地址(可选)
|
||||
- beta:灰度标识(可选,默认0)
|
||||
- **OTA数据模型字段**
|
||||
- OTA:id、verCode、verName、url、md5、force、desc、model、hw、target、beta、pawVerCode、pawVerName、pawUrl、pawMd5、startTime、endTime、status
|
||||
- BlackList:id、ota_id、mac、create_at
|
||||
- OTATargetDevice:id、ota_id、mac_addr、type、create_at
|
||||
- 等化曲线处理器:CurveHandler.NewCurveHandler(curveRepo, curveCache, eqCfg, s3, log)
|
||||
- 分享代码处理器:ShareCodeHandler.NewShareCodeHandler(shareCache, log, maxPerMac)
|
||||
- **等化曲线查询参数说明**
|
||||
- brand:设备品牌(必填)
|
||||
- name:设备型号(必填)
|
||||
- target:目标曲线名称(可选,默认modelCurve固定为Harman over-ear 2018)
|
||||
- base64Resp:是否返回base64编码响应(可选)
|
||||
- **等化曲线数据模型字段**
|
||||
- Model:id、brand_name、name、form、rig、source、eq_key、create_at
|
||||
- Target:id、label、read_csv、file、bassBoost、addTime
|
||||
- **分享代码查询参数说明**
|
||||
- POST /audio/shareCreate:mac(必填)、model(必填)、eq_data(必填)
|
||||
- GET /audio/shareList:mac(必填)
|
||||
- GET /audio/shareQuery:shareCode(必填)
|
||||
- GET /audio/shareAccept:mac(必填)、model(必填)、shareCode(必填)
|
||||
- GET /audio/shareDelete:mac(必填)、shareCode(必填)
|
||||
- **分享代码数据模型字段**
|
||||
- ShareCodeData:share_code、mac_addr、ip_addr、model、eq_data、expire_at、persisted
|
||||
- ShareCodeLog:id、mac_addr、share_code、action、model、ip_addr、eq_data、expire_at、create_at
|
||||
- **数据库表结构**
|
||||
- ota表:存储OTA固件升级记录
|
||||
- black_list表:存储OTA黑名单
|
||||
- ota_target_device表:存储OTA定向设备
|
||||
- share_code_log表:存储分享码操作日志
|
||||
- **常用调用示例(路径引用)**
|
||||
- 品牌查询:[internal/handler/brand.go:25](file://internal/handler/brand.go#L25)
|
||||
- 型号查询:[internal/handler/model.go:25](file://internal/handler/model.go#L25)
|
||||
- 型号检索:[internal/handler/model_list.go:26](file://internal/handler/model_list.go#L26)
|
||||
- 设备上报:[internal/handler/device.go:26](file://internal/handler/device.go#L26)
|
||||
- OTA固件升级:[internal/handler/ota.go:25](file://internal/handler/ota.go#L25)
|
||||
- 等化曲线:[internal/handler/curve.go:56](file://internal/handler/curve.go#L56)
|
||||
- 分享代码创建:[internal/handler/share_code.go:40](file://internal/handler/share_code.go#L40)
|
||||
- 健康检查:[internal/handler/health.go:14](file://internal/handler/health.go#L14)
|
||||
- **配置与启动**
|
||||
- 配置加载与环境变量:[internal/config/config.go:18-64](file://internal/config/config.go#L18-L64)
|
||||
- 服务器启动与优雅关闭:[cmd/server/main.go:27-108](file://cmd/server/main.go#L27-L108)
|
||||
- 等化配置:[internal/config/equalize.go:12-33](file://internal/config/equalize.go#L12-L33)
|
||||
- 分享码TTL配置:[internal/config/share_code_ttl.go:15-59](file://internal/config/share_code_ttl.go#L15-L59)
|
||||
- **中间件**
|
||||
- CORS:[internal/middleware/cors.go:7-21](file://internal/middleware/cors.go#L7-L21)
|
||||
- Logger:[internal/middleware/logger.go:10-45](file://internal/middleware/logger.go#L10-L45)
|
||||
@@ -720,9 +1005,18 @@ ALL --> LOG["zap.Logger"]
|
||||
- **缓存策略**
|
||||
- 品牌缓存:brand:all 键,30分钟TTL
|
||||
- 型号缓存:model:brand:{brand} 和 model:all 键,30分钟TTL
|
||||
- 等化曲线缓存:Redis Hash存储,__fr键独立存储fr数据
|
||||
- 分享码缓存:share:{code}、share:mac:{mac}、share:pending等多键结构
|
||||
- 启动时预热缓存,提升首次查询性能
|
||||
- **OTA查询流程**
|
||||
- 最新OTA查询:按model+hw+beta+status=1排序取第一条
|
||||
- 黑名单检查:检查mac是否在指定ota_id的黑名单中
|
||||
- 定向设备检查:检查mac是否在指定ota_id的定向设备列表中
|
||||
- 版本选择:根据检查结果返回合适的OTA版本
|
||||
- **等化曲线查询流程**
|
||||
- 缓存查询:优先查询Redis缓存,包含独立存储的fr数据优化
|
||||
- 分布式锁:缓存未命中时获取分布式锁避免并发重复请求
|
||||
- 外部API调用:调用EQ计算接口获取参数化EQ数据
|
||||
- 缓存写入:将结果写入Redis缓存,分离存储fr数据
|
||||
- 版本选择:根据检查结果返回合适的OTA版本
|
||||
- **分享码查询流程**
|
||||
- 创建分享码:Lua原子性写入多个Redis键,获取分布式锁
|
||||
- 查询分享码:按MAC查询未过期分享码,主动清理过期成员
|
||||
- 导入分享码:验证分享码有效性,加入导入持久化队列
|
||||
- 删除分享码:校验所有权后删除Redis数据
|
||||
- 持久化任务:定时将分享码操作记录刷入MySQL数据库
|
||||
@@ -1,28 +1,37 @@
|
||||
# 数据模型
|
||||
|
||||
<cite>
|
||||
**本文引用的文件**
|
||||
**本文档引用的文件**
|
||||
- [internal/model/brand.go](file://internal/model/brand.go)
|
||||
- [internal/model/model.go](file://internal/model/model.go)
|
||||
- [internal/model/ota.go](file://internal/model/ota.go)
|
||||
- [internal/model/share_code.go](file://internal/model/share_code.go)
|
||||
- [internal/model/target.go](file://internal/model/target.go)
|
||||
- [internal/model/user_device.go](file://internal/model/user_device.go)
|
||||
- [internal/model/user_active.go](file://internal/model/user_active.go)
|
||||
- [internal/repository/brand.go](file://internal/repository/brand.go)
|
||||
- [internal/repository/model.go](file://internal/repository/model.go)
|
||||
- [internal/repository/ota.go](file://internal/repository/ota.go)
|
||||
- [internal/repository/share_code.go](file://internal/repository/share_code.go)
|
||||
- [internal/repository/curve.go](file://internal/repository/curve.go)
|
||||
- [internal/repository/device.go](file://internal/repository/device.go)
|
||||
- [internal/handler/brand.go](file://internal/handler/brand.go)
|
||||
- [internal/handler/model.go](file://internal/handler/model.go)
|
||||
- [internal/handler/model_list.go](file://internal/handler/model_list.go)
|
||||
- [internal/handler/ota.go](file://internal/handler/ota.go)
|
||||
- [internal/handler/share_code.go](file://internal/handler/share_code.go)
|
||||
- [internal/handler/device.go](file://internal/handler/device.go)
|
||||
- [internal/handler/curve.go](file://internal/handler/curve.go)
|
||||
- [internal/router/router.go](file://internal/router/router.go)
|
||||
- [internal/config/database.go](file://internal/config/database.go)
|
||||
- [internal/config/share_code_ttl.go](file://internal/config/share_code_ttl.go)
|
||||
- [internal/response/response.go](file://internal/response/response.go)
|
||||
- [internal/task/device_persist.go](file://internal/task/device_persist.go)
|
||||
- [internal/task/share_code_persist.go](file://internal/task/share_code_persist.go)
|
||||
- [pkg/encode/base64.go](file://pkg/encode/base64.go)
|
||||
- [sql/model.sql](file://sql/model.sql)
|
||||
- [sql/ota.sql](file://sql/ota.sql)
|
||||
- [sql/share_code_log.sql](file://sql/share_code_log.sql)
|
||||
- [sql/user_device.sql](file://sql/user_device.sql)
|
||||
- [sql/user_active.sql](file://sql/user_active.sql)
|
||||
- [sql/ota_target_device.sql](file://sql/ota_target_device.sql)
|
||||
@@ -31,10 +40,11 @@
|
||||
|
||||
## 更新摘要
|
||||
**变更内容**
|
||||
- 新增OTA固件升级相关模型和功能模块
|
||||
- 新增用户设备跟踪模型和活动记录模型
|
||||
- 新增设备报告接口和异步持久化任务
|
||||
- 扩展路由配置以支持新的API端点
|
||||
- 新增分享代码数据模型(ShareCodeData)和相关处理流程
|
||||
- 新增目标数据模型(Target),支持曲线目标配置
|
||||
- 增强OTA模型,支持布尔值序列化和更多字段
|
||||
- 新增分享码持久化任务和Redis缓存机制
|
||||
- 扩展路由配置以支持分享码相关API端点
|
||||
|
||||
## 目录
|
||||
1. [简介](#简介)
|
||||
@@ -49,10 +59,10 @@
|
||||
10. [附录](#附录)
|
||||
|
||||
## 简介
|
||||
本文件面向 Luxsin 应用 API 的数据模型,系统性梳理 Brand、Model、OTA、UserDevice 和 UserActive 五类数据模型的设计理念、字段定义、约束条件、业务含义以及与数据库表结构的映射关系。文档还覆盖 ORM 映射配置(基于原生 sql.DB 的扫描映射)、模型验证与序列化机制、模型在各层之间的传递方式与性能考量,并给出扩展、版本管理与向后兼容的最佳实践建议。内容兼顾初学者与高级开发者,既提供高层概览,也包含代码级的可视化图示与来源标注。
|
||||
本文件面向 Luxsin 应用 API 的数据模型,系统性梳理 Brand、Model、OTA、ShareCode、Target、UserDevice 和 UserActive 七类数据模型的设计理念、字段定义、约束条件、业务含义以及与数据库表结构的映射关系。文档还覆盖 ORM 映射配置(基于原生 sql.DB 的扫描映射)、模型验证与序列化机制、模型在各层之间的传递方式与性能考量,并给出扩展、版本管理与向后兼容的最佳实践建议。内容兼顾初学者与高级开发者,既提供高层概览,也包含代码级的可视化图示与来源标注。
|
||||
|
||||
## 项目结构
|
||||
该项目采用分层架构:路由层负责请求入口与中间件;处理器层处理业务逻辑与参数解析;仓库层封装数据库访问;模型层承载数据结构;响应层统一返回格式;编码层提供可选的响应体压缩编码;配置层加载数据库等外部服务配置。新增的OTA固件升级、用户设备跟踪和设备活动记录功能进一步完善了系统的数据模型体系。
|
||||
该项目采用分层架构:路由层负责请求入口与中间件;处理器层处理业务逻辑与参数解析;仓库层封装数据库访问;模型层承载数据结构;响应层统一返回格式;编码层提供可选的响应体压缩编码;配置层加载数据库、Redis等外部服务配置。新增的分享码功能、目标曲线模型和增强的OTA模型进一步完善了系统的数据模型体系。
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
@@ -68,12 +78,16 @@ MODEL_H["internal/handler/model.go"]
|
||||
MODEL_LIST_H["internal/handler/model_list.go"]
|
||||
OTA_H["internal/handler/ota.go"]
|
||||
DEVICE_H["internal/handler/device.go"]
|
||||
SHARE_CODE_H["internal/handler/share_code.go"]
|
||||
CURVE_H["internal/handler/curve.go"]
|
||||
end
|
||||
subgraph "仓库层"
|
||||
BRAND_R["internal/repository/brand.go"]
|
||||
MODEL_R["internal/repository/model.go"]
|
||||
OTA_R["internal/repository/ota.go"]
|
||||
DEVICE_R["internal/repository/device.go"]
|
||||
SHARE_CODE_R["internal/repository/share_code.go"]
|
||||
CURVE_R["internal/repository/curve.go"]
|
||||
end
|
||||
subgraph "模型层"
|
||||
MODEL_M["internal/model/brand.go"]
|
||||
@@ -81,6 +95,11 @@ MODEL_M2["internal/model/model.go"]
|
||||
MODEL_M3["internal/model/ota.go"]
|
||||
MODEL_M4["internal/model/user_device.go"]
|
||||
MODEL_M5["internal/model/user_active.go"]
|
||||
MODEL_M6["internal/model/share_code.go"]
|
||||
MODEL_M7["internal/model/target.go"]
|
||||
end
|
||||
subgraph "缓存层"
|
||||
CACHE["internal/cache/*"]
|
||||
end
|
||||
subgraph "响应与编码"
|
||||
RESP["internal/response/response.go"]
|
||||
@@ -88,10 +107,12 @@ ENCODE["pkg/encode/base64.go"]
|
||||
end
|
||||
subgraph "配置与数据库"
|
||||
DB_CFG["internal/config/database.go"]
|
||||
SHARE_TTL["internal/config/share_code_ttl.go"]
|
||||
DB_SQL["sql/*.sql"]
|
||||
end
|
||||
subgraph "任务处理"
|
||||
TASK["internal/task/device_persist.go"]
|
||||
DEVICE_TASK["internal/task/device_persist.go"]
|
||||
SHARE_TASK["internal/task/share_code_persist.go"]
|
||||
end
|
||||
MAIN --> ROUTER
|
||||
ROUTER --> BRAND_H
|
||||
@@ -99,56 +120,77 @@ ROUTER --> MODEL_H
|
||||
ROUTER --> MODEL_LIST_H
|
||||
ROUTER --> OTA_H
|
||||
ROUTER --> DEVICE_H
|
||||
ROUTER --> SHARE_CODE_H
|
||||
ROUTER --> CURVE_H
|
||||
BRAND_H --> BRAND_R
|
||||
MODEL_H --> MODEL_R
|
||||
MODEL_LIST_H --> MODEL_R
|
||||
OTA_H --> OTA_R
|
||||
DEVICE_H --> DEVICE_R
|
||||
SHARE_CODE_H --> CACHE
|
||||
SHARE_CODE_H --> SHARE_CODE_R
|
||||
CURVE_H --> CURVE_R
|
||||
BRAND_R --> MODEL_M
|
||||
MODEL_R --> MODEL_M2
|
||||
OTA_R --> MODEL_M3
|
||||
DEVICE_R --> MODEL_M4
|
||||
DEVICE_R --> MODEL_M5
|
||||
SHARE_CODE_R --> MODEL_M6
|
||||
CURVE_R --> MODEL_M7
|
||||
BRAND_H --> RESP
|
||||
MODEL_H --> RESP
|
||||
MODEL_LIST_H --> RESP
|
||||
OTA_H --> RESP
|
||||
DEVICE_H --> RESP
|
||||
SHARE_CODE_H --> RESP
|
||||
CURVE_H --> RESP
|
||||
DEVICE_H --> ENCODE
|
||||
TASK --> DEVICE_R
|
||||
SHARE_CODE_H --> ENCODE
|
||||
SHARE_TASK --> SHARE_CODE_R
|
||||
DEVICE_TASK --> DEVICE_R
|
||||
DB_CFG --> DB_SQL
|
||||
CACHE --> SHARE_TTL
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
- [cmd/server/main.go:22-64](file://cmd/server/main.go#L22-L64)
|
||||
- [internal/router/router.go:14-56](file://internal/router/router.go#L14-L56)
|
||||
- [internal/router/router.go:14-82](file://internal/router/router.go#L14-L82)
|
||||
- [internal/handler/brand.go:19-50](file://internal/handler/brand.go#L19-L50)
|
||||
- [internal/handler/model.go:19-51](file://internal/handler/model.go#L19-L51)
|
||||
- [internal/handler/model_list.go:19-57](file://internal/handler/model_list.go#L19-L57)
|
||||
- [internal/handler/ota.go:14-133](file://internal/handler/ota.go#L14-L133)
|
||||
- [internal/handler/device.go:15-83](file://internal/handler/device.go#L15-L83)
|
||||
- [internal/handler/share_code.go:1-383](file://internal/handler/share_code.go#L1-L383)
|
||||
- [internal/handler/curve.go:1-582](file://internal/handler/curve.go#L1-L582)
|
||||
- [internal/repository/brand.go:16-51](file://internal/repository/brand.go#L16-L51)
|
||||
- [internal/repository/model.go:16-95](file://internal/repository/model.go#L16-L95)
|
||||
- [internal/repository/ota.go:11-159](file://internal/repository/ota.go#L11-L159)
|
||||
- [internal/repository/device.go:11-88](file://internal/repository/device.go#L11-L88)
|
||||
- [internal/repository/share_code.go:1-59](file://internal/repository/share_code.go#L1-L59)
|
||||
- [internal/repository/curve.go:1-66](file://internal/repository/curve.go#L1-L66)
|
||||
- [internal/model/brand.go:3-7](file://internal/model/brand.go#L3-L7)
|
||||
- [internal/model/model.go:5-15](file://internal/model/model.go#L5-L15)
|
||||
- [internal/model/ota.go:5-43](file://internal/model/ota.go#L5-L43)
|
||||
- [internal/model/ota.go:5-67](file://internal/model/ota.go#L5-L67)
|
||||
- [internal/model/user_device.go:5-12](file://internal/model/user_device.go#L5-L12)
|
||||
- [internal/model/user_active.go:5-13](file://internal/model/user_active.go#L5-L13)
|
||||
- [internal/model/share_code.go:14-25](file://internal/model/share_code.go#L14-L25)
|
||||
- [internal/model/target.go:5-14](file://internal/model/target.go#L5-L14)
|
||||
- [internal/response/response.go:9-37](file://internal/response/response.go#L9-L37)
|
||||
- [pkg/encode/base64.go:21-52](file://pkg/encode/base64.go#L21-L52)
|
||||
- [internal/config/database.go:17-72](file://internal/config/database.go#L17-L72)
|
||||
- [internal/config/share_code_ttl.go:12-60](file://internal/config/share_code_ttl.go#L12-L60)
|
||||
- [sql/model.sql:20-38](file://sql/model.sql#L20-L38)
|
||||
- [sql/ota.sql:23-44](file://sql/ota.sql#L23-L44)
|
||||
- [sql/share_code_log.sql:8-23](file://sql/share_code_log.sql#L8-L23)
|
||||
- [sql/user_device.sql:23-32](file://sql/user_device.sql#L23-L32)
|
||||
- [sql/user_active.sql:23-32](file://sql/user_active.sql#L23-L32)
|
||||
- [sql/ota_target_device.sql:23-31](file://sql/ota_target_device.sql#L23-L31)
|
||||
- [internal/task/device_persist.go:14-167](file://internal/task/device_persist.go#L14-L167)
|
||||
- [internal/task/share_code_persist.go:1-232](file://internal/task/share_code_persist.go#L1-L232)
|
||||
|
||||
**章节来源**
|
||||
- [cmd/server/main.go:22-64](file://cmd/server/main.go#L22-L64)
|
||||
- [internal/router/router.go:14-56](file://internal/router/router.go#L14-L56)
|
||||
- [internal/router/router.go:14-82](file://internal/router/router.go#L14-L82)
|
||||
|
||||
## 核心组件
|
||||
- **传统模型层(Model)**
|
||||
@@ -158,6 +200,11 @@ DB_CFG --> DB_SQL
|
||||
- OTA:固件升级记录,包含版本信息、下载地址、MD5校验、强制升级标志、灰度发布状态、定向升级配置等。
|
||||
- BlackList:OTA黑名单,记录被禁止升级的设备MAC地址。
|
||||
- OTATargetDevice:OTA定向设备,记录允许特定设备升级的白名单或黑名单。
|
||||
- **分享码模型层**
|
||||
- ShareCodeLog:分享码操作日志,记录导出/导入操作及EQ数据快照。
|
||||
- ShareCodeData:分享码缓存数据,包含分享码、MAC地址、设备型号、EQ数据、过期时间等。
|
||||
- **目标曲线模型层**
|
||||
- Target:目标曲线配置,包含标签、CSV读取标志、文件路径、贝斯增强配置等。
|
||||
- **用户设备跟踪模型层**
|
||||
- UserDevice:用户设备信息,包含设备MAC地址、型号、添加时间、当前版本等。
|
||||
- UserActive:用户活动记录,包含设备活跃信息、IP地址、活跃日期等。
|
||||
@@ -166,34 +213,46 @@ DB_CFG --> DB_SQL
|
||||
- ModelRepository:提供按品牌名或型号名模糊查询的型号列表,并处理可空字段的扫描。
|
||||
- OTARepository:提供OTA升级信息查询、黑名单检查、定向设备查询等功能。
|
||||
- DeviceRepository:提供设备信息查询、插入、更新以及活动记录管理。
|
||||
- ShareCodeRepository:提供分享码日志插入、导出记录检查等功能。
|
||||
- CurveRepository:提供型号和目标曲线查询功能。
|
||||
- **处理器层(Handler)**
|
||||
- BrandHandler:接收查询参数,调用仓库层,支持可选的响应体 Base64 编码。
|
||||
- ModelHandler:接收品牌与型号查询参数,调用仓库层,支持可选的响应体 Base64 编码。
|
||||
- ModelListHandler:通过搜索客户端返回模型列表,支持可选的响应体 Base64 编码。
|
||||
- OTAHandler:获取OTA升级信息,支持黑名单检查、定向升级检查等功能。
|
||||
- DeviceHandler:处理设备信息上报,将设备活动信息写入Redis缓存。
|
||||
- ShareCodeHandler:处理分享码创建、查询、导入、删除等操作,支持Redis缓存和数据库持久化。
|
||||
- CurveHandler:处理曲线数据获取,支持目标曲线配置和EQ参数化。
|
||||
- **任务处理层**
|
||||
- DevicePersistTask:定时从Redis缓存批量持久化设备信息到数据库。
|
||||
- ShareCodePersistTask:定时从Redis缓存批量持久化分享码日志到数据库。
|
||||
|
||||
**章节来源**
|
||||
- [internal/model/brand.go:3-7](file://internal/model/brand.go#L3-L7)
|
||||
- [internal/model/model.go:5-15](file://internal/model/model.go#L5-L15)
|
||||
- [internal/model/ota.go:5-43](file://internal/model/ota.go#L5-L43)
|
||||
- [internal/model/ota.go:5-67](file://internal/model/ota.go#L5-L67)
|
||||
- [internal/model/share_code.go:14-25](file://internal/model/share_code.go#L14-L25)
|
||||
- [internal/model/target.go:5-14](file://internal/model/target.go#L5-L14)
|
||||
- [internal/model/user_device.go:5-12](file://internal/model/user_device.go#L5-L12)
|
||||
- [internal/model/user_active.go:5-13](file://internal/model/user_active.go#L5-L13)
|
||||
- [internal/repository/brand.go:20-51](file://internal/repository/brand.go#L20-L51)
|
||||
- [internal/repository/model.go:20-95](file://internal/repository/model.go#L20-L95)
|
||||
- [internal/repository/ota.go:19-159](file://internal/repository/ota.go#L19-L159)
|
||||
- [internal/repository/device.go:19-88](file://internal/repository/device.go#L19-L88)
|
||||
- [internal/repository/share_code.go:12-59](file://internal/repository/share_code.go#L12-L59)
|
||||
- [internal/repository/curve.go:11-66](file://internal/repository/curve.go#L11-L66)
|
||||
- [internal/handler/brand.go:26-50](file://internal/handler/brand.go#L26-L50)
|
||||
- [internal/handler/model.go:26-51](file://internal/handler/model.go#L26-L51)
|
||||
- [internal/handler/model_list.go:26-57](file://internal/handler/model_list.go#L26-L57)
|
||||
- [internal/handler/ota.go:23-133](file://internal/handler/ota.go#L23-L133)
|
||||
- [internal/handler/device.go:27-83](file://internal/handler/device.go#L27-L83)
|
||||
- [internal/handler/share_code.go:15-383](file://internal/handler/share_code.go#L15-L383)
|
||||
- [internal/handler/curve.go:27-582](file://internal/handler/curve.go#L27-L582)
|
||||
- [internal/task/device_persist.go:24-167](file://internal/task/device_persist.go#L24-L167)
|
||||
- [internal/task/share_code_persist.go:14-232](file://internal/task/share_code_persist.go#L14-L232)
|
||||
|
||||
## 架构总览
|
||||
下图展示了从请求到响应的关键路径,包括处理器、仓库、数据库与可选编码流程,以及新增的OTA固件升级和设备跟踪功能。
|
||||
下图展示了从请求到响应的关键路径,包括处理器、仓库、数据库与可选编码流程,以及新增的分享码功能、目标曲线配置和增强的OTA固件升级功能。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
@@ -201,48 +260,47 @@ participant C as "客户端"
|
||||
participant R as "路由层"
|
||||
participant H as "处理器层"
|
||||
participant Repo as "仓库层"
|
||||
participant Cache as "缓存层"
|
||||
participant DB as "数据库"
|
||||
participant Enc as "编码层"
|
||||
C->>R : "GET /audio/ota?model=xxx&hw=1&mac=xx : xx : xx&beta=0"
|
||||
R->>H : "OTAHandler.GetOTA"
|
||||
H->>Repo : "GetLatestOTA(model, hw, beta)"
|
||||
Repo->>DB : "查询最新OTA记录"
|
||||
DB-->>Repo : "OTA记录"
|
||||
Repo-->>H : "OTA对象"
|
||||
H->>Repo : "IsInBlackList(otaID, mac)"
|
||||
Repo->>DB : "检查黑名单"
|
||||
DB-->>Repo : "黑名单状态"
|
||||
Repo-->>H : "黑名单检查结果"
|
||||
alt "在黑名单中"
|
||||
H->>Repo : "GetLatestOTANotInBlackList"
|
||||
Repo->>DB : "查询非黑名单OTA"
|
||||
DB-->>Repo : "OTA记录"
|
||||
Repo-->>H : "OTA对象"
|
||||
else "非定向升级"
|
||||
H->>Repo : "FindTargetDevice(otaID, mac)"
|
||||
Repo->>DB : "检查定向设备"
|
||||
DB-->>Repo : "设备信息"
|
||||
Repo-->>H : "设备检查结果"
|
||||
else "定向升级"
|
||||
H->>Repo : "GetLatestOTANotTarget"
|
||||
Repo->>DB : "查询非定向OTA"
|
||||
DB-->>Repo : "OTA记录"
|
||||
Repo-->>H : "OTA对象"
|
||||
end
|
||||
alt "base64Resp=true"
|
||||
H->>Enc : "EncodeJSON(OTA)"
|
||||
Enc-->>H : "Base64 字符串"
|
||||
H-->>C : "200 OK + Base64"
|
||||
else "默认"
|
||||
H-->>C : "200 OK + JSON"
|
||||
end
|
||||
C->>R : "POST /audio/shareCreate"
|
||||
R->>H : "ShareCodeHandler.ExportShareCode"
|
||||
H->>Cache : "Create(分享码, EQ数据)"
|
||||
Cache-->>H : "ShareCodeData"
|
||||
H->>Repo : "InsertLog(分享码日志)"
|
||||
Repo->>DB : "插入分享码日志"
|
||||
DB-->>Repo : "确认插入"
|
||||
Repo-->>H : "确认"
|
||||
H-->>C : "200 OK + 分享码信息"
|
||||
C->>R : "GET /audio/shareQuery?shareCode=ABCDE"
|
||||
R->>H : "ShareCodeHandler.QueryShareCode"
|
||||
H->>Cache : "Get(分享码)"
|
||||
Cache-->>H : "ShareCodeData"
|
||||
H-->>C : "200 OK + EQ数据"
|
||||
C->>R : "GET /audio/shareAccept?mac=xx&model=Luxsin-X9&shareCode=ABCDE"
|
||||
R->>H : "ShareCodeHandler.ImportShareCode"
|
||||
H->>Cache : "EnqueueImportLog(导入日志)"
|
||||
Cache-->>H : "排队成功"
|
||||
H-->>C : "200 OK + EQ数据"
|
||||
C->>R : "GET /audio/getCurve?brand=xxx&name=xxx&target=xxx"
|
||||
R->>H : "CurveHandler.GetCurve"
|
||||
H->>Repo : "GetTargetByLabel(目标曲线)"
|
||||
Repo->>DB : "查询目标曲线"
|
||||
DB-->>Repo : "Target配置"
|
||||
Repo-->>H : "Target配置"
|
||||
H->>Cache : "GetWithFR(缓存)"
|
||||
Cache-->>H : "曲线数据"
|
||||
H-->>C : "200 OK + parametric_eq"
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
- [internal/router/router.go:51](file://internal/router/router.go#L51)
|
||||
- [internal/handler/ota.go:25-133](file://internal/handler/ota.go#L25-L133)
|
||||
- [internal/repository/ota.go:19-159](file://internal/repository/ota.go#L19-L159)
|
||||
- [pkg/encode/base64.go:35-52](file://pkg/encode/base64.go#L35-L52)
|
||||
- [internal/router/router.go:73-77](file://internal/router/router.go#L73-L77)
|
||||
- [internal/handler/share_code.go:40-125](file://internal/handler/share_code.go#L40-L125)
|
||||
- [internal/handler/share_code.go:192-211](file://internal/handler/share_code.go#L192-L211)
|
||||
- [internal/handler/share_code.go:228-279](file://internal/handler/share_code.go#L228-L279)
|
||||
- [internal/handler/curve.go:145-198](file://internal/handler/curve.go#L145-L198)
|
||||
- [internal/repository/curve.go:44-66](file://internal/repository/curve.go#L44-L66)
|
||||
- [internal/cache/curve_cache.go:27-102](file://internal/cache/curve_cache.go#L27-L102)
|
||||
|
||||
## 详细组件分析
|
||||
|
||||
@@ -351,12 +409,12 @@ ModelRepository --> Model : "返回"
|
||||
- verName:字符串,版本名称。
|
||||
- url:字符串,固件下载地址。
|
||||
- md5:字符串,固件MD5校验值。
|
||||
- force:整数,是否强制升级(0-否,1-是)。
|
||||
- force:BoolInt,是否强制升级(true/false)。
|
||||
- desc:字符串指针,升级描述。
|
||||
- model:字符串指针,对应设备型号。
|
||||
- hw:整数,硬件版本号。
|
||||
- target:整数,是否定向升级(0-否,1-是)。
|
||||
- beta:整数,是否灰度发布(0-否,1-是)。
|
||||
- target:BoolInt,是否定向升级(true/false)。
|
||||
- beta:BoolInt,是否灰度发布(true/false)。
|
||||
- pawVerCode:整数,配套软件版本号。
|
||||
- pawVerName:字符串,配套软件版本名称。
|
||||
- pawUrl:字符串,配套软件下载地址。
|
||||
@@ -382,6 +440,7 @@ ModelRepository --> Model : "返回"
|
||||
- 字段:完整映射关系详见数据库表结构。
|
||||
- **ORM 映射配置**
|
||||
- 使用 sql.NullString 和 sql.NullTime 扫描可空列。
|
||||
- BoolInt类型支持数据库整型与JSON布尔值的双向转换。
|
||||
- JSON 标签用于序列化输出,可空字段支持 omitempty。
|
||||
- **查询流程**
|
||||
- 支持多种查询策略:最新OTA记录、非黑名单OTA记录、非定向OTA记录等。
|
||||
@@ -395,12 +454,12 @@ class OTA {
|
||||
+string verName
|
||||
+string url
|
||||
+string md5
|
||||
+int force
|
||||
+BoolInt force
|
||||
+*string desc
|
||||
+*string model
|
||||
+int hw
|
||||
+int target
|
||||
+int beta
|
||||
+BoolInt target
|
||||
+BoolInt beta
|
||||
+int pawVerCode
|
||||
+string pawVerName
|
||||
+string pawUrl
|
||||
@@ -436,17 +495,140 @@ OTARepository --> OTATargetDevice : "返回"
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
- [internal/model/ota.go:6-42](file://internal/model/ota.go#L6-L42)
|
||||
- [internal/model/ota.go:29-67](file://internal/model/ota.go#L29-L67)
|
||||
- [internal/repository/ota.go:19-159](file://internal/repository/ota.go#L19-L159)
|
||||
- [sql/ota.sql:24-44](file://sql/ota.sql#L24-L44)
|
||||
- [sql/ota_target_device.sql:24-31](file://sql/ota_target_device.sql#L24-L31)
|
||||
|
||||
**章节来源**
|
||||
- [internal/model/ota.go:5-43](file://internal/model/ota.go#L5-L43)
|
||||
- [internal/model/ota.go:5-67](file://internal/model/ota.go#L5-L67)
|
||||
- [internal/repository/ota.go:19-159](file://internal/repository/ota.go#L19-L159)
|
||||
- [sql/ota.sql:23-44](file://sql/ota.sql#L23-L44)
|
||||
- [sql/ota_target_device.sql:23-31](file://sql/ota_target_device.sql#L23-L31)
|
||||
|
||||
### 分享码数据模型
|
||||
- **设计理念**
|
||||
- ShareCodeLog用于记录分享码的操作日志,支持导出和导入两种操作类型。
|
||||
- ShareCodeData用于Redis缓存中的分享码数据,包含完整的分享码信息和缓存状态。
|
||||
- **字段定义与约束**
|
||||
- ShareCodeLog模型:
|
||||
- ID:整数,主键,自增。
|
||||
- MacAddr:字符串,设备MAC地址。
|
||||
- ShareCode:字符串,5位分享码。
|
||||
- Action:枚举,操作类型(export/import)。
|
||||
- Model:枚举,设备型号(Luxsin-X9/Luxsin-X8)。
|
||||
- IpAddr:字符串,用户IP地址。
|
||||
- EqData:JSON,EQ数据快照。
|
||||
- ExpireAt:时间戳指针,分享码到期时间。
|
||||
- CreateAt:时间戳,创建时间。
|
||||
- ShareCodeData结构:
|
||||
- ShareCode:字符串,5位分享码。
|
||||
- MacAddr:字符串,创建者MAC地址。
|
||||
- IpAddr:字符串,创建者IP地址。
|
||||
- Model:字符串,设备型号。
|
||||
- EqData:字符串,EQ参数JSON。
|
||||
- ExpireAt:时间戳,过期时间。
|
||||
- Persisted:布尔值,是否已刷入数据库。
|
||||
- **业务含义**
|
||||
- 支持EQ数据的分享与导入功能,提供完整的操作审计和数据快照。
|
||||
- **数据库映射**
|
||||
- 表名:share_code_log。
|
||||
- 字段:完整映射关系详见数据库表结构。
|
||||
- 索引:对mac_addr、share_code、create_at建立索引。
|
||||
- **ORM 映射配置**
|
||||
- 使用 sql.NullString 和 sql.NullTime 扫描可空列。
|
||||
- JSON 标签用于序列化输出,支持复杂JSON数据存储。
|
||||
- **查询流程**
|
||||
- 支持按分享码查询导出记录存在性检查。
|
||||
- 支持分享码日志的插入和查询。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class ShareCodeLog {
|
||||
+int ID
|
||||
+string MacAddr
|
||||
+string ShareCode
|
||||
+string Action
|
||||
+string Model
|
||||
+string IpAddr
|
||||
+[]byte EqData
|
||||
+*time ExpireAt
|
||||
+time CreateAt
|
||||
}
|
||||
class ShareCodeData {
|
||||
+string ShareCode
|
||||
+string MacAddr
|
||||
+string IpAddr
|
||||
+string Model
|
||||
+string EqData
|
||||
+time ExpireAt
|
||||
+bool Persisted
|
||||
}
|
||||
class ShareCodeRepository {
|
||||
-db *sql.DB
|
||||
+InsertLog(ctx, log) error
|
||||
+HasExportLog(ctx, shareCode) bool
|
||||
}
|
||||
ShareCodeRepository --> ShareCodeLog : "返回"
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
- [internal/model/share_code.go:14-25](file://internal/model/share_code.go#L14-L25)
|
||||
- [internal/repository/share_code.go:20-59](file://internal/repository/share_code.go#L20-L59)
|
||||
- [sql/share_code_log.sql:9-23](file://sql/share_code_log.sql#L9-L23)
|
||||
|
||||
**章节来源**
|
||||
- [internal/model/share_code.go:14-25](file://internal/model/share_code.go#L14-L25)
|
||||
- [internal/repository/share_code.go:12-59](file://internal/repository/share_code.go#L12-L59)
|
||||
- [sql/share_code_log.sql:8-23](file://sql/share_code_log.sql#L8-L23)
|
||||
|
||||
### 目标曲线数据模型
|
||||
- **设计理念**
|
||||
- Target模型用于定义目标曲线配置,支持从CSV文件读取目标数据和贝斯增强配置。
|
||||
- **字段定义与约束**
|
||||
- ID:整数,主键,自增。
|
||||
- Label:字符串,目标曲线标签。
|
||||
- ReadCSV:BoolInt,是否从CSV文件读取目标数据。
|
||||
- File:字符串指针,CSV文件路径。
|
||||
- BassBoost:字符串指针,贝斯增强配置JSON。
|
||||
- AddTime:时间戳,添加时间。
|
||||
- **业务含义**
|
||||
- 支持灵活的目标曲线配置,可以使用预定义的曲线名称或从CSV文件读取自定义曲线。
|
||||
- **数据库映射**
|
||||
- 表名:target。
|
||||
- 字段:完整映射关系详见数据库表结构。
|
||||
- **ORM 映射配置**
|
||||
- 使用 BoolInt 类型支持布尔值序列化。
|
||||
- JSON 标签用于序列化输出,可空字段支持 omitempty。
|
||||
- **查询流程**
|
||||
- 支持按标签查询目标曲线配置。
|
||||
- 支持CSV文件路径和贝斯增强配置的动态加载。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class Target {
|
||||
+int ID
|
||||
+string Label
|
||||
+BoolInt ReadCSV
|
||||
+*string File
|
||||
+*string BassBoost
|
||||
+time AddTime
|
||||
}
|
||||
class CurveRepository {
|
||||
-db *sql.DB
|
||||
+GetTargetByLabel(ctx, label) *Target
|
||||
}
|
||||
CurveRepository --> Target : "返回"
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
- [internal/model/target.go:5-14](file://internal/model/target.go#L5-L14)
|
||||
- [internal/repository/curve.go:44-66](file://internal/repository/curve.go#L44-L66)
|
||||
|
||||
**章节来源**
|
||||
- [internal/model/target.go:5-14](file://internal/model/target.go#L5-L14)
|
||||
- [internal/repository/curve.go:44-66](file://internal/repository/curve.go#L44-L66)
|
||||
|
||||
### 用户设备跟踪模型
|
||||
- **设计理念**
|
||||
- UserDevice模型用于跟踪用户设备信息,支持设备注册、版本更新等功能。
|
||||
@@ -535,53 +717,42 @@ DeviceRepository --> UserActive : "返回"
|
||||
- **设备处理器特殊逻辑**
|
||||
- 将设备信息写入Redis缓存,支持异步持久化。
|
||||
- 提供设备信息上报接口。
|
||||
- **分享码处理器特殊逻辑**
|
||||
- 支持分享码创建、查询、导入、删除等完整生命周期管理。
|
||||
- 使用Redis缓存提高性能,支持分布式锁保证数据一致性。
|
||||
- 提供分享码数量限制和过期时间控制。
|
||||
- **曲线处理器特殊逻辑**
|
||||
- 支持目标曲线配置查询和EQ参数化计算。
|
||||
- 使用Redis缓存优化曲线数据访问性能。
|
||||
- **错误处理**
|
||||
- 处理器捕获仓库层错误,记录日志并通过统一响应体返回内部错误。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant C as "客户端"
|
||||
participant H as "OTAHandler"
|
||||
participant Repo as "OTARepository"
|
||||
participant H as "ShareCodeHandler"
|
||||
participant Cache as "ShareCodeCache"
|
||||
participant Repo as "ShareCodeRepository"
|
||||
participant DB as "数据库"
|
||||
participant Enc as "编码层"
|
||||
C->>H : "GET /audio/ota?model=...&hw=...&mac=...&beta=..."
|
||||
H->>Repo : "GetLatestOTA(model, hw, beta)"
|
||||
Repo->>DB : "查询最新OTA记录"
|
||||
DB-->>Repo : "OTA记录"
|
||||
Repo-->>H : "OTA对象"
|
||||
H->>Repo : "IsInBlackList(otaID, mac)"
|
||||
Repo->>DB : "检查黑名单"
|
||||
DB-->>Repo : "黑名单状态"
|
||||
Repo-->>H : "检查结果"
|
||||
alt "在黑名单中"
|
||||
H->>Repo : "GetLatestOTANotInBlackList"
|
||||
Repo->>DB : "查询非黑名单OTA"
|
||||
DB-->>Repo : "OTA记录"
|
||||
Repo-->>H : "OTA对象"
|
||||
else "非定向升级"
|
||||
H->>Repo : "FindTargetDevice(otaID, mac)"
|
||||
Repo->>DB : "检查定向设备"
|
||||
DB-->>Repo : "设备信息"
|
||||
Repo-->>H : "检查结果"
|
||||
else "定向升级"
|
||||
H->>Repo : "GetLatestOTANotTarget"
|
||||
Repo->>DB : "查询非定向OTA"
|
||||
DB-->>Repo : "OTA记录"
|
||||
Repo-->>H : "OTA对象"
|
||||
end
|
||||
alt "base64Resp=true"
|
||||
H->>Enc : "EncodeJSON(OTA)"
|
||||
Enc-->>H : "Base64 字符串"
|
||||
H-->>C : "200 OK + Base64"
|
||||
else "默认"
|
||||
H-->>C : "200 OK + JSON"
|
||||
end
|
||||
C->>H : "POST /audio/shareCreate"
|
||||
H->>Cache : "Create(mac, model, eqData)"
|
||||
Cache-->>H : "ShareCodeData"
|
||||
H->>Repo : "InsertLog(export)"
|
||||
Repo->>DB : "插入日志"
|
||||
DB-->>Repo : "确认"
|
||||
Repo-->>H : "确认"
|
||||
H-->>C : "200 OK + 分享码信息"
|
||||
C->>H : "GET /audio/shareAccept?shareCode=ABCDE"
|
||||
H->>Cache : "EnqueueImportLog(mac, model, eqData)"
|
||||
Cache-->>H : "排队成功"
|
||||
H-->>C : "200 OK + EQ数据"
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
- [internal/handler/ota.go:25-133](file://internal/handler/ota.go#L25-L133)
|
||||
- [internal/repository/ota.go:19-159](file://internal/repository/ota.go#L19-L159)
|
||||
- [internal/handler/share_code.go:40-125](file://internal/handler/share_code.go#L40-L125)
|
||||
- [internal/handler/share_code.go:228-279](file://internal/handler/share_code.go#L228-L279)
|
||||
- [internal/repository/share_code.go:20-59](file://internal/repository/share_code.go#L20-L59)
|
||||
- [pkg/encode/base64.go:21-52](file://pkg/encode/base64.go#L21-L52)
|
||||
- [internal/response/response.go:9-37](file://internal/response/response.go#L9-L37)
|
||||
|
||||
@@ -591,6 +762,8 @@ end
|
||||
- [internal/handler/model_list.go:26-57](file://internal/handler/model_list.go#L26-L57)
|
||||
- [internal/handler/ota.go:23-133](file://internal/handler/ota.go#L23-L133)
|
||||
- [internal/handler/device.go:27-83](file://internal/handler/device.go#L27-L83)
|
||||
- [internal/handler/share_code.go:15-383](file://internal/handler/share_code.go#L15-L383)
|
||||
- [internal/handler/curve.go:27-582](file://internal/handler/curve.go#L27-L582)
|
||||
- [pkg/encode/base64.go:21-52](file://pkg/encode/base64.go#L21-L52)
|
||||
- [internal/response/response.go:9-37](file://internal/response/response.go#L9-L37)
|
||||
|
||||
@@ -608,53 +781,66 @@ end
|
||||
- 支持按MAC地址查询设备信息。
|
||||
- 支持按MAC地址和日期查询活跃记录。
|
||||
- 扫描时将 sql.NullString 转换为指针字符串,避免零值歧义。
|
||||
- **分享码查询**
|
||||
- 支持按MAC地址查询未过期的分享码列表。
|
||||
- 支持按分享码查询单个分享码详情。
|
||||
- 支持分享码导入操作的日志排队和持久化。
|
||||
- **目标曲线查询**
|
||||
- 支持按标签查询目标曲线配置。
|
||||
- 支持CSV文件路径和贝斯增强配置的动态加载。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start(["进入 OTA 查询"]) --> Params["参数校验"]
|
||||
Params --> CheckBrand{"model和hw是否非空?"}
|
||||
CheckBrand --> |是| QueryOTA["GetLatestOTA 查询"]
|
||||
CheckBrand --> |否| Error["返回错误"]
|
||||
QueryOTA --> CheckBlackList["IsInBlackList 检查"]
|
||||
CheckBlackList --> |在黑名单| QueryNotInBlackList["GetLatestOTANotInBlackList"]
|
||||
CheckBlackList --> |不在黑名单| CheckTarget{"ota.target 是否为0?"}
|
||||
QueryNotInBlackList --> ReturnOTA["返回OTA"]
|
||||
CheckTarget --> |是| ReturnOTA
|
||||
CheckTarget --> |否| CheckTargetDevice["FindTargetDevice 检查"]
|
||||
CheckTargetDevice --> |在定向设备| ReturnOTA
|
||||
CheckTargetDevice --> |不在定向设备| QueryNotTarget["GetLatestOTANotTarget"]
|
||||
QueryNotTarget --> ReturnOTA
|
||||
ReturnOTA --> End(["返回结果"])
|
||||
Start(["进入分享码查询"]) --> Params["参数校验"]
|
||||
Params --> CheckMac{"mac参数是否非空?"}
|
||||
CheckMac --> |是| ListByMac["ListByMac 查询"]
|
||||
CheckMac --> |否| CheckCode{"shareCode参数是否5位?"}
|
||||
CheckCode --> |是| GetByCode["Get 查询"]
|
||||
CheckCode --> |否| Error["返回错误"]
|
||||
ListByMac --> CleanExpired["清理过期条目"]
|
||||
CleanExpired --> GetDetails["逐个获取详情"]
|
||||
GetDetails --> ReturnList["返回分享码列表"]
|
||||
GetByCode --> ReturnDetail["返回分享码详情"]
|
||||
ReturnList --> End(["返回结果"])
|
||||
ReturnDetail --> End
|
||||
Error --> End
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
- [internal/handler/ota.go:25-133](file://internal/handler/ota.go#L25-L133)
|
||||
- [internal/repository/ota.go:19-159](file://internal/repository/ota.go#L19-L159)
|
||||
- [internal/handler/share_code.go:138-177](file://internal/handler/share_code.go#L138-L177)
|
||||
- [internal/handler/share_code.go:192-211](file://internal/handler/share_code.go#L192-L211)
|
||||
- [internal/cache/share_code_cache.go:281-319](file://internal/cache/share_code_cache.go#L281-L319)
|
||||
|
||||
**章节来源**
|
||||
- [internal/repository/model.go:20-61](file://internal/repository/model.go#L20-L61)
|
||||
- [internal/repository/brand.go:20-51](file://internal/repository/brand.go#L20-L51)
|
||||
- [internal/repository/ota.go:19-159](file://internal/repository/ota.go#L19-L159)
|
||||
- [internal/repository/device.go:19-88](file://internal/repository/device.go#L19-L88)
|
||||
- [internal/repository/share_code.go:20-59](file://internal/repository/share_code.go#L20-L59)
|
||||
- [internal/repository/curve.go:44-66](file://internal/repository/curve.go#L44-L66)
|
||||
- [internal/handler/share_code.go:138-177](file://internal/handler/share_code.go#L138-L177)
|
||||
|
||||
## 依赖分析
|
||||
- **层间耦合**
|
||||
- Handler 依赖 Repository;Repository 依赖 sql.DB;Model 为纯数据结构。
|
||||
- 统一响应体与编码层被 Handler 调用,降低重复逻辑。
|
||||
- 新增的Redis依赖用于设备信息缓存。
|
||||
- 新增的Redis依赖用于分享码缓存和设备信息缓存。
|
||||
- 分享码功能依赖Redis缓存和数据库的双重存储。
|
||||
- 目标曲线功能依赖CurveRepository和CurveCache。
|
||||
- **外部依赖**
|
||||
- 数据库:MySQL,通过 sql.DB 访问。
|
||||
- 日志:zap。
|
||||
- Web 框架:Gin。
|
||||
- 搜索:Meilisearch(ModelListHandler)。
|
||||
- 缓存:Redis(Device 相关处理器)。
|
||||
- 任务调度:定时任务用于设备信息持久化。
|
||||
- 缓存:Redis(Device、ShareCode、Curve相关处理器)。
|
||||
- 对象存储:S3(曲线数据CSV文件)。
|
||||
- 任务调度:定时任务用于设备信息和分享码持久化。
|
||||
- **潜在循环依赖**
|
||||
- 当前结构清晰,无循环导入迹象。
|
||||
- **新增依赖关系**
|
||||
- 分享码功能依赖Redis缓存和数据库的双重存储。
|
||||
- 目标曲线功能依赖CurveRepository和CurveCache。
|
||||
- OTA功能依赖多个表的关联查询。
|
||||
- 设备跟踪功能依赖Redis缓存和数据库的双重存储。
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
@@ -663,23 +849,33 @@ H_Model["ModelHandler"] --> Repo_Model["ModelRepository"]
|
||||
H_ModelList["ModelListHandler"] --> Search["Meilisearch 客户端"]
|
||||
H_OTA["OTAHandler"] --> Repo_OTA["OTARepository"]
|
||||
H_Device["DeviceHandler"] --> Repo_Device["DeviceRepository"]
|
||||
H_ShareCode["ShareCodeHandler"] --> Cache_Share["ShareCodeCache"]
|
||||
H_ShareCode --> Repo_Share["ShareCodeRepository"]
|
||||
H_Curve["CurveHandler"] --> Repo_Curve["CurveRepository"]
|
||||
Repo_Brand --> DB["sql.DB"]
|
||||
Repo_Model --> DB
|
||||
Repo_OTA --> DB
|
||||
Repo_Device --> DB
|
||||
Repo_Share --> DB
|
||||
Repo_Curve --> DB
|
||||
H_Device --> Redis["Redis Client"]
|
||||
Repo_Device --> Redis
|
||||
H_ShareCode --> Redis
|
||||
H_Curve --> Redis
|
||||
H_Curve --> S3["S3 Storage"]
|
||||
H_Brand --> Resp["统一响应体"]
|
||||
H_Model --> Resp
|
||||
H_ModelList --> Resp
|
||||
H_OTA --> Resp
|
||||
H_Device --> Resp
|
||||
H_ShareCode --> Resp
|
||||
H_Curve --> Resp
|
||||
H_Brand --> Encode["Base64 编码"]
|
||||
H_Model --> Encode
|
||||
H_ModelList --> Encode
|
||||
Task["DevicePersistTask"] --> Repo_Device
|
||||
Task --> Redis
|
||||
Task --> DB
|
||||
Task_Device["DevicePersistTask"] --> Repo_Device
|
||||
Task_Device --> Redis
|
||||
Task_Share["ShareCodePersistTask"] --> Repo_Share
|
||||
Task_Share --> Redis
|
||||
```
|
||||
|
||||
**图表来源**
|
||||
@@ -688,16 +884,21 @@ Task --> DB
|
||||
- [internal/handler/model_list.go:14-57](file://internal/handler/model_list.go#L14-L57)
|
||||
- [internal/handler/ota.go:14-133](file://internal/handler/ota.go#L14-L133)
|
||||
- [internal/handler/device.go:15-83](file://internal/handler/device.go#L15-L83)
|
||||
- [internal/handler/share_code.go:15-383](file://internal/handler/share_code.go#L15-L383)
|
||||
- [internal/handler/curve.go:27-582](file://internal/handler/curve.go#L27-L582)
|
||||
- [internal/repository/brand.go:12-51](file://internal/repository/brand.go#L12-L51)
|
||||
- [internal/repository/model.go:12-95](file://internal/repository/model.go#L12-L95)
|
||||
- [internal/repository/ota.go:11-159](file://internal/repository/ota.go#L11-L159)
|
||||
- [internal/repository/device.go:11-88](file://internal/repository/device.go#L11-L88)
|
||||
- [internal/repository/share_code.go:12-59](file://internal/repository/share_code.go#L12-L59)
|
||||
- [internal/repository/curve.go:11-66](file://internal/repository/curve.go#L11-L66)
|
||||
- [internal/response/response.go:9-37](file://internal/response/response.go#L9-L37)
|
||||
- [pkg/encode/base64.go:21-52](file://pkg/encode/base64.go#L21-L52)
|
||||
- [internal/task/device_persist.go:14-167](file://internal/task/device_persist.go#L14-L167)
|
||||
- [internal/task/share_code_persist.go:14-232](file://internal/task/share_code_persist.go#L14-L232)
|
||||
|
||||
**章节来源**
|
||||
- [internal/router/router.go:14-56](file://internal/router/router.go#L14-L56)
|
||||
- [internal/router/router.go:14-82](file://internal/router/router.go#L14-L82)
|
||||
- [internal/config/database.go:17-72](file://internal/config/database.go#L17-L72)
|
||||
|
||||
## 性能考虑
|
||||
@@ -706,30 +907,38 @@ Task --> DB
|
||||
- OTA表对(model, hw, beta, status)建立索引,支持快速查询最新OTA记录。
|
||||
- UserDevice表对(mac_addr)建立唯一索引,支持快速设备查询。
|
||||
- UserActive表对(mac_addr, active_date)建立联合索引,支持按日期分区查询。
|
||||
- share_code_log表对(mac_addr, share_code, create_at)建立索引,支持分享码查询。
|
||||
- 查询时优先按品牌名匹配,减少 LIKE 的范围。
|
||||
- **扫描与内存**
|
||||
- 使用 sql.NullString 扫描可空列,避免零值歧义;转换为指针字符串减少冗余存储。
|
||||
- OTA模型使用sql.NullTime处理可空时间字段。
|
||||
- OTA模型使用BoolInt类型处理布尔值,支持数据库整型与JSON布尔值的双向转换。
|
||||
- ShareCodeLog模型使用[]byte存储JSON数据,减少字符串处理开销。
|
||||
- **缓存策略**
|
||||
- 设备信息先写入Redis缓存,通过定时任务批量持久化到数据库,减少数据库压力。
|
||||
- 品牌和型号信息使用Redis缓存提升查询性能。
|
||||
- 分享码数据使用Redis缓存,支持TTL自动过期和分布式锁保证一致性。
|
||||
- 目标曲线数据使用Redis缓存,支持fr数据独立存储优化缓存空间。
|
||||
- **编码策略**
|
||||
- 可选的自定义 Base64 编码可降低响应体积,适合大列表传输场景。
|
||||
- **并发与超时**
|
||||
- 服务器设置读写超时与优雅关闭,保障稳定性。
|
||||
- 设备持久化任务使用定时器定期执行,避免阻塞主线程。
|
||||
- 设备持久化任务和分享码持久化任务使用定时器定期执行,避免阻塞主线程。
|
||||
- 分布式锁机制保证Redis操作的原子性和数据一致性。
|
||||
|
||||
**章节来源**
|
||||
- [sql/model.sql:34-35](file://sql/model.sql#L34-L35)
|
||||
- [sql/ota.sql:24-44](file://sql/ota.sql#L24-L44)
|
||||
- [sql/share_code_log.sql:20-23](file://sql/share_code_log.sql#L20-L23)
|
||||
- [sql/user_device.sql:24-32](file://sql/user_device.sql#L24-L32)
|
||||
- [sql/user_active.sql:24-32](file://sql/user_active.sql#L24-L32)
|
||||
- [internal/repository/model.go:63-95](file://internal/repository/model.go#L63-L95)
|
||||
- [internal/repository/ota.go:20-159](file://internal/repository/ota.go#L20-L159)
|
||||
- [internal/repository/device.go:19-88](file://internal/repository/device.go#L19-L88)
|
||||
- [internal/repository/share_code.go:20-59](file://internal/repository/share_code.go#L20-L59)
|
||||
- [pkg/encode/base64.go:21-52](file://pkg/encode/base64.go#L21-L52)
|
||||
- [cmd/server/main.go:66-95](file://cmd/server/main.go#L66-L95)
|
||||
- [internal/task/device_persist.go:24-91](file://internal/task/device_persist.go#L24-L91)
|
||||
- [internal/task/share_code_persist.go:24-113](file://internal/task/share_code_persist.go#L24-L113)
|
||||
|
||||
## 故障排查指南
|
||||
- **常见问题**
|
||||
@@ -738,12 +947,16 @@ Task --> DB
|
||||
- 编码异常:确认 base64Resp 参数与 JSON 序列化是否成功。
|
||||
- OTA查询失败:检查model、hw参数是否正确,确认OTA记录状态是否为1。
|
||||
- 设备信息未持久化:检查Redis连接和数据库连接,确认定时任务是否正常运行。
|
||||
- 分享码创建失败:检查Redis连接、分享码生成算法、TTL配置。
|
||||
- 分享码导入失败:检查导入日志队列、数据库连接、分布式锁状态。
|
||||
- 目标曲线查询失败:检查目标曲线配置、CSV文件路径、S3访问权限。
|
||||
- **排查步骤**
|
||||
- 查看日志:处理器记录错误日志,统一响应体返回错误码。
|
||||
- 核对数据库:确认表结构与索引是否存在。
|
||||
- 验证参数:确认查询参数是否符合预期。
|
||||
- 检查Redis:确认设备信息是否正确写入Redis缓存。
|
||||
- 监控任务:确认设备持久化任务是否按预期执行。
|
||||
- 检查Redis:确认设备信息、分享码数据是否正确写入Redis缓存。
|
||||
- 监控任务:确认设备持久化任务和分享码持久化任务是否按预期执行。
|
||||
- 检查分布式锁:确认分享码操作的分布式锁状态和超时处理。
|
||||
|
||||
**章节来源**
|
||||
- [internal/config/database.go:57-72](file://internal/config/database.go#L57-L72)
|
||||
@@ -752,10 +965,12 @@ Task --> DB
|
||||
- [internal/handler/model_list.go:39-42](file://internal/handler/model_list.go#L39-L42)
|
||||
- [internal/handler/ota.go:31-48](file://internal/handler/ota.go#L31-L48)
|
||||
- [internal/handler/device.go:33-39](file://internal/handler/device.go#L33-L39)
|
||||
- [internal/handler/share_code.go:46-81](file://internal/handler/share_code.go#L46-81)
|
||||
- [internal/handler/curve.go:302-368](file://internal/handler/curve.go#L302-L368)
|
||||
- [internal/response/response.go:30-37](file://internal/response/response.go#L30-L37)
|
||||
|
||||
## 结论
|
||||
本项目的数据模型设计简洁明确:Brand 与 Model 分别承担品牌与型号的维度,通过仓库层的原生 SQL 访问实现高效查询;处理器层统一响应与可选编码,提升传输效率与前端体验。新增的OTA固件升级模型、用户设备跟踪模型和用户活动模型进一步完善了系统的数据模型体系,支持复杂的固件升级策略、设备信息跟踪和用户行为分析。数据库层面通过唯一索引与合理字段设计保障一致性与性能。建议在后续迭代中引入显式的校验与转换层,增强健壮性与可维护性。
|
||||
本项目的数据模型设计简洁明确:Brand 与 Model 分别承担品牌与型号的维度,通过仓库层的原生 SQL 访问实现高效查询;处理器层统一响应与可选编码,提升传输效率与前端体验。新增的分享码功能、目标曲线模型和增强的OTA模型进一步完善了系统的数据模型体系,支持复杂的固件升级策略、设备信息跟踪、用户行为分析和EQ数据分享功能。数据库层面通过唯一索引与合理字段设计保障一致性与性能。Redis缓存层提供了高性能的临时数据存储和分布式锁机制。建议在后续迭代中引入显式的校验与转换层,增强健壮性与可维护性,同时考虑添加更多的监控指标和告警机制。
|
||||
|
||||
## 附录
|
||||
|
||||
@@ -778,6 +993,12 @@ Task --> DB
|
||||
- **表:user_active**
|
||||
- 字段:id、mac_addr、model、active_date、ip_addr、create_at。
|
||||
- 约束:联合主键 (id, active_date),联合索引 (mac_addr, active_date)。
|
||||
- **表:share_code_log**
|
||||
- 字段:id(主键)、mac_addr、share_code、action、model、ip_addr、eq_data、expire_at、create_at。
|
||||
- 约束:索引 idx_mac_addr、idx_share_code、idx_create_at。
|
||||
- **表:target**
|
||||
- 字段:id(主键)、label、read_csv、file、bassBoost、addtime。
|
||||
- 约束:无显式约束。
|
||||
- **映射关系**
|
||||
- Model.id ↔ model.id
|
||||
- Model.brandName ↔ model.brand_name
|
||||
@@ -820,6 +1041,21 @@ Task --> DB
|
||||
- UserActive.active_date ↔ user_active.active_date
|
||||
- UserActive.ip_addr ↔ user_active.ip_addr
|
||||
- UserActive.create_at ↔ user_active.create_at
|
||||
- ShareCodeLog.ID ↔ share_code_log.id
|
||||
- ShareCodeLog.MacAddr ↔ share_code_log.mac_addr
|
||||
- ShareCodeLog.ShareCode ↔ share_code_log.share_code
|
||||
- ShareCodeLog.Action ↔ share_code_log.action
|
||||
- ShareCodeLog.Model ↔ share_code_log.model
|
||||
- ShareCodeLog.IpAddr ↔ share_code_log.ip_addr
|
||||
- ShareCodeLog.EqData ↔ share_code_log.eq_data
|
||||
- ShareCodeLog.ExpireAt ↔ share_code_log.expire_at
|
||||
- ShareCodeLog.CreateAt ↔ share_code_log.create_at
|
||||
- Target.ID ↔ target.id
|
||||
- Target.Label ↔ target.label
|
||||
- Target.ReadCSV ↔ target.read_csv
|
||||
- Target.File ↔ target.file
|
||||
- Target.BassBoost ↔ target.bassBoost
|
||||
- Target.AddTime ↔ target.addtime
|
||||
|
||||
**章节来源**
|
||||
- [sql/model.sql:24-35](file://sql/model.sql#L24-L35)
|
||||
@@ -827,10 +1063,14 @@ Task --> DB
|
||||
- [sql/ota_target_device.sql:24-31](file://sql/ota_target_device.sql#L24-L31)
|
||||
- [sql/user_device.sql:24-32](file://sql/user_device.sql#L24-L32)
|
||||
- [sql/user_active.sql:24-32](file://sql/user_active.sql#L24-L32)
|
||||
- [sql/share_code_log.sql:9-23](file://sql/share_code_log.sql#L9-L23)
|
||||
- [sql/target.sql:24-31](file://sql/target.sql#L24-L31)
|
||||
- [internal/model/model.go:5-15](file://internal/model/model.go#L5-L15)
|
||||
- [internal/model/ota.go:6-42](file://internal/model/ota.go#L6-L42)
|
||||
- [internal/model/ota.go:29-67](file://internal/model/ota.go#L29-L67)
|
||||
- [internal/model/user_device.go:5-12](file://internal/model/user_device.go#L5-L12)
|
||||
- [internal/model/user_active.go:5-13](file://internal/model/user_active.go#L5-L13)
|
||||
- [internal/model/share_code.go:14-25](file://internal/model/share_code.go#L14-L25)
|
||||
- [internal/model/target.go:5-14](file://internal/model/target.go#L5-L14)
|
||||
|
||||
### 请求与响应示例(路径参考)
|
||||
- **获取品牌列表**
|
||||
@@ -842,55 +1082,98 @@ Task --> DB
|
||||
- **获取型号列表**
|
||||
- 路由:/audio/getModel
|
||||
- 方法:GET
|
||||
- 参数:brandName(可选)、modelName(可选)、base64Resp(可选)
|
||||
- 参数:brandName(可选)、modelName(可选)、base64Resp(可选)
|
||||
- 返回:[]Model 或 Base64 编码后的 JSON
|
||||
- 参考路径:[internal/handler/model.go:26-51](file://internal/handler/model.go#L26-L51)
|
||||
- **搜索模型列表**
|
||||
- 路由:/audio/modelList
|
||||
- 方法:GET
|
||||
- 参数:key(必需)、count(可选)、base64Resp(可选)
|
||||
- 参数:key(必需)、count(可选)、base64Resp(可选)
|
||||
- 返回:[]Model 或 Base64 编码后的 JSON
|
||||
- 参考路径:[internal/handler/model_list.go:26-57](file://internal/handler/model_list.go#L26-L57)
|
||||
- **获取OTA升级信息**
|
||||
- 路由:/audio/ota
|
||||
- 方法:GET
|
||||
- 参数:model(必需)、hw(必需)、mac(可选)、beta(可选)、base64Resp(可选)
|
||||
- 参数:model(必需)、hw(必需)、mac(可选)、beta(可选)、base64Resp(可选)
|
||||
- 返回:OTA对象或 Base64 编码后的 JSON
|
||||
- 参考路径:[internal/handler/ota.go:23-133](file://internal/handler/ota.go#L23-L133)
|
||||
- **设备信息上报**
|
||||
- 路由:/audio/reportDevInfo
|
||||
- 方法:GET
|
||||
- 参数:mac(必需)、model(必需)、ver(可选)
|
||||
- 参数:mac(必需)、model(必需)、ver(可选)
|
||||
- 返回:操作结果
|
||||
- 参考路径:[internal/handler/device.go:27-83](file://internal/handler/device.go#L27-L83)
|
||||
- **创建分享码**
|
||||
- 路由:/audio/shareCreate
|
||||
- 方法:POST
|
||||
- 参数:mac(必需)、model(必需,Luxsin-X9或Luxsin-X8)、eq_data(必需,JSON)
|
||||
- 返回:分享码信息和过期时间
|
||||
- 参考路径:[internal/handler/share_code.go:40-125](file://internal/handler/share_code.go#L40-L125)
|
||||
- **查询分享码**
|
||||
- 路由:/audio/shareQuery
|
||||
- 方法:GET
|
||||
- 参数:shareCode(必需,5位)
|
||||
- 返回:EQ数据和设备型号
|
||||
- 参考路径:[internal/handler/share_code.go:192-211](file://internal/handler/share_code.go#L192-L211)
|
||||
- **导入分享码**
|
||||
- 路由:/audio/shareAccept
|
||||
- 方法:GET
|
||||
- 参数:mac(必需)、model(必需,Luxsin-X9或Luxsin-X8)、shareCode(必需,5位)
|
||||
- 返回:EQ数据和设备型号
|
||||
- 参考路径:[internal/handler/share_code.go:228-279](file://internal/handler/share_code.go#L228-L279)
|
||||
- **获取目标曲线**
|
||||
- 路由:/audio/getCurve
|
||||
- 方法:GET
|
||||
- 参数:brand(必需)、name(必需)、target(必需)、base64Resp(可选)
|
||||
- 返回:parametric_eq数据
|
||||
- 参考路径:[internal/handler/curve.go:145-198](file://internal/handler/curve.go#L145-L198)
|
||||
|
||||
**章节来源**
|
||||
- [internal/router/router.go:45-52](file://internal/router/router.go#L45-L52)
|
||||
- [internal/router/router.go:63-78](file://internal/router/router.go#L63-L78)
|
||||
- [internal/handler/brand.go:26-50](file://internal/handler/brand.go#L26-L50)
|
||||
- [internal/handler/model.go:26-51](file://internal/handler/model.go#L26-L51)
|
||||
- [internal/handler/model_list.go:26-57](file://internal/handler/model_list.go#L26-L57)
|
||||
- [internal/handler/ota.go:23-133](file://internal/handler/ota.go#L23-L133)
|
||||
- [internal/handler/device.go:27-83](file://internal/handler/device.go#L27-L83)
|
||||
- [internal/handler/share_code.go:40-125](file://internal/handler/share_code.go#L40-L125)
|
||||
- [internal/handler/share_code.go:192-211](file://internal/handler/share_code.go#L192-L211)
|
||||
- [internal/handler/share_code.go:228-279](file://internal/handler/share_code.go#L228-L279)
|
||||
- [internal/handler/curve.go:145-198](file://internal/handler/curve.go#L145-L198)
|
||||
|
||||
### 最佳实践建议
|
||||
- **模型扩展**
|
||||
- 引入显式的校验与转换层,如参数清洗、长度限制、正则校验等。
|
||||
- 对可空字段提供默认值策略,避免前端空值判断复杂化。
|
||||
- OTA模型支持复杂的升级策略,建议在业务层添加更多的参数验证。
|
||||
- 分享码模型支持多种设备型号,建议添加设备型号验证和限制。
|
||||
- **版本管理与向后兼容**
|
||||
- 通过 API 版本号(如 /api/v1)隔离变更;新增字段采用可选策略,保持旧字段必填。
|
||||
- 对于破坏性变更,提供迁移脚本与双写策略。
|
||||
- OTA升级策略的变更需要谨慎处理,确保向后兼容性。
|
||||
- 分享码功能的新增不影响现有API,保持向前兼容。
|
||||
- **性能优化**
|
||||
- 为高频查询字段建立索引;避免 SELECT *,仅选择必要字段。
|
||||
- 对大列表启用可选 Base64 编码;结合分页与缓存策略。
|
||||
- 设备信息使用Redis缓存,定期批量持久化到数据库。
|
||||
- OTA查询使用复合索引,支持快速定位最新OTA记录。
|
||||
- 分享码使用Redis缓存,支持TTL自动过期和分布式锁。
|
||||
- 目标曲线使用Redis缓存,优化fr数据的独立存储。
|
||||
- **错误处理与可观测性**
|
||||
- 统一错误码与消息格式;记录关键链路日志;对数据库与外部服务增加超时与重试。
|
||||
- OTA查询失败需要详细的日志记录,包括参数、查询结果等。
|
||||
- 设备持久化任务需要监控执行状态和错误日志。
|
||||
- 分享码持久化任务需要监控Redis队列状态和数据库插入结果。
|
||||
- 目标曲线查询需要监控S3访问权限和CSV文件读取。
|
||||
- **安全考虑**
|
||||
- OTA下载链接需要安全性验证,防止恶意下载。
|
||||
- 设备信息上报需要参数验证,防止注入攻击。
|
||||
- 黑名单和白名单管理需要权限控制和审计日志。
|
||||
- 黑名单和白名单管理需要权限控制和审计日志。
|
||||
- 分享码功能需要防止暴力破解,建议添加频率限制。
|
||||
- 分享码删除操作需要MAC地址验证,防止越权操作。
|
||||
- EQ数据存储需要JSON格式验证,防止恶意数据注入。
|
||||
- **监控与运维**
|
||||
- 添加Redis连接池监控,确保缓存层稳定运行。
|
||||
- 添加数据库连接池监控,避免连接泄漏。
|
||||
- 添加任务调度监控,确保持久化任务正常执行。
|
||||
- 添加分布式锁监控,防止死锁和资源竞争。
|
||||
- 添加S3访问监控,确保CSV文件读取正常。
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user