更新 wiki
This commit is contained in:
@@ -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文件读取正常。
|
||||
Reference in New Issue
Block a user