package manager import ( "encoding/json" "errors" "fmt" "github.com/gogf/gf/container/gmap" "github.com/gogf/gf/encoding/gjson" "sparrow/pkg/server" "sparrow/pkg/utils" "time" weather "weather-api-sdk" ) // WeatherSceneConfig 天气监控任务配置 type WeatherSceneConfig struct { SceneId string `json:"scene_id"` // 任务id DecisionExpr string `json:"decision_expr"` // 条件表达式 and or Conditions []*WeatherCondition `json:"conditions"` // 条件 Interval int `json:"interval"` // 检查间隔(分钟) Actions []*Action `json:"actions"` // 执行动作 ticker *time.Ticker `json:"-"` // 定时器 stopChan chan struct{} `json:"-"` // 停止信号通道 } type WeatherCondition struct { Location string `json:"location"` // 地点 FieldType int `json:"field_type"` // 字段类型 1字符串 2数值 Operator int `json:"operator"` // 比较类型 数值比较 1 > 2 >= 3 = 4 <= 5 < 6 != 字符串比较 1 相等 2 不相等 Field string `json:"field"` // 字段名 TargetValue string `json:"target_value"` // 目标值 } type WeatherSceneService struct { tasks *gmap.HashMap } func NewWeatherSceneService() *WeatherSceneService { return &WeatherSceneService{ tasks: gmap.NewHashMap(true), } } func (w *WeatherSceneService) Add(config string) error { var c WeatherSceneConfig err := json.Unmarshal([]byte(config), &c) if err != nil { } if len(c.Conditions) == 0 { return errors.New("天气监控任务配置错误:判断条件不能为空") } // 初始化Ticker和停止通道 c.ticker = time.NewTicker(time.Duration(c.Interval) * time.Minute) c.stopChan = make(chan struct{}) // 启动监控协程 go w.monitorTask(c) w.tasks.Set(c.SceneId, c) return nil } // monitorTask 监控任务:使用select监听Ticker和停止信号 func (w *WeatherSceneService) monitorTask(task WeatherSceneConfig) { for { select { case <-task.ticker.C: // 定时触发 result, err := w.checkWeatherCondition(task) if err != nil { server.Log.Errorf("compare weather condition error :%s", err.Error()) } if result { if err = NewTaskExecutor(task.Actions).Do(); err != nil { server.Log.Errorf("weather do taskid :%s error:%s", task.SceneId, err.Error()) } } case <-task.stopChan: // 收到停止信号 task.ticker.Stop() return } } } func (w *WeatherSceneService) Update(config string) error { var c WeatherSceneConfig err := json.Unmarshal([]byte(config), &c) if err != nil { server.Log.Errorf("config to timerConfig error :%s", err.Error()) } _ = w.Stop(c.SceneId) // 初始化Ticker和停止通道 c.ticker = time.NewTicker(time.Duration(c.Interval) * time.Minute) c.stopChan = make(chan struct{}) // 启动监控协程 go w.monitorTask(c) w.tasks.Set(c.SceneId, c) server.Log.Debugf("UpdateWeatherScene :%s", config) return nil } func (w *WeatherSceneService) Remove(config string) error { var c WeatherSceneConfig err := json.Unmarshal([]byte(config), &c) if err != nil { server.Log.Errorf("config to timerConfig error :%s", err.Error()) } w.tasks.Remove(c.SceneId) server.Log.Debugf("RemoveTimeScene :%s", c.SceneId) return nil } // Start 停止任务 func (w *WeatherSceneService) Start(id string) error { if !w.tasks.Contains(id) { return errors.New("任务不存在") } task := w.tasks.Get(id) c := task.(WeatherSceneConfig) go w.monitorTask(c) return nil } // Stop 停止任务 func (w *WeatherSceneService) Stop(id string) error { if !w.tasks.Contains(id) { return errors.New("任务不存在") } task := w.tasks.Get(id) c := task.(WeatherSceneConfig) c.stopChan <- struct{}{} return nil } // checkWeatherCondition 检查天气 func (w *WeatherSceneService) checkWeatherCondition(config WeatherSceneConfig) (bool, error) { results := make([]bool, len(config.Conditions)) for _, condition := range config.Conditions { // 获取天气数据 weatherInfo, err := getWeatherInfo(condition.Location) fmt.Printf("任务 %s: 获取天气数据成功: %v\n", config.SceneId, weatherInfo) if err != nil { fmt.Printf("任务 %s: 获取天气数据失败: %v\n", config.SceneId, err) return false, err } results = append(results, utils.CheckValue(condition.TargetValue, weatherInfo[condition.Field], condition.FieldType, condition.Operator)) } switch config.DecisionExpr { case "and": for _, v := range results { if !v { return false, nil } } case "or": for _, v := range results { if v { return true, nil } } } return true, nil } func getWeatherInfo(location string) (map[string]interface{}, error) { weatherInfo, err := weather.GetWeatherInfo(location, "SgqF9ZGBUj7R0dLAb") if err != nil { return nil, err } return gjson.New(weatherInfo).Map(), nil }