123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293 |
- 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
- }
|