154 lines
3.5 KiB
Go
154 lines
3.5 KiB
Go
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"
|
|
}
|