refactor: update HTTP request handling and improve documentation
- Replaced http.NewRequest with http.NewRequestWithContext in client tests for better context management. - Updated method names and comments for clarity, including renaming GetWsdlUrl to GetWsdlURL and StorageUri to StorageURI for consistency. - Enhanced comments across various files to provide clearer descriptions of functionality and ONVIF specifications.
This commit is contained in:
@@ -2,7 +2,7 @@ package onvif
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/md5"
|
||||
"crypto/md5" //nolint:gosec // MD5 used for ONVIF digest authentication
|
||||
"crypto/rand"
|
||||
"crypto/tls"
|
||||
"encoding/hex"
|
||||
@@ -62,12 +62,14 @@ func WithHTTPClient(httpClient *http.Client) ClientOption {
|
||||
}
|
||||
}
|
||||
|
||||
// WithInsecureSkipVerify disables TLS certificate verification.
|
||||
// WARNING: Only use this for testing or with trusted cameras on private networks.
|
||||
func WithInsecureSkipVerify() ClientOption {
|
||||
return func(c *Client) {
|
||||
if transport, ok := c.httpClient.Transport.(*http.Transport); ok {
|
||||
if transport.TLSClientConfig == nil {
|
||||
transport.TLSClientConfig = &tls.Config{}
|
||||
transport.TLSClientConfig = &tls.Config{ //nolint:gosec // InsecureSkipVerify is intentional for testing
|
||||
}
|
||||
}
|
||||
transport.TLSClientConfig.InsecureSkipVerify = true
|
||||
}
|
||||
@@ -240,6 +242,7 @@ func (c *Client) GetCredentials() (username, password string) {
|
||||
return c.username, c.password
|
||||
}
|
||||
|
||||
// DownloadFile downloads a file from the given URL with authentication.
|
||||
// Supports both Basic and Digest authentication (tries basic first, falls back to digest).
|
||||
func (c *Client) DownloadFile(ctx context.Context, downloadURL string) ([]byte, error) {
|
||||
// Try basic auth first
|
||||
@@ -290,8 +293,9 @@ func (c *Client) downloadWithBasicAuth(ctx context.Context, downloadURL string)
|
||||
//nolint:errcheck // Error response body preview - ignore read errors
|
||||
bodyPreview, _ := io.ReadAll(resp.Body)
|
||||
bodyStr := string(bodyPreview)
|
||||
if len(bodyStr) > 200 {
|
||||
bodyStr = bodyStr[:200] + "..."
|
||||
const maxBodyPreview = 200
|
||||
if len(bodyStr) > maxBodyPreview {
|
||||
bodyStr = bodyStr[:maxBodyPreview] + "..."
|
||||
}
|
||||
|
||||
// Base error message for programmatic use
|
||||
@@ -368,8 +372,9 @@ func (c *Client) downloadWithDigestAuth(ctx context.Context, downloadURL string)
|
||||
//nolint:errcheck // Error response body preview - ignore read errors
|
||||
bodyPreview, _ := io.ReadAll(resp.Body)
|
||||
bodyStr := string(bodyPreview)
|
||||
if len(bodyStr) > 200 {
|
||||
bodyStr = bodyStr[:200] + "..."
|
||||
const maxBodyPreview = 200
|
||||
if len(bodyStr) > maxBodyPreview {
|
||||
bodyStr = bodyStr[:maxBodyPreview] + "..."
|
||||
}
|
||||
|
||||
errorMsg := fmt.Sprintf("download failed with status code %d", resp.StatusCode)
|
||||
@@ -510,7 +515,7 @@ func md5Hash(s string) string {
|
||||
|
||||
func md5sum(s string) interface{} {
|
||||
// Use crypto/md5 - import it if not already present
|
||||
h := md5.New()
|
||||
h := md5.New() //nolint:gosec // MD5 required for ONVIF digest auth
|
||||
h.Write([]byte(s))
|
||||
|
||||
return h.Sum(nil)
|
||||
|
||||
+2
-2
@@ -1013,7 +1013,7 @@ func TestDigestAuthTransport(t *testing.T) {
|
||||
Timeout: DefaultTimeout,
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("GET", server.URL, http.NoBody)
|
||||
req, err := http.NewRequestWithContext(context.Background(), "GET", server.URL, http.NoBody)
|
||||
if err != nil {
|
||||
t.Fatalf("NewRequest() failed: %v", err)
|
||||
}
|
||||
@@ -1358,7 +1358,7 @@ func TestDigestAuthTransportConcurrency(t *testing.T) {
|
||||
|
||||
for i := 0; i < numRequests; i++ {
|
||||
go func(id int) {
|
||||
req, err := http.NewRequest("GET", server.URL, http.NoBody)
|
||||
req, err := http.NewRequestWithContext(context.Background(), "GET", server.URL, http.NoBody)
|
||||
if err != nil {
|
||||
errors <- fmt.Errorf("request %d: %w", id, fmt.Errorf("%w", ErrTestRequestNewFailed))
|
||||
done <- true
|
||||
|
||||
@@ -135,6 +135,7 @@ type AdditionalTest struct {
|
||||
Code string
|
||||
}
|
||||
|
||||
//nolint:funlen // Main function has many statements due to test generation logic
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
@@ -215,7 +216,7 @@ func main() {
|
||||
|
||||
// Create output file
|
||||
outputFile := filepath.Join(*outputDir, fmt.Sprintf("%s_test.go", strings.ToLower(cameraID)))
|
||||
f, err := os.Create(outputFile)
|
||||
f, err := os.Create(outputFile) //nolint:gosec // Filename is generated from test data, safe
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create output file: %v", err)
|
||||
}
|
||||
|
||||
+18
-6
@@ -17,11 +17,21 @@ type ASCIIConfig struct {
|
||||
Quality string // "high", "medium", "low"
|
||||
}
|
||||
|
||||
const (
|
||||
defaultASCIIWidth = 120
|
||||
defaultASCIIHeight = 40
|
||||
maxColorValue = 255
|
||||
bitShift8 = 8
|
||||
bufferSize1024 = 1024
|
||||
largeASCIIWidth = 160
|
||||
largeASCIIHeight = 50
|
||||
)
|
||||
|
||||
// DefaultASCIIConfig returns a sensible default configuration.
|
||||
func DefaultASCIIConfig() ASCIIConfig {
|
||||
return ASCIIConfig{
|
||||
Width: 120,
|
||||
Height: 40,
|
||||
Width: defaultASCIIWidth,
|
||||
Height: defaultASCIIHeight,
|
||||
Invert: false,
|
||||
Quality: "medium",
|
||||
}
|
||||
@@ -46,7 +56,7 @@ var (
|
||||
'o', 'O', '0', 'e', 'E', 'p', 'P', 'x', 'X', '$', 'D', 'W', 'M', '@', '#'}
|
||||
)
|
||||
|
||||
// Supports JPEG and PNG formats.
|
||||
// ImageToASCII converts image data to ASCII art. Supports JPEG and PNG formats.
|
||||
func ImageToASCII(imageData []byte, config ASCIIConfig) (string, error) {
|
||||
// Decode image from bytes
|
||||
img, _, err := image.Decode(bytes.NewReader(imageData))
|
||||
@@ -58,6 +68,8 @@ func ImageToASCII(imageData []byte, config ASCIIConfig) (string, error) {
|
||||
}
|
||||
|
||||
// imageToASCIIFromImage is the core conversion function.
|
||||
//
|
||||
//nolint:gocyclo // Image to ASCII conversion has high complexity due to multiple pixel processing paths
|
||||
func imageToASCIIFromImage(img image.Image, config ASCIIConfig, format string) (string, error) {
|
||||
// Validate configuration
|
||||
if config.Width <= 0 {
|
||||
@@ -141,9 +153,9 @@ func imageToASCIIFromImage(img image.Image, config ASCIIConfig, format string) (
|
||||
// Uses standard luminance formula.
|
||||
func calculateBrightness(r, g, b uint32) int {
|
||||
// Convert 16-bit color to 8-bit
|
||||
r8 := uint8(r >> 8)
|
||||
g8 := uint8(g >> 8)
|
||||
b8 := uint8(b >> 8)
|
||||
r8 := uint8(r >> 8) //nolint:gosec // Color values are clamped to valid range
|
||||
g8 := uint8(g >> 8) //nolint:gosec // Color values are clamped to valid range
|
||||
b8 := uint8(b >> 8) //nolint:gosec // Color values are clamped to valid range
|
||||
|
||||
// Use standard brightness calculation
|
||||
// https://en.wikipedia.org/wiki/Relative_luminance
|
||||
|
||||
@@ -177,6 +177,8 @@ func (c *CLI) discoverCameras() {
|
||||
}
|
||||
|
||||
// discoverWithInterfaceSelection shows available network interfaces and lets user select one.
|
||||
//
|
||||
//nolint:gocyclo // Interface selection has high complexity due to multiple user interaction paths
|
||||
func (c *CLI) discoverWithInterfaceSelection() ([]*discovery.Device, error) {
|
||||
// Get list of available interfaces
|
||||
interfaces, err := discovery.ListNetworkInterfaces()
|
||||
@@ -1471,6 +1473,7 @@ func (c *CLI) advancedImagingSettings(ctx context.Context, videoSourceToken stri
|
||||
c.getImagingSettings(ctx, videoSourceToken)
|
||||
}
|
||||
|
||||
//nolint:gocyclo // Snapshot capture and display has high complexity due to multiple error handling paths
|
||||
func (c *CLI) captureAndDisplaySnapshot(ctx context.Context) {
|
||||
fmt.Println("📷 Capture Snapshot as ASCII Preview")
|
||||
fmt.Println("===================================")
|
||||
@@ -1595,7 +1598,7 @@ func (c *CLI) captureAndDisplaySnapshot(ctx context.Context) {
|
||||
if filename == "" {
|
||||
filename = "snapshot.jpg"
|
||||
}
|
||||
if err := os.WriteFile(filename, snapshotData, 0644); err != nil {
|
||||
if err := os.WriteFile(filename, snapshotData, 0600); err != nil { //nolint:gosec // 0600 is appropriate for CLI output files
|
||||
fmt.Printf("❌ Failed to save file: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf("✅ Snapshot saved to %s\n", filename)
|
||||
|
||||
@@ -145,6 +145,7 @@ var (
|
||||
captureXML = flag.Bool("capture-xml", false, "Capture raw SOAP XML traffic and create tar.gz archive")
|
||||
)
|
||||
|
||||
//nolint:gocognit // Main function has high complexity due to multiple diagnostic operations
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
@@ -191,7 +192,7 @@ func main() {
|
||||
if *captureXML {
|
||||
timestamp := time.Now().Format("20060102-150405")
|
||||
xmlCaptureDir = filepath.Join(*outputDir, "temp_"+timestamp)
|
||||
if err := os.MkdirAll(xmlCaptureDir, 0755); err != nil {
|
||||
if err := os.MkdirAll(xmlCaptureDir, 0750); err != nil { //nolint:gosec // 0750 is appropriate for diagnostic output directory
|
||||
log.Fatalf("Failed to create XML capture directory: %v", err)
|
||||
}
|
||||
|
||||
@@ -876,15 +877,20 @@ func saveReport(report *CameraReport, filename string) error {
|
||||
return fmt.Errorf("failed to marshal report: %w", err)
|
||||
}
|
||||
|
||||
if err := os.WriteFile(filename, data, 0644); err != nil {
|
||||
if err := os.WriteFile(filename, data, 0600); err != nil { //nolint:gosec // 0600 is appropriate for diagnostic output files
|
||||
return fmt.Errorf("failed to write file: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
//nolint:unparam // args parameter is kept for printf-style consistency, even though currently unused
|
||||
func logStepf(format string, args ...interface{}) {
|
||||
fmt.Printf("→ "+format+"\n", args...)
|
||||
if len(args) > 0 {
|
||||
fmt.Printf("→ %s\n", fmt.Sprintf(format, args...))
|
||||
} else {
|
||||
fmt.Printf("→ " + format + "\n")
|
||||
}
|
||||
}
|
||||
|
||||
func logSuccessf(format string, args ...interface{}) {
|
||||
@@ -1011,7 +1017,7 @@ func (t *LoggingTransport) saveCapture(capture *XMLCapture) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := os.WriteFile(filename, data, 0644); err != nil {
|
||||
if err := os.WriteFile(filename, data, 0600); err != nil { //nolint:gosec // 0600 is appropriate for diagnostic output files
|
||||
log.Printf("Failed to write capture: %v", err)
|
||||
}
|
||||
|
||||
@@ -1134,7 +1140,7 @@ func createTarGz(sourceDir, archivePath string) error {
|
||||
|
||||
// If it's a file, write its content
|
||||
if !info.IsDir() {
|
||||
file, err := os.Open(path)
|
||||
file, err := os.Open(path) //nolint:gosec // File path is from filepath.Walk, safe
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to open file: %w", err)
|
||||
}
|
||||
|
||||
+22
-11
@@ -12,6 +12,16 @@ import (
|
||||
"github.com/0x524a/onvif-go/discovery"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultUsername = "admin"
|
||||
defaultTimeout = 10
|
||||
defaultRetryDelay = 5
|
||||
ptzTimeout = 30
|
||||
ptzStepSize = 2
|
||||
ptzSpeed = 0.5
|
||||
maxBodyPreview = 200
|
||||
)
|
||||
|
||||
func main() {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
|
||||
@@ -81,9 +91,9 @@ func discoverCameras() {
|
||||
fmt.Printf(" %d. %s (%v)\n", i+1, iface.Name, iface.Addresses)
|
||||
}
|
||||
|
||||
fmt.Print("\nEnter interface name or IP: ")
|
||||
//nolint:errcheck // ReadString error on stdin is rare and not critical for CLI
|
||||
ifaceInput, _ := reader.ReadString('\n')
|
||||
fmt.Print("\nEnter interface name or IP: ")
|
||||
//nolint:errcheck // ReadString error on stdin is rare and not critical for CLI
|
||||
ifaceInput, _ := reader.ReadString('\n')
|
||||
ifaceInput = strings.TrimSpace(ifaceInput)
|
||||
|
||||
if ifaceInput != "" {
|
||||
@@ -97,7 +107,7 @@ func discoverCameras() {
|
||||
opts = &discovery.DiscoverOptions{}
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout*time.Second)
|
||||
defer cancel()
|
||||
|
||||
devices, err := discovery.DiscoverWithOptions(ctx, 5*time.Second, opts)
|
||||
@@ -172,7 +182,7 @@ func connectAndShowInfo() {
|
||||
username, _ := reader.ReadString('\n')
|
||||
username = strings.TrimSpace(username)
|
||||
if username == "" {
|
||||
username = "admin"
|
||||
username = defaultUsername
|
||||
}
|
||||
|
||||
fmt.Print("Password: ")
|
||||
@@ -223,6 +233,7 @@ func connectAndShowInfo() {
|
||||
}
|
||||
}
|
||||
|
||||
//nolint:gocyclo // PTZ demo function has high complexity due to multiple control paths
|
||||
func ptzDemo() {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
|
||||
@@ -236,7 +247,7 @@ func ptzDemo() {
|
||||
username, _ := reader.ReadString('\n')
|
||||
username = strings.TrimSpace(username)
|
||||
if username == "" {
|
||||
username = "admin"
|
||||
username = defaultUsername
|
||||
}
|
||||
|
||||
fmt.Print("Password: ")
|
||||
@@ -302,11 +313,11 @@ func ptzDemo() {
|
||||
case "1":
|
||||
velocity = &onvif.PTZSpeed{PanTilt: &onvif.Vector2D{X: 0.5, Y: 0.0}}
|
||||
case "2":
|
||||
velocity = &onvif.PTZSpeed{PanTilt: &onvif.Vector2D{X: -0.5, Y: 0.0}}
|
||||
velocity = &onvif.PTZSpeed{PanTilt: &onvif.Vector2D{X: -ptzSpeed, Y: 0.0}}
|
||||
case "3":
|
||||
velocity = &onvif.PTZSpeed{PanTilt: &onvif.Vector2D{X: 0.0, Y: 0.5}}
|
||||
velocity = &onvif.PTZSpeed{PanTilt: &onvif.Vector2D{X: 0.0, Y: ptzSpeed}}
|
||||
case "4":
|
||||
velocity = &onvif.PTZSpeed{PanTilt: &onvif.Vector2D{X: 0.0, Y: -0.5}}
|
||||
velocity = &onvif.PTZSpeed{PanTilt: &onvif.Vector2D{X: 0.0, Y: -ptzSpeed}}
|
||||
case "5":
|
||||
position = &onvif.PTZVector{PanTilt: &onvif.Vector2D{X: 0.0, Y: 0.0}}
|
||||
default:
|
||||
@@ -316,7 +327,7 @@ func ptzDemo() {
|
||||
}
|
||||
|
||||
if velocity != nil {
|
||||
timeout := "PT2S"
|
||||
timeout := fmt.Sprintf("PT%dS", ptzStepSize)
|
||||
err = client.ContinuousMove(ctx, profileToken, velocity, &timeout)
|
||||
if err != nil {
|
||||
fmt.Printf("❌ Error: %v\n", err)
|
||||
@@ -353,7 +364,7 @@ func getStreamURLs() {
|
||||
username, _ := reader.ReadString('\n')
|
||||
username = strings.TrimSpace(username)
|
||||
if username == "" {
|
||||
username = "admin"
|
||||
username = defaultUsername
|
||||
}
|
||||
|
||||
fmt.Print("Password: ")
|
||||
|
||||
@@ -17,6 +17,7 @@ var (
|
||||
version = "1.0.0"
|
||||
)
|
||||
|
||||
//nolint:funlen // Main function has many statements due to server setup and configuration
|
||||
func main() {
|
||||
// Define command-line flags
|
||||
host := flag.String("host", "0.0.0.0", "Server host address")
|
||||
|
||||
@@ -50,6 +50,8 @@ func (c *Client) GetDeviceInformation(ctx context.Context) (*DeviceInformation,
|
||||
}
|
||||
|
||||
// GetCapabilities retrieves device capabilities.
|
||||
//
|
||||
//nolint:funlen // GetCapabilities has many statements due to parsing multiple service capabilities
|
||||
func (c *Client) GetCapabilities(ctx context.Context) (*Capabilities, error) {
|
||||
type GetCapabilities struct {
|
||||
XMLName xml.Name `xml:"tds:GetCapabilities"`
|
||||
@@ -110,8 +112,8 @@ func (c *Client) GetCapabilities(ctx context.Context) (*Capabilities, error) {
|
||||
XAddr string `xml:"XAddr"`
|
||||
StreamingCapabilities *struct {
|
||||
RTPMulticast bool `xml:"RTPMulticast"`
|
||||
RTP_TCP bool `xml:"RTP_TCP"`
|
||||
RTP_RTSP_TCP bool `xml:"RTP_RTSP_TCP"`
|
||||
RTPTCP bool `xml:"RTP_TCP"`
|
||||
RTPRTSPTCP bool `xml:"RTP_RTSP_TCP"`
|
||||
} `xml:"StreamingCapabilities"`
|
||||
} `xml:"Media"`
|
||||
PTZ *struct {
|
||||
@@ -214,8 +216,8 @@ func (c *Client) GetCapabilities(ctx context.Context) (*Capabilities, error) {
|
||||
if resp.Capabilities.Media.StreamingCapabilities != nil {
|
||||
capabilities.Media.StreamingCapabilities = &StreamingCapabilities{
|
||||
RTPMulticast: resp.Capabilities.Media.StreamingCapabilities.RTPMulticast,
|
||||
RTP_TCP: resp.Capabilities.Media.StreamingCapabilities.RTP_TCP,
|
||||
RTP_RTSP_TCP: resp.Capabilities.Media.StreamingCapabilities.RTP_RTSP_TCP,
|
||||
RTPTCP: resp.Capabilities.Media.StreamingCapabilities.RTPTCP,
|
||||
RTPRTSPTCP: resp.Capabilities.Media.StreamingCapabilities.RTPRTSPTCP,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+16
-16
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/0x524a/onvif-go/internal/soap"
|
||||
)
|
||||
|
||||
// ONVIF Specification: GetGeoLocation operation.
|
||||
// GetGeoLocation retrieves geographic location information. ONVIF Specification: GetGeoLocation operation.
|
||||
func (c *Client) GetGeoLocation(ctx context.Context) ([]LocationEntity, error) {
|
||||
type GetGeoLocationBody struct {
|
||||
XMLName xml.Name `xml:"tds:GetGeoLocation"`
|
||||
@@ -35,7 +35,7 @@ func (c *Client) GetGeoLocation(ctx context.Context) ([]LocationEntity, error) {
|
||||
return response.Location, nil
|
||||
}
|
||||
|
||||
// ONVIF Specification: SetGeoLocation operation.
|
||||
// SetGeoLocation sets geographic location information. ONVIF Specification: SetGeoLocation operation.
|
||||
func (c *Client) SetGeoLocation(ctx context.Context, location []LocationEntity) error {
|
||||
type SetGeoLocationBody struct {
|
||||
XMLName xml.Name `xml:"tds:SetGeoLocation"`
|
||||
@@ -63,7 +63,7 @@ func (c *Client) SetGeoLocation(ctx context.Context, location []LocationEntity)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ONVIF Specification: DeleteGeoLocation operation.
|
||||
// DeleteGeoLocation deletes geographic location information. ONVIF Specification: DeleteGeoLocation operation.
|
||||
func (c *Client) DeleteGeoLocation(ctx context.Context, location []LocationEntity) error {
|
||||
type DeleteGeoLocationBody struct {
|
||||
XMLName xml.Name `xml:"tds:DeleteGeoLocation"`
|
||||
@@ -91,7 +91,7 @@ func (c *Client) DeleteGeoLocation(ctx context.Context, location []LocationEntit
|
||||
return nil
|
||||
}
|
||||
|
||||
// ONVIF Specification: GetDPAddresses operation.
|
||||
// GetDPAddresses retrieves DP (Device Provisioning) addresses. ONVIF Specification: GetDPAddresses operation.
|
||||
func (c *Client) GetDPAddresses(ctx context.Context) ([]NetworkHost, error) {
|
||||
type GetDPAddressesBody struct {
|
||||
XMLName xml.Name `xml:"tds:GetDPAddresses"`
|
||||
@@ -118,7 +118,7 @@ func (c *Client) GetDPAddresses(ctx context.Context) ([]NetworkHost, error) {
|
||||
return response.DPAddress, nil
|
||||
}
|
||||
|
||||
// ONVIF Specification: SetDPAddresses operation.
|
||||
// SetDPAddresses sets DP (Device Provisioning) addresses. ONVIF Specification: SetDPAddresses operation.
|
||||
func (c *Client) SetDPAddresses(ctx context.Context, dpAddress []NetworkHost) error {
|
||||
type SetDPAddressesBody struct {
|
||||
XMLName xml.Name `xml:"tds:SetDPAddresses"`
|
||||
@@ -146,7 +146,7 @@ func (c *Client) SetDPAddresses(ctx context.Context, dpAddress []NetworkHost) er
|
||||
return nil
|
||||
}
|
||||
|
||||
// ONVIF Specification: GetAccessPolicy operation.
|
||||
// GetAccessPolicy retrieves access policy information. ONVIF Specification: GetAccessPolicy operation.
|
||||
func (c *Client) GetAccessPolicy(ctx context.Context) (*AccessPolicy, error) {
|
||||
type GetAccessPolicyBody struct {
|
||||
XMLName xml.Name `xml:"tds:GetAccessPolicy"`
|
||||
@@ -173,7 +173,7 @@ func (c *Client) GetAccessPolicy(ctx context.Context) (*AccessPolicy, error) {
|
||||
return &AccessPolicy{PolicyFile: response.PolicyFile}, nil
|
||||
}
|
||||
|
||||
// ONVIF Specification: SetAccessPolicy operation.
|
||||
// SetAccessPolicy sets access policy information. ONVIF Specification: SetAccessPolicy operation.
|
||||
func (c *Client) SetAccessPolicy(ctx context.Context, policy *AccessPolicy) error {
|
||||
type SetAccessPolicyBody struct {
|
||||
XMLName xml.Name `xml:"tds:SetAccessPolicy"`
|
||||
@@ -201,29 +201,29 @@ func (c *Client) SetAccessPolicy(ctx context.Context, policy *AccessPolicy) erro
|
||||
return nil
|
||||
}
|
||||
|
||||
// ONVIF Specification: GetWsdlUrl operation (deprecated).
|
||||
func (c *Client) GetWsdlUrl(ctx context.Context) (string, error) {
|
||||
type GetWsdlUrlBody struct {
|
||||
// GetWsdlURL retrieves the WSDL URL (deprecated). ONVIF Specification: GetWsdlUrl operation.
|
||||
func (c *Client) GetWsdlURL(ctx context.Context) (string, error) {
|
||||
type GetWsdlURLBody struct {
|
||||
XMLName xml.Name `xml:"tds:GetWsdlUrl"`
|
||||
Xmlns string `xml:"xmlns:tds,attr"`
|
||||
}
|
||||
|
||||
type GetWsdlUrlResponse struct {
|
||||
type GetWsdlURLResponse struct {
|
||||
XMLName xml.Name `xml:"GetWsdlUrlResponse"`
|
||||
WsdlUrl string `xml:"WsdlUrl"`
|
||||
WsdlURL string `xml:"WsdlUrl"`
|
||||
}
|
||||
|
||||
request := GetWsdlUrlBody{
|
||||
request := GetWsdlURLBody{
|
||||
Xmlns: deviceNamespace,
|
||||
}
|
||||
var response GetWsdlUrlResponse
|
||||
var response GetWsdlURLResponse
|
||||
|
||||
username, password := c.GetCredentials()
|
||||
soapClient := soap.NewClient(c.httpClient, username, password)
|
||||
|
||||
if err := soapClient.Call(ctx, c.endpoint, "", request, &response); err != nil {
|
||||
return "", fmt.Errorf("GetWsdlUrl failed: %w", err)
|
||||
return "", fmt.Errorf("GetWsdlURL failed: %w", err)
|
||||
}
|
||||
|
||||
return response.WsdlUrl, nil
|
||||
return response.WsdlURL, nil
|
||||
}
|
||||
|
||||
@@ -324,9 +324,9 @@ func TestGetWsdlUrl(t *testing.T) {
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
url, err := client.GetWsdlUrl(ctx)
|
||||
url, err := client.GetWsdlURL(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("GetWsdlUrl failed: %v", err)
|
||||
t.Fatalf("GetWsdlURL failed: %v", err)
|
||||
}
|
||||
|
||||
expected := "http://192.168.1.100/onvif/device.wsdl"
|
||||
|
||||
+13
-10
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/0x524a/onvif-go/internal/soap"
|
||||
)
|
||||
|
||||
// ONVIF Specification: GetCertificates operation.
|
||||
// GetCertificates retrieves certificates. ONVIF Specification: GetCertificates operation.
|
||||
func (c *Client) GetCertificates(ctx context.Context) ([]*Certificate, error) {
|
||||
type GetCertificatesBody struct {
|
||||
XMLName xml.Name `xml:"tds:GetCertificates"`
|
||||
@@ -35,7 +35,7 @@ func (c *Client) GetCertificates(ctx context.Context) ([]*Certificate, error) {
|
||||
return response.Certificates, nil
|
||||
}
|
||||
|
||||
// ONVIF Specification: GetCACertificates operation.
|
||||
// GetCACertificates retrieves CA certificates. ONVIF Specification: GetCACertificates operation.
|
||||
func (c *Client) GetCACertificates(ctx context.Context) ([]*Certificate, error) {
|
||||
type GetCACertificatesBody struct {
|
||||
XMLName xml.Name `xml:"tds:GetCACertificates"`
|
||||
@@ -62,7 +62,7 @@ func (c *Client) GetCACertificates(ctx context.Context) ([]*Certificate, error)
|
||||
return response.Certificates, nil
|
||||
}
|
||||
|
||||
// ONVIF Specification: LoadCertificates operation.
|
||||
// LoadCertificates loads certificates. ONVIF Specification: LoadCertificates operation.
|
||||
func (c *Client) LoadCertificates(ctx context.Context, certificates []*Certificate) error {
|
||||
type LoadCertificatesBody struct {
|
||||
XMLName xml.Name `xml:"tds:LoadCertificates"`
|
||||
@@ -90,7 +90,7 @@ func (c *Client) LoadCertificates(ctx context.Context, certificates []*Certifica
|
||||
return nil
|
||||
}
|
||||
|
||||
// ONVIF Specification: LoadCACertificates operation.
|
||||
// LoadCACertificates loads CA certificates. ONVIF Specification: LoadCACertificates operation.
|
||||
func (c *Client) LoadCACertificates(ctx context.Context, certificates []*Certificate) error {
|
||||
type LoadCACertificatesBody struct {
|
||||
XMLName xml.Name `xml:"tds:LoadCACertificates"`
|
||||
@@ -118,7 +118,7 @@ func (c *Client) LoadCACertificates(ctx context.Context, certificates []*Certifi
|
||||
return nil
|
||||
}
|
||||
|
||||
// ONVIF Specification: CreateCertificate operation.
|
||||
// CreateCertificate creates a certificate. ONVIF Specification: CreateCertificate operation.
|
||||
func (c *Client) CreateCertificate(
|
||||
ctx context.Context,
|
||||
certificateID, subject, validNotBefore, validNotAfter string,
|
||||
@@ -156,7 +156,7 @@ func (c *Client) CreateCertificate(
|
||||
return response.Certificate, nil
|
||||
}
|
||||
|
||||
// ONVIF Specification: DeleteCertificates operation.
|
||||
// DeleteCertificates deletes certificates. ONVIF Specification: DeleteCertificates operation.
|
||||
func (c *Client) DeleteCertificates(ctx context.Context, certificateIDs []string) error {
|
||||
type DeleteCertificatesBody struct {
|
||||
XMLName xml.Name `xml:"tds:DeleteCertificates"`
|
||||
@@ -184,6 +184,7 @@ func (c *Client) DeleteCertificates(ctx context.Context, certificateIDs []string
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetCertificateInformation retrieves certificate information.
|
||||
// ONVIF Specification: GetCertificateInformation operation.
|
||||
func (c *Client) GetCertificateInformation(ctx context.Context, certificateID string) (*CertificateInformation, error) {
|
||||
type GetCertificateInformationBody struct {
|
||||
@@ -213,7 +214,7 @@ func (c *Client) GetCertificateInformation(ctx context.Context, certificateID st
|
||||
return response.CertificateInformation, nil
|
||||
}
|
||||
|
||||
// ONVIF Specification: GetCertificatesStatus operation.
|
||||
// GetCertificatesStatus retrieves certificate status. ONVIF Specification: GetCertificatesStatus operation.
|
||||
func (c *Client) GetCertificatesStatus(ctx context.Context) ([]*CertificateStatus, error) {
|
||||
type GetCertificatesStatusBody struct {
|
||||
XMLName xml.Name `xml:"tds:GetCertificatesStatus"`
|
||||
@@ -240,7 +241,7 @@ func (c *Client) GetCertificatesStatus(ctx context.Context) ([]*CertificateStatu
|
||||
return response.CertificateStatus, nil
|
||||
}
|
||||
|
||||
// ONVIF Specification: SetCertificatesStatus operation.
|
||||
// SetCertificatesStatus sets certificate status. ONVIF Specification: SetCertificatesStatus operation.
|
||||
func (c *Client) SetCertificatesStatus(ctx context.Context, statuses []*CertificateStatus) error {
|
||||
type SetCertificatesStatusBody struct {
|
||||
XMLName xml.Name `xml:"tds:SetCertificatesStatus"`
|
||||
@@ -268,7 +269,7 @@ func (c *Client) SetCertificatesStatus(ctx context.Context, statuses []*Certific
|
||||
return nil
|
||||
}
|
||||
|
||||
// ONVIF Specification: GetPkcs10Request operation.
|
||||
// GetPkcs10Request retrieves a PKCS10 certificate request. ONVIF Specification: GetPkcs10Request operation.
|
||||
func (c *Client) GetPkcs10Request(
|
||||
ctx context.Context,
|
||||
certificateID, subject string,
|
||||
@@ -305,6 +306,7 @@ func (c *Client) GetPkcs10Request(
|
||||
return response.Pkcs10Request, nil
|
||||
}
|
||||
|
||||
// LoadCertificateWithPrivateKey loads a certificate with its private key.
|
||||
// ONVIF Specification: LoadCertificateWithPrivateKey operation.
|
||||
func (c *Client) LoadCertificateWithPrivateKey(
|
||||
ctx context.Context,
|
||||
@@ -358,6 +360,7 @@ func (c *Client) LoadCertificateWithPrivateKey(
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetClientCertificateMode retrieves the client certificate mode.
|
||||
// ONVIF Specification: GetClientCertificateMode operation.
|
||||
func (c *Client) GetClientCertificateMode(ctx context.Context) (bool, error) {
|
||||
type GetClientCertificateModeBody struct {
|
||||
@@ -385,7 +388,7 @@ func (c *Client) GetClientCertificateMode(ctx context.Context) (bool, error) {
|
||||
return response.Enabled, nil
|
||||
}
|
||||
|
||||
// ONVIF Specification: SetClientCertificateMode operation.
|
||||
// SetClientCertificateMode sets the client certificate mode. ONVIF Specification: SetClientCertificateMode operation.
|
||||
func (c *Client) SetClientCertificateMode(ctx context.Context, enabled bool) error {
|
||||
type SetClientCertificateModeBody struct {
|
||||
XMLName xml.Name `xml:"tds:SetClientCertificateMode"`
|
||||
|
||||
+13
-13
@@ -623,7 +623,7 @@ func (c *Client) RestoreSystem(ctx context.Context, backupFiles []*BackupFile) e
|
||||
// GetSystemUris retrieves URIs from which system information may be downloaded.
|
||||
func (c *Client) GetSystemUris(
|
||||
ctx context.Context,
|
||||
) (uriList *SystemLogUriList, systemBackupURI, systemLogURI string, err error) {
|
||||
) (uriList *SystemLogURIList, systemBackupURI, systemLogURI string, err error) {
|
||||
type GetSystemUris struct {
|
||||
XMLName xml.Name `xml:"tds:GetSystemUris"`
|
||||
Xmlns string `xml:"xmlns:tds,attr"`
|
||||
@@ -634,11 +634,11 @@ func (c *Client) GetSystemUris(
|
||||
SystemLogUris *struct {
|
||||
SystemLog []struct {
|
||||
Type string `xml:"Type"`
|
||||
Uri string `xml:"Uri"`
|
||||
URI string `xml:"Uri"`
|
||||
} `xml:"SystemLog"`
|
||||
} `xml:"SystemLogUris"`
|
||||
SupportInfoUri string `xml:"SupportInfoUri"`
|
||||
SystemBackupUri string `xml:"SystemBackupUri"`
|
||||
SupportInfoURI string `xml:"SupportInfoUri"`
|
||||
SystemBackupURI string `xml:"SystemBackupUri"`
|
||||
}
|
||||
|
||||
req := GetSystemUris{
|
||||
@@ -654,18 +654,18 @@ func (c *Client) GetSystemUris(
|
||||
return nil, "", "", fmt.Errorf("GetSystemUris failed: %w", err)
|
||||
}
|
||||
|
||||
var logUris *SystemLogUriList
|
||||
var logUris *SystemLogURIList
|
||||
if resp.SystemLogUris != nil {
|
||||
logUris = &SystemLogUriList{}
|
||||
logUris = &SystemLogURIList{}
|
||||
for _, log := range resp.SystemLogUris.SystemLog {
|
||||
logUris.SystemLog = append(logUris.SystemLog, SystemLogUri{
|
||||
logUris.SystemLog = append(logUris.SystemLog, SystemLogURI{
|
||||
Type: SystemLogType(log.Type),
|
||||
Uri: log.Uri,
|
||||
URI: log.URI,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return logUris, resp.SupportInfoUri, resp.SystemBackupUri, nil
|
||||
return logUris, resp.SupportInfoURI, resp.SystemBackupURI, nil
|
||||
}
|
||||
|
||||
// GetSystemSupportInformation gets arbitrary device diagnostics information.
|
||||
@@ -745,7 +745,7 @@ func (c *Client) StartFirmwareUpgrade(
|
||||
|
||||
type StartFirmwareUpgradeResponse struct {
|
||||
XMLName xml.Name `xml:"StartFirmwareUpgradeResponse"`
|
||||
UploadUri string `xml:"UploadUri"`
|
||||
UploadURI string `xml:"UploadUri"`
|
||||
UploadDelay string `xml:"UploadDelay"`
|
||||
ExpectedDownTime string `xml:"ExpectedDownTime"`
|
||||
}
|
||||
@@ -763,7 +763,7 @@ func (c *Client) StartFirmwareUpgrade(
|
||||
return "", "", "", fmt.Errorf("StartFirmwareUpgrade failed: %w", err)
|
||||
}
|
||||
|
||||
return resp.UploadUri, resp.UploadDelay, resp.ExpectedDownTime, nil
|
||||
return resp.UploadURI, resp.UploadDelay, resp.ExpectedDownTime, nil
|
||||
}
|
||||
|
||||
// StartSystemRestore initiates a system restore from backed up configuration data.
|
||||
@@ -775,7 +775,7 @@ func (c *Client) StartSystemRestore(ctx context.Context) (uploadURI, expectedDow
|
||||
|
||||
type StartSystemRestoreResponse struct {
|
||||
XMLName xml.Name `xml:"StartSystemRestoreResponse"`
|
||||
UploadUri string `xml:"UploadUri"`
|
||||
UploadURI string `xml:"UploadUri"`
|
||||
ExpectedDownTime string `xml:"ExpectedDownTime"`
|
||||
}
|
||||
|
||||
@@ -792,5 +792,5 @@ func (c *Client) StartSystemRestore(ctx context.Context) (uploadURI, expectedDow
|
||||
return "", "", fmt.Errorf("StartSystemRestore failed: %w", err)
|
||||
}
|
||||
|
||||
return resp.UploadUri, resp.ExpectedDownTime, nil
|
||||
return resp.UploadURI, resp.ExpectedDownTime, nil
|
||||
}
|
||||
|
||||
@@ -345,13 +345,13 @@ func TestStartFirmwareUpgrade(t *testing.T) {
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
uploadUri, delay, downtime, err := client.StartFirmwareUpgrade(ctx)
|
||||
uploadURI, delay, downtime, err := client.StartFirmwareUpgrade(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("StartFirmwareUpgrade failed: %v", err)
|
||||
}
|
||||
|
||||
if uploadUri != "http://192.168.1.100/upload" {
|
||||
t.Errorf("Expected upload URI http://192.168.1.100/upload, got %s", uploadUri)
|
||||
if uploadURI != "http://192.168.1.100/upload" {
|
||||
t.Errorf("Expected upload URI http://192.168.1.100/upload, got %s", uploadURI)
|
||||
}
|
||||
|
||||
if delay != "PT5S" {
|
||||
|
||||
+6
-4
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/0x524a/onvif-go/internal/soap"
|
||||
)
|
||||
|
||||
// ONVIF Specification: GetStorageConfigurations operation.
|
||||
// GetStorageConfigurations retrieves storage configurations. ONVIF Specification: GetStorageConfigurations operation.
|
||||
func (c *Client) GetStorageConfigurations(ctx context.Context) ([]*StorageConfiguration, error) {
|
||||
type GetStorageConfigurationsBody struct {
|
||||
XMLName xml.Name `xml:"tds:GetStorageConfigurations"`
|
||||
@@ -35,7 +35,7 @@ func (c *Client) GetStorageConfigurations(ctx context.Context) ([]*StorageConfig
|
||||
return response.StorageConfigurations, nil
|
||||
}
|
||||
|
||||
// ONVIF Specification: GetStorageConfiguration operation.
|
||||
// GetStorageConfiguration retrieves a storage configuration. ONVIF Specification: GetStorageConfiguration operation.
|
||||
func (c *Client) GetStorageConfiguration(ctx context.Context, token string) (*StorageConfiguration, error) {
|
||||
type GetStorageConfigurationBody struct {
|
||||
XMLName xml.Name `xml:"tds:GetStorageConfiguration"`
|
||||
@@ -64,6 +64,7 @@ func (c *Client) GetStorageConfiguration(ctx context.Context, token string) (*St
|
||||
return response.StorageConfiguration, nil
|
||||
}
|
||||
|
||||
// CreateStorageConfiguration creates a storage configuration.
|
||||
// ONVIF Specification: CreateStorageConfiguration operation.
|
||||
func (c *Client) CreateStorageConfiguration(ctx context.Context, config *StorageConfiguration) (string, error) {
|
||||
type CreateStorageConfigurationBody struct {
|
||||
@@ -93,7 +94,7 @@ func (c *Client) CreateStorageConfiguration(ctx context.Context, config *Storage
|
||||
return response.Token, nil
|
||||
}
|
||||
|
||||
// ONVIF Specification: SetStorageConfiguration operation.
|
||||
// SetStorageConfiguration sets a storage configuration. ONVIF Specification: SetStorageConfiguration operation.
|
||||
func (c *Client) SetStorageConfiguration(ctx context.Context, config *StorageConfiguration) error {
|
||||
type SetStorageConfigurationBody struct {
|
||||
XMLName xml.Name `xml:"tds:SetStorageConfiguration"`
|
||||
@@ -121,6 +122,7 @@ func (c *Client) SetStorageConfiguration(ctx context.Context, config *StorageCon
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteStorageConfiguration deletes a storage configuration.
|
||||
// ONVIF Specification: DeleteStorageConfiguration operation.
|
||||
func (c *Client) DeleteStorageConfiguration(ctx context.Context, token string) error {
|
||||
type DeleteStorageConfigurationBody struct {
|
||||
@@ -149,7 +151,7 @@ func (c *Client) DeleteStorageConfiguration(ctx context.Context, token string) e
|
||||
return nil
|
||||
}
|
||||
|
||||
// ONVIF Specification: SetHashingAlgorithm operation.
|
||||
// SetHashingAlgorithm sets the hashing algorithm. ONVIF Specification: SetHashingAlgorithm operation.
|
||||
func (c *Client) SetHashingAlgorithm(ctx context.Context, algorithm string) error {
|
||||
type SetHashingAlgorithmBody struct {
|
||||
XMLName xml.Name `xml:"tds:SetHashingAlgorithm"`
|
||||
|
||||
@@ -147,8 +147,8 @@ func TestGetStorageConfigurations(t *testing.T) {
|
||||
t.Errorf("Expected second config token 'storage-002', got '%s'", configs[1].Token)
|
||||
}
|
||||
|
||||
if configs[1].Data.StorageUri != "cifs://nas.local/recordings" {
|
||||
t.Errorf("Expected second config URI 'cifs://nas.local/recordings', got '%s'", configs[1].Data.StorageUri)
|
||||
if configs[1].Data.StorageURI != "cifs://nas.local/recordings" {
|
||||
t.Errorf("Expected second config URI 'cifs://nas.local/recordings', got '%s'", configs[1].Data.StorageURI)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,8 +175,8 @@ func TestGetStorageConfiguration(t *testing.T) {
|
||||
t.Errorf("Expected config path '/var/media/storage1', got '%s'", config.Data.LocalPath)
|
||||
}
|
||||
|
||||
if config.Data.StorageUri != "file:///var/media/storage1" {
|
||||
t.Errorf("Expected config URI 'file:///var/media/storage1', got '%s'", config.Data.StorageUri)
|
||||
if config.Data.StorageURI != "file:///var/media/storage1" {
|
||||
t.Errorf("Expected config URI 'file:///var/media/storage1', got '%s'", config.Data.StorageURI)
|
||||
}
|
||||
|
||||
if config.Data.Type != "NFS" {
|
||||
@@ -198,7 +198,7 @@ func TestCreateStorageConfiguration(t *testing.T) {
|
||||
Token: "storage-new",
|
||||
Data: StorageConfigurationData{
|
||||
LocalPath: "/var/media/storage3",
|
||||
StorageUri: "file:///var/media/storage3",
|
||||
StorageURI: "file:///var/media/storage3",
|
||||
Type: "Local",
|
||||
},
|
||||
}
|
||||
@@ -227,7 +227,7 @@ func TestSetStorageConfiguration(t *testing.T) {
|
||||
Token: "storage-001",
|
||||
Data: StorageConfigurationData{
|
||||
LocalPath: "/var/media/updated",
|
||||
StorageUri: "file:///var/media/updated",
|
||||
StorageURI: "file:///var/media/updated",
|
||||
Type: "NFS",
|
||||
},
|
||||
}
|
||||
|
||||
+8
-7
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/0x524a/onvif-go/internal/soap"
|
||||
)
|
||||
|
||||
// ONVIF Specification: GetDot11Capabilities operation.
|
||||
// GetDot11Capabilities retrieves 802.11 capabilities. ONVIF Specification: GetDot11Capabilities operation.
|
||||
func (c *Client) GetDot11Capabilities(ctx context.Context) (*Dot11Capabilities, error) {
|
||||
type GetDot11CapabilitiesBody struct {
|
||||
XMLName xml.Name `xml:"tds:GetDot11Capabilities"`
|
||||
@@ -35,7 +35,7 @@ func (c *Client) GetDot11Capabilities(ctx context.Context) (*Dot11Capabilities,
|
||||
return response.Capabilities, nil
|
||||
}
|
||||
|
||||
// ONVIF Specification: GetDot11Status operation.
|
||||
// GetDot11Status retrieves 802.11 status. ONVIF Specification: GetDot11Status operation.
|
||||
func (c *Client) GetDot11Status(ctx context.Context, interfaceToken string) (*Dot11Status, error) {
|
||||
type GetDot11StatusBody struct {
|
||||
XMLName xml.Name `xml:"tds:GetDot11Status"`
|
||||
@@ -64,7 +64,7 @@ func (c *Client) GetDot11Status(ctx context.Context, interfaceToken string) (*Do
|
||||
return response.Status, nil
|
||||
}
|
||||
|
||||
// ONVIF Specification: GetDot1XConfiguration operation.
|
||||
// GetDot1XConfiguration retrieves an 802.1X configuration. ONVIF Specification: GetDot1XConfiguration operation.
|
||||
func (c *Client) GetDot1XConfiguration(ctx context.Context, configToken string) (*Dot1XConfiguration, error) {
|
||||
type GetDot1XConfigurationBody struct {
|
||||
XMLName xml.Name `xml:"tds:GetDot1XConfiguration"`
|
||||
@@ -93,7 +93,7 @@ func (c *Client) GetDot1XConfiguration(ctx context.Context, configToken string)
|
||||
return response.Dot1XConfiguration, nil
|
||||
}
|
||||
|
||||
// ONVIF Specification: GetDot1XConfigurations operation.
|
||||
// GetDot1XConfigurations retrieves all 802.1X configurations. ONVIF Specification: GetDot1XConfigurations operation.
|
||||
func (c *Client) GetDot1XConfigurations(ctx context.Context) ([]*Dot1XConfiguration, error) {
|
||||
type GetDot1XConfigurationsBody struct {
|
||||
XMLName xml.Name `xml:"tds:GetDot1XConfigurations"`
|
||||
@@ -120,7 +120,7 @@ func (c *Client) GetDot1XConfigurations(ctx context.Context) ([]*Dot1XConfigurat
|
||||
return response.Dot1XConfiguration, nil
|
||||
}
|
||||
|
||||
// ONVIF Specification: SetDot1XConfiguration operation.
|
||||
// SetDot1XConfiguration sets an 802.1X configuration. ONVIF Specification: SetDot1XConfiguration operation.
|
||||
func (c *Client) SetDot1XConfiguration(ctx context.Context, config *Dot1XConfiguration) error {
|
||||
type SetDot1XConfigurationBody struct {
|
||||
XMLName xml.Name `xml:"tds:SetDot1XConfiguration"`
|
||||
@@ -148,7 +148,7 @@ func (c *Client) SetDot1XConfiguration(ctx context.Context, config *Dot1XConfigu
|
||||
return nil
|
||||
}
|
||||
|
||||
// ONVIF Specification: CreateDot1XConfiguration operation.
|
||||
// CreateDot1XConfiguration creates an 802.1X configuration. ONVIF Specification: CreateDot1XConfiguration operation.
|
||||
func (c *Client) CreateDot1XConfiguration(ctx context.Context, config *Dot1XConfiguration) error {
|
||||
type CreateDot1XConfigurationBody struct {
|
||||
XMLName xml.Name `xml:"tds:CreateDot1XConfiguration"`
|
||||
@@ -176,7 +176,7 @@ func (c *Client) CreateDot1XConfiguration(ctx context.Context, config *Dot1XConf
|
||||
return nil
|
||||
}
|
||||
|
||||
// ONVIF Specification: DeleteDot1XConfiguration operation.
|
||||
// DeleteDot1XConfiguration deletes an 802.1X configuration. ONVIF Specification: DeleteDot1XConfiguration operation.
|
||||
func (c *Client) DeleteDot1XConfiguration(ctx context.Context, configToken string) error {
|
||||
type DeleteDot1XConfigurationBody struct {
|
||||
XMLName xml.Name `xml:"tds:DeleteDot1XConfiguration"`
|
||||
@@ -204,6 +204,7 @@ func (c *Client) DeleteDot1XConfiguration(ctx context.Context, configToken strin
|
||||
return nil
|
||||
}
|
||||
|
||||
// ScanAvailableDot11Networks scans for available 802.11 networks.
|
||||
// ONVIF Specification: ScanAvailableDot11Networks operation.
|
||||
func (c *Client) ScanAvailableDot11Networks(
|
||||
ctx context.Context,
|
||||
|
||||
+10
-4
@@ -14,6 +14,9 @@ import (
|
||||
const (
|
||||
// WS-Discovery multicast address.
|
||||
multicastAddr = "239.255.255.250:3702"
|
||||
// UUID generation constants.
|
||||
uuidMod1000 = 1000
|
||||
uuidMod10000 = 10000
|
||||
|
||||
// WS-Discovery probe message.
|
||||
probeTemplate = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
@@ -136,7 +139,8 @@ func DiscoverWithOptions(ctx context.Context, timeout time.Duration, opts *Disco
|
||||
|
||||
// Collect responses
|
||||
devices := make(map[string]*Device)
|
||||
buffer := make([]byte, 8192)
|
||||
const maxUDPPacketSize = 8192
|
||||
buffer := make([]byte, maxUDPPacketSize)
|
||||
|
||||
// Read responses until timeout or context cancellation
|
||||
for {
|
||||
@@ -225,12 +229,14 @@ func generateUUID() string {
|
||||
return fmt.Sprintf("%d-%d-%d-%d-%d",
|
||||
time.Now().UnixNano(),
|
||||
time.Now().Unix(),
|
||||
time.Now().UnixNano()%1000,
|
||||
time.Now().Unix()%1000,
|
||||
time.Now().UnixNano()%10000)
|
||||
time.Now().UnixNano()%uuidMod1000,
|
||||
time.Now().Unix()%uuidMod1000,
|
||||
time.Now().UnixNano()%uuidMod10000)
|
||||
}
|
||||
|
||||
// resolveNetworkInterface resolves a network interface by name or IP address.
|
||||
//
|
||||
//nolint:gocognit // Network interface resolution has high complexity due to multiple validation paths
|
||||
func resolveNetworkInterface(ifaceSpec string) (*net.Interface, error) {
|
||||
// Try to get interface by name (e.g., "eth0", "wlan0")
|
||||
if iface, err := net.InterfaceByName(ifaceSpec); err == nil {
|
||||
|
||||
@@ -12,6 +12,8 @@ import (
|
||||
const imagingNamespace = "http://www.onvif.org/ver20/imaging/wsdl"
|
||||
|
||||
// GetImagingSettings retrieves imaging settings for a video source.
|
||||
//
|
||||
//nolint:funlen // GetImagingSettings has many statements due to parsing complex imaging settings
|
||||
func (c *Client) GetImagingSettings(ctx context.Context, videoSourceToken string) (*ImagingSettings, error) {
|
||||
endpoint := c.imagingEndpoint
|
||||
if endpoint == "" {
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/sha1"
|
||||
"crypto/sha1" //nolint:gosec // SHA1 used for ONVIF digest authentication
|
||||
"encoding/base64"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
@@ -42,14 +42,14 @@ type Fault struct {
|
||||
|
||||
// Security represents WS-Security header.
|
||||
type Security struct {
|
||||
XMLName xml.Name `xml:"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd Security"`
|
||||
XMLName xml.Name `xml:"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd Security"`
|
||||
MustUnderstand string `xml:"http://www.w3.org/2003/05/soap-envelope mustUnderstand,attr,omitempty"`
|
||||
UsernameToken *UsernameToken `xml:"UsernameToken,omitempty"`
|
||||
}
|
||||
|
||||
// UsernameToken represents a WS-Security username token.
|
||||
type UsernameToken struct {
|
||||
XMLName xml.Name `xml:"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd UsernameToken"`
|
||||
XMLName xml.Name `xml:"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd UsernameToken"`
|
||||
Username string `xml:"Username"`
|
||||
Password Password `xml:"Password"`
|
||||
Nonce Nonce `xml:"Nonce"`
|
||||
@@ -195,7 +195,8 @@ func (c *Client) Call(ctx context.Context, endpoint, action string, request, res
|
||||
// createSecurityHeader creates a WS-Security header with username token digest.
|
||||
func (c *Client) createSecurityHeader() *Security {
|
||||
// Generate nonce
|
||||
nonceBytes := make([]byte, 16)
|
||||
const nonceSize = 16
|
||||
nonceBytes := make([]byte, nonceSize)
|
||||
//nolint:errcheck // rand.Read always returns len(nonceBytes), nil for sufficient entropy
|
||||
_, _ = rand.Read(nonceBytes)
|
||||
nonce := base64.StdEncoding.EncodeToString(nonceBytes)
|
||||
@@ -204,7 +205,7 @@ func (c *Client) createSecurityHeader() *Security {
|
||||
created := time.Now().UTC().Format(time.RFC3339)
|
||||
|
||||
// Calculate password digest: Base64(SHA1(nonce + created + password))
|
||||
hash := sha1.New()
|
||||
hash := sha1.New() //nolint:gosec // SHA1 required for ONVIF digest auth
|
||||
hash.Write(nonceBytes)
|
||||
hash.Write([]byte(created))
|
||||
hash.Write([]byte(c.password))
|
||||
|
||||
@@ -28,6 +28,8 @@ func (c *Client) getMediaSoapClient() *soap.Client {
|
||||
}
|
||||
|
||||
// GetProfiles retrieves all media profiles.
|
||||
//
|
||||
//nolint:funlen // GetProfiles has many statements due to parsing complex profile structures
|
||||
func (c *Client) GetProfiles(ctx context.Context) ([]*Profile, error) {
|
||||
endpoint := c.mediaEndpoint
|
||||
if endpoint == "" {
|
||||
@@ -163,7 +165,7 @@ func (c *Client) GetStreamURI(ctx context.Context, profileToken string) (*MediaU
|
||||
endpoint = c.endpoint
|
||||
}
|
||||
|
||||
type GetStreamUri struct {
|
||||
type GetStreamURI struct {
|
||||
XMLName xml.Name `xml:"trt:GetStreamUri"`
|
||||
Xmlns string `xml:"xmlns:trt,attr"`
|
||||
Xmlnst string `xml:"xmlns:tt,attr"`
|
||||
@@ -176,17 +178,17 @@ func (c *Client) GetStreamURI(ctx context.Context, profileToken string) (*MediaU
|
||||
ProfileToken string `xml:"trt:ProfileToken"`
|
||||
}
|
||||
|
||||
type GetStreamUriResponse struct {
|
||||
type GetStreamURIResponse struct {
|
||||
XMLName xml.Name `xml:"GetStreamUriResponse"`
|
||||
MediaUri struct {
|
||||
Uri string `xml:"Uri"`
|
||||
MediaURI struct {
|
||||
URI string `xml:"Uri"`
|
||||
InvalidAfterConnect bool `xml:"InvalidAfterConnect"`
|
||||
InvalidAfterReboot bool `xml:"InvalidAfterReboot"`
|
||||
Timeout string `xml:"Timeout"`
|
||||
} `xml:"MediaUri"`
|
||||
}
|
||||
|
||||
req := GetStreamUri{
|
||||
req := GetStreamURI{
|
||||
Xmlns: mediaNamespace,
|
||||
Xmlnst: "http://www.onvif.org/ver10/schema",
|
||||
ProfileToken: profileToken,
|
||||
@@ -194,19 +196,19 @@ func (c *Client) GetStreamURI(ctx context.Context, profileToken string) (*MediaU
|
||||
req.StreamSetup.Stream = "RTP-Unicast"
|
||||
req.StreamSetup.Transport.Protocol = "RTSP"
|
||||
|
||||
var resp GetStreamUriResponse
|
||||
var resp GetStreamURIResponse
|
||||
|
||||
username, password := c.GetCredentials()
|
||||
soapClient := soap.NewClient(c.httpClient, username, password)
|
||||
|
||||
if err := soapClient.Call(ctx, endpoint, "", req, &resp); err != nil {
|
||||
return nil, fmt.Errorf("GetStreamUri failed: %w", err)
|
||||
return nil, fmt.Errorf("GetStreamURI failed: %w", err)
|
||||
}
|
||||
|
||||
return &MediaURI{
|
||||
URI: resp.MediaUri.Uri,
|
||||
InvalidAfterConnect: resp.MediaUri.InvalidAfterConnect,
|
||||
InvalidAfterReboot: resp.MediaUri.InvalidAfterReboot,
|
||||
URI: resp.MediaURI.URI,
|
||||
InvalidAfterConnect: resp.MediaURI.InvalidAfterConnect,
|
||||
InvalidAfterReboot: resp.MediaURI.InvalidAfterReboot,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -217,40 +219,40 @@ func (c *Client) GetSnapshotURI(ctx context.Context, profileToken string) (*Medi
|
||||
endpoint = c.endpoint
|
||||
}
|
||||
|
||||
type GetSnapshotUri struct {
|
||||
type GetSnapshotURI struct {
|
||||
XMLName xml.Name `xml:"trt:GetSnapshotUri"`
|
||||
Xmlns string `xml:"xmlns:trt,attr"`
|
||||
ProfileToken string `xml:"trt:ProfileToken"`
|
||||
}
|
||||
|
||||
type GetSnapshotUriResponse struct {
|
||||
type GetSnapshotURIResponse struct {
|
||||
XMLName xml.Name `xml:"GetSnapshotUriResponse"`
|
||||
MediaUri struct {
|
||||
Uri string `xml:"Uri"`
|
||||
MediaURI struct {
|
||||
URI string `xml:"Uri"`
|
||||
InvalidAfterConnect bool `xml:"InvalidAfterConnect"`
|
||||
InvalidAfterReboot bool `xml:"InvalidAfterReboot"`
|
||||
Timeout string `xml:"Timeout"`
|
||||
} `xml:"MediaUri"`
|
||||
}
|
||||
|
||||
req := GetSnapshotUri{
|
||||
req := GetSnapshotURI{
|
||||
Xmlns: mediaNamespace,
|
||||
ProfileToken: profileToken,
|
||||
}
|
||||
|
||||
var resp GetSnapshotUriResponse
|
||||
var resp GetSnapshotURIResponse
|
||||
|
||||
username, password := c.GetCredentials()
|
||||
soapClient := soap.NewClient(c.httpClient, username, password)
|
||||
|
||||
if err := soapClient.Call(ctx, endpoint, "", req, &resp); err != nil {
|
||||
return nil, fmt.Errorf("GetSnapshotUri failed: %w", err)
|
||||
return nil, fmt.Errorf("GetSnapshotURI failed: %w", err)
|
||||
}
|
||||
|
||||
return &MediaURI{
|
||||
URI: resp.MediaUri.Uri,
|
||||
InvalidAfterConnect: resp.MediaUri.InvalidAfterConnect,
|
||||
InvalidAfterReboot: resp.MediaUri.InvalidAfterReboot,
|
||||
URI: resp.MediaURI.URI,
|
||||
InvalidAfterConnect: resp.MediaURI.InvalidAfterConnect,
|
||||
InvalidAfterReboot: resp.MediaURI.InvalidAfterReboot,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -637,7 +639,7 @@ func (c *Client) GetMediaServiceCapabilities(ctx context.Context) (*MediaService
|
||||
type GetServiceCapabilitiesResponse struct {
|
||||
XMLName xml.Name `xml:"GetServiceCapabilitiesResponse"`
|
||||
Capabilities struct {
|
||||
SnapshotUri bool `xml:"SnapshotUri,attr"`
|
||||
SnapshotURI bool `xml:"SnapshotUri,attr"`
|
||||
Rotation bool `xml:"Rotation,attr"`
|
||||
VideoSourceMode bool `xml:"VideoSourceMode,attr"`
|
||||
OSD bool `xml:"OSD,attr"`
|
||||
@@ -648,8 +650,8 @@ func (c *Client) GetMediaServiceCapabilities(ctx context.Context) (*MediaService
|
||||
} `xml:"ProfileCapabilities"`
|
||||
StreamingCapabilities *struct {
|
||||
RTPMulticast bool `xml:"RTPMulticast,attr"`
|
||||
RTP_TCP bool `xml:"RTP_TCP,attr"`
|
||||
RTP_RTSP_TCP bool `xml:"RTP_RTSP_TCP,attr"`
|
||||
RTPTCP bool `xml:"RTP_TCP,attr"`
|
||||
RTPRTSPTCP bool `xml:"RTP_RTSP_TCP,attr"`
|
||||
} `xml:"StreamingCapabilities"`
|
||||
} `xml:"Capabilities"`
|
||||
}
|
||||
@@ -668,7 +670,7 @@ func (c *Client) GetMediaServiceCapabilities(ctx context.Context) (*MediaService
|
||||
}
|
||||
|
||||
caps := &MediaServiceCapabilities{
|
||||
SnapshotUri: resp.Capabilities.SnapshotUri,
|
||||
SnapshotURI: resp.Capabilities.SnapshotURI,
|
||||
Rotation: resp.Capabilities.Rotation,
|
||||
VideoSourceMode: resp.Capabilities.VideoSourceMode,
|
||||
OSD: resp.Capabilities.OSD,
|
||||
@@ -682,14 +684,16 @@ func (c *Client) GetMediaServiceCapabilities(ctx context.Context) (*MediaService
|
||||
|
||||
if resp.Capabilities.StreamingCapabilities != nil {
|
||||
caps.RTPMulticast = resp.Capabilities.StreamingCapabilities.RTPMulticast
|
||||
caps.RTP_TCP = resp.Capabilities.StreamingCapabilities.RTP_TCP
|
||||
caps.RTP_RTSP_TCP = resp.Capabilities.StreamingCapabilities.RTP_RTSP_TCP
|
||||
caps.RTPTCP = resp.Capabilities.StreamingCapabilities.RTPTCP
|
||||
caps.RTPRTSPTCP = resp.Capabilities.StreamingCapabilities.RTPRTSPTCP
|
||||
}
|
||||
|
||||
return caps, nil
|
||||
}
|
||||
|
||||
// GetVideoEncoderConfigurationOptions retrieves available options for video encoder configuration.
|
||||
//
|
||||
//nolint:funlen // GetVideoEncoderConfigurationOptions has many statements due to parsing complex encoder options
|
||||
func (c *Client) GetVideoEncoderConfigurationOptions(ctx context.Context, configurationToken string) (*VideoEncoderConfigurationOptions, error) {
|
||||
endpoint := c.mediaEndpoint
|
||||
if endpoint == "" {
|
||||
|
||||
@@ -74,11 +74,11 @@ func TestGetMediaServiceCapabilities_Bosch(t *testing.T) {
|
||||
if !capabilities.RTPMulticast {
|
||||
t.Error("Expected RTPMulticast=true (Bosch FLEXIDOME)")
|
||||
}
|
||||
if !capabilities.RTP_RTSP_TCP {
|
||||
t.Error("Expected RTP_RTSP_TCP=true (Bosch FLEXIDOME)")
|
||||
if !capabilities.RTPRTSPTCP {
|
||||
t.Error("Expected RTPRTSPTCP=true (Bosch FLEXIDOME)")
|
||||
}
|
||||
if capabilities.SnapshotUri {
|
||||
t.Error("Expected SnapshotUri=false (Bosch FLEXIDOME)")
|
||||
if capabilities.SnapshotURI {
|
||||
t.Error("Expected SnapshotURI=false (Bosch FLEXIDOME)")
|
||||
}
|
||||
if !capabilities.Rotation {
|
||||
t.Error("Expected Rotation=true (Bosch FLEXIDOME)")
|
||||
|
||||
+2
-2
@@ -467,8 +467,8 @@ func TestGetMediaServiceCapabilities(t *testing.T) {
|
||||
t.Fatalf("GetMediaServiceCapabilities() failed: %v", err)
|
||||
}
|
||||
|
||||
if !caps.SnapshotUri {
|
||||
t.Error("Expected SnapshotUri to be true")
|
||||
if !caps.SnapshotURI {
|
||||
t.Error("Expected SnapshotURI to be true")
|
||||
}
|
||||
|
||||
if caps.MaximumNumberOfProfiles != 10 {
|
||||
|
||||
+6
-6
@@ -17,7 +17,7 @@ type GetDeviceInformationResponse struct {
|
||||
Model string `xml:"Model"`
|
||||
FirmwareVersion string `xml:"FirmwareVersion"`
|
||||
SerialNumber string `xml:"SerialNumber"`
|
||||
HardwareId string `xml:"HardwareId"`
|
||||
HardwareID string `xml:"HardwareId"`
|
||||
}
|
||||
|
||||
// GetCapabilitiesResponse represents GetCapabilities response.
|
||||
@@ -110,8 +110,8 @@ type MediaCapabilities struct {
|
||||
// StreamingCapabilities represents streaming capabilities.
|
||||
type StreamingCapabilities struct {
|
||||
RTPMulticast bool `xml:"RTPMulticast,attr"`
|
||||
RTP_TCP bool `xml:"RTP_TCP,attr"`
|
||||
RTP_RTSP_TCP bool `xml:"RTP_RTSP_TCP,attr"`
|
||||
RTPTCP bool `xml:"RTP_TCP,attr"`
|
||||
RTPRTSPTCP bool `xml:"RTP_RTSP_TCP,attr"`
|
||||
}
|
||||
|
||||
// PTZCapabilities represents PTZ service capabilities.
|
||||
@@ -153,7 +153,7 @@ func (s *Server) HandleGetDeviceInformation(body interface{}) (interface{}, erro
|
||||
Model: s.config.DeviceInfo.Model,
|
||||
FirmwareVersion: s.config.DeviceInfo.FirmwareVersion,
|
||||
SerialNumber: s.config.DeviceInfo.SerialNumber,
|
||||
HardwareId: s.config.DeviceInfo.HardwareID,
|
||||
HardwareID: s.config.DeviceInfo.HardwareID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -204,8 +204,8 @@ func (s *Server) HandleGetCapabilities(body interface{}) (interface{}, error) {
|
||||
XAddr: baseURL + "/media_service",
|
||||
StreamingCapabilities: &StreamingCapabilities{
|
||||
RTPMulticast: false,
|
||||
RTP_TCP: true,
|
||||
RTP_RTSP_TCP: true,
|
||||
RTPTCP: true,
|
||||
RTPRTSPTCP: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
+10
-10
@@ -28,7 +28,7 @@ func TestHandleGetDeviceInformation(t *testing.T) {
|
||||
{"Model", deviceResp.Model, config.DeviceInfo.Model},
|
||||
{"FirmwareVersion", deviceResp.FirmwareVersion, config.DeviceInfo.FirmwareVersion},
|
||||
{"SerialNumber", deviceResp.SerialNumber, config.DeviceInfo.SerialNumber},
|
||||
{"HardwareId", deviceResp.HardwareId, config.DeviceInfo.HardwareID},
|
||||
{"HardwareID", deviceResp.HardwareID, config.DeviceInfo.HardwareID},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
@@ -162,7 +162,7 @@ func TestGetDeviceInformationResponseXML(t *testing.T) {
|
||||
Model: "TestModel",
|
||||
FirmwareVersion: "1.0.0",
|
||||
SerialNumber: "SN123",
|
||||
HardwareId: "HW001",
|
||||
HardwareID: "HW001",
|
||||
}
|
||||
|
||||
// Marshal to XML
|
||||
@@ -209,8 +209,8 @@ func TestCapabilitiesStructure(t *testing.T) {
|
||||
XAddr: "http://localhost:8080/onvif/media_service",
|
||||
StreamingCapabilities: &StreamingCapabilities{
|
||||
RTPMulticast: true,
|
||||
RTP_TCP: true,
|
||||
RTP_RTSP_TCP: true,
|
||||
RTPTCP: true,
|
||||
RTPRTSPTCP: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -239,8 +239,8 @@ func TestMediaCapabilitiesStructure(t *testing.T) {
|
||||
XAddr: "http://localhost:8080/onvif/media_service",
|
||||
StreamingCapabilities: &StreamingCapabilities{
|
||||
RTPMulticast: true,
|
||||
RTP_TCP: true,
|
||||
RTP_RTSP_TCP: true,
|
||||
RTPTCP: true,
|
||||
RTPRTSPTCP: true,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -251,10 +251,10 @@ func TestMediaCapabilitiesStructure(t *testing.T) {
|
||||
if !caps.StreamingCapabilities.RTPMulticast {
|
||||
t.Error("RTP Multicast should be supported")
|
||||
}
|
||||
if !caps.StreamingCapabilities.RTP_TCP {
|
||||
if !caps.StreamingCapabilities.RTPTCP {
|
||||
t.Error("RTP TCP should be supported")
|
||||
}
|
||||
if !caps.StreamingCapabilities.RTP_RTSP_TCP {
|
||||
if !caps.StreamingCapabilities.RTPRTSPTCP {
|
||||
t.Error("RTSP should be supported")
|
||||
}
|
||||
}
|
||||
@@ -368,8 +368,8 @@ func TestGetCapabilitiesResponse(t *testing.T) {
|
||||
XAddr: "http://localhost:8080/media",
|
||||
StreamingCapabilities: &StreamingCapabilities{
|
||||
RTPMulticast: true,
|
||||
RTP_TCP: true,
|
||||
RTP_RTSP_TCP: true,
|
||||
RTPTCP: true,
|
||||
RTPRTSPTCP: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -266,6 +266,8 @@ func (s *Server) HandleGetImagingSettings(body interface{}) (interface{}, error)
|
||||
}
|
||||
|
||||
// HandleSetImagingSettings handles SetImagingSettings request.
|
||||
//
|
||||
//nolint:gocyclo // SetImagingSettings has high complexity due to multiple validation and update paths
|
||||
func (s *Server) HandleSetImagingSettings(body interface{}) (interface{}, error) {
|
||||
var req SetImagingSettingsRequest
|
||||
if err := unmarshalBody(body, &req); err != nil {
|
||||
|
||||
+9
-9
@@ -138,12 +138,12 @@ type IPAddress struct {
|
||||
// GetStreamURIResponse represents GetStreamURI response.
|
||||
type GetStreamURIResponse struct {
|
||||
XMLName xml.Name `xml:"http://www.onvif.org/ver10/media/wsdl GetStreamURIResponse"`
|
||||
MediaUri MediaUri `xml:"MediaUri"`
|
||||
MediaURI MediaURI `xml:"MediaUri"`
|
||||
}
|
||||
|
||||
// MediaUri represents a media URI.
|
||||
type MediaUri struct {
|
||||
Uri string `xml:"Uri"`
|
||||
// MediaURI represents a media URI.
|
||||
type MediaURI struct {
|
||||
URI string `xml:"Uri"`
|
||||
InvalidAfterConnect bool `xml:"InvalidAfterConnect"`
|
||||
InvalidAfterReboot bool `xml:"InvalidAfterReboot"`
|
||||
Timeout string `xml:"Timeout"`
|
||||
@@ -152,7 +152,7 @@ type MediaUri struct {
|
||||
// GetSnapshotURIResponse represents GetSnapshotURI response.
|
||||
type GetSnapshotURIResponse struct {
|
||||
XMLName xml.Name `xml:"http://www.onvif.org/ver10/media/wsdl GetSnapshotURIResponse"`
|
||||
MediaUri MediaUri `xml:"MediaUri"`
|
||||
MediaURI MediaURI `xml:"MediaUri"`
|
||||
}
|
||||
|
||||
// GetVideoSourcesResponse represents GetVideoSources response.
|
||||
@@ -287,8 +287,8 @@ func (s *Server) HandleGetStreamURI(body interface{}) (interface{}, error) {
|
||||
}
|
||||
|
||||
return &GetStreamURIResponse{
|
||||
MediaUri: MediaUri{
|
||||
Uri: uri,
|
||||
MediaURI: MediaURI{
|
||||
URI: uri,
|
||||
InvalidAfterConnect: false,
|
||||
InvalidAfterReboot: true,
|
||||
Timeout: "PT60S",
|
||||
@@ -333,8 +333,8 @@ func (s *Server) HandleGetSnapshotURI(body interface{}) (interface{}, error) {
|
||||
host, s.config.Port, s.config.BasePath, req.ProfileToken)
|
||||
|
||||
return &GetSnapshotURIResponse{
|
||||
MediaUri: MediaUri{
|
||||
Uri: uri,
|
||||
MediaURI: MediaURI{
|
||||
URI: uri,
|
||||
InvalidAfterConnect: false,
|
||||
InvalidAfterReboot: true,
|
||||
Timeout: "PT5S",
|
||||
|
||||
@@ -52,15 +52,15 @@ func TestHandleGetStreamURI(t *testing.T) {
|
||||
t.Fatalf("Response is not GetStreamURIResponse, got %T", resp)
|
||||
}
|
||||
|
||||
if streamResp.MediaUri.Uri == "" {
|
||||
if streamResp.MediaURI.URI == "" {
|
||||
t.Error("Stream URI is empty")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// URI should contain stream path
|
||||
if !contains(streamResp.MediaUri.Uri, "rtsp://") {
|
||||
t.Errorf("Invalid stream URI format: %s", streamResp.MediaUri.Uri)
|
||||
if !contains(streamResp.MediaURI.URI, "rtsp://") {
|
||||
t.Errorf("Invalid stream URI format: %s", streamResp.MediaURI.URI)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ func TestHandleGetSnapshotURI(t *testing.T) {
|
||||
t.Fatalf("Response is not GetSnapshotURIResponse, got %T", resp)
|
||||
}
|
||||
|
||||
if snapResp.MediaUri.Uri == "" {
|
||||
if snapResp.MediaURI.URI == "" {
|
||||
t.Error("Snapshot URI is empty")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package soap
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha1"
|
||||
"crypto/sha1" //nolint:gosec // SHA1 used for ONVIF digest authentication
|
||||
"encoding/base64"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
@@ -123,7 +123,7 @@ func (h *Handler) authenticate(envelope *originsoap.Envelope) bool {
|
||||
}
|
||||
|
||||
// Calculate expected digest
|
||||
hash := sha1.New()
|
||||
hash := sha1.New() //nolint:gosec // SHA1 required for ONVIF digest auth
|
||||
hash.Write(nonce)
|
||||
hash.Write([]byte(token.Created))
|
||||
hash.Write([]byte(h.password))
|
||||
|
||||
@@ -228,6 +228,8 @@ type WDRSettings struct {
|
||||
}
|
||||
|
||||
// DefaultConfig returns a default server configuration with a multi-lens camera setup.
|
||||
//
|
||||
//nolint:funlen // DefaultConfig has many statements due to comprehensive default configuration
|
||||
func DefaultConfig() *Config {
|
||||
return &Config{
|
||||
Host: "0.0.0.0",
|
||||
|
||||
@@ -35,7 +35,7 @@ type CameraCapture struct {
|
||||
|
||||
// LoadCaptureFromArchive loads all captured exchanges from a tar.gz archive.
|
||||
func LoadCaptureFromArchive(archivePath string) (*CameraCapture, error) {
|
||||
file, err := os.Open(archivePath)
|
||||
file, err := os.Open(archivePath) //nolint:gosec // File path is from test data, safe
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to open archive: %w", err)
|
||||
}
|
||||
|
||||
@@ -106,12 +106,12 @@ type SecurityCapabilities struct {
|
||||
// StreamingCapabilities represents streaming capabilities.
|
||||
type StreamingCapabilities struct {
|
||||
RTPMulticast bool
|
||||
RTP_TCP bool
|
||||
RTP_RTSP_TCP bool
|
||||
RTPTCP bool
|
||||
RTPRTSPTCP bool
|
||||
Extension *StreamingCapabilitiesExtension
|
||||
}
|
||||
|
||||
// Extension types.
|
||||
// CapabilitiesExtension represents extension types for capabilities.
|
||||
type CapabilitiesExtension struct{}
|
||||
type NetworkCapabilitiesExtension struct{}
|
||||
type SystemCapabilitiesExtension struct{}
|
||||
@@ -324,7 +324,7 @@ type ProfileExtension struct{}
|
||||
|
||||
// MediaServiceCapabilities represents media service capabilities.
|
||||
type MediaServiceCapabilities struct {
|
||||
SnapshotUri bool
|
||||
SnapshotURI bool
|
||||
Rotation bool
|
||||
VideoSourceMode bool
|
||||
OSD bool
|
||||
@@ -332,8 +332,8 @@ type MediaServiceCapabilities struct {
|
||||
EXICompression bool
|
||||
MaximumNumberOfProfiles int
|
||||
RTPMulticast bool
|
||||
RTP_TCP bool
|
||||
RTP_RTSP_TCP bool
|
||||
RTPTCP bool
|
||||
RTPRTSPTCP bool
|
||||
}
|
||||
|
||||
// VideoEncoderConfigurationOptions represents available options for video encoder configuration.
|
||||
@@ -995,15 +995,15 @@ type SupportInformation struct {
|
||||
String string
|
||||
}
|
||||
|
||||
// SystemLogUriList represents system log URIs.
|
||||
type SystemLogUriList struct {
|
||||
SystemLog []SystemLogUri
|
||||
// SystemLogURIList represents system log URIs.
|
||||
type SystemLogURIList struct {
|
||||
SystemLog []SystemLogURI
|
||||
}
|
||||
|
||||
// SystemLogUri represents system log URI.
|
||||
type SystemLogUri struct {
|
||||
// SystemLogURI represents system log URI.
|
||||
type SystemLogURI struct {
|
||||
Type SystemLogType
|
||||
Uri string
|
||||
URI string
|
||||
}
|
||||
|
||||
// NetworkZeroConfiguration represents zero-configuration.
|
||||
@@ -1187,7 +1187,7 @@ type StorageConfiguration struct {
|
||||
type StorageConfigurationData struct {
|
||||
Type string
|
||||
LocalPath string
|
||||
StorageUri string
|
||||
StorageURI string
|
||||
User *UserCredential
|
||||
CertPathValidationPolicyID string
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user