147 lines
3.6 KiB
Go
147 lines
3.6 KiB
Go
package handler
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/luxsin/app-api/pkg/encode"
|
|
"github.com/redis/go-redis/v9"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
const redisHeadphoneImpedancesKey = "headphone_impedances"
|
|
|
|
type ImpedanceHandler struct {
|
|
redis *redis.Client
|
|
log *zap.Logger
|
|
}
|
|
|
|
func NewImpedanceHandler(redis *redis.Client, log *zap.Logger) *ImpedanceHandler {
|
|
return &ImpedanceHandler{
|
|
redis: redis,
|
|
log: log,
|
|
}
|
|
}
|
|
|
|
// ReportImpedance 上报耳机阻抗
|
|
//
|
|
// @Summary 上报耳机阻抗
|
|
// @Tags Device
|
|
// @Produce json
|
|
// @Param mac query string true "设备 MAC 地址"
|
|
// @Param name query string true "设备型号"
|
|
// @Param brand query string true "耳机品牌"
|
|
// @Param model query string true "耳机型号"
|
|
// @Param value query int true "阻抗值(整数)"
|
|
// @Success 200 {object} map[string]any "操作成功"
|
|
// @Failure 500 {object} object
|
|
// @Router /audio/reportImpedance [get]
|
|
func (h *ImpedanceHandler) ReportImpedance(c *gin.Context) {
|
|
mac := strings.TrimSpace(c.Query("mac"))
|
|
deviceModel := strings.TrimSpace(c.Query("name"))
|
|
brand := strings.TrimSpace(c.Query("brand"))
|
|
headphoneModel := strings.TrimSpace(c.Query("model"))
|
|
valueStr := strings.TrimSpace(c.Query("value"))
|
|
clientIP := encode.ClientPublicIP(c)
|
|
|
|
if mac == "" || deviceModel == "" || brand == "" || headphoneModel == "" || valueStr == "" {
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"code": 400,
|
|
"msg": "参数校验失败",
|
|
})
|
|
return
|
|
}
|
|
|
|
// 品牌/型号含乱码或控制字符、超长属于无效数据,静默丢弃
|
|
if !isValidHeadphoneText(brand) || !isValidHeadphoneText(headphoneModel) {
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"code": 200,
|
|
"msg": "操作成功",
|
|
})
|
|
return
|
|
}
|
|
|
|
impedance, err := strconv.Atoi(valueStr)
|
|
if err != nil {
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"code": 400,
|
|
"msg": "参数校验失败",
|
|
})
|
|
return
|
|
}
|
|
|
|
// 阻抗值为 0 属于无效数据,静默丢弃
|
|
if impedance == 0 {
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"code": 200,
|
|
"msg": "操作成功",
|
|
})
|
|
return
|
|
}
|
|
|
|
brandNorm := normalizeHeadphoneText(brand)
|
|
modelNorm := normalizeHeadphoneText(headphoneModel)
|
|
|
|
impedanceInfo := map[string]any{
|
|
"mac_addr": mac,
|
|
"device_model": deviceModel,
|
|
"impedance_ohm": impedance,
|
|
"headphone_brand": brand,
|
|
"headphone_model": headphoneModel,
|
|
"headphone_brand_norm": brandNorm,
|
|
"headphone_model_norm": modelNorm,
|
|
"ip_addr": clientIP,
|
|
}
|
|
|
|
jsonData, err := json.Marshal(impedanceInfo)
|
|
if err != nil {
|
|
h.log.Error("marshal impedance info failed", zap.Error(err))
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"code": 500,
|
|
"msg": "系统错误",
|
|
})
|
|
return
|
|
}
|
|
|
|
field := impedanceRedisField(mac, brandNorm, modelNorm)
|
|
ctx := c.Request.Context()
|
|
if err := h.redis.HSet(ctx, redisHeadphoneImpedancesKey, field, jsonData).Err(); err != nil {
|
|
h.log.Error("redis hset failed", zap.Error(err))
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"code": 500,
|
|
"msg": "系统错误",
|
|
})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"code": 200,
|
|
"msg": "操作成功",
|
|
})
|
|
}
|
|
|
|
func normalizeHeadphoneText(s string) string {
|
|
return strings.ToLower(strings.TrimSpace(s))
|
|
}
|
|
|
|
// isValidHeadphoneText 校验耳机品牌/型号:拒绝含乱码字符(U+FFFD)、控制字符及超长(>100 字符)的输入
|
|
func isValidHeadphoneText(s string) bool {
|
|
if len(s) > 100 {
|
|
return false
|
|
}
|
|
for _, r := range s {
|
|
if r == '\ufffd' || r < 0x20 || r == 0x7f {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func impedanceRedisField(mac, brandNorm, modelNorm string) string {
|
|
return fmt.Sprintf("%s|%s|%s", mac, brandNorm, modelNorm)
|
|
}
|