onvif/api/api.go

375 lines
9.4 KiB
Go
Raw Permalink Normal View History

2018-04-05 20:18:28 +08:00
package api
import (
2023-12-19 03:16:21 +08:00
"errors"
"fmt"
2018-05-16 14:11:00 +08:00
"io/ioutil"
"net/http"
"path"
2018-04-07 03:25:40 +08:00
"reflect"
2018-04-10 05:12:58 +08:00
"regexp"
"strings"
2018-05-16 14:11:00 +08:00
2018-04-10 05:12:58 +08:00
"github.com/beevik/etree"
"github.com/gin-gonic/gin"
2021-06-05 03:51:49 +08:00
"github.com/kerberos-io/onvif"
"github.com/kerberos-io/onvif/gosoap"
"github.com/kerberos-io/onvif/networking"
wsdiscovery "github.com/kerberos-io/onvif/ws-discovery"
2018-04-05 20:18:28 +08:00
)
2018-05-16 14:11:00 +08:00
func RunApi() {
2018-04-10 05:12:58 +08:00
router := gin.Default()
router.POST("/:service/:method", func(c *gin.Context) {
2018-05-11 01:54:07 +08:00
c.Header("Access-Control-Allow-Origin", "*")
//c.Header("Access-Control-Allow-Headers", "access-control-allow-origin, access-control-allow-headers")
2018-04-10 05:12:58 +08:00
serviceName := c.Param("service")
methodName := c.Param("method")
2018-04-10 19:20:39 +08:00
username := c.GetHeader("username")
pass := c.GetHeader("password")
xaddr := c.GetHeader("xaddr")
2018-04-10 05:12:58 +08:00
acceptedData, err := c.GetRawData()
2018-04-10 07:08:46 +08:00
if err != nil {
2023-12-19 03:16:21 +08:00
fmt.Println(err)
2018-04-10 07:08:46 +08:00
}
2018-04-10 18:33:32 +08:00
2018-04-10 19:20:39 +08:00
message, err := callNecessaryMethod(serviceName, methodName, string(acceptedData), username, pass, xaddr)
2018-04-10 18:33:32 +08:00
if err != nil {
c.XML(http.StatusBadRequest, err.Error())
} else {
2018-05-11 01:54:07 +08:00
c.String(http.StatusOK, message)
2018-04-10 18:33:32 +08:00
}
2018-04-10 05:12:58 +08:00
})
2018-05-11 01:54:07 +08:00
router.GET("/discovery", func(context *gin.Context) {
context.Header("Access-Control-Allow-Origin", "*")
context.Header("Access-Control-Allow-Headers", "access-control-allow-origin, access-control-allow-headers")
interfaceName := context.GetHeader("interface")
2023-12-19 03:16:21 +08:00
var response = "["
// TODO: Handle this error.
devices, _ := wsdiscovery.SendProbe(interfaceName, nil, []string{"dn:NetworkVideoTransmitter"}, map[string]string{"dn": "http://www.onvif.org/ver10/network/wsdl"})
2020-04-29 10:53:49 +08:00
2023-12-19 03:16:21 +08:00
for _, j := range devices {
doc := etree.NewDocument()
if err := doc.ReadFromString(j); err != nil {
context.XML(http.StatusBadRequest, err.Error())
} else {
2018-05-11 01:54:07 +08:00
2023-12-19 03:16:21 +08:00
endpoints := doc.Root().FindElements("./Body/ProbeMatches/ProbeMatch/XAddrs")
scopes := doc.Root().FindElements("./Body/ProbeMatches/ProbeMatch/Scopes")
2018-05-11 01:54:07 +08:00
2023-12-19 03:16:21 +08:00
flag := false
2018-05-11 01:54:07 +08:00
2023-12-19 03:16:21 +08:00
for _, xaddr := range endpoints {
xaddr := strings.Split(strings.Split(xaddr.Text(), " ")[0], "/")[2]
if strings.Contains(response, xaddr) {
flag = true
2018-05-11 01:54:07 +08:00
break
}
2023-12-19 03:16:21 +08:00
response += "{"
response += `"url":"` + xaddr + `",`
}
if flag {
break
}
for _, scope := range scopes {
re := regexp.MustCompile(`onvif:\/\/www\.onvif\.org\/name\/[A-Za-z0-9-]+`)
match := re.FindStringSubmatch(scope.Text())
response += `"name":"` + path.Base(match[0]) + `"`
2018-05-11 01:54:07 +08:00
}
2023-12-19 03:16:21 +08:00
response += "},"
2018-05-11 01:54:07 +08:00
}
2023-12-19 03:16:21 +08:00
}
response = strings.TrimRight(response, ",")
response += "]"
if response != "" {
2018-05-11 01:54:07 +08:00
context.String(http.StatusOK, response)
}
})
2018-04-10 05:12:58 +08:00
router.Run()
}
2023-12-19 03:16:21 +08:00
//func soapHandling(tp interface{}, tags* map[string]string) {
// ifaceValue := reflect.ValueOf(tp).Elem()
// typeOfStruct := ifaceValue.Type()
// if ifaceValue.Kind() != reflect.Struct {
// return
// }
// for i := 0; i < ifaceValue.NumField(); i++ {
// field := ifaceValue.Field(i)
// tg, err := typeOfStruct.FieldByName(typeOfStruct.Field(i).Name)
// if err == false {
// fmt.Println(err)
// }
// (*tags)[typeOfStruct.Field(i).Name] = string(tg.Tag)
//
// subStruct := reflect.New(reflect.TypeOf( field.Interface() ))
// soapHandling(subStruct.Interface(), tags)
// }
//}
2018-04-10 19:20:39 +08:00
func callNecessaryMethod(serviceName, methodName, acceptedData, username, password, xaddr string) (string, error) {
2018-04-10 05:12:58 +08:00
var methodStruct interface{}
var err error
2018-04-10 18:33:32 +08:00
switch strings.ToLower(serviceName) {
case "device":
2018-04-11 07:26:22 +08:00
methodStruct, err = getDeviceStructByName(methodName)
2018-04-10 18:33:32 +08:00
case "ptz":
2018-04-11 07:26:22 +08:00
methodStruct, err = getPTZStructByName(methodName)
2018-04-11 23:29:07 +08:00
case "media":
methodStruct, err = getMediaStructByName(methodName)
2018-04-11 07:26:22 +08:00
default:
return "", errors.New("there is no such service")
2018-04-10 05:12:58 +08:00
}
2018-04-10 18:33:32 +08:00
if err != nil { //done
2023-12-19 03:16:21 +08:00
return "", err
2018-04-10 05:12:58 +08:00
}
2018-04-10 18:33:32 +08:00
2018-04-10 07:08:46 +08:00
resp, err := xmlAnalize(methodStruct, &acceptedData)
2018-04-10 05:12:58 +08:00
if err != nil {
2023-12-19 03:16:21 +08:00
return "", err
2018-04-10 18:33:32 +08:00
}
2018-04-10 19:20:39 +08:00
endpoint, err := getEndpoint(serviceName, xaddr)
2018-04-10 18:33:32 +08:00
if err != nil {
2023-12-19 03:16:21 +08:00
return "", err
2018-04-10 05:12:58 +08:00
}
soap := gosoap.NewEmptySOAP()
soap.AddStringBodyContent(*resp)
2020-04-29 10:53:49 +08:00
soap.AddRootNamespaces(onvif.Xlmns)
2018-04-10 19:20:39 +08:00
soap.AddWSSecurity(username, password)
2018-04-10 07:08:46 +08:00
2021-02-25 00:47:09 +08:00
servResp, err := networking.SendSoap(new(http.Client), endpoint, soap.String())
2018-04-10 18:33:32 +08:00
if err != nil {
2023-12-19 03:16:21 +08:00
return "", err
2018-04-10 05:12:58 +08:00
}
2018-04-10 07:08:46 +08:00
rsp, err := ioutil.ReadAll(servResp.Body)
if err != nil {
2023-12-19 03:16:21 +08:00
return "", err
2018-04-10 07:08:46 +08:00
}
2018-04-10 18:33:32 +08:00
return string(rsp), nil
2018-04-10 07:08:46 +08:00
}
2018-04-10 05:12:58 +08:00
2018-05-16 14:11:00 +08:00
func getEndpoint(service, xaddr string) (string, error) {
2021-02-25 00:47:09 +08:00
dev, err := onvif.NewDevice(onvif.DeviceParams{Xaddr: xaddr})
2018-04-10 07:08:46 +08:00
if err != nil {
2023-12-19 03:16:21 +08:00
return "", err
2018-04-10 07:08:46 +08:00
}
pkg := strings.ToLower(service)
2018-04-10 05:12:58 +08:00
var endpoint string
switch pkg {
2018-05-16 14:11:00 +08:00
case "device":
endpoint = dev.GetEndpoint("Device")
case "event":
endpoint = dev.GetEndpoint("Event")
case "imaging":
endpoint = dev.GetEndpoint("Imaging")
case "media":
endpoint = dev.GetEndpoint("Media")
case "ptz":
endpoint = dev.GetEndpoint("PTZ")
2018-04-10 05:12:58 +08:00
}
2018-04-10 18:33:32 +08:00
return endpoint, nil
2018-04-10 05:12:58 +08:00
}
2018-05-16 14:11:00 +08:00
func xmlAnalize(methodStruct interface{}, acceptedData *string) (*string, error) {
test := make([]map[string]string, 0) //tags
2018-04-10 05:12:58 +08:00
testunMarshal := make([][]interface{}, 0) //data
2018-05-16 14:11:00 +08:00
var mas []string //idnt
2018-04-10 05:12:58 +08:00
soapHandling(methodStruct, &test)
test = mapProcessing(test)
doc := etree.NewDocument()
if err := doc.ReadFromString(*acceptedData); err != nil {
2023-12-19 03:16:21 +08:00
return nil, err
2018-04-10 05:12:58 +08:00
}
etr := doc.FindElements("./*")
2018-04-10 18:33:32 +08:00
xmlUnmarshal(etr, &testunMarshal, &mas)
2018-04-10 05:12:58 +08:00
ident(&mas)
2018-05-16 14:11:00 +08:00
document := etree.NewDocument()
2018-04-10 05:12:58 +08:00
var el *etree.Element
var idntIndex = 0
for lstIndex := 0; lstIndex < len(testunMarshal); {
lst := (testunMarshal)[lstIndex]
2018-04-10 18:33:32 +08:00
elemName, attr, value, err := xmlMaker(&lst, &test, lstIndex)
if err != nil {
2023-12-19 03:16:21 +08:00
return nil, err
2018-04-10 18:33:32 +08:00
}
2018-04-10 05:12:58 +08:00
if mas[lstIndex] == "Push" && lstIndex == 0 { //done
el = document.CreateElement(elemName)
el.SetText(value)
if len(attr) != 0 {
for key, value := range attr {
el.CreateAttr(key, value)
}
}
} else if mas[idntIndex] == "Push" {
pushTmp := etree.NewElement(elemName)
pushTmp.SetText(value)
if len(attr) != 0 {
for key, value := range attr {
pushTmp.CreateAttr(key, value)
}
}
el.AddChild(pushTmp)
el = pushTmp
2018-04-11 18:23:19 +08:00
} else if mas[idntIndex] == "PushPop" {
2018-04-10 05:12:58 +08:00
popTmp := etree.NewElement(elemName)
popTmp.SetText(value)
if len(attr) != 0 {
for key, value := range attr {
popTmp.CreateAttr(key, value)
}
}
2018-04-11 18:23:19 +08:00
if el == nil {
2018-04-11 19:09:04 +08:00
document.AddChild(popTmp)
2018-04-11 18:23:19 +08:00
} else {
el.AddChild(popTmp)
}
2018-04-10 05:12:58 +08:00
} else if mas[idntIndex] == "Pop" {
el = el.Parent()
2018-05-16 14:11:00 +08:00
lstIndex -= 1
2018-04-10 05:12:58 +08:00
}
idntIndex += 1
2018-05-16 14:11:00 +08:00
lstIndex += 1
2018-04-10 05:12:58 +08:00
}
2018-04-10 18:33:32 +08:00
2018-04-10 05:12:58 +08:00
resp, err := document.WriteToString()
if err != nil {
2023-12-19 03:16:21 +08:00
return nil, err
2018-04-10 05:12:58 +08:00
}
2018-04-10 18:33:32 +08:00
2023-12-19 03:16:21 +08:00
return &resp, err
2018-04-10 05:12:58 +08:00
}
2018-05-16 14:11:00 +08:00
func xmlMaker(lst *[]interface{}, tags *[]map[string]string, lstIndex int) (string, map[string]string, string, error) {
2018-04-10 05:12:58 +08:00
var elemName, value string
attr := make(map[string]string)
for tgIndx, tg := range *tags {
if tgIndx == lstIndex {
for index, elem := range *lst {
if reflect.TypeOf(elem).String() == "[]etree.Attr" {
conversion := elem.([]etree.Attr)
for _, i := range conversion {
attr[i.Key] = i.Value
}
} else {
conversion := elem.(string)
if index == 0 && lstIndex == 0 {
res, err := xmlProcessing(tg["XMLName"])
if err != nil {
2023-12-19 03:16:21 +08:00
return "", nil, "", err
2018-04-10 05:12:58 +08:00
}
elemName = res
} else if index == 0 {
res, err := xmlProcessing(tg[conversion])
if err != nil {
2023-12-19 03:16:21 +08:00
return "", nil, "", err
2018-04-10 05:12:58 +08:00
}
elemName = res
} else {
value = conversion
}
}
}
}
}
2018-04-10 18:33:32 +08:00
return elemName, attr, value, nil
2018-04-10 05:12:58 +08:00
}
2018-05-16 14:11:00 +08:00
func xmlProcessing(tg string) (string, error) {
2018-04-11 03:58:56 +08:00
r, _ := regexp.Compile(`"(.*?)"`)
2018-04-10 05:12:58 +08:00
str := r.FindStringSubmatch(tg)
if len(str) == 0 {
return "", errors.New("out of range")
}
attr := strings.Index(str[1], ",attr")
2018-04-10 07:08:46 +08:00
omit := strings.Index(str[1], ",omitempty")
2018-04-10 18:33:32 +08:00
attrOmit := strings.Index(str[1], ",attr,omitempty")
omitAttr := strings.Index(str[1], ",omitempty,attr")
if attr > -1 && attrOmit == -1 && omitAttr == -1 {
return str[1][0:attr], nil
} else if omit > -1 && attrOmit == -1 && omitAttr == -1 {
2018-04-10 07:08:46 +08:00
return str[1][0:omit], nil
2018-04-10 18:33:32 +08:00
} else if attr == -1 && omit == -1 {
return str[1], nil
} else if attrOmit > -1 {
return str[1][0:attrOmit], nil
} else {
return str[1][0:omitAttr], nil
2018-04-10 05:12:58 +08:00
}
2023-12-19 03:16:21 +08:00
return "", errors.New("something went wrong")
2018-04-10 05:12:58 +08:00
}
func mapProcessing(mapVar []map[string]string) []map[string]string {
for indx := 0; indx < len(mapVar); indx++ {
element := mapVar[indx]
for _, value := range element {
if value == "" {
mapVar = append(mapVar[:indx], mapVar[indx+1:]...)
indx--
}
if strings.Index(value, ",attr") != -1 {
mapVar = append(mapVar[:indx], mapVar[indx+1:]...)
indx--
}
}
}
return mapVar
}
2018-05-16 14:11:00 +08:00
func soapHandling(tp interface{}, tags *[]map[string]string) {
2018-04-10 05:12:58 +08:00
s := reflect.ValueOf(tp).Elem()
typeOfT := s.Type()
if s.Kind() != reflect.Struct {
2018-04-07 03:25:40 +08:00
return
2018-04-05 20:18:28 +08:00
}
2018-04-10 05:12:58 +08:00
for i := 0; i < s.NumField(); i++ {
f := s.Field(i)
2023-12-19 03:16:21 +08:00
tmp, err := typeOfT.FieldByName(typeOfT.Field(i).Name)
if err == false {
fmt.Println(err)
2018-04-07 03:25:40 +08:00
}
2018-05-16 14:11:00 +08:00
*tags = append(*tags, map[string]string{typeOfT.Field(i).Name: string(tmp.Tag)})
subStruct := reflect.New(reflect.TypeOf(f.Interface()))
2018-04-07 03:25:40 +08:00
soapHandling(subStruct.Interface(), tags)
}
2018-04-05 20:18:28 +08:00
}
2018-05-16 14:11:00 +08:00
func xmlUnmarshal(elems []*etree.Element, data *[][]interface{}, mas *[]string) {
2018-04-10 05:12:58 +08:00
for _, elem := range elems {
2018-05-16 14:11:00 +08:00
*data = append(*data, []interface{}{elem.Tag, elem.Attr, elem.Text()})
2018-04-10 05:12:58 +08:00
*mas = append(*mas, "Push")
2018-04-10 18:33:32 +08:00
xmlUnmarshal(elem.FindElements("./*"), data, mas)
2018-04-10 05:12:58 +08:00
*mas = append(*mas, "Pop")
2018-04-05 20:18:28 +08:00
}
}
2018-05-16 14:11:00 +08:00
func ident(mas *[]string) {
2018-04-10 05:12:58 +08:00
var buffer string
for _, j := range *mas {
buffer += j + " "
2018-04-07 03:25:40 +08:00
}
2018-04-10 05:12:58 +08:00
buffer = strings.Replace(buffer, "Push Pop ", "PushPop ", -1)
buffer = strings.TrimSpace(buffer)
*mas = strings.Split(buffer, " ")
2018-05-16 14:11:00 +08:00
}