From 9ba49e0742b28c4e9db29aa71efb620f1f132be8 Mon Sep 17 00:00:00 2001 From: imbytecat Date: Thu, 22 Aug 2024 10:18:23 +0800 Subject: [PATCH] =?UTF-8?q?refactor(router):=20=E6=94=B9=E4=B8=BA=E7=BB=93?= =?UTF-8?q?=E6=9E=84=E5=8C=96=20web=20=E9=A1=B9=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.go | 95 +--------------------- onvif.go | 113 --------------------------- router/handler/onvif/connection.go | 41 ++++++++++ router/handler/onvif/subscription.go | 38 +++++++++ router/handler/onvif_handler.go | 16 ---- router/router.go | 14 +++- service/onvif/connection.go | 40 ++++++++++ service/onvif/device.go | 18 +++++ service/onvif/event.go | 34 ++++++++ service/onvif/util.go | 30 +++++++ 10 files changed, 214 insertions(+), 225 deletions(-) delete mode 100644 onvif.go create mode 100644 router/handler/onvif/connection.go create mode 100644 router/handler/onvif/subscription.go delete mode 100644 router/handler/onvif_handler.go create mode 100644 service/onvif/connection.go create mode 100644 service/onvif/device.go create mode 100644 service/onvif/event.go create mode 100644 service/onvif/util.go diff --git a/main.go b/main.go index e38353b..c609d9a 100644 --- a/main.go +++ b/main.go @@ -2,34 +2,15 @@ package main import ( "fmt" - "github.com/IOTechSystems/onvif/event" - "github.com/IOTechSystems/onvif/gosoap" - "log" - "net/http" - "time" - "github.com/gin-gonic/gin" + "onvif-agent/router" ) -var connections = make(map[string]*Connection) - func main() { r := gin.Default() - r.GET("/ping", func(c *gin.Context) { - c.JSON(http.StatusOK, gin.H{ - "message": "pong", - }) - }) - - r.POST("/onvif", createConnection) - r.GET("/onvif", getConnections) - r.GET("/onvif/:xaddr", getConnectionByXaddr) - r.DELETE("/onvif/:xaddr", deleteConnection) - - r.POST("/events/subscribe/:xaddr", eventsSubscribe) - r.POST("/events/callback", eventsCallback) + router.SetupRoutes(r) go func() { if err := r.Run(":8080"); err != nil { @@ -44,75 +25,3 @@ func main() { // block main() select {} } - -func createConnection(c *gin.Context) { - conn, err := NewConnection("172.16.19.239", "admin", "admin123") - if err != nil { - c.JSON(http.StatusServiceUnavailable, gin.H{ - "message": err.Error(), - }) - return - } - - connections[conn.Device.GetDeviceParams().Xaddr] = conn - - info, err := conn.GetDeviceInformation() - c.JSON(http.StatusOK, gin.H{ - "connectionParams": conn.Params, - "deviceInfo": info, - }) -} - -func getConnections(c *gin.Context) { - c.JSON(http.StatusOK, connections) -} - -func getConnectionByXaddr(c *gin.Context) { - xaddr := c.Param("xaddr") - c.JSON(http.StatusOK, connections[xaddr]) -} - -func deleteConnection(c *gin.Context) { - xaddr := c.Param("xaddr") - delete(connections, xaddr) -} - -func eventsSubscribe(c *gin.Context) { - xaddr := c.Param("xaddr") - result, err := connections[xaddr].SubscribeEvents("http://172.16.19.230:8080/events/callback", "PT60S") - if err != nil { - c.JSON(http.StatusServiceUnavailable, gin.H{ - "message": err.Error(), - }) - return - } - - c.JSON(http.StatusOK, result) -} - -func eventsCallback(c *gin.Context) { - var notify event.Notify - envelope := gosoap.NewSOAPEnvelope(¬ify) - if err := c.ShouldBindXML(&envelope); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - - for _, msg := range envelope.Body.Content.(*event.Notify).NotificationMessage { - log.Println(msg.Topic.TopicKinds, msg.Message.Message) - } - - c.String(http.StatusOK, "OK") -} - -func printTime() { - ticker := time.NewTicker(1 * time.Second) // 每秒触发一次 - defer ticker.Stop() // 确保在函数结束时停止 ticker - - for { - select { - case t := <-ticker.C: - fmt.Println("当前时间:", t.Format("2006-01-02 15:04:05")) - } - } -} diff --git a/onvif.go b/onvif.go deleted file mode 100644 index f305332..0000000 --- a/onvif.go +++ /dev/null @@ -1,113 +0,0 @@ -package main - -import ( - "encoding/xml" - goonvif "github.com/IOTechSystems/onvif" - "github.com/IOTechSystems/onvif/device" - "github.com/IOTechSystems/onvif/event" - "github.com/IOTechSystems/onvif/gosoap" - "github.com/IOTechSystems/onvif/xsd" - "io" - "net/http" -) - -type Connection struct { - Params DeviceParams `json:"params"` - Device *goonvif.Device `json:"device"` -} - -type DeviceParams struct { - Xaddr string `json:"xaddr"` - EndpointRefAddress string `json:"endpointRefAddress"` - Username string `json:"username"` - Password string `json:"password"` - AuthMode string `json:"authMode"` -} - -func readResponse(resp *http.Response) (string, error) { - b, err := io.ReadAll(resp.Body) - if err != nil { - return "", err - } - - return string(b), nil -} - -func unmarshalResponse(resp *http.Response, target any) error { - b, err := io.ReadAll(resp.Body) - if err != nil { - return err - } - - if err = xml.Unmarshal(b, gosoap.NewSOAPEnvelope(target)); err != nil { - return err - } - - return nil -} - -func NewConnection(addr string, username string, password string) (*Connection, error) { - dev, err := goonvif.NewDevice(goonvif.DeviceParams{ - Xaddr: addr, - Username: username, - Password: password, - //AuthMode: goonvif.UsernameTokenAuth, - }) - if err != nil { - return nil, err - } - - return &Connection{ - Params: DeviceParams{ - Xaddr: dev.GetDeviceParams().Xaddr, - EndpointRefAddress: dev.GetDeviceParams().EndpointRefAddress, - Username: dev.GetDeviceParams().Username, - Password: dev.GetDeviceParams().Password, - AuthMode: dev.GetDeviceParams().AuthMode, - }, - Device: dev, - }, nil -} - -func (c *Connection) GetDeviceInformation() (*device.GetDeviceInformationResponse, error) { - resp, err := c.Device.CallMethod(device.GetDeviceInformation{}) - if err != nil { - return nil, err - } - - result := &device.GetDeviceInformationResponse{} - err = unmarshalResponse(resp, result) - if err != nil { - return nil, err - } - - return result, nil -} - -func (c *Connection) SubscribeEvents( - consumerAddress event.AttributedURIType, - terminationTime xsd.String, // PT60S -) (*event.SubscribeResponse, error) { - resp, err := c.Device.CallMethod(event.Subscribe{ - ConsumerReference: &event.EndpointReferenceType{ - Address: consumerAddress, - }, - Filter: &event.FilterType{ - TopicExpression: &event.TopicExpressionType{ - TopicKinds: "tns1:VideoSource//.", - }, - }, - TerminationTime: &terminationTime, - }) - if err != nil { - return nil, err - } - - result := &event.SubscribeResponse{} - err = unmarshalResponse(resp, result) - if err != nil { - return nil, err - } - - return result, nil -} diff --git a/router/handler/onvif/connection.go b/router/handler/onvif/connection.go new file mode 100644 index 0000000..e4fb256 --- /dev/null +++ b/router/handler/onvif/connection.go @@ -0,0 +1,41 @@ +package onvif + +import ( + "github.com/gin-gonic/gin" + "net/http" + "onvif-agent/service/onvif" +) + +var conns = make(map[string]*onvif.Connection) + +func CreateConnection(c *gin.Context) { + conn, err := onvif.NewConnection("172.16.19.239", "admin", "admin123") + if err != nil { + c.JSON(http.StatusServiceUnavailable, gin.H{ + "message": err.Error(), + }) + return + } + + conns[conn.Device.GetDeviceParams().Xaddr] = conn + + info, err := conn.GetDeviceInformation() + c.JSON(http.StatusOK, gin.H{ + "connectionParams": conn.Params, + "deviceInfo": info, + }) +} + +func GetConnections(c *gin.Context) { + c.JSON(http.StatusOK, conns) +} + +func GetConnectionByXaddr(c *gin.Context) { + xaddr := c.Param("xaddr") + c.JSON(http.StatusOK, conns[xaddr]) +} + +func DeleteConnection(c *gin.Context) { + xaddr := c.Param("xaddr") + delete(conns, xaddr) +} diff --git a/router/handler/onvif/subscription.go b/router/handler/onvif/subscription.go new file mode 100644 index 0000000..e944404 --- /dev/null +++ b/router/handler/onvif/subscription.go @@ -0,0 +1,38 @@ +package onvif + +import ( + "github.com/IOTechSystems/onvif/event" + "github.com/IOTechSystems/onvif/gosoap" + "github.com/gin-gonic/gin" + "log" + "net/http" +) + +func CreateEventSubscription(c *gin.Context) { + xaddr := c.Param("xaddr") + // FIXME: 把参数变成传入的参数 + result, err := conns[xaddr].SubscribeEvents("http://172.16.19.230:8080/events/callback", "PT60S") + if err != nil { + c.JSON(http.StatusServiceUnavailable, gin.H{ + "message": err.Error(), + }) + return + } + + c.JSON(http.StatusOK, result) +} + +func EventNotifyCallback(c *gin.Context) { + var notify event.Notify + envelope := gosoap.NewSOAPEnvelope(¬ify) + if err := c.ShouldBindXML(&envelope); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + for _, msg := range envelope.Body.Content.(*event.Notify).NotificationMessage { + log.Println(msg.Topic.TopicKinds, msg.Message.Message) + } + + c.String(http.StatusOK, "OK") +} diff --git a/router/handler/onvif_handler.go b/router/handler/onvif_handler.go deleted file mode 100644 index 02a2076..0000000 --- a/router/handler/onvif_handler.go +++ /dev/null @@ -1,16 +0,0 @@ -package handler - -import ( - "github.com/gin-gonic/gin" - "net/http" -) - -func GetConnections(c *gin.Context) { - // 这里可以添加获取产品的逻辑 - c.JSON(http.StatusOK, gin.H{"message": "Get Connections"}) -} - -func CreateConnection(c *gin.Context) { - // 这里可以添加创建产品的逻辑 - c.JSON(http.StatusCreated, gin.H{"message": "Connection Created"}) -} diff --git a/router/router.go b/router/router.go index 0cb466a..d2bc1f7 100644 --- a/router/router.go +++ b/router/router.go @@ -2,7 +2,7 @@ package router import ( "github.com/gin-gonic/gin" - "onvif-agent/router/handler" + "onvif-agent/router/handler/onvif" ) func SetupRoutes(r *gin.Engine) { @@ -11,8 +11,16 @@ func SetupRoutes(r *gin.Engine) { { connectionGroup := userGroup.Group("/connections") { - connectionGroup.GET("/", handler.GetConnections) - connectionGroup.POST("/", handler.CreateConnection) + connectionGroup.POST("/", onvif.CreateConnection) + connectionGroup.GET("/", onvif.GetConnections) + connectionGroup.GET("/:xaddr", onvif.GetConnectionByXaddr) + connectionGroup.DELETE("/:xaddr", onvif.DeleteConnection) + } + + subscriptionGroup := userGroup.Group("/subscriptions") + { + subscriptionGroup.POST("/:xaddr", onvif.CreateEventSubscription) + subscriptionGroup.POST("/callback", onvif.EventNotifyCallback) } } } diff --git a/service/onvif/connection.go b/service/onvif/connection.go new file mode 100644 index 0000000..ffaeb20 --- /dev/null +++ b/service/onvif/connection.go @@ -0,0 +1,40 @@ +package onvif + +import ( + "github.com/IOTechSystems/onvif" +) + +type Connection struct { + Params DeviceParams `json:"params"` + Device *onvif.Device `json:"device"` +} + +type DeviceParams struct { + Xaddr string `json:"xaddr"` + EndpointRefAddress string `json:"endpointRefAddress"` + Username string `json:"username"` + Password string `json:"password"` + AuthMode string `json:"authMode"` +} + +func NewConnection(addr string, username string, password string) (*Connection, error) { + dev, err := onvif.NewDevice(onvif.DeviceParams{ + Xaddr: addr, + Username: username, + Password: password, + }) + if err != nil { + return nil, err + } + + return &Connection{ + Params: DeviceParams{ + Xaddr: dev.GetDeviceParams().Xaddr, + EndpointRefAddress: dev.GetDeviceParams().EndpointRefAddress, + Username: dev.GetDeviceParams().Username, + Password: dev.GetDeviceParams().Password, + AuthMode: dev.GetDeviceParams().AuthMode, + }, + Device: dev, + }, nil +} diff --git a/service/onvif/device.go b/service/onvif/device.go new file mode 100644 index 0000000..b955ebd --- /dev/null +++ b/service/onvif/device.go @@ -0,0 +1,18 @@ +package onvif + +import "github.com/IOTechSystems/onvif/device" + +func (c *Connection) GetDeviceInformation() (*device.GetDeviceInformationResponse, error) { + resp, err := c.Device.CallMethod(device.GetDeviceInformation{}) + if err != nil { + return nil, err + } + + result := &device.GetDeviceInformationResponse{} + err = unmarshalResponse(resp, result) + if err != nil { + return nil, err + } + + return result, nil +} diff --git a/service/onvif/event.go b/service/onvif/event.go new file mode 100644 index 0000000..c15c438 --- /dev/null +++ b/service/onvif/event.go @@ -0,0 +1,34 @@ +package onvif + +import ( + "github.com/IOTechSystems/onvif/event" + "github.com/IOTechSystems/onvif/xsd" +) + +func (c *Connection) SubscribeEvents( + consumerAddress event.AttributedURIType, + terminationTime xsd.String, // PT60S +) (*event.SubscribeResponse, error) { + resp, err := c.Device.CallMethod(event.Subscribe{ + ConsumerReference: &event.EndpointReferenceType{ + Address: consumerAddress, + }, + Filter: &event.FilterType{ + TopicExpression: &event.TopicExpressionType{ + TopicKinds: "tns1:VideoSource//.", + }, + }, + TerminationTime: &terminationTime, + }) + if err != nil { + return nil, err + } + + result := &event.SubscribeResponse{} + err = unmarshalResponse(resp, result) + if err != nil { + return nil, err + } + + return result, nil +} diff --git a/service/onvif/util.go b/service/onvif/util.go new file mode 100644 index 0000000..8a1b4e7 --- /dev/null +++ b/service/onvif/util.go @@ -0,0 +1,30 @@ +package onvif + +import ( + "encoding/xml" + "github.com/IOTechSystems/onvif/gosoap" + "io" + "net/http" +) + +func readResponse(resp *http.Response) (string, error) { + b, err := io.ReadAll(resp.Body) + if err != nil { + return "", err + } + + return string(b), nil +} + +func unmarshalResponse(resp *http.Response, target any) error { + b, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + if err = xml.Unmarshal(b, gosoap.NewSOAPEnvelope(target)); err != nil { + return err + } + + return nil +}