2018-04-05 20:18:28 +08:00
|
|
|
|
package api
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
2018-04-07 03:25:40 +08:00
|
|
|
|
"reflect"
|
2018-04-10 05:12:58 +08:00
|
|
|
|
"regexp"
|
|
|
|
|
"errors"
|
|
|
|
|
"strings"
|
|
|
|
|
"github.com/beevik/etree"
|
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
|
"github.com/yakovlevdmv/gosoap"
|
|
|
|
|
"github.com/yakovlevdmv/goonvif"
|
|
|
|
|
"github.com/yakovlevdmv/goonvif/networking"
|
|
|
|
|
"log"
|
|
|
|
|
"net/http"
|
2018-04-10 07:08:46 +08:00
|
|
|
|
"io/ioutil"
|
|
|
|
|
"encoding/xml"
|
2018-04-05 20:18:28 +08:00
|
|
|
|
)
|
|
|
|
|
|
2018-04-10 05:12:58 +08:00
|
|
|
|
func RunApi () {
|
|
|
|
|
router := gin.Default()
|
|
|
|
|
|
|
|
|
|
router.POST("/:service/:method", func(c *gin.Context) {
|
|
|
|
|
serviceName := c.Param("service")
|
|
|
|
|
methodName := c.Param("method")
|
|
|
|
|
acceptedData, err := c.GetRawData()
|
2018-04-10 07:08:46 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Println(err)
|
|
|
|
|
}
|
|
|
|
|
message := callNecessaryMethod(serviceName, methodName, string(acceptedData), "192.168.13.12")
|
2018-04-10 05:12:58 +08:00
|
|
|
|
c.XML(http.StatusOK, message)
|
|
|
|
|
})
|
|
|
|
|
router.Run()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//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)
|
2018-04-07 03:25:40 +08:00
|
|
|
|
//
|
2018-04-10 05:12:58 +08:00
|
|
|
|
// subStruct := reflect.New(reflect.TypeOf( field.Interface() ))
|
|
|
|
|
// soapHandling(subStruct.Interface(), tags)
|
|
|
|
|
// }
|
2018-04-07 03:25:40 +08:00
|
|
|
|
//}
|
2018-04-05 20:18:28 +08:00
|
|
|
|
|
2018-04-10 05:12:58 +08:00
|
|
|
|
|
2018-04-10 07:08:46 +08:00
|
|
|
|
func callNecessaryMethod(serviceName string, methodName string, acceptedData string, deviceXaddr string) string {
|
2018-04-10 05:12:58 +08:00
|
|
|
|
var methodStruct interface{}
|
|
|
|
|
var err error
|
|
|
|
|
switch serviceName {
|
|
|
|
|
case "Device", "device":
|
|
|
|
|
methodStruct, err = GetDeviceStructByName(methodName)
|
|
|
|
|
case "PTZ", "ptz":
|
|
|
|
|
methodStruct, err = GetPTZStructByName(methodName)
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
|
|
|
|
//todo: нормально написать
|
|
|
|
|
}
|
2018-04-10 07:08:46 +08:00
|
|
|
|
resp, err := xmlAnalize(methodStruct, &acceptedData)
|
2018-04-10 05:12:58 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
//todo: нормально написать
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
soap := gosoap.NewEmptySOAP()
|
|
|
|
|
soap.AddStringBodyContent(*resp)
|
|
|
|
|
soap.AddRootNamespaces(goonvif.Xlmns)
|
2018-04-10 07:08:46 +08:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Getting an WS-Security struct representation
|
|
|
|
|
*/
|
|
|
|
|
auth := goonvif.NewSecurity("admin", "Supervisor")
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Adding WS-Security namespaces to root element of SOAP message
|
|
|
|
|
*/
|
|
|
|
|
soap.AddRootNamespace("wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext1.0.xsd")
|
|
|
|
|
soap.AddRootNamespace("wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility1.0.xsd")
|
|
|
|
|
|
|
|
|
|
soapReq, err := xml.MarshalIndent(auth, "", " ")
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Adding WS-Security struct to SOAP header
|
|
|
|
|
*/
|
|
|
|
|
soap.AddStringHeaderContent(string(soapReq))
|
|
|
|
|
|
|
|
|
|
endpoint:= getEndpoint(serviceName, deviceXaddr)
|
|
|
|
|
servResp, srvErr := networking.SendSoap(endpoint, soap.String())
|
2018-04-10 05:12:58 +08:00
|
|
|
|
if srvErr != nil {
|
2018-04-10 07:08:46 +08:00
|
|
|
|
panic(srvErr)
|
2018-04-10 05:12:58 +08:00
|
|
|
|
//todo: нормально написать
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-10 07:08:46 +08:00
|
|
|
|
rsp, err := ioutil.ReadAll(servResp.Body)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Println(err)
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
return string(rsp)
|
|
|
|
|
}
|
2018-04-10 05:12:58 +08:00
|
|
|
|
|
2018-04-10 07:08:46 +08:00
|
|
|
|
func getEndpoint(service, xaddr string) string {
|
|
|
|
|
dev, err := goonvif.NewDevice(xaddr)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Println(err)
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
pkg := strings.ToLower(service)
|
2018-04-10 05:12:58 +08:00
|
|
|
|
|
|
|
|
|
var endpoint string
|
|
|
|
|
switch pkg {
|
2018-04-10 07:08:46 +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
|
|
|
|
}
|
|
|
|
|
return endpoint
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
NEW
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
func xmlAnalize(methodStruct interface{}, acceptedData* string) (*string, error) {
|
|
|
|
|
test := make([]map[string]string, 0) //tags
|
|
|
|
|
testunMarshal := make([][]interface{}, 0) //data
|
|
|
|
|
//tmp, err := GetPTZStructByName("Stop")
|
|
|
|
|
//if err != nil {
|
|
|
|
|
// fmt.Println(err)
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
soapHandling(methodStruct, &test)
|
|
|
|
|
test = mapProcessing(test)
|
|
|
|
|
|
|
|
|
|
doc := etree.NewDocument()
|
|
|
|
|
if err := doc.ReadFromString(*acceptedData); err != nil {
|
|
|
|
|
fmt.Println(err)
|
|
|
|
|
return nil, nil //todo: нормально написать
|
|
|
|
|
}
|
|
|
|
|
etr := doc.FindElements("./*")
|
|
|
|
|
xmlUnmarshal(etr, &testunMarshal)
|
|
|
|
|
|
|
|
|
|
etr_ := doc.FindElements("./*")
|
|
|
|
|
var mas []string //idnt
|
|
|
|
|
getPos(etr_, &mas)
|
|
|
|
|
ident(&mas)
|
|
|
|
|
|
|
|
|
|
//todo: может возникнуть проблема с типами данных без тегов. От таких типов надо избавляться
|
|
|
|
|
//todo: попробовать всунуть все вызовы (soapHandling, xmlUnmarshal)сюда
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
document:= etree.NewDocument()
|
|
|
|
|
var el *etree.Element
|
|
|
|
|
var idntIndex = 0
|
|
|
|
|
|
|
|
|
|
for lstIndex := 0; lstIndex < len(testunMarshal); {
|
|
|
|
|
lst := (testunMarshal)[lstIndex]
|
|
|
|
|
elemName, attr, value:= xmlMaker(&lst, &test, lstIndex)
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
} else if mas[idntIndex] == "PushPop" { //done
|
|
|
|
|
popTmp := etree.NewElement(elemName)
|
|
|
|
|
popTmp.SetText(value)
|
|
|
|
|
if len(attr) != 0 {
|
|
|
|
|
for key, value := range attr {
|
|
|
|
|
popTmp.CreateAttr(key, value)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
el.AddChild(popTmp)
|
|
|
|
|
} else if mas[idntIndex] == "Pop" {
|
|
|
|
|
el = el.Parent()
|
|
|
|
|
lstIndex -= 1
|
|
|
|
|
}
|
|
|
|
|
idntIndex += 1
|
|
|
|
|
lstIndex += 1
|
|
|
|
|
}
|
|
|
|
|
//document.Indent(2)
|
|
|
|
|
//fmt.Println(document.WriteToString())
|
|
|
|
|
resp, err := document.WriteToString()
|
|
|
|
|
if err != nil {
|
|
|
|
|
//todo нормально расписать
|
|
|
|
|
}
|
|
|
|
|
return &resp, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func xmlMaker(lst* []interface{}, tags* []map[string]string, lstIndex int) (string, map[string]string, string) {
|
|
|
|
|
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 {
|
|
|
|
|
fmt.Println(err)
|
|
|
|
|
}
|
|
|
|
|
elemName = res
|
|
|
|
|
} else if index == 0 {
|
|
|
|
|
res, err := xmlProcessing(tg[conversion])
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Println(err)
|
|
|
|
|
}
|
|
|
|
|
elemName = res
|
|
|
|
|
} else {
|
|
|
|
|
value = conversion
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return elemName, attr, value
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func xmlProcessing (tg string) (string, error) {
|
|
|
|
|
r, _ := regexp.Compile(`\"(.*?)\"`)
|
|
|
|
|
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")
|
|
|
|
|
if attr == -1 && omit == -1 { //todo: проработать вариант, когдв omitempty и attr вместе
|
2018-04-10 05:12:58 +08:00
|
|
|
|
return str[1], nil
|
2018-04-10 07:08:46 +08:00
|
|
|
|
} else if omit > -1 {
|
|
|
|
|
return str[1][0:omit], nil
|
|
|
|
|
}else {
|
2018-04-10 05:12:58 +08:00
|
|
|
|
return str[0:attr][0], nil
|
|
|
|
|
}
|
|
|
|
|
return "", errors.New("something went wrong")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func soapHandling(tp interface{}, tags* []map[string]string) {
|
|
|
|
|
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)
|
|
|
|
|
tmp, err := typeOfT.FieldByName(typeOfT.Field(i).Name)
|
2018-04-07 03:25:40 +08:00
|
|
|
|
if err == false {
|
|
|
|
|
fmt.Println(err)
|
|
|
|
|
}
|
2018-04-10 05:12:58 +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-04-10 05:12:58 +08:00
|
|
|
|
//todo: передавать в него отступы
|
|
|
|
|
func xmlUnmarshal(elems []*etree.Element, data* [][]interface{}) {
|
|
|
|
|
for _, elem := range elems {
|
|
|
|
|
*data = append(*data, []interface{}{elem.Tag,elem.Attr,elem.Text()})
|
|
|
|
|
xmlUnmarshal(elem.FindElements("./*"), data)
|
2018-04-07 03:25:40 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-10 05:12:58 +08:00
|
|
|
|
|
|
|
|
|
//todo лишняя функция, засунуть в xmlUnmarshal
|
|
|
|
|
func getPos(elems []*etree.Element, mas* []string) {
|
|
|
|
|
for _, elem := range elems {
|
|
|
|
|
*mas = append(*mas, "Push")
|
|
|
|
|
getPos(elem.FindElements("./*"), mas)
|
|
|
|
|
*mas = append(*mas, "Pop")
|
2018-04-05 20:18:28 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-10 05:12:58 +08:00
|
|
|
|
func ident(mas* []string) {
|
|
|
|
|
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-04-05 20:18:28 +08:00
|
|
|
|
}
|