| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- package lc
- import (
- "context"
- "github.com/sirupsen/logrus"
- "lc-smartX/util"
- "lc-smartX/util/gopool"
- "time"
- // 仅引入Redis客户端核心依赖
- "github.com/redis/go-redis/v9"
- )
- // Redis基础配置(极简版,仅用于初始化连接)
- const (
- RedisInitKey = "sentinel:init:flag" // 仅用于标记Redis初始化完成的空Key
- RedisKeyPrefix = "plate_results"
- )
- // 单个哨兵服务(仅新增Redis客户端和上下文字段)
- type SentinelServer struct {
- RadarServer *RadarServer
- CameraServer *CameraServer
- Device IDevice // 本哨兵的设备(屏幕+喇叭)
- StateTicker *time.Ticker // 状态回滚定时器
- ReTicker *time.Ticker // 重连定时器
- // === 仅新增Redis核心字段 ===
- rdb *redis.Client // Redis客户端
- ctx context.Context // 上下文(用于Redis操作)
- fetchTicker *time.Ticker // 定时任务ticker
- stopChan chan struct{} // 停止信号通道
- }
- // 启动哨兵服务
- func StartSentinelServer() {
- s := &SentinelServer{
- StateTicker: time.NewTicker(5 * time.Second), // 5秒后自动回滚
- ReTicker: time.NewTicker(30 * time.Second), // 30秒重连检查
- ctx: context.Background(), // 初始化Redis上下文
- }
- // === 第一步:优先初始化Redis(极简版) ===
- s.initRedis()
- // 原有逻辑:初始化设备
- s.initDevice()
- time.Sleep(2 * time.Second)
- // 原有逻辑:启动雷达服务
- if util.Config.Server.SupportRadar {
- s.RadarServer = NewRadarEventServer()
- s.RadarServer.RegisterCallback(s) // 注册雷达回调
- gopool.Go(s.RadarServer.Start)
- }
- // 原有逻辑:启动摄像头服务
- if util.Config.Server.SupportCamera {
- s.CameraServer = NewCameraEventServer()
- s.CameraServer.RegisterCallback(s) // 注册摄像头回调
- gopool.Go(s.CameraServer.Start)
- }
- // 启动定时任务:每3秒获取最新一条车牌号
- s.StartFetchingLatestPlate()
- // 原有逻辑:启动主循环
- s.Serve()
- }
- // === 核心:极简Redis初始化(仅连接+标记初始化) ===
- func (s *SentinelServer) initRedis() {
- // 1. 创建Redis客户端
- s.rdb = redis.NewClient(&redis.Options{
- Addr: util.Config.RedisConfig.Addr,
- Password: util.Config.RedisConfig.Password,
- DB: util.Config.RedisConfig.DB,
- })
- // 2. 测试Redis连接
- if err := s.rdb.Ping(s.ctx).Err(); err != nil {
- logrus.Warn("⚠️ Redis连接失败,哨兵服务正常启动(无Redis支持)", "err", err)
- s.rdb = nil // 标记Redis不可用
- return
- }
- // 3. 写入初始化标记Key(仅标记,无业务数据)
- if err := s.rdb.Set(s.ctx, RedisInitKey, "initialized", 0).Err(); err != nil {
- logrus.Warn("⚠️ Redis初始化标记写入失败", "err", err)
- } else {
- logrus.Info("✅ Redis初始化完成(仅连接+标记)")
- }
- }
- // 原有逻辑:初始化本哨兵的设备(屏幕+喇叭)
- func (s *SentinelServer) initDevice() {
- // 屏幕配置(取第一个屏幕)
- screenCfg := util.Config.Screens[0]
- screen := NewScreen(screenCfg.Name, screenCfg.Ip, screenCfg.Port)
- // 喇叭配置(取第一个喇叭)
- speakerCfg := util.Config.Speakers[0]
- speaker := NewIpCast(
- speakerCfg.Port,
- )
- // 组合设备
- s.Device = &SentinelDevice{
- Info: DeviceInfo{
- Name: screenCfg.Name,
- Ip: screenCfg.Ip,
- Port: screenCfg.Port,
- Audio: "支路来车",
- },
- Screen: screen,
- Speaker: speaker,
- }
- }
- // 原有逻辑:实现Notifier接口,处理雷达/摄像头事件
- func (s *SentinelServer) Notify(text string, isProgram, speed int) {
- s.StateTicker.Reset(5 * time.Second) // 重置回滚定时器
- go s.Device.Call(text, isProgram, speed)
- //gopool.Go(func() {
- // s.Device.Call(text, isProgram, speed)
- //}) // 触发设备警告
- }
- // 原有逻辑:主循环:处理状态回滚和重连
- func (s *SentinelServer) Serve() {
- for {
- select {
- case <-s.StateTicker.C:
- // 定时器触发,回滚设备状态
- gopool.Go(s.Device.Rollback)
- case <-s.ReTicker.C:
- // 定时重连设备
- gopool.Go(s.Device.Reconnect)
- }
- }
- }
|