package eventServer import ( "encoding/xml" "errors" "fmt" "github.com/sirupsen/logrus" mail "github.com/xhit/go-simple-mail/v2" "io" "io/ioutil" "lc-fangdaosha/global" "lc-fangdaosha/model/app" "lc-fangdaosha/service" "log" "math" "mime/multipart" "net/http" "strconv" "strings" "time" ) // MQDEvent (MQTT Data Event) 用于mqtt传输事件 type MQDEvent struct { EventCode string `json:"eventCode"` EId int `json:"eId"` Ip string `json:"ip"` Type string `json:"type"` StartTime string `json:"startTime"` Name string `json:"name"` Data []byte `json:"data"` } func StartEventServer() { //记录长宽高 go func() { for { l, w, h := CalcCap() dumps := []Constant{ {l, w, h, l * w * h}, } // 遍历结构体并进行比对 for _, variable := range global.Config.Dump { bestMatch := FindBestMatch(dumps, Constant{ variable[0], variable[1], variable[2], variable[3], }) fmt.Println("最匹配的常量数据:", bestMatch) //todo 保存数据库 var cars []*app.CarInfo newCar := &app.CarInfo{ Height: bestMatch.Height, Width: bestMatch.Width, Length: bestMatch.Length, Volume: bestMatch.Volume, } cars = append(cars, newCar) //将新创建的车辆信息添加到cars切片的末尾 // 保存到数据库 carInfoService.Save(cars) } fmt.Println("长", l, "宽", w, "高", h) time.Sleep(500 * time.Millisecond) } }() http.HandleFunc("/event", handler) logrus.Fatal("事件监听服务启动失败", http.ListenAndServe(":8850", nil)) } func handler(w http.ResponseWriter, r *http.Request) { go func() { //监听主机应答固定,直接先应答 w.WriteHeader(200) w.Header().Add("Date", time.Now().String()) w.Header().Add("Connection", "close") }() logRequest(r) contentType := r.Header.Get("Content-Type") if strings.Contains(contentType, "application/xml") { bytes, err := ioutil.ReadAll(r.Body) if err != nil { logrus.Error("事件处理-读取错误:", err) return } var event EventNotificationAlert err = xml.Unmarshal(bytes, &event) if err != nil { logrus.Error("事件处理-解析错误:", err) return } //处理事件 todo 邮箱 handleEvent_(event) } else if strings.Contains(contentType, "multipart/form-data") { handleMultipart(r) } else { logrus.WithField("Content-Type", contentType).Error("该Content-Type没有写处理逻辑") return } } //TODO 限制事件重复触发,一段时间内不重复发送邮件,但保持报警状态 var eventService = service.ServiceGroupApp.AppServiceGroup.EventService var carInfoService = service.ServiceGroupApp.AppServiceGroup.CarInfoService // 保留小数 func round(num float64, places int) float64 { shift := math.Pow(10, float64(places)) return math.Round(num*shift) / shift } // 保存摄像机获取到的长度,高度,宽度以及时间 var bulk = make(map[string][]float64) // 处理多文件事件 func handleMultipart(r *http.Request) { // todo 远程联动 multipartReader := multipart.NewReader(r.Body, "boundary") var msg string //邮件消息 // 循环读取每个 part var eventAlert EventNotificationAlert for { part, err := multipartReader.NextPart() fmt.Println("is", errors.Is(err, io.EOF)) fmt.Println("as", errors.As(err, &io.EOF)) if errors.Is(err, io.EOF) { break } if err != nil { log.Println("Failed to read part:", err) continue } // 检查 part 的 Content-Disposition formName := part.FormName() //if formName != "intrusionImage" { if !strings.Contains(formName, "Image") { //不含图片的xml部分数据 xmlData, err := ioutil.ReadAll(part) if err != nil { return } xml.Unmarshal(xmlData, &eventAlert) msg = handleEvent_(eventAlert) continue } //处理图片部分数据 contentType := part.Header.Get("Content-Type") eventCode := part.Header.Get("Content-ID") picName := timeFmt(eventAlert.DateTime) + ".jpeg" data, _ := ioutil.ReadAll(part) if strings.Contains(eventAlert.ChannelName, "plateNumber") { // 识别车牌,记录次数 number, err := CallLicensePlateRecognitionAPI(data) if err != nil { fmt.Println("车牌识别失败:", err) //time.Sleep(1000) } //todo 处理车牌号 carInfoService.ProcessPlateNumber(number) return } if strings.Contains(eventAlert.ChannelName, "metering1") { //测量车的长度和高度 targetRect := eventAlert.DetectionRegionList.DetectionRegionEntry[0].TargetRect //x, _ := strconv.ParseFloat(targetRect.X, 64) y, _ := strconv.ParseFloat(targetRect.Y, 64) h, _ := strconv.ParseFloat(targetRect.Height, 64) w, _ := strconv.ParseFloat(targetRect.Width, 64) n := int(round(y+h, 1) * 10) b := float64(global.Config.Metering.Camera1.B[n]) a := float64(global.Config.Metering.Camera1.A[n]) rh := h / (y + h) * b rl := w * a //dateTime := eventAlert.DateTime //bulk[dateTime] = append(bulk[dateTime], rh, rl) LhChan <- [2]float64{rl, rh} return } if strings.Contains(eventAlert.ChannelName, "metering2") { //todo 测量车的宽度 targetRect := eventAlert.DetectionRegionList.DetectionRegionEntry[0].TargetRect //x, _ := strconv.ParseFloat(targetRect.X, 64) y, _ := strconv.ParseFloat(targetRect.Y, 64) h, _ := strconv.ParseFloat(targetRect.Height, 64) w, _ := strconv.ParseFloat(targetRect.Width, 64) n := int(round(y+h, 1) * 10) a := float64(global.Config.Metering.Camera2.A[n]) rw := w * a WChan <- rw //dateTime := eventAlert.DateTime //bulk[dateTime] = append(bulk[dateTime], rw) //// 识别车牌,记录次数 //number, err := CallLicensePlateRecognitionAPI(data) //if err != nil { // fmt.Println("车牌识别失败:", err) // //time.Sleep(1000) //} //// 处理车牌号 //carInfoService.ProcessPlateNumber(number) return } f := &mail.File{ Name: picName, MimeType: contentType, Data: data, Inline: true, } picture := &app.Picture{ Name: picName, Time: time.Now(), Mime: contentType, Size: len(data), } pictureData := &app.PictureData{ Data: data, } event := &app.Event{ EventCode: eventCode, MacAddress: eventAlert.MacAddress, EventType: eventAlert.EventType, } //保存图片 go eventService.Save(event, picture, pictureData) //邮件通知 SendAlarmEmail(eventAlert.MacAddress, msg, f) } } func handleEvent_(event EventNotificationAlert) string { var eType string if event.EventType == "duration" { eType = event.DurationList.Duration[0].RelationEvent } else { eType = event.EventType } return fmt.Sprintf("事件类型:%s,时间:%s", sMap[eType], timeFmt(event.DateTime)) } func timeFmt(str string) string { s := strings.Split(str, "T") t := s[0] s1 := strings.Split(s[1], ".") s2 := strings.Split(s1[0], "+") return t + " " + s2[0] } func logRequest(req *http.Request) { // 打印请求行 fmt.Printf("%s %s %s\n", req.Method, req.URL.Path, req.Proto) // 打印请求头 for name, headers := range req.Header { for _, h := range headers { fmt.Printf("%v: %v\n", name, h) } } // 打印请求体 body, _ := ioutil.ReadAll(req.Body) fmt.Printf("%s\n", body) }