This commit is contained in:
程广 2024-10-30 18:51:51 +08:00
commit 80b1e1f940
13 changed files with 10163 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
vendor/

402
common.xsd Normal file
View File

@ -0,0 +1,402 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--W3C XML Schema generated by XMLSpy v2017 (x64) (http://www.altova.com)-->
<!--
Copyright (c) 2008-2023 by ONVIF: Open Network Video Interface Forum. All rights reserved.
Recipients of this document may copy, distribute, publish, or display this document so long as this copyright notice, license and disclaimer are retained with all copies of the document. No license is granted to modify this document.
THIS DOCUMENT IS PROVIDED "AS IS," AND THE CORPORATION AND ITS MEMBERS AND THEIR AFFILIATES, MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, OR TITLE; THAT THE CONTENTS OF THIS DOCUMENT ARE SUITABLE FOR ANY PURPOSE; OR THAT THE IMPLEMENTATION OF SUCH CONTENTS WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
IN NO EVENT WILL THE CORPORATION OR ITS MEMBERS OR THEIR AFFILIATES BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL, PUNITIVE OR CONSEQUENTIAL DAMAGES, ARISING OUT OF OR RELATING TO ANY USE OR DISTRIBUTION OF THIS DOCUMENT, WHETHER OR NOT (1) THE CORPORATION, MEMBERS OR THEIR AFFILIATES HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, OR (2) SUCH DAMAGES WERE REASONABLY FORESEEABLE, AND ARISING OUT OF OR RELATING TO ANY USE OR DISTRIBUTION OF THIS DOCUMENT. THE FOREGOING DISCLAIMER AND LIMITATION ON LIABILITY DO NOT APPLY TO, INVALIDATE, OR LIMIT REPRESENTATIONS AND WARRANTIES MADE BY THE MEMBERS AND THEIR RESPECTIVE AFFILIATES TO THE CORPORATION AND OTHER MEMBERS IN CERTAIN WRITTEN POLICIES OF THE CORPORATION.
-->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tt="http://www.onvif.org/ver10/schema" xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2" targetNamespace="http://www.onvif.org/ver10/schema" elementFormDefault="qualified" version="23.06">
<!--===============================-->
<!-- Generic Types -->
<!--===============================-->
<xs:simpleType name="ReferenceToken">
<xs:annotation>
<xs:documentation>Unique identifier for a physical or logical resource.
Tokens should be assigned such that they are unique within a device. Tokens must be at least unique within its class.
Length up to 64 characters. Token may be extended by intermediate terminal with adding prefix to make it global unique.
The length should be within 36 characters for generating at local device. See "Remote Token" section in Resource Query specification.</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:maxLength value="64"/>
</xs:restriction>
</xs:simpleType>
<!--===============================-->
<xs:complexType name="IntRange">
<xs:annotation>
<xs:documentation>Range of values greater equal Min value and less equal Max value.</xs:documentation>
</xs:annotation>
<xs:sequence>
<xs:element name="Min" type="xs:int"/>
<xs:element name="Max" type="xs:int"/>
</xs:sequence>
</xs:complexType>
<!--===============================-->
<!-- Start PTZ Related Types -->
<!--===============================-->
<xs:complexType name="Vector2D">
<xs:attribute name="x" type="xs:float" use="required"/>
<xs:attribute name="y" type="xs:float" use="required"/>
<xs:attribute name="space" type="xs:anyURI" use="optional">
<xs:annotation>
<xs:documentation>
Pan/tilt coordinate space selector. The following options are defined:<ul>
<li> http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace</li>
<li> http://www.onvif.org/ver10/tptz/PanTiltSpaces/TranslationGenericSpace</li>
<li> http://www.onvif.org/ver10/tptz/PanTiltSpaces/VelocityGenericSpace</li>
<li> http://www.onvif.org/ver10/tptz/PanTiltSpaces/GenericSpeedSpace</li>
</ul>
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
<xs:complexType name="Vector1D">
<xs:attribute name="x" type="xs:float" use="required"/>
<xs:attribute name="space" type="xs:anyURI" use="optional">
<xs:annotation>
<xs:documentation>
Zoom coordinate space selector. The following options are defined:<ul style="">
<li> http://www.onvif.org/ver10/tptz/ZoomSpaces/PositionGenericSpace</li>
<li> http://www.onvif.org/ver10/tptz/ZoomSpaces/TranslationGenericSpace</li>
<li> http://www.onvif.org/ver10/tptz/ZoomSpaces/VelocityGenericSpace</li>
<li> http://www.onvif.org/ver10/tptz/ZoomSpaces/ZoomGenericSpeedSpace</li>
</ul>
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
<xs:complexType name="PTZVector">
<xs:sequence>
<xs:element name="PanTilt" type="tt:Vector2D" minOccurs="0">
<xs:annotation>
<xs:documentation>Pan and tilt position. The x component corresponds to pan and the y component to tilt.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="Zoom" type="tt:Vector1D" minOccurs="0">
<xs:annotation>
<xs:documentation>
A zoom position.
</xs:documentation>
</xs:annotation>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:complexType name="PTZStatus">
<xs:sequence>
<xs:element name="Position" type="tt:PTZVector" minOccurs="0">
<xs:annotation>
<xs:documentation>
Specifies the absolute position of the PTZ unit together with the Space references. The default absolute spaces of the corresponding PTZ configuration MUST be referenced within the Position element.
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="MoveStatus" type="tt:PTZMoveStatus" minOccurs="0">
<xs:annotation>
<xs:documentation>
Indicates if the Pan/Tilt/Zoom device unit is currently moving, idle or in an unknown state.
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="Error" type="xs:string" minOccurs="0">
<xs:annotation>
<xs:documentation>
States a current PTZ error.
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="UtcTime" type="xs:dateTime">
<xs:annotation>
<xs:documentation>
Specifies the UTC time when this status was generated.
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/> <!-- first Vendor then ONVIF -->
</xs:sequence>
<xs:anyAttribute processContents="lax"/>
</xs:complexType>
<xs:complexType name="PTZMoveStatus">
<xs:sequence>
<xs:element name="PanTilt" type="tt:MoveStatus" minOccurs="0">
<xs:annotation>
<xs:documentation>
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="Zoom" type="tt:MoveStatus" minOccurs="0">
<xs:annotation>
<xs:documentation>
</xs:documentation>
</xs:annotation>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:simpleType name="MoveStatus">
<xs:restriction base="xs:string">
<xs:enumeration value="IDLE"/>
<xs:enumeration value="MOVING"/>
<xs:enumeration value="UNKNOWN"/>
</xs:restriction>
</xs:simpleType>
<!--===============================-->
<!-- Event and Analytics Types -->
<!--===============================-->
<xs:complexType name="Vector">
<xs:attribute name="x" type="xs:float"/>
<xs:attribute name="y" type="xs:float"/>
</xs:complexType>
<xs:complexType name="Rectangle">
<xs:attribute name="bottom" type="xs:float"/>
<xs:attribute name="top" type="xs:float"/>
<xs:attribute name="right" type="xs:float"/>
<xs:attribute name="left" type="xs:float"/>
</xs:complexType>
<xs:complexType name="Polygon">
<xs:sequence>
<xs:element name="Point" type="tt:Vector" minOccurs="3" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:element name="Polygon" type="tt:Polygon"/>
<xs:complexType name="Color">
<xs:attribute name="X" type="xs:float" use="required"/>
<xs:attribute name="Y" type="xs:float" use="required"/>
<xs:attribute name="Z" type="xs:float" use="required"/>
<xs:attribute name="Colorspace" type="xs:anyURI">
<xs:annotation>
<xs:documentation>
Acceptable values:
<ul>
<li>http://www.onvif.org/ver10/colorspace/YCbCr - YCbCr
<ul><li>X attribute = Y value</li>
<li>Y attribute = Cb value</li>
<li>Z attribute = Cr value</li></ul>
</li>
<li>http://www.onvif.org/ver10/colorspace/RGB - RGB
<ul><li>X attribute = R value</li>
<li>Y attribute = G value</li>
<li>Z attribute = B value</li></ul>
</li>
</ul>
If the Colorspace attribute is absent and not defined on higher level, YCbCr is implied.
Deprecated values:
<ul>
<li>http://www.onvif.org/ver10/colorspace/CIELUV - CIE LUV</li>
<li>http://www.onvif.org/ver10/colorspace/CIELAB - CIE 1976 (L*a*b*)</li>
<li>http://www.onvif.org/ver10/colorspace/HSV - HSV</li>
</ul>
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="Likelihood" type="xs:float">
<xs:annotation>
<xs:documentation>Likelihood that the color is correct.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:anyAttribute processContents="lax"/>
</xs:complexType>
<xs:complexType name="ColorCovariance">
<xs:attribute name="XX" type="xs:float" use="required"/>
<xs:attribute name="YY" type="xs:float" use="required"/>
<xs:attribute name="ZZ" type="xs:float" use="required"/>
<xs:attribute name="XY" type="xs:float"/>
<xs:attribute name="XZ" type="xs:float"/>
<xs:attribute name="YZ" type="xs:float"/>
<xs:attribute name="Colorspace" type="xs:anyURI">
<xs:annotation>
<xs:documentation>
Acceptable values are the same as in tt:Color.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:anyAttribute processContents="lax"/>
</xs:complexType>
<xs:complexType name="ColorDescriptor">
<xs:sequence>
<xs:element name="ColorCluster" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="Color" type="tt:Color"/>
<xs:element name="Weight" type="xs:float" minOccurs="0"/>
<xs:element name="Covariance" type="tt:ColorCovariance" minOccurs="0"/>
<xs:any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/> <!-- reserved for ONVIF -->
</xs:sequence>
<xs:anyAttribute processContents="lax"/>
</xs:complexType>
</xs:element>
<xs:element name="Extension" type="xs:anyType" minOccurs="0"/>
<xs:any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/> <!-- reserved for ONVIF -->
</xs:sequence>
<xs:anyAttribute processContents="lax"/>
</xs:complexType>
<!--===============================-->
<!-- Scene Description Types -->
<!--===============================-->
<xs:complexType name="Transformation">
<xs:sequence>
<xs:element name="Translate" type="tt:Vector" minOccurs="0"/>
<xs:element name="Scale" type="tt:Vector" minOccurs="0"/>
<xs:element name="Extension" type="tt:TransformationExtension" minOccurs="0"/>
</xs:sequence>
<xs:anyAttribute processContents="lax"/>
</xs:complexType>
<xs:complexType name="TransformationExtension">
<xs:sequence>
<xs:any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/> <!-- first Vendor then ONVIF -->
</xs:sequence>
</xs:complexType>
<!--===============================-->
<!-- Location/Orientation Types -->
<!--===============================-->
<xs:complexType name="GeoLocation">
<xs:sequence>
<xs:any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/> <!-- first ONVIF then Vendor -->
</xs:sequence>
<xs:attribute name="lon" type="xs:double">
<xs:annotation>
<xs:documentation>East west location as angle.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="lat" type="xs:double">
<xs:annotation>
<xs:documentation>North south location as angle.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="elevation" type="xs:float">
<xs:annotation>
<xs:documentation>Hight in meters above sea level.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:anyAttribute/>
</xs:complexType>
<!--===============================-->
<xs:complexType name="GeoOrientation">
<xs:sequence>
<xs:any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/> <!-- first ONVIF then Vendor -->
</xs:sequence>
<xs:attribute name="roll" type="xs:float">
<xs:annotation>
<xs:documentation>Rotation around the x axis.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="pitch" type="xs:float">
<xs:annotation>
<xs:documentation>Rotation around the y axis.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="yaw" type="xs:float">
<xs:annotation>
<xs:documentation>Rotation around the z axis.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:anyAttribute/>
</xs:complexType>
<!--===============================-->
<xs:complexType name="LocalLocation">
<xs:sequence>
<xs:any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/> <!-- first ONVIF then Vendor -->
</xs:sequence>
<xs:attribute name="x" type="xs:float">
<xs:annotation>
<xs:documentation>East west location as angle.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="y" type="xs:float">
<xs:annotation>
<xs:documentation>North south location as angle.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="z" type="xs:float">
<xs:annotation>
<xs:documentation>Offset in meters from the sea level.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:anyAttribute/>
</xs:complexType>
<!--===============================-->
<xs:complexType name="LocalOrientation">
<xs:sequence>
<xs:any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/> <!-- first ONVIF then Vendor -->
</xs:sequence>
<xs:attribute name="pan" type="xs:float">
<xs:annotation>
<xs:documentation>Rotation around the y axis.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="tilt" type="xs:float">
<xs:annotation>
<xs:documentation>Rotation around the z axis.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="roll" type="xs:float">
<xs:annotation>
<xs:documentation>Rotation around the x axis.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:anyAttribute/>
</xs:complexType>
<!--===============================-->
<xs:complexType name="SphericalCoordinate">
<xs:sequence>
<xs:any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/> <!-- first ONVIF then Vendor -->
</xs:sequence>
<xs:attribute name="Distance" type="xs:float">
<xs:annotation>
<xs:documentation>Distance in meters to the object.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="ElevationAngle" type="xs:float">
<xs:annotation>
<xs:documentation>Elevation angle in the range -90 to 90 degrees, where 0 is in level with the x-y plane.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="AzimuthAngle" type="xs:float">
<xs:annotation>
<xs:documentation>Azimuth angle in the range -180 to 180 degrees counter clockwise, where 0 is rightwards.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
<!--===============================-->
<xs:simpleType name="Entity">
<xs:restriction base="xs:string">
<xs:enumeration value="Device"/>
<xs:enumeration value="VideoSource"/>
<xs:enumeration value="AudioSource"/>
</xs:restriction>
</xs:simpleType>
<!--===============================-->
<xs:complexType name="LocationEntity">
<xs:sequence>
<xs:element name="GeoLocation" type="tt:GeoLocation" minOccurs="0">
<xs:annotation><xs:documentation>Location on earth.</xs:documentation></xs:annotation>
</xs:element>
<xs:element name="GeoOrientation" type="tt:GeoOrientation" minOccurs="0">
<xs:annotation><xs:documentation>Orientation relative to earth.</xs:documentation></xs:annotation>
</xs:element>
<xs:element name="LocalLocation" type="tt:LocalLocation" minOccurs="0">
<xs:annotation><xs:documentation>Indoor location offset.</xs:documentation></xs:annotation>
</xs:element>
<xs:element name="LocalOrientation" type="tt:LocalOrientation" minOccurs="0">
<xs:annotation><xs:documentation>Indoor orientation offset.</xs:documentation></xs:annotation>
</xs:element>
</xs:sequence>
<xs:attribute name="Entity" type="xs:string">
<xs:annotation><xs:documentation>Entity type the entry refers to, use a value from the tt:Entity enumeration.</xs:documentation></xs:annotation>
</xs:attribute>
<xs:attribute name="Token" type="tt:ReferenceToken">
<xs:annotation><xs:documentation>Optional entity token.</xs:documentation></xs:annotation>
</xs:attribute>
<xs:attribute name="Fixed" type="xs:boolean">
<xs:annotation><xs:documentation>If this value is true the entity cannot be deleted.</xs:documentation></xs:annotation>
</xs:attribute>
<xs:attribute name="GeoSource" type="xs:anyURI">
<xs:annotation><xs:documentation>Optional reference to the XAddr of another devices DeviceManagement service.</xs:documentation></xs:annotation>
</xs:attribute>
<xs:attribute name="AutoGeo" type="xs:boolean">
<xs:annotation><xs:documentation>If set the geo location is obtained internally.</xs:documentation></xs:annotation>
</xs:attribute>
</xs:complexType>
<!--===============================-->
</xs:schema>

153
device.go Normal file
View File

@ -0,0 +1,153 @@
package goonvif
import (
"context"
"errors"
"net"
"net/http"
"strings"
search_sdk "git.pyer.club/kingecg/goonvif/sdk/search"
"git.pyer.club/kingecg/goonvif/search"
"github.com/beevik/etree"
"github.com/use-go/onvif"
device "github.com/use-go/onvif/device"
sdk "github.com/use-go/onvif/sdk/device"
wsdiscovery "github.com/use-go/onvif/ws-discovery"
)
type Device struct {
onvif.DeviceParams
device *onvif.Device
ctx context.Context
}
var ErrAuthRequired = errors.New("auth required")
func NewDevice(params onvif.DeviceParams) *Device {
return &Device{DeviceParams: params, ctx: context.Background()}
}
func (d *Device) check() error {
if d.device != nil {
return nil
}
if d.Username == "" || d.Password == "" {
return ErrAuthRequired
}
if d.HttpClient == nil {
d.HttpClient = new(http.Client)
}
device, err := onvif.NewDevice(d.DeviceParams)
if err != nil {
return err
}
d.device = device
return nil
}
func (d *Device) GetCapabilities() (interface{}, error) {
err := d.check()
if err != nil {
return nil, err
}
cap := device.GetCapabilities{Category: "All"}
getCapabilitiesResponse, err := sdk.Call_GetCapabilities(d.ctx, d.device, cap)
if err != nil {
return nil, err
}
r := getCapabilitiesResponse.Capabilities
return r, err
}
func (d *Device) GetRecordingSummary() (search.RecordingSummary, error) {
err := d.check()
if err != nil {
return search.RecordingSummary{}, err
}
resp, rerr := search_sdk.Call_GetRecordingSummary(d.ctx, d.device, search.GetRecordingSummary{})
if rerr != nil {
return search.RecordingSummary{}, rerr
}
return resp.Summary, nil
}
func (d *Device) GetEndpoints() (map[string]string, error) {
err := d.check()
if err != nil {
return nil, err
}
return d.device.GetServices(), nil
}
func GetAvailableDevicesAtSpecificEthernetInterface(interfaceName string) ([]Device, error) {
// Call a ws-discovery Probe Message to Discover NVT type Devices
devices, err := wsdiscovery.SendProbe(interfaceName, nil, []string{"dn:" + onvif.NVT.String()}, map[string]string{"dn": "http://www.onvif.org/ver10/network/wsdl"})
if err != nil {
return nil, err
}
nvtDevicesSeen := make(map[string]bool)
nvtDevices := make([]Device, 0)
for _, j := range devices {
doc := etree.NewDocument()
if err := doc.ReadFromString(j); err != nil {
return nil, err
}
for _, xaddr := range doc.Root().FindElements("./Body/ProbeMatches/ProbeMatch/XAddrs") {
xaddr := strings.Split(strings.Split(xaddr.Text(), " ")[0], "/")[2]
if !nvtDevicesSeen[xaddr] {
dev := NewDevice(onvif.DeviceParams{Xaddr: strings.Split(xaddr, " ")[0]})
nvtDevicesSeen[xaddr] = true
nvtDevices = append(nvtDevices, *dev)
}
}
}
return nvtDevices, nil
}
func Discovery() ([]Device, error) {
ifaces, err := listLocalNetworkInterfaces()
if err != nil {
return nil, err
}
devices := make([]Device, 0)
for _, iface := range ifaces {
idevices, err := GetAvailableDevicesAtSpecificEthernetInterface(iface)
if err != nil {
continue
}
devices = append(devices, idevices...)
}
return devices, nil
}
func listLocalNetworkInterfaces() ([]string, error) {
interfaces, err := net.Interfaces()
if err != nil {
return nil, err
}
var ifaceNames []string
for _, iface := range interfaces {
// 判断是否为局域网
if (iface.Flags&net.FlagUp) == 0 || (iface.Flags&net.FlagRunning) == 0 || (iface.Flags&net.FlagLoopback) != 0 {
continue
}
ifaceNames = append(ifaceNames, iface.Name)
}
return ifaceNames, nil
}
func Init() {
onvif.Xlmns["tse"] = "https://www.onvif.org/ver10/search.wsdl"
}

76
device_test.go Normal file
View File

@ -0,0 +1,76 @@
package goonvif
import (
"testing"
"github.com/use-go/onvif"
)
func TestListInterfaces(t *testing.T) {
ifaces, err := listLocalNetworkInterfaces()
if err != nil {
t.Fatal(err)
}
t.Log(ifaces)
}
func TestDiscovery(t *testing.T) {
devices, err := Discovery()
if err != nil {
t.Fatal(err)
}
for _, device := range devices {
t.Log(device)
}
}
func TestGetCapabilities(t *testing.T) {
// 创建一个模拟的 Device 对象
d := &Device{
DeviceParams: onvif.DeviceParams{
Xaddr: "192.168.12.52",
Username: "dctdev",
Password: "dacenT2017",
},
}
// 测试正常情况
response, err := d.GetCapabilities()
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
t.Log(response)
// 模拟 check 函数返回错误
}
func TestGetEndpoints(t *testing.T) {
// 创建一个模拟的 Device 对象
d := &Device{
DeviceParams: onvif.DeviceParams{
Xaddr: "192.168.12.52",
Username: "dctdev",
Password: "dacenT2017",
},
}
response, err := d.GetEndpoints()
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
t.Log(response)
}
func TestGetRecordingSummary(t *testing.T) {
// 创建一个模拟的 Device 对象
d := &Device{
DeviceParams: onvif.DeviceParams{
Xaddr: "192.168.12.52",
Username: "dctdev",
Password: "dacenT2017",
},
}
response, err := d.GetRecordingSummary()
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
t.Log(response)
}

14
go.mod Normal file
View File

@ -0,0 +1,14 @@
module git.pyer.club/kingecg/goonvif
go 1.23.1
require (
github.com/beevik/etree v1.1.0 // indirect
github.com/elgs/gostrgen v0.0.0-20161222160715-9d61ae07eeae // indirect
github.com/gofrs/uuid v3.2.0+incompatible // indirect
github.com/juju/errors v0.0.0-20220331221717-b38fca44723b // indirect
github.com/rs/zerolog v1.26.1 // indirect
github.com/use-go/onvif v0.0.9 // indirect
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d // indirect
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e // indirect
)

77
go.sum Normal file
View File

@ -0,0 +1,77 @@
github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs=
github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/elgs/gostrgen v0.0.0-20161222160715-9d61ae07eeae h1:3KvK2DmA7TxQ6PZ2f0rWbdqjgJhRcqgbY70bBeE4clI=
github.com/elgs/gostrgen v0.0.0-20161222160715-9d61ae07eeae/go.mod h1:wruC5r2gHdr/JIUs5Rr1V45YtsAzKXZxAnn/5rPC97g=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.7.0/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/juju/errors v0.0.0-20220331221717-b38fca44723b h1:AxFeSQJfcm2O3ov1wqAkTKYFsnMw2g1B4PkYujfAdkY=
github.com/juju/errors v0.0.0-20220331221717-b38fca44723b/go.mod h1:jMGj9DWF/qbo91ODcfJq6z/RYc3FX3taCBZMCcpI4Ls=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.26.1 h1:/ihwxqH+4z8UxyI70wM1z9yCvkWcfz/a3mj48k/Zngc=
github.com/rs/zerolog v1.26.1/go.mod h1:/wSSJWX7lVrsOwlbyTRSOJvqRlc+WjWlfes+CiJ+tmc=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/use-go/onvif v0.0.9 h1:t6y5uN1LGrdSpNDiy4Vn9HazYgVxdWUBfdBb5cApR7g=
github.com/use-go/onvif v0.0.9/go.mod h1:l6K5BgFel7AARm7a9oVj5uvTdwvgttudcP8pUxUf5go=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

9127
onvif.xsd Normal file

File diff suppressed because it is too large Load Diff

38
request.xml Normal file
View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<soap-env:Envelope xmlns:soap-env="http://www.w3.org/2003/05/soap-envelope"
xmlns:soap-enc="http://www.w3.org/2003/05/soap-encoding"
xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2"
xmlns:trt="http://www.onvif.org/ver10/media/wsdl"
xmlns:tptz="http://www.onvif.org/ver20/ptz/wsdl" xmlns:xmime="http://www.w3.org/2005/05/xmlmime"
xmlns:wsa="http://www.w3.org/2005/08/addressing"
xmlns:tds="http://www.onvif.org/ver10/device/wsdl"
xmlns:wsntw="http://docs.oasis-open.org/wsn/bw-2"
xmlns:wsrf-rw="http://docs.oasis-open.org/wsrf/rw-2"
xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl"
xmlns:tev="http://www.onvif.org/ver10/events/wsdl"
xmlns:timg="http://www.onvif.org/ver20/imaging/wsdl"
xmlns:tan="http://www.onvif.org/ver20/analytics/wsdl"
xmlns:xop="http://www.w3.org/2004/08/xop/include"
xmlns:wstop="http://docs.oasis-open.org/wsn/t-1" xmlns:onvif="http://www.onvif.org/ver10/schema">
<soap-env:Header>
<Security
xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<UsernameToken>
<Username>dctdev</Username>
<Password
Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">
toXf3eaQVUyRYdQVzq91BbfnjTE=</Password>
<Nonce
EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">
mi9zbm1fihxxb8ypsaq4styjtdtlcwem</Nonce>
<Created
xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
2024-10-30T09:32:28.847926976Z</Created>
</UsernameToken>
</Security>
</soap-env:Header>
<soap-env:Body>
<tds:GetRecordingSummary />
</soap-env:Body>
</soap-env:Envelope>

46
response.xml Normal file
View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope"
xmlns:soapenc="http://www.w3.org/2003/05/soap-encoding"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tt="http://www.onvif.org/ver10/schema"
xmlns:tds="http://www.onvif.org/ver10/device/wsdl"
xmlns:trt="http://www.onvif.org/ver10/media/wsdl"
xmlns:timg="http://www.onvif.org/ver20/imaging/wsdl"
xmlns:tev="http://www.onvif.org/ver10/events/wsdl"
xmlns:tptz="http://www.onvif.org/ver20/ptz/wsdl"
xmlns:tan="http://www.onvif.org/ver20/analytics/wsdl"
xmlns:tst="http://www.onvif.org/ver10/storage/wsdl" xmlns:ter="http://www.onvif.org/ver10/error"
xmlns:dn="http://www.onvif.org/ver10/network/wsdl"
xmlns:tns1="http://www.onvif.org/ver10/topics"
xmlns:tmd="http://www.onvif.org/ver10/deviceIO/wsdl"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl"
xmlns:wsoap12="http://schemas.xmlsoap.org/wsdl/soap12"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http"
xmlns:d="http://schemas.xmlsoap.org/ws/2005/04/discovery"
xmlns:wsadis="http://schemas.xmlsoap.org/ws/2004/08/addressing"
xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2" xmlns:wsa="http://www.w3.org/2005/08/addressing"
xmlns:wstop="http://docs.oasis-open.org/wsn/t-1"
xmlns:wsrf-bf="http://docs.oasis-open.org/wsrf/bf-2"
xmlns:wsntw="http://docs.oasis-open.org/wsn/bw-2"
xmlns:wsrf-rw="http://docs.oasis-open.org/wsrf/rw-2"
xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl"
xmlns:wsrf-r="http://docs.oasis-open.org/wsrf/r-2"
xmlns:trc="http://www.onvif.org/ver10/recording/wsdl"
xmlns:tse="http://www.onvif.org/ver10/search/wsdl"
xmlns:trp="http://www.onvif.org/ver10/replay/wsdl"
xmlns:tnshik="http://www.hikvision.com/2011/event/topics"
xmlns:hikwsd="http://www.onvifext.com/onvif/ext/ver10/wsdl"
xmlns:hikxsd="http://www.onvifext.com/onvif/ext/ver10/schema"
xmlns:tas="http://www.onvif.org/ver10/advancedsecurity/wsdl"
xmlns:tr2="http://www.onvif.org/ver20/media/wsdl"
xmlns:axt="http://www.onvif.org/ver20/analytics">
<env:Body>
<tse:GetRecordingSummaryResponse>
<tse:Summary>
<tt:DataFrom>2024-10-16T01:03:32Z</tt:DataFrom>
<tt:DataUntil>2024-10-30T09:41:47Z</tt:DataUntil>
<tt:NumberRecordings>1</tt:NumberRecordings>
</tse:Summary>
</tse:GetRecordingSummaryResponse>
</env:Body>
</env:Envelope>

78
sdk/codegen/main.go Normal file
View File

@ -0,0 +1,78 @@
// Copyright (c) 2022 Jean-Francois SMIGIELSKI
// Distributed under the MIT License
package main
import (
"flag"
"log"
"os"
"text/template"
)
var mainTemplate = `// Code generated : DO NOT EDIT.
// Copyright (c) 2022 Jean-Francois SMIGIELSKI
// Distributed under the MIT License
package {{.Package}}
import (
"context"
"github.com/juju/errors"
"github.com/use-go/onvif"
"github.com/use-go/onvif/sdk"
"git.pyer.club/kingecg/goonvif/{{.StructPackage}}"
)
// Call_{{.TypeRequest}} forwards the call to dev.CallMethod() then parses the payload of the reply as a {{.TypeReply}}.
func Call_{{.TypeRequest}}(ctx context.Context, dev *onvif.Device, request {{.StructPackage}}.{{.TypeRequest}}) ({{.StructPackage}}.{{.TypeReply}}, error) {
type Envelope struct {
Header struct{}
Body struct {
{{.TypeReply}} {{.StructPackage}}.{{.TypeReply}}
}
}
var reply Envelope
if httpReply, err := dev.CallMethod(request); err != nil {
return reply.Body.{{.TypeReply}}, errors.Annotate(err, "call")
} else {
err = sdk.ReadAndParse(ctx, httpReply, &reply, "{{.TypeRequest}}")
return reply.Body.{{.TypeReply}}, errors.Annotate(err, "reply")
}
}
`
type parserEnv struct {
Package string
StructPackage string
TypeReply string
TypeRequest string
}
func main() {
flag.Parse()
env := parserEnv{
Package: flag.Arg(0),
StructPackage: flag.Arg(1),
TypeRequest: flag.Arg(2),
TypeReply: flag.Arg(2) + "Response",
}
log.Println(env)
body, err := template.New("body").Parse(mainTemplate)
if err != nil {
log.Fatalln(err)
}
fout, err := os.Create(env.TypeRequest + "_auto.go")
if err != nil {
log.Fatalln(err)
}
defer fout.Close()
err = body.Execute(fout, &env)
if err != nil {
log.Fatalln(err)
}
}

View File

@ -0,0 +1,30 @@
// Code generated : DO NOT EDIT.
// Copyright (c) 2022 Jean-Francois SMIGIELSKI
// Distributed under the MIT License
package search
import (
"context"
"github.com/juju/errors"
"github.com/use-go/onvif"
"github.com/use-go/onvif/sdk"
"git.pyer.club/kingecg/goonvif/search"
)
// Call_GetRecordingSummary forwards the call to dev.CallMethod() then parses the payload of the reply as a GetRecordingSummaryResponse.
func Call_GetRecordingSummary(ctx context.Context, dev *onvif.Device, request search.GetRecordingSummary) (search.GetRecordingSummaryResponse, error) {
type Envelope struct {
Header struct{}
Body struct {
GetRecordingSummaryResponse search.GetRecordingSummaryResponse
}
}
var reply Envelope
if httpReply, err := dev.CallMethod(request); err != nil {
return reply.Body.GetRecordingSummaryResponse, errors.Annotate(err, "call")
} else {
err = sdk.ReadAndParse(ctx, httpReply, &reply, "GetRecordingSummary")
return reply.Body.GetRecordingSummaryResponse, errors.Annotate(err, "reply")
}
}

38
search/search.go Normal file
View File

@ -0,0 +1,38 @@
package search
import (
xsd "github.com/use-go/onvif/xsd"
onvifmodel "github.com/use-go/onvif/xsd/onvif"
)
type SourceReference onvifmodel.ReferenceToken
type RecordingReference onvifmodel.ReferenceToken
type SearchScope struct {
IncludedSources []SourceReference `xml:"onvif:IncludedSources"`
IncludedRecordings []RecordingReference `xml:"onvif:IncludedRecordings"`
RecordingInformationFilter xsd.String `xml:"onvif:RecordingInformationFilter"`
Extension SearchScopeExtension `xml:"onvif:Extension"`
}
type SearchScopeExtension []xsd.AnyType
type FindingRecordings struct {
XMLName string `xml:"tse:FindingRecordings"`
Scope SearchScope `xml:"tse:Scope"`
MaxMatches xsd.Int `xml:"tse:MaxMatches"`
KeepAliveTimeout xsd.Duration `xml:"tse:KeepAliveTimeout"`
}
type GetRecordingSummary struct {
XMLName string `xml:"tse:GetRecordingSummary"`
}
type RecordingSummary struct {
DataFrom xsd.DateTime
DataUntil xsd.DateTime
NumberRecordings xsd.Int
}
type GetRecordingSummaryResponse struct {
Summary RecordingSummary
}

83
search/search_test.go Normal file
View File

@ -0,0 +1,83 @@
package search
import (
"encoding/xml"
"testing"
xsd "github.com/use-go/onvif/xsd"
)
func TestMarshallSummary(t *testing.T) {
summary := RecordingSummary{
DataFrom: xsd.DateTime("2019-01-01T00:00:00Z"),
DataUntil: xsd.DateTime("2019-01-01T00:00:00Z"),
NumberRecordings: xsd.Int(1),
}
b, err := xml.Marshal(summary)
if err != nil {
t.Fatal(err)
}
t.Log(string(b))
}
func TestUnmarshallSummary(t *testing.T) {
data := `<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope"
xmlns:soapenc="http://www.w3.org/2003/05/soap-encoding"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tt="http://www.onvif.org/ver10/schema"
xmlns:tds="http://www.onvif.org/ver10/device/wsdl"
xmlns:trt="http://www.onvif.org/ver10/media/wsdl"
xmlns:timg="http://www.onvif.org/ver20/imaging/wsdl"
xmlns:tev="http://www.onvif.org/ver10/events/wsdl"
xmlns:tptz="http://www.onvif.org/ver20/ptz/wsdl"
xmlns:tan="http://www.onvif.org/ver20/analytics/wsdl"
xmlns:tst="http://www.onvif.org/ver10/storage/wsdl" xmlns:ter="http://www.onvif.org/ver10/error"
xmlns:dn="http://www.onvif.org/ver10/network/wsdl"
xmlns:tns1="http://www.onvif.org/ver10/topics"
xmlns:tmd="http://www.onvif.org/ver10/deviceIO/wsdl"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl"
xmlns:wsoap12="http://schemas.xmlsoap.org/wsdl/soap12"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http"
xmlns:d="http://schemas.xmlsoap.org/ws/2005/04/discovery"
xmlns:wsadis="http://schemas.xmlsoap.org/ws/2004/08/addressing"
xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2" xmlns:wsa="http://www.w3.org/2005/08/addressing"
xmlns:wstop="http://docs.oasis-open.org/wsn/t-1"
xmlns:wsrf-bf="http://docs.oasis-open.org/wsrf/bf-2"
xmlns:wsntw="http://docs.oasis-open.org/wsn/bw-2"
xmlns:wsrf-rw="http://docs.oasis-open.org/wsrf/rw-2"
xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl"
xmlns:wsrf-r="http://docs.oasis-open.org/wsrf/r-2"
xmlns:trc="http://www.onvif.org/ver10/recording/wsdl"
xmlns:tse="http://www.onvif.org/ver10/search/wsdl"
xmlns:trp="http://www.onvif.org/ver10/replay/wsdl"
xmlns:tnshik="http://www.hikvision.com/2011/event/topics"
xmlns:hikwsd="http://www.onvifext.com/onvif/ext/ver10/wsdl"
xmlns:hikxsd="http://www.onvifext.com/onvif/ext/ver10/schema"
xmlns:tas="http://www.onvif.org/ver10/advancedsecurity/wsdl"
xmlns:tr2="http://www.onvif.org/ver20/media/wsdl"
xmlns:axt="http://www.onvif.org/ver20/analytics">
<env:Body>
<tse:GetRecordingSummaryResponse>
<tse:Summary>
<tt:DataFrom>2024-10-16T01:03:32Z</tt:DataFrom>
<tt:DataUntil>2024-10-30T09:41:47Z</tt:DataUntil>
<tt:NumberRecordings>1</tt:NumberRecordings>
</tse:Summary>
</tse:GetRecordingSummaryResponse>
</env:Body>
</env:Envelope>`
type Envelope struct {
Header struct{}
Body struct {
GetRecordingSummaryResponse GetRecordingSummaryResponse
}
}
var reply Envelope
// var reply GetRecordingSummaryResponse
err := xml.Unmarshal([]byte(data), &reply)
if err != nil {
t.Fatal(err)
}
t.Log(reply)
}