| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- package lc
- import (
- "context"
- "github.com/gin-gonic/gin"
- "github.com/sirupsen/logrus"
- "lc-smartX/util"
- "lc-smartX/util/gopool"
- "log/slog"
- "time"
- // 仅引入Redis客户端核心依赖
- "github.com/redis/go-redis/v9"
- )
- // 单个哨兵服务(仅新增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{} // 停止信号通道
- ginEngine *gin.Engine
- }
- // 启动哨兵服务
- 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()
- deviceData, err := s.GetDeviceDataFromRedis()
- if err != nil {
- return
- }
- DeviceInitData = deviceData
- s.initGin()
- // 原有逻辑:初始化设备
- 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()
- // 原有逻辑:启动主循环
- go s.Serve()
- err = s.ginEngine.Run(":8080")
- if err != nil {
- return
- }
- }
- // === 核心:极简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
- }
- }
- // 原有逻辑:初始化本哨兵的设备(屏幕+喇叭)
- 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,
- }
- }
- // ========== 修改Gin初始化:整合handler和路由 ==========
- func (s *SentinelServer) initGin() {
- // 1. 初始化Gin引擎
- gin.SetMode(gin.DebugMode)
- s.ginEngine = gin.Default()
- // 2. 创建业务处理实例(注入哨兵服务依赖)
- handler := NewPlateDeviceHandler(s)
- // 3. 调用路由注册函数(路由与业务解耦)
- RegisterRoutes(s.ginEngine, handler)
- slog.Info("✅ Gin路由初始化成功")
- }
- // 原有逻辑:实现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)
- }
- }
- }
|