package monitor import ( "context" "encoding/json" "fmt" "github.com/jinzhu/gorm" "smart-alarm/consts" "smart-alarm/errors" "smart-alarm/model" "smart-alarm/pb" "smart-alarm/pb/v1" "smart-alarm/utils" "strings" "time" "github.com/jaryhe/gopkgs/database" "github.com/jaryhe/gopkgs/logger" "go.uber.org/zap" ) var DeviceTypeMap = map[uint32]string { 5:"扬尘设备", 1:"塔吊设备", 2:"门禁设备", 4:"升降机设备", } // 解析时间 func parseTime(str string) time.Time { layOut := "2006-01-02 15:04:05" if strings.Contains(str, ":") == false && strings.Contains(str, "-") == false { layOut = "20060102150405" } else if strings.Contains(str, "T") { layOut = "2006-01-02T15:04:05" } loc, _ := time.LoadLocation("Local") t, err := time.ParseInLocation(layOut, str, loc) if err != nil { return time.Now() } return t } func TaskAdd(db *gorm.DB, reason string, projectId int64) (int64, error) { project := model.ProjectInfo{} where := map[string]interface{}{ "ID": projectId, } err := project.Find(db, where) if err != nil && err != gorm.ErrRecordNotFound { return 0, errors.DataBaseError } if project.ID == 0 { return 0, errors.ProjectNotExistError } finishDate := time.Now().Add(4 * 24 * time.Hour) finishDate = time.Date(finishDate.Year(), finishDate.Month(), finishDate.Day(), 0, 0, 0, 0, finishDate.Location()) now := time.Now() p := model.TaskProcessingInfo{ Code: project.Code, ProjectID: projectId, TaskName: reason, TaskDesc: reason, AssignmentDate: now, FinishDate: finishDate, TaskType: 3, Status: 1, } pipe := model.TaskPipeline{ PipeType: model.PipelineCreate, PipeTime: now.Format("2006-01-02 15:04:05"), Person: "", Desc: p.TaskDesc, Img: p.TaskImg, ApproveStatus: false, } if pipe.Img == "" { pipe.Img = "[]" } pipeArray := []model.TaskPipeline{pipe} pipeBytes, _ := json.Marshal(pipeArray) p.Pipeline = string(pipeBytes) for i := 0; i < 10; i++ { p.TaskID = fmt.Sprintf("%s%s", time.Now().Format("20060102"), utils.GenerateRandomStr(8, "char")) err = p.Insert(db) if err != nil { if strings.Contains(strings.ToLower(err.Error()), "duplicate") { time.Sleep(200 * time.Microsecond) continue } return 0, errors.DataBaseError } break } if err != nil { return 0, errors.DataBaseError } return p.ID, nil } // 存储告警信息 func WriteAlarm(req *v1.AlarmAddRequest) (bool, error) { alarm := &model.TAlarm{ ProjectId: req.ProjectId, Sn: req.Sn, AlarmCode: req.AlarmCode, AlarmReason: req.AlarmReason, IsHandle: false, Time: req.Date, DeviceCode: uint32(req.DeviceCode), } p := &model.TAlarm{} where := map[string]interface{}{ "SN": req.Sn, "AlarmCode": req.AlarmCode, "IsHandle": false, "DeviceCode": req.DeviceCode, } // 分布式锁,政府端处理告警同样需加分布式锁 key := fmt.Sprintf("%s-%s-%d", req.Sn, req.AlarmCode, req.DeviceCode) ok, err := utils.RedisLock(key, 500, 10) if err != nil { return false, err } if !ok { return false, errors.SystemError } defer utils.RedisUnlock(key) err = p.Query(database.DB(), where) if err != nil && err != gorm.ErrRecordNotFound { return false, err } ret := false if p.Id == 0 { db := database.DB().Begin() alarm.First = true taskId := int64(0) var err error if alarm.First && DeviceTypeMap[alarm.DeviceCode]!= "" { alarmReason := fmt.Sprintf("%s%s于%s%s ", DeviceTypeMap[alarm.DeviceCode],alarm.Sn, alarm.Time, alarm.AlarmReason) taskId, err = TaskAdd(db, alarmReason, alarm.ProjectId) if err != nil { db.Rollback() return false, err } } alarm.TaskID = taskId err = alarm.Insert(db) if err != nil { return false, err } db.Commit() ret = true } return ret, nil /*projectIdStr := strconv.Itoa(int(req.ProjectId)) tags := map[string]string{"sn": req.Sn, "project_id": projectIdStr, "alarm_code": req.AlarmCode} fields := map[string]interface{}{ "alarm_reason": req.AlarmReason, "is_handled": false, } return model.WriteAlarmData(tags, fields, t, req.ProjectId)*/ } func sendAlarm(ctx context.Context, req *v1.AlarmAddRequest, contacts []model.TAlarmContact) { for _, contact := range contacts { fmt.Println("send to notify:", contact.Phone, contact.Email) name := req.DeviceName if name == "" { name = req.Sn } deviceName := name rpcReq := &v1.SendAlarmRequest{ PhoneNumber: contact.Phone, Email: contact.Email, DeviceName: deviceName, AlarmReason: req.AlarmReason, AlarmTime: req.Date, } _, err := pb.ThirdParty.SendAlarm(ctx, rpcReq) if err != nil { reqByte, _ := json.Marshal(*rpcReq) logger.Error("rpc", zap.String("call", "pb.ThirdParty.SendAlarm"), zap.String("params", string(reqByte)), zap.String("error", err.Error())) } } } // 处理告警 func HandlAlarm(ctx context.Context, req *v1.AlarmAddRequest, rule *model.TAlarmRule, contact []model.TAlarmContact) { // 1 获取本地告警记录 statistics := utils.GetAlarmStatistics(req.Sn, req.AlarmCode) // 重置统计数据 defer utils.SetAlarmStatistics(req.Sn, req.AlarmCode, statistics) timeNow := time.Now().Unix() // 判断是否在连续时间范围内 // 第一次获取 if statistics.Timestamp == 0 { statistics.Timestamp = timeNow } // 发送过,判断是否超过发送间隔 if statistics.IsSend { // 超过发送间隔 if (timeNow - statistics.Timestamp) > int64(rule.SilencePeriod*60) { statistics.IsSend = false statistics.Timestamp = timeNow } else { // 在发送间隔内不再发送 return } } // 不在一个周期内,重置告警重新计算 if (timeNow - statistics.Timestamp) > int64(rule.ContinuePeriod*60) { // 重置统计数据 statistics.Timestamp = timeNow statistics.AlarmCount = 1 return } else { // 统计数据加1 statistics.AlarmCount++ } // 达到告警次数 if statistics.AlarmCount >= rule.AlarmCount { sendAlarm(ctx, req, contact) // 重置统计数据 statistics.Timestamp = timeNow statistics.AlarmCount = 0 statistics.IsSend = true } } // 添加告警 func AlarmAdd(ctx context.Context, req *v1.AlarmAddRequest) (reply *v1.AlarmAddReply, err error) { reply = &v1.AlarmAddReply{} if req.Sn == "" || req.ProjectId <= 0 || req.AlarmReason == "" { return nil, errors.ParamsError } req.Date = parseTime(req.Date).Format(consts.TimeSecondLayOut) // 如果是离线状态 if req.AlarmCode == consts.DeviceOfflineCode { req.AlarmReason = "离线" } // 获取告警联系人 contact := utils.GetAlarmContact(req.ProjectId) /* if contact != nil { // 如果是离线告警不需要检查告警规则 if req.AlarmCode == consts.DeviceOfflineCode { sendAlarm(ctx, req, contact) } else { // 获取告警规则 rule := utils.GetAlarmRule(req.ProjectId, req.Sn) if rule != nil { HandlAlarm(ctx, req, rule, contact) } } }*/ isNewRecord, _ := WriteAlarm(req) if contact != nil { if isNewRecord { sendAlarm(ctx, req, contact) } } return reply, nil }