refactor(router): 改为结构化 web 项目

This commit is contained in:
Liam Chan 2024-08-22 10:18:23 +08:00
parent 7047d896f8
commit 9ba49e0742
10 changed files with 214 additions and 225 deletions

95
main.go
View File

@ -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(&notify)
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"))
}
}
}

113
onvif.go
View File

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

View File

@ -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)
}

View File

@ -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(&notify)
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")
}

View File

@ -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"})
}

View File

@ -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)
}
}
}

View File

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

18
service/onvif/device.go Normal file
View File

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

34
service/onvif/event.go Normal file
View File

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

30
service/onvif/util.go Normal file
View File

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