ipc_event.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. package main
  2. import (
  3. "context"
  4. "runtime/debug"
  5. "time"
  6. "github.com/sirupsen/logrus"
  7. "lc/common/mqtt"
  8. "lc/common/onvif/profiles/event"
  9. "lc/common/onvif/soap"
  10. "lc/common/protocol"
  11. )
  12. type EventActuator struct {
  13. parent *LcDevice
  14. ctx context.Context
  15. cancel context.CancelFunc
  16. }
  17. func NewEventActuator(parent *LcDevice) *EventActuator {
  18. ctx, cancel := context.WithCancel(context.Background())
  19. ea := EventActuator{
  20. parent: parent,
  21. ctx: ctx,
  22. cancel: cancel,
  23. }
  24. return &ea
  25. }
  26. func (o *EventActuator) Cancel() {
  27. o.cancel()
  28. }
  29. func (o *EventActuator) EventHandle(XAddr string) {
  30. defer func() {
  31. if err := recover(); err != nil {
  32. logrus.Errorf("EventActuator.EventHandle发生异常:%v", err)
  33. logrus.Errorf("EventActuator.EventHandle发生异常,堆栈信息:%s", string(debug.Stack()))
  34. }
  35. if o.parent.EventActuator != nil {
  36. o.parent.EventActuator.Cancel()
  37. o.parent.EventActuator = nil
  38. }
  39. }()
  40. Retry:
  41. //onvif事件
  42. client := soap.NewClient(soap.WithTimeout(time.Second * 0))
  43. client.AddHeader(soap.NewWSSSecurityHeader(o.parent.onvifDev.User, o.parent.onvifDev.Password))
  44. epy := event.NewEventPortType(client, XAddr)
  45. resp0, err0 := epy.GetServiceCapabilities(&event.GetServiceCapabilities{})
  46. if err0 != nil {
  47. logrus.Errorf("GetServiceCapabilities:设备[%s]获取事件能力集失败:%s", o.parent.onvifDev.Code, err0.Error())
  48. return
  49. }
  50. if !resp0.Capabilities.WSPullPointSupport {
  51. logrus.Errorf("EventsCoroutine:设备[%s]不支持事件拉点通知方式", o.parent.onvifDev.Code)
  52. return
  53. }
  54. resp1, err1 := epy.GetEventProperties(&event.GetEventProperties{})
  55. if err1 != nil {
  56. logrus.Errorf("GetEventProperties:设备[%s]获取事件属性失败:%s", o.parent.onvifDev.Code, err1.Error())
  57. return
  58. }
  59. //订阅在onvif.json中Event配置的事件主题
  60. var TopicExpressionDialect event.AnyURI = "https://www.onvif.org/ver10/tev/topicExpression/ConcreteSet"
  61. if len(resp1.TopicExpressionDialect) > 0 && len(resp1.TopicExpressionDialect[0]) > 0 {
  62. TopicExpressionDialect = event.AnyURI(resp1.TopicExpressionDialect[0])
  63. }
  64. cps := event.CreatePullPointSubscription{
  65. Filter: event.FilterType{
  66. TopicExpression: event.TopicExpressionType{
  67. TopicKinds: o.parent.onvifDev.Event,
  68. Dialect: TopicExpressionDialect,
  69. },
  70. },
  71. }
  72. resp2, err2 := epy.CreatePullPointSubscription(&cps)
  73. if err2 != nil {
  74. logrus.Errorf("CreatePullPointSubscription:设备[%s]创建拉点失败:%s", o.parent.onvifDev.Code, err2.Error())
  75. return
  76. }
  77. pps := event.NewPullPointSubscription(client, string(resp2.SubscriptionReference.Address))
  78. pm := event.PullMessages{MessageLimit: resp0.Capabilities.MaxPullPoints}
  79. errCnt := 0
  80. for {
  81. select {
  82. case <-o.ctx.Done():
  83. logrus.Errorf("设备[%s]的EventActuator.EventHandle退出,原因:%v", o.parent.onvifDev.Code, o.ctx.Err())
  84. return
  85. default:
  86. resp, err := pps.PullMessages(&pm)
  87. if err != nil {
  88. if serr, ok := err.(*soap.SOAPFault); ok {
  89. logrus.Errorf("PullMessages:设备[%s]拉取事件失败:%s", o.parent.onvifDev.Code, serr.Error())
  90. } else {
  91. logrus.Errorf("PullMessages:设备[%s]拉取事件失败:%s", o.parent.onvifDev.Code, err.Error())
  92. }
  93. //发生错误,则停3秒再重试
  94. time.Sleep(3 * time.Second)
  95. if errCnt++; errCnt > 5 {
  96. logrus.Errorf("PullMessages连续5次调用发生错误,重启事件订阅服务.[code=%s]", o.parent.onvifDev.Code)
  97. goto Retry
  98. }
  99. break
  100. } else {
  101. errCnt = 0
  102. }
  103. if resp == nil {
  104. break
  105. }
  106. for _, v := range resp.NotificationMessage {
  107. logrus.Warnf("收到设备[%s]的告警信息:%v", o.parent.onvifDev.Code, v)
  108. //一键告警按键告警,v.Topic.TopicKinds == "tns1:Device/Trigger/tnshik:AlarmIn"
  109. t, err := time.Parse("2006-01-02T15:04:05Z", v.Message.Message.UtcTime)
  110. if err != nil {
  111. continue
  112. }
  113. ca := protocol.OnvifAlarmInfo{
  114. AlarmTopic: v.Topic.TopicKinds,
  115. Time: protocol.ToBJTime(t).Format("2006-01-02 15:04:05"),
  116. }
  117. if len(v.Message.Message.Source.SimpleItem) > 0 {
  118. ca.Source = make(map[string]string)
  119. for _, si := range v.Message.Message.Source.SimpleItem {
  120. ca.Source[si.Name] = si.Value
  121. }
  122. }
  123. if len(v.Message.Message.Key.SimpleItem) > 0 {
  124. ca.Key = make(map[string]string)
  125. for _, si := range v.Message.Message.Key.SimpleItem {
  126. ca.Key[si.Name] = si.Value
  127. }
  128. }
  129. if len(v.Message.Message.Data.SimpleItem) > 0 {
  130. ca.Data = make(map[string]string)
  131. for _, si := range v.Message.Message.Data.SimpleItem {
  132. ca.Data[si.Name] = si.Value
  133. }
  134. }
  135. seq := GetNextUint64()
  136. var obj protocol.Pack_OnvifAlarm
  137. if str, err := obj.EnCode(o.parent.onvifDev.Code, appConfig.GID, seq, &ca); err == nil {
  138. topic := GetTopic(o.parent.GetDevType(), o.parent.onvifDev.Code, protocol.TP_ONVIF_ALARM)
  139. GetMQTTMgr().Publish(topic, str, mqtt.AtMostOnce, ToAll)
  140. }
  141. switch v.Topic.TopicKinds {
  142. case "tns1:Device/Trigger/tnshik:AlarmIn": //海康一键报警
  143. o.HandleDeviceTriggerAlarmin(seq, &ca) //录像抓图
  144. case "tns1:RuleEngine/LineDetector/Crossed": //遮挡告警
  145. o.HandleRuleengineCrossedLinedetector(seq, &ca)
  146. }
  147. }
  148. }
  149. }
  150. }
  151. func (o *EventActuator) HandleRuleengineCrossedLinedetector(seq uint64, ca *protocol.OnvifAlarmInfo) {
  152. go o.parent.Snapshot("")
  153. }
  154. func (o *EventActuator) HandleDeviceTriggerAlarmin(seq uint64, ca *protocol.OnvifAlarmInfo) {
  155. if v, ok := ca.Data["State"]; ok && v == "true" {
  156. go o.parent.RecordToFLV("", 20) //告警开始,抓拍视频
  157. }
  158. go o.parent.Snapshot("") //告警开始或结束,抓拍图片
  159. }