耳机阻抗上报
This commit is contained in:
@@ -0,0 +1,162 @@
|
||||
package task
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/luxsin/app-api/internal/model"
|
||||
"github.com/luxsin/app-api/internal/repository"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
const redisHeadphoneImpedancesKey = "headphone_impedances"
|
||||
|
||||
type ImpedancePersistTask struct {
|
||||
rdb *redis.Client
|
||||
repo *repository.HeadphoneImpedanceRepository
|
||||
log *zap.Logger
|
||||
}
|
||||
|
||||
func NewImpedancePersistTask(
|
||||
rdb *redis.Client,
|
||||
repo *repository.HeadphoneImpedanceRepository,
|
||||
log *zap.Logger,
|
||||
) *ImpedancePersistTask {
|
||||
return &ImpedancePersistTask{rdb: rdb, repo: repo, log: log}
|
||||
}
|
||||
|
||||
// Start 启动定时刷入协程,每 interval 执行一次
|
||||
func (t *ImpedancePersistTask) Start(interval time.Duration) {
|
||||
go func() {
|
||||
ticker := time.NewTicker(interval)
|
||||
defer ticker.Stop()
|
||||
|
||||
for range ticker.C {
|
||||
t.Persist()
|
||||
}
|
||||
}()
|
||||
t.log.Info("impedance persist task started", zap.String("interval", interval.String()))
|
||||
}
|
||||
|
||||
// Persist 从 Redis Hash headphone_impedances 中读取数据刷入数据库
|
||||
func (t *ImpedancePersistTask) Persist() {
|
||||
ctx := context.Background()
|
||||
|
||||
records, err := t.rdb.HGetAll(ctx, redisHeadphoneImpedancesKey).Result()
|
||||
if err != nil {
|
||||
t.log.Error("redis HGetAll headphone_impedances failed", zap.Error(err))
|
||||
return
|
||||
}
|
||||
|
||||
if len(records) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
t.log.Info("persisting headphone impedances from redis", zap.Int("count", len(records)))
|
||||
|
||||
var succeeded []string
|
||||
|
||||
for field, jsonStr := range records {
|
||||
var info struct {
|
||||
MacAddr string `json:"mac_addr"`
|
||||
DeviceModel string `json:"device_model"`
|
||||
ImpedanceOhm int `json:"impedance_ohm"`
|
||||
HeadphoneBrand string `json:"headphone_brand"`
|
||||
HeadphoneModel string `json:"headphone_model"`
|
||||
HeadphoneBrandNorm string `json:"headphone_brand_norm"`
|
||||
HeadphoneModelNorm string `json:"headphone_model_norm"`
|
||||
IpAddr string `json:"ip_addr"`
|
||||
}
|
||||
|
||||
if err := json.Unmarshal([]byte(jsonStr), &info); err != nil {
|
||||
t.log.Error("unmarshal impedance info failed", zap.String("field", field), zap.Error(err))
|
||||
continue
|
||||
}
|
||||
|
||||
if t.persistOne(ctx, info) {
|
||||
succeeded = append(succeeded, field)
|
||||
}
|
||||
}
|
||||
|
||||
total := len(records)
|
||||
persisted := len(succeeded)
|
||||
failed := total - persisted
|
||||
|
||||
if persisted > 0 {
|
||||
if err := t.rdb.HDel(ctx, redisHeadphoneImpedancesKey, succeeded...).Err(); err != nil {
|
||||
t.log.Error("redis HDel failed after persist",
|
||||
zap.Int("persisted", persisted),
|
||||
zap.Error(err),
|
||||
)
|
||||
} else {
|
||||
t.log.Info("headphone impedances persisted to database and removed from redis",
|
||||
zap.Int("persisted", persisted),
|
||||
zap.Int("total", total),
|
||||
zap.Int("failed", failed),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if failed > 0 {
|
||||
t.log.Warn("some headphone impedances failed to persist, kept in redis for retry",
|
||||
zap.Int("failed", failed),
|
||||
zap.Int("total", total),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *ImpedancePersistTask) persistOne(ctx context.Context, info struct {
|
||||
MacAddr string `json:"mac_addr"`
|
||||
DeviceModel string `json:"device_model"`
|
||||
ImpedanceOhm int `json:"impedance_ohm"`
|
||||
HeadphoneBrand string `json:"headphone_brand"`
|
||||
HeadphoneModel string `json:"headphone_model"`
|
||||
HeadphoneBrandNorm string `json:"headphone_brand_norm"`
|
||||
HeadphoneModelNorm string `json:"headphone_model_norm"`
|
||||
IpAddr string `json:"ip_addr"`
|
||||
}) bool {
|
||||
existing, err := t.repo.FindByMacAndNorm(ctx, info.MacAddr, info.HeadphoneBrandNorm, info.HeadphoneModelNorm)
|
||||
if err != nil {
|
||||
t.log.Error("find headphone impedance failed",
|
||||
zap.String("mac", info.MacAddr),
|
||||
zap.String("brand_norm", info.HeadphoneBrandNorm),
|
||||
zap.String("model_norm", info.HeadphoneModelNorm),
|
||||
zap.Error(err),
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
rec := model.UserHeadphoneImpedance{
|
||||
MacAddr: info.MacAddr,
|
||||
DeviceModel: info.DeviceModel,
|
||||
ImpedanceOhm: info.ImpedanceOhm,
|
||||
HeadphoneBrand: info.HeadphoneBrand,
|
||||
HeadphoneModel: info.HeadphoneModel,
|
||||
HeadphoneBrandNorm: info.HeadphoneBrandNorm,
|
||||
HeadphoneModelNorm: info.HeadphoneModelNorm,
|
||||
IpAddr: info.IpAddr,
|
||||
}
|
||||
|
||||
if existing == nil {
|
||||
if err := t.repo.Insert(ctx, rec); err != nil {
|
||||
t.log.Error("insert user_headphone_impedance failed",
|
||||
zap.String("mac", info.MacAddr),
|
||||
zap.Error(err),
|
||||
)
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
rec.ID = existing.ID
|
||||
if err := t.repo.Update(ctx, rec); err != nil {
|
||||
t.log.Error("update user_headphone_impedance failed",
|
||||
zap.String("mac", info.MacAddr),
|
||||
zap.Error(err),
|
||||
)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
Reference in New Issue
Block a user