Concurrency audit (third review) flagged that caller.SendSoap is not
ctx-aware: cancelling ctx does not unblock a pull or renew goroutine
parked in the underlying http.Client.Do. The previous Close()
unconditionally did <-s.done before its 5s unsubscribe timeout, so a
wedged SendSoap could hang Close indefinitely — taking the agent's
shutdown down with it.
Adds closeDrainTimeout (5s) to bound the wait for the run goroutines
to exit. When the drain times out:
* Close returns a 'did not drain' error so the caller can move on.
* Unsubscribe is skipped; the subscription expires at the camera
once InitialTermination elapses without a Renew.
* The wedged goroutines exit later, when the HTTP transport
eventually gives up. They are effectively leaked until then —
documented in the caller interface comment as the contract
callers must accept (or fix, by configuring an http.Client.Timeout).
The caller interface doc-comment now states both invariants
explicitly: must be goroutine-safe AND must enforce its own per-
request timeout, because we cannot from here.
Test
----
TestClose_BoundedWhenLoopsStuckOnHungHTTP: drives the fakeCaller
with blockAllSendSoap (new flag) so every SendSoap parks. Waits for
pullLoop to actually reach the blocked SendSoap before calling
Close (a race the previous attempt had: Close raced the loop and
exited via the ctx pre-check). Asserts Close returns within
closeDrainTimeout + 2s slack with a drain-timeout error.
Other concurrency audit findings disposition
--------------------------------------------
* unsubscribe goroutine leaks past 5s: intentional, already
documented at closeUnsubscribeTimeout.
* now func() time.Time data race: written once before goroutines
start; safe by happens-before. Tests do not swap it today.
* closeOnce self-deadlock if Close called from inside a loop:
no path exists; not exposed via the API.
Onvif library
Simple management of onvif IP-devices cameras. onvif is an implementation of ONVIF protocol for managing onvif IP devices. The purpose of this library is convenient and easy management of IP cameras and other devices that support ONVIF standard.
Overview
This repository is forked from: use-go/onvif
Supported services
The following services are implemented:
- Device
- Media
- PTZ
- Event
- Discovery
Using
General concept
- Connecting to the device
- Authentication (if necessary)
- Defining Data Types
- Carrying out the required method
Connecting to the device
If there is a device on the network at the address 192.168.13.42, and its ONVIF services use the 1234 port, then you can connect to the device in the following way:
dev, err := onvif.NewDevice(onvif.DeviceParams{Xaddr: "192.168.13.42:1234"})
The ONVIF port may differ depending on the device , to find out which port to use, you can go to the web interface of the device. Usually this is 80 port.
Authentication
If any function of the ONVIF services requires authentication, you must use the Authenticate method.
device := onvif.NewDevice(onvif.DeviceParams{Xaddr: "192.168.13.42:1234", Username: "username", Password: password})
Defining Data Types
Each ONVIF service in this library has its own package, in which all data types of this service are defined, and the package name is identical to the service name and begins with a capital letter. onvif defines the structures for each function of each ONVIF service supported by this library. Define the data type of the GetCapabilities function of the Device service. This is done as follows:
capabilities := device.GetCapabilities{Category:"All"}
Why does the GetCapabilities structure have the Category field and why is the value of this field All?
The figure below shows the documentation for the GetCapabilities. It can be seen that the function takes one Category parameter and its value should be one of the following: 'All', 'Analytics',' Device ',' Events', 'Imaging', 'Media' or 'PTZ'`.
An example of defining the data type of GetServiceCapabilities function in PTZ:
ptzCapabilities := ptz.GetServiceCapabilities{}
The figure below shows that GetServiceCapabilities does not accept any arguments.
Common data types are in the xsd/onvif package. The types of data (structures) that can be shared by all services are defined in the onvif package.
An example of how to define the data type of the CreateUsers function in Devicemgmt:
createUsers := device.CreateUsers{User: onvif.User{Username:"admin", Password:"qwerty", UserLevel:"User"}}
The figure below shows that ,in this example, the CreateUsers structure field must be a User whose data type is the User structure containing the Username, Password, UserLevel, and optional Extension fields. The User structure is in the onvif package.
Carrying out the required method
To perform any function of one of the ONVIF services whose structure has been defined, you must use the CallMethod of the device object.
createUsers := device.CreateUsers{User: onvif.User{Username:"admin", Password:"qwerty", UserLevel:"User"}}
device := onvif.NewDevice(onvif.DeviceParams{Xaddr: "192.168.13.42:1234", Username: "username", Password: password})
device.Authenticate("username", "password")
resp, err := dev.CallMethod(createUsers)
Development
See here


