From c8e7d4c3c1a78f4fd0b379fa13c32415b84c9c75 Mon Sep 17 00:00:00 2001 From: George Palanjyan Date: Thu, 5 Apr 2018 15:18:28 +0300 Subject: [PATCH 1/4] Add API --- api/api.go | 37 +++++++++++++++++++++++++++++++++++++ networking/networking.go | 3 +-- 2 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 api/api.go diff --git a/api/api.go b/api/api.go new file mode 100644 index 0000000..cac7a77 --- /dev/null +++ b/api/api.go @@ -0,0 +1,37 @@ +package api + +import ( + "github.com/gin-gonic/gin" + "net/http" + "github.com/yakovlevdmv/goonvif" + "github.com/yakovlevdmv/goonvif/Device" + "fmt" +) + +func RunApi () { + router := gin.Default() + + device := goonvif.NewDevice() + data, err := device.CallMethod("http://192.168.13.12/onvif/device_service", Device.GetCapabilities{Category:"All"}) + //_=data + if err != nil { + fmt.Println(err) + } + + router.GET("/:dima", func(c *gin.Context) { + //name := c.Param("name") + c.XML(http.StatusOK, data) + }) + router.Run() +} + +func callNecessaryMethod(serviceName, methodName string) { + switch serviceName { + case "Device", "device": + callDeviceMethonds(methodName) + } +} + +func callDeviceMethonds(methodName string) { + +} \ No newline at end of file diff --git a/networking/networking.go b/networking/networking.go index 8f1cc70..23facd7 100644 --- a/networking/networking.go +++ b/networking/networking.go @@ -4,7 +4,6 @@ import ( "net/http" "bytes" "io/ioutil" - "log" ) func SendSoap(endpoint, message string) string { @@ -14,7 +13,7 @@ func SendSoap(endpoint, message string) string { b, _ := ioutil.ReadAll(resp.Body) - log.Println(string(b)) + //log.Println(string(b)) return string(b) } From ebdecc4c7f85505ceae43eb718744498988b4c53 Mon Sep 17 00:00:00 2001 From: George Palanjyan Date: Fri, 6 Apr 2018 22:25:40 +0300 Subject: [PATCH 2/4] xml processing --- Device.go | 9 ++++-- PTZ/types.go | 6 ++-- api/api.go | 77 +++++++++++++++++++++++++++++++--------------- api/get_structs.go | 69 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 133 insertions(+), 28 deletions(-) create mode 100644 api/get_structs.go diff --git a/Device.go b/Device.go index 118bb27..7082cba 100644 --- a/Device.go +++ b/Device.go @@ -7,11 +7,12 @@ import ( "github.com/beevik/etree" "github.com/yakovlevdmv/gosoap" "strconv" - "github.com/yakovlevdmv/WS-Discovery" - "github.com/yakovlevdmv/goonvif/Networking" "reflect" "strings" "github.com/yakovlevdmv/goonvif/Device" + "github.com/yakovlevdmv/goonvif/networking" + "github.com/yakovlevdmv/WS-Discovery" + "errors" ) var xlmns = map[string]string { @@ -170,6 +171,10 @@ func (dev device) CallMethod(method interface{}) (string, error) { case "PTZ": endpoint = dev.endpoints["PTZ"] } + if len(endpoint) == 0 { + return "", errors.New("Requested service is not implemented") + } + //TODO: Get endpoint automatically if dev.login != "" && dev.password != "" { return dev.CallAuthorizedMethod(endpoint, method) diff --git a/PTZ/types.go b/PTZ/types.go index d281283..8fd3a33 100644 --- a/PTZ/types.go +++ b/PTZ/types.go @@ -1,7 +1,9 @@ package PTZ -import "github.com/yakovlevdmv/goonvif/xsd" -import "github.com/yakovlevdmv/goonvif/xsd/onvif" +import ( + "github.com/yakovlevdmv/goonvif/xsd" + "github.com/yakovlevdmv/goonvif/xsd/onvif" +) type Capabilities struct { EFlip xsd.Boolean `xml:"EFlip,attr"` diff --git a/api/api.go b/api/api.go index cac7a77..58aae06 100644 --- a/api/api.go +++ b/api/api.go @@ -1,37 +1,66 @@ package api import ( - "github.com/gin-gonic/gin" - "net/http" "github.com/yakovlevdmv/goonvif" "github.com/yakovlevdmv/goonvif/Device" "fmt" + "reflect" ) -func RunApi () { - router := gin.Default() +//func RunApi () { +// router := gin.Default() +// +// router.POST("/:service/:method", func(c *gin.Context) { +// serviceName := c.Param("service") +// methodName := c.Param("method") +// message := callNecessaryMethod(&serviceName, &methodName, "192.168.13.12") +// c.XML(http.StatusOK, message) +// }) +// router.Run() +//} - device := goonvif.NewDevice() - data, err := device.CallMethod("http://192.168.13.12/onvif/device_service", Device.GetCapabilities{Category:"All"}) - //_=data +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) + } +} + + +func callNecessaryMethod(serviceName* string, methodName* string, deviceXaddr* string) *string { + switch *serviceName { + case "Device", "device": + return callDeviceMethods(methodName, deviceXaddr) + } + return nil +} + +func callDeviceMethods(methodName* string, deviceXaddr* string) *string { + switch *methodName { + case "GetCapabilities": + return GetCapabilities(deviceXaddr) + default: + return nil + } +} + +func GetCapabilities(deviceXaddr* string) *string { + device := goonvif.NewDevice(*deviceXaddr) + data, err := device.CallMethod(Device.GetCapabilities{Category:"All"}) if err != nil { fmt.Println(err) } - - router.GET("/:dima", func(c *gin.Context) { - //name := c.Param("name") - c.XML(http.StatusOK, data) - }) - router.Run() -} - -func callNecessaryMethod(serviceName, methodName string) { - switch serviceName { - case "Device", "device": - callDeviceMethonds(methodName) - } -} - -func callDeviceMethonds(methodName string) { - + return &data } \ No newline at end of file diff --git a/api/get_structs.go b/api/get_structs.go new file mode 100644 index 0000000..ab930f1 --- /dev/null +++ b/api/get_structs.go @@ -0,0 +1,69 @@ +package api + +import ( + "github.com/yakovlevdmv/goonvif/PTZ" + "errors" +) + +func GetPTZStructByName(name string) (interface{}, error) { + switch name { + case "GetServiceCapabilities": + return &PTZ.GetServiceCapabilities{}, nil + case "GetNodes": + return &PTZ.GetNodes{}, nil + case "GetNode": + return &PTZ.GetNode{}, nil + case "GetConfiguration": + return &PTZ.GetConfiguration{}, nil + case "GetConfigurations": + return &PTZ.GetConfigurations{}, nil + case "SetConfiguration": + return &PTZ.SetConfiguration{}, nil + case "GetConfigurationOptions": + return &PTZ.GetConfigurationOptions{}, nil + case "SendAuxiliaryCommand": + return &PTZ.SendAuxiliaryCommand{}, nil + case "GetPresets": + return &PTZ.GetPresets{}, nil + case "SetPreset": + return &PTZ.SetPreset{}, nil + case "RemovePreset": + return &PTZ.RemovePreset{}, nil + case "GotoPreset": + return &PTZ.GotoPreset{}, nil + case "GotoHomePosition": + return &PTZ.GotoHomePosition{}, nil + case "SetHomePosition": + return &PTZ.SetHomePosition{}, nil + case "ContinuousMove": + return &PTZ.ContinuousMove{}, nil + case "RelativeMove": + return &PTZ.RelativeMove{}, nil + case "GetStatus": + return &PTZ.GetStatus{}, nil + case "AbsoluteMove": + return &PTZ.AbsoluteMove{}, nil + case "GeoMove": + return &PTZ.GeoMove{}, nil + case "Stop": + return &PTZ.Stop{}, nil + case "GetPresetTours": + return &PTZ.GetPresetTours{}, nil + case "GetPresetTour": + return &PTZ.GetPresetTour{}, nil + case "GetPresetTourOptions": + return &PTZ.GetPresetTourOptions{}, nil + case "CreatePresetTour": + return &PTZ.CreatePresetTour{}, nil + case "ModifyPresetTour": + return &PTZ.ModifyPresetTour{}, nil + case "OperatePresetTour": + return &PTZ.OperatePresetTour{}, nil + case "RemovePresetTour": + return &PTZ.RemovePresetTour{}, nil + case "GetCompatibleConfigurations": + return &PTZ.GetCompatibleConfigurations{}, nil + default: + return nil, errors.New("invalid structure") + } +} \ No newline at end of file From 9c02c509c7c2fe5b30689ae0ffe62f0212d95294 Mon Sep 17 00:00:00 2001 From: George Palanjyan Date: Tue, 10 Apr 2018 00:12:58 +0300 Subject: [PATCH 3/4] add api --- Device.go | 16 ++- api/api.go | 311 +++++++++++++++++++++++++++++++++++++++------ api/get_structs.go | 10 ++ 3 files changed, 289 insertions(+), 48 deletions(-) diff --git a/Device.go b/Device.go index 7082cba..9abe022 100644 --- a/Device.go +++ b/Device.go @@ -10,12 +10,12 @@ import ( "reflect" "strings" "github.com/yakovlevdmv/goonvif/Device" - "github.com/yakovlevdmv/goonvif/networking" "github.com/yakovlevdmv/WS-Discovery" "errors" + "github.com/yakovlevdmv/goonvif/networking" ) -var xlmns = map[string]string { +var Xlmns = map[string]string { "onvif":"http://www.onvif.org/ver10/schema", "tds":"http://www.onvif.org/ver10/device/wsdl", "trt":"http://www.onvif.org/ver10/media/wsdl", @@ -138,6 +138,10 @@ func (dev *device) Authenticate(username, password string) { dev.password = password } +func (dev *device) GetEndpoint(name string) string { + return dev.endpoints[name] +} + func buildMethodSOAP(msg string) (gosoap.SoapMessage, error) { doc := etree.NewDocument() if err := doc.ReadFromString(msg); err != nil { @@ -172,7 +176,7 @@ func (dev device) CallMethod(method interface{}) (string, error) { } if len(endpoint) == 0 { - return "", errors.New("Requested service is not implemented") + return "", errors.New("requested service is not implemented") } //TODO: Get endpoint automatically @@ -204,7 +208,7 @@ func (dev device) CallNonAuthorizedMethod(endpoint string, method interface{}) ( return "", err } - soap.AddRootNamespaces(xlmns) + soap.AddRootNamespaces(Xlmns) /* Sending request and returns the response @@ -243,7 +247,7 @@ func (dev device) CallAuthorizedMethod(endpoint string, method interface{}) (str 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") - soap.AddRootNamespaces(xlmns) + soap.AddRootNamespaces(Xlmns) soapReq, err := xml.MarshalIndent(auth, "", " ") if err != nil { @@ -260,4 +264,4 @@ func (dev device) CallAuthorizedMethod(endpoint string, method interface{}) (str Sending request and returns the response */ return networking.SendSoap(endpoint, soap.String()) -} +} \ No newline at end of file diff --git a/api/api.go b/api/api.go index 58aae06..99deb9f 100644 --- a/api/api.go +++ b/api/api.go @@ -1,66 +1,293 @@ package api import ( - "github.com/yakovlevdmv/goonvif" - "github.com/yakovlevdmv/goonvif/Device" "fmt" "reflect" + "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" ) -//func RunApi () { -// router := gin.Default() +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() + acpData := string(acceptedData) + _=err + //fmt.Println(string(acceptedData), err,serviceName, methodName) + message := callNecessaryMethod(serviceName, methodName, &acpData, "192.168.13.12") + 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) // -// router.POST("/:service/:method", func(c *gin.Context) { -// serviceName := c.Param("service") -// methodName := c.Param("method") -// message := callNecessaryMethod(&serviceName, &methodName, "192.168.13.12") -// c.XML(http.StatusOK, message) -// }) -// router.Run() +// subStruct := reflect.New(reflect.TypeOf( field.Interface() )) +// soapHandling(subStruct.Interface(), tags) +// } //} -func soapHandling(tp interface{}, tags* map[string]string) { - ifaceValue := reflect.ValueOf(tp).Elem() - typeOfStruct := ifaceValue.Type() - if ifaceValue.Kind() != reflect.Struct { + +func callNecessaryMethod(serviceName string, methodName string, acceptedData* string, deviceXaddr string) *string { + 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: нормально написать + } + resp, err := xmlAnalize(methodStruct, acceptedData) + if err != nil { + //todo: нормально написать + } + + soap := gosoap.NewEmptySOAP() + soap.AddStringBodyContent(*resp) + soap.AddRootNamespaces(goonvif.Xlmns) + log.Println(soap.String()) + servResp, srvErr := networking.SendSoap(getEndpoint(methodStruct, deviceXaddr), soap.String()) + if srvErr != nil { + //todo: нормально написать + } + return &servResp +} + +func getEndpoint(method interface{}, deviceXaddr string) string { + dev := goonvif.NewDevice(deviceXaddr) + + pkgPath := strings.Split(reflect.TypeOf(method).PkgPath(),"/") + pkg := pkgPath[len(pkgPath)-1] + + var endpoint string + switch pkg { + 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") + } + 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") + if attr == -1 { + return str[1], nil + } else { + 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 { return } - for i := 0; i < ifaceValue.NumField(); i++ { - field := ifaceValue.Field(i) - tg, err := typeOfStruct.FieldByName(typeOfStruct.Field(i).Name) + for i := 0; i < s.NumField(); i++ { + f := s.Field(i) + tmp, err := typeOfT.FieldByName(typeOfT.Field(i).Name) if err == false { fmt.Println(err) } - (*tags)[typeOfStruct.Field(i).Name] = string(tg.Tag) - - subStruct := reflect.New(reflect.TypeOf( field.Interface() )) + *tags = append(*tags, map[string]string{typeOfT.Field(i).Name : string(tmp.Tag)}) + subStruct := reflect.New(reflect.TypeOf( f.Interface() )) soapHandling(subStruct.Interface(), tags) } } - -func callNecessaryMethod(serviceName* string, methodName* string, deviceXaddr* string) *string { - switch *serviceName { - case "Device", "device": - return callDeviceMethods(methodName, deviceXaddr) - } - return nil -} - -func callDeviceMethods(methodName* string, deviceXaddr* string) *string { - switch *methodName { - case "GetCapabilities": - return GetCapabilities(deviceXaddr) - default: - return nil +//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) } } -func GetCapabilities(deviceXaddr* string) *string { - device := goonvif.NewDevice(*deviceXaddr) - data, err := device.CallMethod(Device.GetCapabilities{Category:"All"}) - if err != nil { - fmt.Println(err) + +//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") } - return &data +} + +func ident(mas* []string) { + var buffer string + for _, j := range *mas { + buffer += j + " " + } + buffer = strings.Replace(buffer, "Push Pop ", "PushPop ", -1) + buffer = strings.TrimSpace(buffer) + *mas = strings.Split(buffer, " ") } \ No newline at end of file diff --git a/api/get_structs.go b/api/get_structs.go index ab930f1..8463ad8 100644 --- a/api/get_structs.go +++ b/api/get_structs.go @@ -3,6 +3,7 @@ package api import ( "github.com/yakovlevdmv/goonvif/PTZ" "errors" + "github.com/yakovlevdmv/goonvif/Device" ) func GetPTZStructByName(name string) (interface{}, error) { @@ -66,4 +67,13 @@ func GetPTZStructByName(name string) (interface{}, error) { default: return nil, errors.New("invalid structure") } +} + +func GetDeviceStructByName(name string) (interface{}, error) { + switch name { + case "CreateUsers": + return &Device.CreateUsers{}, nil + default: + return nil, errors.New("invalid structure") + } } \ No newline at end of file From 86ca55954a68ca600b47bf33fa79cca6c405b47c Mon Sep 17 00:00:00 2001 From: George Palanjyan Date: Tue, 10 Apr 2018 02:08:46 +0300 Subject: [PATCH 4/4] fix bugs --- Device.go | 2 +- api/api.go | 75 +++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 55 insertions(+), 22 deletions(-) diff --git a/Device.go b/Device.go index 154fcbc..3c2e17b 100644 --- a/Device.go +++ b/Device.go @@ -309,7 +309,7 @@ func (dev device) callAuthorizedMethod(endpoint string, method interface{}) (*ht /* Getting an WS-Security struct representation */ - auth := newSecurity(dev.login, dev.password) + auth := NewSecurity(dev.login, dev.password) /* Adding WS-Security namespaces to root element of SOAP message diff --git a/api/api.go b/api/api.go index 99deb9f..2616a2f 100644 --- a/api/api.go +++ b/api/api.go @@ -13,6 +13,8 @@ import ( "github.com/yakovlevdmv/goonvif/networking" "log" "net/http" + "io/ioutil" + "encoding/xml" ) func RunApi () { @@ -22,10 +24,10 @@ func RunApi () { serviceName := c.Param("service") methodName := c.Param("method") acceptedData, err := c.GetRawData() - acpData := string(acceptedData) - _=err - //fmt.Println(string(acceptedData), err,serviceName, methodName) - message := callNecessaryMethod(serviceName, methodName, &acpData, "192.168.13.12") + if err != nil { + fmt.Println(err) + } + message := callNecessaryMethod(serviceName, methodName, string(acceptedData), "192.168.13.12") c.XML(http.StatusOK, message) }) router.Run() @@ -51,7 +53,7 @@ func RunApi () { //} -func callNecessaryMethod(serviceName string, methodName string, acceptedData* string, deviceXaddr string) *string { +func callNecessaryMethod(serviceName string, methodName string, acceptedData string, deviceXaddr string) string { var methodStruct interface{} var err error switch serviceName { @@ -63,7 +65,7 @@ func callNecessaryMethod(serviceName string, methodName string, acceptedData* st if err != nil { //todo: нормально написать } - resp, err := xmlAnalize(methodStruct, acceptedData) + resp, err := xmlAnalize(methodStruct, &acceptedData) if err != nil { //todo: нормально написать } @@ -71,27 +73,55 @@ func callNecessaryMethod(serviceName string, methodName string, acceptedData* st soap := gosoap.NewEmptySOAP() soap.AddStringBodyContent(*resp) soap.AddRootNamespaces(goonvif.Xlmns) - log.Println(soap.String()) - servResp, srvErr := networking.SendSoap(getEndpoint(methodStruct, deviceXaddr), soap.String()) + + /* + 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()) if srvErr != nil { + panic(srvErr) //todo: нормально написать } - return &servResp + + rsp, err := ioutil.ReadAll(servResp.Body) + if err != nil { + log.Println(err) + return "" + } + return string(rsp) } -func getEndpoint(method interface{}, deviceXaddr string) string { - dev := goonvif.NewDevice(deviceXaddr) - - pkgPath := strings.Split(reflect.TypeOf(method).PkgPath(),"/") - pkg := pkgPath[len(pkgPath)-1] +func getEndpoint(service, xaddr string) string { + dev, err := goonvif.NewDevice(xaddr) + if err != nil { + log.Println(err) + return "" + } + pkg := strings.ToLower(service) var endpoint string switch pkg { - 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") + 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") } return endpoint } @@ -221,9 +251,12 @@ func xmlProcessing (tg string) (string, error) { return "", errors.New("out of range") } attr := strings.Index(str[1], ",attr") - if attr == -1 { + omit := strings.Index(str[1], ",omitempty") + if attr == -1 && omit == -1 { //todo: проработать вариант, когдв omitempty и attr вместе return str[1], nil - } else { + } else if omit > -1 { + return str[1][0:omit], nil + }else { return str[0:attr][0], nil } return "", errors.New("something went wrong")