Refactor XML response handling in device extended and security tests
- Adjusted formatting in XML response strings for consistency in device_extended_test.go and device_security_test.go. - Improved readability by aligning XML declaration and body content. - Updated mock server responses to ensure proper handling of various ONVIF operations. Enhance device security and storage handling - Refactored struct field declarations in device_security.go and device_storage_test.go for improved clarity. - Ensured consistent formatting across struct definitions and XML tags. Standardize whitespace and formatting across multiple files - Removed unnecessary blank lines and adjusted indentation in discovery, imaging, media, and PTZ server files. - Improved overall code readability and maintainability by ensuring consistent formatting. Update example applications for better readability - Cleaned up whitespace in example applications to enhance code clarity. - Ensured consistent formatting in main.go files across various examples. Refactor server and SOAP handler code for consistency - Standardized struct field declarations and XML tag formatting in server and SOAP handler files. - Improved readability by aligning struct fields and ensuring consistent use of whitespace. General code cleanup and formatting adjustments - Applied consistent formatting across various files, including types.go and test files. - Enhanced readability by aligning struct fields and removing unnecessary blank lines.
This commit is contained in:
+18
-18
@@ -18,15 +18,15 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@d632cb752374ac6c22015e4b4bef1d19db85d69f # v4.2.0
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@0a12ed9d6470c3512128ab8f076f97fbbff3da52 # v5.0.1
|
||||||
with:
|
with:
|
||||||
go-version: '1.23'
|
go-version: '1.23'
|
||||||
|
|
||||||
- name: Cache Go modules
|
- name: Cache Go modules
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
|
||||||
with:
|
with:
|
||||||
path: ~/go/pkg/mod
|
path: ~/go/pkg/mod
|
||||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||||
@@ -45,7 +45,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Lint
|
- name: Lint
|
||||||
uses: golangci/golangci-lint-action@v4
|
uses: golangci/golangci-lint-action@3cfe3a4ac716397848d91e4042119f51a40b6aaf # v4.0.0
|
||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
args: --timeout=5m --fix=false
|
args: --timeout=5m --fix=false
|
||||||
@@ -58,15 +58,15 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@d632cb752374ac6c22015e4b4bef1d19db85d69f # v4.2.0
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@0a12ed9d6470c3512128ab8f076f97fbbff3da52 # v5.0.1
|
||||||
with:
|
with:
|
||||||
go-version: '1.23'
|
go-version: '1.23'
|
||||||
|
|
||||||
- name: Cache Go modules
|
- name: Cache Go modules
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
|
||||||
with:
|
with:
|
||||||
path: ~/go/pkg/mod
|
path: ~/go/pkg/mod
|
||||||
key: ${{ runner.os }}-go-1.23-${{ hashFiles('**/go.sum') }}
|
key: ${{ runner.os }}-go-1.23-${{ hashFiles('**/go.sum') }}
|
||||||
@@ -83,7 +83,7 @@ jobs:
|
|||||||
run: go tool cover -html=coverage.out -o coverage.html
|
run: go tool cover -html=coverage.out -o coverage.html
|
||||||
|
|
||||||
- name: Upload coverage to Codecov
|
- name: Upload coverage to Codecov
|
||||||
uses: codecov/codecov-action@v4
|
uses: codecov/codecov-action@8a4b2d1c64a2a31fb92d9fa9f1e2b02e35d2db1a # v4.0.1
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.CODECOV_TOKEN }}
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
files: ./coverage.out
|
files: ./coverage.out
|
||||||
@@ -93,7 +93,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Archive coverage
|
- name: Archive coverage
|
||||||
if: always()
|
if: always()
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@89ef406dd8d8a50a2f1e5e903c0e970c27a27de8 # v4.3.5
|
||||||
with:
|
with:
|
||||||
name: coverage-report
|
name: coverage-report
|
||||||
path: |
|
path: |
|
||||||
@@ -119,15 +119,15 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@d632cb752374ac6c22015e4b4bef1d19db85d69f # v4.2.0
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@0a12ed9d6470c3512128ab8f076f97fbbff3da52 # v5.0.1
|
||||||
with:
|
with:
|
||||||
go-version: ${{ matrix.go-version }}
|
go-version: ${{ matrix.go-version }}
|
||||||
|
|
||||||
- name: Cache Go modules
|
- name: Cache Go modules
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.cache/go-build
|
~/.cache/go-build
|
||||||
@@ -151,17 +151,17 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@d632cb752374ac6c22015e4b4bef1d19db85d69f # v4.2.0
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Download coverage from test job
|
- name: Download coverage from test job
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
|
||||||
with:
|
with:
|
||||||
name: coverage-report
|
name: coverage-report
|
||||||
|
|
||||||
- name: SonarCloud Scan
|
- name: SonarCloud Scan
|
||||||
uses: SonarSource/sonarcloud-github-action@master
|
uses: SonarSource/sonarcloud-github-action@3b335e14ab49358d133eef17b8c1590fe7c21c0e # v2.2.0
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||||
@@ -179,15 +179,15 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@d632cb752374ac6c22015e4b4bef1d19db85d69f # v4.2.0
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@0a12ed9d6470c3512128ab8f076f97fbbff3da52 # v5.0.1
|
||||||
with:
|
with:
|
||||||
go-version: '1.23'
|
go-version: '1.23'
|
||||||
|
|
||||||
- name: Cache Go modules
|
- name: Cache Go modules
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
|
||||||
with:
|
with:
|
||||||
path: ~/go/pkg/mod
|
path: ~/go/pkg/mod
|
||||||
key: ${{ runner.os }}-go-1.23-${{ hashFiles('**/go.sum') }}
|
key: ${{ runner.os }}-go-1.23-${{ hashFiles('**/go.sum') }}
|
||||||
|
|||||||
@@ -15,10 +15,10 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@d632cb752374ac6c22015e4b4bef1d19db85d69f # v4.2.0
|
||||||
|
|
||||||
- name: Download artifacts
|
- name: Download artifacts
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
|
||||||
with:
|
with:
|
||||||
name: coverage-report
|
name: coverage-report
|
||||||
|
|
||||||
|
|||||||
@@ -39,12 +39,12 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@d632cb752374ac6c22015e4b4bef1d19db85d69f # v4.2.0
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@0a12ed9d6470c3512128ab8f076f97fbbff3da52 # v5.0.1
|
||||||
with:
|
with:
|
||||||
go-version: '1.21'
|
go-version: '1.21'
|
||||||
|
|
||||||
@@ -142,12 +142,12 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@d632cb752374ac6c22015e4b4bef1d19db85d69f # v4.2.0
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Download all artifacts
|
- name: Download all artifacts
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
|
||||||
with:
|
with:
|
||||||
path: all-releases
|
path: all-releases
|
||||||
pattern: release-*
|
pattern: release-*
|
||||||
@@ -177,7 +177,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Create Release
|
- name: Create Release
|
||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@c062e08bd532815e2082a85e87e3ef29c3e6d191 # v2.0.8
|
||||||
with:
|
with:
|
||||||
files: all-releases/*
|
files: all-releases/*
|
||||||
draft: true
|
draft: true
|
||||||
@@ -228,23 +228,23 @@ jobs:
|
|||||||
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
|
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@d632cb752374ac6c22015e4b4bef1d19db85d69f # v4.2.0
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v3
|
uses: docker/setup-qemu-action@49b3bc8e6f341ff684fb5300544cda1ff1a290d5 # v3.2.0
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@4fd812986e6c8ec69f87869bf8f84174f3426a6d # v3.4.0
|
||||||
|
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1b4ee7e33440 # v3.3.0
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1b4ee7e33440 # v3.3.0
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
@@ -255,7 +255,7 @@ jobs:
|
|||||||
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
|
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@5f63d2b5a0f13e6fe58a2658b1cf779280e04def # v6.2.0
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
platforms: linux/amd64,linux/arm64,linux/arm/v7
|
platforms: linux/amd64,linux/arm64,linux/arm/v7
|
||||||
|
|||||||
@@ -18,15 +18,15 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@d632cb752374ac6c22015e4b4bef1d19db85d69f # v4.2.0
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@0a12ed9d6470c3512128ab8f076f97fbbff3da52 # v5.0.1
|
||||||
with:
|
with:
|
||||||
go-version: ${{ matrix.go-version }}
|
go-version: ${{ matrix.go-version }}
|
||||||
|
|
||||||
- name: Cache Go modules
|
- name: Cache Go modules
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
|
||||||
with:
|
with:
|
||||||
path: ~/go/pkg/mod
|
path: ~/go/pkg/mod
|
||||||
key: ${{ runner.os }}-go-${{ matrix.go-version }}-${{ hashFiles('**/go.sum') }}
|
key: ${{ runner.os }}-go-${{ matrix.go-version }}-${{ hashFiles('**/go.sum') }}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ type Client struct {
|
|||||||
password string
|
password string
|
||||||
httpClient *http.Client
|
httpClient *http.Client
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
|
|
||||||
// Service endpoints
|
// Service endpoints
|
||||||
mediaEndpoint string
|
mediaEndpoint string
|
||||||
ptzEndpoint string
|
ptzEndpoint string
|
||||||
@@ -130,7 +130,7 @@ func normalizeEndpoint(endpoint string) (string, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("invalid IP address or hostname: %w", err)
|
return "", fmt.Errorf("invalid IP address or hostname: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if parsedURL.Host == "" {
|
if parsedURL.Host == "" {
|
||||||
return "", fmt.Errorf("invalid endpoint format")
|
return "", fmt.Errorf("invalid endpoint format")
|
||||||
}
|
}
|
||||||
@@ -497,4 +497,3 @@ func generateNonce() string {
|
|||||||
// Generate a simple nonce
|
// Generate a simple nonce
|
||||||
return fmt.Sprintf("%d", time.Now().UnixNano())
|
return fmt.Sprintf("%d", time.Now().UnixNano())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+28
-28
@@ -95,19 +95,19 @@ func TestNormalizeEndpoint(t *testing.T) {
|
|||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
result, err := normalizeEndpoint(tt.input)
|
result, err := normalizeEndpoint(tt.input)
|
||||||
|
|
||||||
if tt.wantErr {
|
if tt.wantErr {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("normalizeEndpoint() expected error but got none")
|
t.Errorf("normalizeEndpoint() expected error but got none")
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("normalizeEndpoint() unexpected error: %v", err)
|
t.Errorf("normalizeEndpoint() unexpected error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if result != tt.expected {
|
if result != tt.expected {
|
||||||
t.Errorf("normalizeEndpoint() = %v, want %v", result, tt.expected)
|
t.Errorf("normalizeEndpoint() = %v, want %v", result, tt.expected)
|
||||||
}
|
}
|
||||||
@@ -453,7 +453,7 @@ func TestGetDeviceInformationWithMockServer(t *testing.T) {
|
|||||||
// Return empty response - will cause EOF error which is expected for now
|
// Return empty response - will cause EOF error which is expected for now
|
||||||
}))
|
}))
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
client, err := NewClient(
|
client, err := NewClient(
|
||||||
server.URL,
|
server.URL,
|
||||||
WithCredentials("admin", "password"),
|
WithCredentials("admin", "password"),
|
||||||
@@ -461,14 +461,14 @@ func TestGetDeviceInformationWithMockServer(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("NewClient() failed: %v", err)
|
t.Fatalf("NewClient() failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
_, err = client.GetDeviceInformation(ctx)
|
_, err = client.GetDeviceInformation(ctx)
|
||||||
// We expect an error since we're not returning valid SOAP
|
// We expect an error since we're not returning valid SOAP
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected error with empty response, but got none")
|
t.Errorf("Expected error with empty response, but got none")
|
||||||
}
|
}
|
||||||
|
|
||||||
// This test just verifies the client can be created and make requests
|
// This test just verifies the client can be created and make requests
|
||||||
t.Logf("Expected error occurred: %v", err)
|
t.Logf("Expected error occurred: %v", err)
|
||||||
}
|
}
|
||||||
@@ -479,18 +479,18 @@ func TestGetDeviceInformationWithAuth(t *testing.T) {
|
|||||||
w.WriteHeader(http.StatusUnauthorized)
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
}))
|
}))
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
client, err := NewClient(server.URL)
|
client, err := NewClient(server.URL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("NewClient() failed: %v", err)
|
t.Fatalf("NewClient() failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
_, err = client.GetDeviceInformation(ctx)
|
_, err = client.GetDeviceInformation(ctx)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected authentication error, but got none")
|
t.Errorf("Expected authentication error, but got none")
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Logf("Authentication error (expected): %v", err)
|
t.Logf("Authentication error (expected): %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -504,16 +504,16 @@ func TestInitializeEndpointDiscovery(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("NewClient() failed: %v", err)
|
t.Fatalf("NewClient() failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
err = client.Initialize(ctx)
|
err = client.Initialize(ctx)
|
||||||
// We expect this to fail due to network timeout
|
// We expect this to fail due to network timeout
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected network error, but got none")
|
t.Errorf("Expected network error, but got none")
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Logf("Network error (expected): %v", err)
|
t.Logf("Network error (expected): %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -525,21 +525,21 @@ func TestGetProfilesRequiresInitialization(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("NewClient() failed: %v", err)
|
t.Fatalf("NewClient() failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
_, err = client.GetProfiles(ctx)
|
_, err = client.GetProfiles(ctx)
|
||||||
// Should fail because Initialize was not called
|
// Should fail because Initialize was not called
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected error when GetProfiles called without Initialize")
|
t.Errorf("Expected error when GetProfiles called without Initialize")
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Logf("Expected error: %v", err)
|
t.Logf("Expected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContextTimeout(t *testing.T) {
|
func TestContextTimeout(t *testing.T) {
|
||||||
mock := NewMockONVIFServer()
|
mock := NewMockONVIFServer()
|
||||||
defer mock.Close()
|
defer mock.Close()
|
||||||
|
|
||||||
client, err := NewClient(
|
client, err := NewClient(
|
||||||
mock.URL(),
|
mock.URL(),
|
||||||
WithCredentials("admin", "password"),
|
WithCredentials("admin", "password"),
|
||||||
@@ -547,17 +547,17 @@ func TestContextTimeout(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("NewClient() failed: %v", err)
|
t.Fatalf("NewClient() failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create context with very short timeout
|
// Create context with very short timeout
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond)
|
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// This should timeout
|
// This should timeout
|
||||||
_, err = client.GetDeviceInformation(ctx)
|
_, err = client.GetDeviceInformation(ctx)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected timeout error, but got none")
|
t.Errorf("Expected timeout error, but got none")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !strings.Contains(err.Error(), "context deadline exceeded") {
|
if !strings.Contains(err.Error(), "context deadline exceeded") {
|
||||||
t.Errorf("Expected context deadline exceeded error, got: %v", err)
|
t.Errorf("Expected context deadline exceeded error, got: %v", err)
|
||||||
}
|
}
|
||||||
@@ -598,7 +598,7 @@ func BenchmarkNewClient(b *testing.B) {
|
|||||||
func BenchmarkGetDeviceInformation(b *testing.B) {
|
func BenchmarkGetDeviceInformation(b *testing.B) {
|
||||||
mock := NewMockONVIFServer()
|
mock := NewMockONVIFServer()
|
||||||
defer mock.Close()
|
defer mock.Close()
|
||||||
|
|
||||||
client, err := NewClient(
|
client, err := NewClient(
|
||||||
mock.URL(),
|
mock.URL(),
|
||||||
WithCredentials("admin", "password"),
|
WithCredentials("admin", "password"),
|
||||||
@@ -606,9 +606,9 @@ func BenchmarkGetDeviceInformation(b *testing.B) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("NewClient() failed: %v", err)
|
b.Fatalf("NewClient() failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_, err := client.GetDeviceInformation(ctx)
|
_, err := client.GetDeviceInformation(ctx)
|
||||||
@@ -629,24 +629,24 @@ func ExampleClient_GetDeviceInformation() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get device information
|
// Get device information
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
info, err := client.GetDeviceInformation(ctx)
|
info, err := client.GetDeviceInformation(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Camera: %s %s\n", info.Manufacturer, info.Model)
|
fmt.Printf("Camera: %s %s\n", info.Manufacturer, info.Model)
|
||||||
fmt.Printf("Firmware: %s\n", info.FirmwareVersion)
|
fmt.Printf("Firmware: %s\n", info.FirmwareVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFixLocalhostURL(t *testing.T) {
|
func TestFixLocalhostURL(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
clientURL string
|
clientURL string
|
||||||
serviceURL string
|
serviceURL string
|
||||||
expectedURL string
|
expectedURL string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "localhost hostname",
|
name: "localhost hostname",
|
||||||
|
|||||||
@@ -11,10 +11,10 @@ import (
|
|||||||
|
|
||||||
// ASCIIConfig controls ASCII art generation parameters
|
// ASCIIConfig controls ASCII art generation parameters
|
||||||
type ASCIIConfig struct {
|
type ASCIIConfig struct {
|
||||||
Width int // Output width in characters
|
Width int // Output width in characters
|
||||||
Height int // Output height in characters
|
Height int // Output height in characters
|
||||||
Invert bool // Invert brightness
|
Invert bool // Invert brightness
|
||||||
Quality string // "high", "medium", "low"
|
Quality string // "high", "medium", "low"
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultASCIIConfig returns a sensible default configuration
|
// DefaultASCIIConfig returns a sensible default configuration
|
||||||
@@ -31,18 +31,18 @@ func DefaultASCIIConfig() ASCIIConfig {
|
|||||||
var (
|
var (
|
||||||
// Full charset with many shades
|
// Full charset with many shades
|
||||||
charsetFull = []rune{' ', '.', ':', '-', '=', '+', '*', '#', '%', '@'}
|
charsetFull = []rune{' ', '.', ':', '-', '=', '+', '*', '#', '%', '@'}
|
||||||
|
|
||||||
// Medium charset - balanced
|
// Medium charset - balanced
|
||||||
charsetMedium = []rune{' ', '.', '-', '=', '+', '#', '@'}
|
charsetMedium = []rune{' ', '.', '-', '=', '+', '#', '@'}
|
||||||
|
|
||||||
// Simple charset - just a few chars
|
// Simple charset - just a few chars
|
||||||
charsetSimple = []rune{' ', '-', '#', '@'}
|
charsetSimple = []rune{' ', '-', '#', '@'}
|
||||||
|
|
||||||
// Block charset - using block characters
|
// Block charset - using block characters
|
||||||
charsetBlock = []rune{' ', '░', '▒', '▓', '█'}
|
charsetBlock = []rune{' ', '░', '▒', '▓', '█'}
|
||||||
|
|
||||||
// Detailed charset
|
// Detailed charset
|
||||||
charsetDetailed = []rune{' ', '`', '.', ',', ':', ';', '!', 'i', 'l', 'I',
|
charsetDetailed = []rune{' ', '`', '.', ',', ':', ';', '!', 'i', 'l', 'I',
|
||||||
'o', 'O', '0', 'e', 'E', 'p', 'P', 'x', 'X', '$', 'D', 'W', 'M', '@', '#'}
|
'o', 'O', '0', 'e', 'E', 'p', 'P', 'x', 'X', '$', 'D', 'W', 'M', '@', '#'}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+32
-32
@@ -101,7 +101,7 @@ func (c *CLI) discoverCameras() {
|
|||||||
// Try auto-discovery first (no specific interface)
|
// Try auto-discovery first (no specific interface)
|
||||||
fmt.Println("⏳ Attempting auto-discovery on default interface...")
|
fmt.Println("⏳ Attempting auto-discovery on default interface...")
|
||||||
devices, err := discovery.DiscoverWithOptions(ctx, 5*time.Second, &discovery.DiscoverOptions{})
|
devices, err := discovery.DiscoverWithOptions(ctx, 5*time.Second, &discovery.DiscoverOptions{})
|
||||||
|
|
||||||
// If auto-discovery fails or finds nothing, offer interface selection
|
// If auto-discovery fails or finds nothing, offer interface selection
|
||||||
if err != nil || len(devices) == 0 {
|
if err != nil || len(devices) == 0 {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -109,11 +109,11 @@ func (c *CLI) discoverCameras() {
|
|||||||
} else {
|
} else {
|
||||||
fmt.Println("⚠️ No cameras found on default interface")
|
fmt.Println("⚠️ No cameras found on default interface")
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
fmt.Println("💡 Trying specific network interfaces...")
|
fmt.Println("💡 Trying specific network interfaces...")
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
|
|
||||||
// Get available interfaces and let user select
|
// Get available interfaces and let user select
|
||||||
devices, err = c.discoverWithInterfaceSelection()
|
devices, err = c.discoverWithInterfaceSelection()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -139,17 +139,17 @@ func (c *CLI) discoverCameras() {
|
|||||||
for i, device := range devices {
|
for i, device := range devices {
|
||||||
fmt.Printf("📹 Camera #%d:\n", i+1)
|
fmt.Printf("📹 Camera #%d:\n", i+1)
|
||||||
fmt.Printf(" Endpoint: %s\n", device.GetDeviceEndpoint())
|
fmt.Printf(" Endpoint: %s\n", device.GetDeviceEndpoint())
|
||||||
|
|
||||||
name := device.GetName()
|
name := device.GetName()
|
||||||
if name != "" {
|
if name != "" {
|
||||||
fmt.Printf(" Name: %s\n", name)
|
fmt.Printf(" Name: %s\n", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
location := device.GetLocation()
|
location := device.GetLocation()
|
||||||
if location != "" {
|
if location != "" {
|
||||||
fmt.Printf(" Location: %s\n", location)
|
fmt.Printf(" Location: %s\n", location)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf(" Types: %v\n", device.Types)
|
fmt.Printf(" Types: %v\n", device.Types)
|
||||||
fmt.Printf(" XAddrs: %v\n", device.XAddrs)
|
fmt.Printf(" XAddrs: %v\n", device.XAddrs)
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
@@ -280,16 +280,16 @@ func (c *CLI) selectAndConnectCamera(devices []*discovery.Device) {
|
|||||||
|
|
||||||
func (c *CLI) connectToDiscoveredCamera(device *discovery.Device) {
|
func (c *CLI) connectToDiscoveredCamera(device *discovery.Device) {
|
||||||
endpoint := device.GetDeviceEndpoint()
|
endpoint := device.GetDeviceEndpoint()
|
||||||
|
|
||||||
fmt.Printf("Connecting to: %s\n", endpoint)
|
fmt.Printf("Connecting to: %s\n", endpoint)
|
||||||
|
|
||||||
// Warn if using HTTPS
|
// Warn if using HTTPS
|
||||||
if strings.HasPrefix(endpoint, "https://") {
|
if strings.HasPrefix(endpoint, "https://") {
|
||||||
fmt.Println("⚠️ HTTPS endpoint detected - you may need to skip TLS verification for self-signed certificates")
|
fmt.Println("⚠️ HTTPS endpoint detected - you may need to skip TLS verification for self-signed certificates")
|
||||||
}
|
}
|
||||||
|
|
||||||
username := c.readInputWithDefault("Username", "admin")
|
username := c.readInputWithDefault("Username", "admin")
|
||||||
|
|
||||||
fmt.Print("Password: ")
|
fmt.Print("Password: ")
|
||||||
password, _ := c.reader.ReadString('\n')
|
password, _ := c.reader.ReadString('\n')
|
||||||
password = strings.TrimSpace(password)
|
password = strings.TrimSpace(password)
|
||||||
@@ -309,14 +309,14 @@ func (c *CLI) connectToCamera() {
|
|||||||
fmt.Println("===================")
|
fmt.Println("===================")
|
||||||
|
|
||||||
endpoint := c.readInputWithDefault("Camera endpoint (http://ip:port/onvif/device_service)", "http://192.168.1.100/onvif/device_service")
|
endpoint := c.readInputWithDefault("Camera endpoint (http://ip:port/onvif/device_service)", "http://192.168.1.100/onvif/device_service")
|
||||||
|
|
||||||
// Warn if using HTTPS
|
// Warn if using HTTPS
|
||||||
if strings.HasPrefix(endpoint, "https://") {
|
if strings.HasPrefix(endpoint, "https://") {
|
||||||
fmt.Println("⚠️ HTTPS endpoint detected - you may need to skip TLS verification for self-signed certificates")
|
fmt.Println("⚠️ HTTPS endpoint detected - you may need to skip TLS verification for self-signed certificates")
|
||||||
}
|
}
|
||||||
|
|
||||||
username := c.readInputWithDefault("Username", "admin")
|
username := c.readInputWithDefault("Username", "admin")
|
||||||
|
|
||||||
fmt.Print("Password: ")
|
fmt.Print("Password: ")
|
||||||
password, _ := c.reader.ReadString('\n')
|
password, _ := c.reader.ReadString('\n')
|
||||||
password = strings.TrimSpace(password)
|
password = strings.TrimSpace(password)
|
||||||
@@ -442,7 +442,7 @@ func (c *CLI) getCapabilities(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("✅ Device Capabilities:")
|
fmt.Println("✅ Device Capabilities:")
|
||||||
|
|
||||||
if caps.Device != nil {
|
if caps.Device != nil {
|
||||||
fmt.Printf(" ✓ Device Service\n")
|
fmt.Printf(" ✓ Device Service\n")
|
||||||
}
|
}
|
||||||
@@ -582,11 +582,11 @@ func (c *CLI) inspectRTSPStream(streamURI string) map[string]interface{} {
|
|||||||
if firstVideo := streamInfo.GetFirstVideoMedia(); firstVideo != nil {
|
if firstVideo := streamInfo.GetFirstVideoMedia(); firstVideo != nil {
|
||||||
// Get codec format (H264, H265, MJPEG, etc.)
|
// Get codec format (H264, H265, MJPEG, etc.)
|
||||||
details["codec"] = firstVideo.Format
|
details["codec"] = firstVideo.Format
|
||||||
|
|
||||||
// Extract resolution directly from the video media
|
// Extract resolution directly from the video media
|
||||||
if firstVideo.Resolution != nil {
|
if firstVideo.Resolution != nil {
|
||||||
details["resolution"] = fmt.Sprintf("%dx%d",
|
details["resolution"] = fmt.Sprintf("%dx%d",
|
||||||
firstVideo.Resolution.Width,
|
firstVideo.Resolution.Width,
|
||||||
firstVideo.Resolution.Height)
|
firstVideo.Resolution.Height)
|
||||||
} else {
|
} else {
|
||||||
// Fallback to resolution strings
|
// Fallback to resolution strings
|
||||||
@@ -673,7 +673,7 @@ func (c *CLI) getStreamURIs(ctx context.Context) {
|
|||||||
fmt.Printf(" Stream URI: ❌ Error - %v\n", err)
|
fmt.Printf(" Stream URI: ❌ Error - %v\n", err)
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf(" Stream URI: %s\n", streamURI.URI)
|
fmt.Printf(" Stream URI: %s\n", streamURI.URI)
|
||||||
|
|
||||||
// Warn if camera returns HTTPS when we connected via HTTP
|
// Warn if camera returns HTTPS when we connected via HTTP
|
||||||
if strings.HasPrefix(c.client.Endpoint(), "http://") && strings.HasPrefix(streamURI.URI, "https://") {
|
if strings.HasPrefix(c.client.Endpoint(), "http://") && strings.HasPrefix(streamURI.URI, "https://") {
|
||||||
fmt.Printf(" ⚠️ WARNING: Camera returned HTTPS URL but you connected via HTTP\n")
|
fmt.Printf(" ⚠️ WARNING: Camera returned HTTPS URL but you connected via HTTP\n")
|
||||||
@@ -735,14 +735,14 @@ func (c *CLI) getSnapshotURIs(ctx context.Context) {
|
|||||||
fmt.Printf(" Snapshot URI: ❌ Error - %v\n", err)
|
fmt.Printf(" Snapshot URI: ❌ Error - %v\n", err)
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf(" Snapshot URI: %s\n", snapshotURI.URI)
|
fmt.Printf(" Snapshot URI: %s\n", snapshotURI.URI)
|
||||||
|
|
||||||
// Warn if camera returns HTTPS when we connected via HTTP
|
// Warn if camera returns HTTPS when we connected via HTTP
|
||||||
if strings.HasPrefix(c.client.Endpoint(), "http://") && strings.HasPrefix(snapshotURI.URI, "https://") {
|
if strings.HasPrefix(c.client.Endpoint(), "http://") && strings.HasPrefix(snapshotURI.URI, "https://") {
|
||||||
fmt.Printf(" ⚠️ WARNING: Camera returned HTTPS URL but you connected via HTTP\n")
|
fmt.Printf(" ⚠️ WARNING: Camera returned HTTPS URL but you connected via HTTP\n")
|
||||||
fmt.Printf(" 💡 Snapshot may fail due to TLS certificate issues\n")
|
fmt.Printf(" 💡 Snapshot may fail due to TLS certificate issues\n")
|
||||||
fmt.Printf(" 💡 Consider reconnecting with https:// endpoint and skip TLS verification\n")
|
fmt.Printf(" 💡 Consider reconnecting with https:// endpoint and skip TLS verification\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf(" 🌐 Open this URL in a browser to see the snapshot\n")
|
fmt.Printf(" 🌐 Open this URL in a browser to see the snapshot\n")
|
||||||
}
|
}
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
@@ -792,13 +792,13 @@ func (c *CLI) getVideoEncoderConfig(ctx context.Context) {
|
|||||||
fmt.Printf(" Token: %s\n", config.Token)
|
fmt.Printf(" Token: %s\n", config.Token)
|
||||||
fmt.Printf(" Use Count: %d\n", config.UseCount)
|
fmt.Printf(" Use Count: %d\n", config.UseCount)
|
||||||
fmt.Printf(" Encoding: %s\n", config.Encoding)
|
fmt.Printf(" Encoding: %s\n", config.Encoding)
|
||||||
|
|
||||||
if config.Resolution != nil {
|
if config.Resolution != nil {
|
||||||
fmt.Printf(" Resolution: %dx%d\n", config.Resolution.Width, config.Resolution.Height)
|
fmt.Printf(" Resolution: %dx%d\n", config.Resolution.Width, config.Resolution.Height)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf(" Quality: %.1f\n", config.Quality)
|
fmt.Printf(" Quality: %.1f\n", config.Quality)
|
||||||
|
|
||||||
if config.RateControl != nil {
|
if config.RateControl != nil {
|
||||||
fmt.Printf(" Frame Rate Limit: %d\n", config.RateControl.FrameRateLimit)
|
fmt.Printf(" Frame Rate Limit: %d\n", config.RateControl.FrameRateLimit)
|
||||||
fmt.Printf(" Encoding Interval: %d\n", config.RateControl.EncodingInterval)
|
fmt.Printf(" Encoding Interval: %d\n", config.RateControl.EncodingInterval)
|
||||||
@@ -888,7 +888,7 @@ func (c *CLI) getPTZStatus(ctx context.Context, profileToken string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("✅ PTZ Status:")
|
fmt.Println("✅ PTZ Status:")
|
||||||
|
|
||||||
if status.Position != nil {
|
if status.Position != nil {
|
||||||
if status.Position.PanTilt != nil {
|
if status.Position.PanTilt != nil {
|
||||||
fmt.Printf(" Pan: %.3f\n", status.Position.PanTilt.X)
|
fmt.Printf(" Pan: %.3f\n", status.Position.PanTilt.X)
|
||||||
@@ -1035,10 +1035,10 @@ func (c *CLI) getPTZPresets(ctx context.Context, profileToken string) {
|
|||||||
fmt.Printf("📍 Preset #%d:\n", i+1)
|
fmt.Printf("📍 Preset #%d:\n", i+1)
|
||||||
fmt.Printf(" Name: %s\n", preset.Name)
|
fmt.Printf(" Name: %s\n", preset.Name)
|
||||||
fmt.Printf(" Token: %s\n", preset.Token)
|
fmt.Printf(" Token: %s\n", preset.Token)
|
||||||
|
|
||||||
if preset.PTZPosition != nil {
|
if preset.PTZPosition != nil {
|
||||||
if preset.PTZPosition.PanTilt != nil {
|
if preset.PTZPosition.PanTilt != nil {
|
||||||
fmt.Printf(" Pan: %.3f, Tilt: %.3f\n",
|
fmt.Printf(" Pan: %.3f, Tilt: %.3f\n",
|
||||||
preset.PTZPosition.PanTilt.X,
|
preset.PTZPosition.PanTilt.X,
|
||||||
preset.PTZPosition.PanTilt.Y)
|
preset.PTZPosition.PanTilt.Y)
|
||||||
}
|
}
|
||||||
@@ -1161,11 +1161,11 @@ func (c *CLI) getImagingSettings(ctx context.Context, videoSourceToken string) {
|
|||||||
settings, err := c.client.GetImagingSettings(ctx, videoSourceToken)
|
settings, err := c.client.GetImagingSettings(ctx, videoSourceToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("❌ Error: %v\n", err)
|
fmt.Printf("❌ Error: %v\n", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("✅ Current Imaging Settings:")
|
fmt.Println("✅ Current Imaging Settings:")
|
||||||
|
|
||||||
if settings.Brightness != nil {
|
if settings.Brightness != nil {
|
||||||
fmt.Printf(" Brightness: %.1f\n", *settings.Brightness)
|
fmt.Printf(" Brightness: %.1f\n", *settings.Brightness)
|
||||||
}
|
}
|
||||||
@@ -1284,7 +1284,7 @@ func (c *CLI) setSaturation(ctx context.Context, videoSourceToken string) {
|
|||||||
saturation, err := strconv.ParseFloat(saturationStr, 64)
|
saturation, err := strconv.ParseFloat(saturationStr, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("❌ Invalid saturation value")
|
fmt.Println("❌ Invalid saturation value")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
currentSettings.ColorSaturation = &saturation
|
currentSettings.ColorSaturation = &saturation
|
||||||
@@ -1313,7 +1313,7 @@ func (c *CLI) setSharpness(ctx context.Context, videoSourceToken string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sharpnessStr := c.readInputWithDefault(fmt.Sprintf("Sharpness (0-100, current: %s)", currentValue), currentValue)
|
sharpnessStr := c.readInputWithDefault(fmt.Sprintf("Sharpness (0-100, current: %s)", currentValue), currentValue)
|
||||||
sharpness, err := strconv.ParseFloat(sharpnessStr, 64)
|
sharpness, err := strconv.ParseFloat(sharpnessStr, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("❌ Invalid sharpness value")
|
fmt.Println("❌ Invalid sharpness value")
|
||||||
return
|
return
|
||||||
@@ -1409,7 +1409,7 @@ func (c *CLI) captureAndDisplaySnapshot(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
profile := profiles[0]
|
profile := profiles[0]
|
||||||
|
|
||||||
fmt.Println("⏳ Getting snapshot URI...")
|
fmt.Println("⏳ Getting snapshot URI...")
|
||||||
|
|
||||||
// Get snapshot URI from camera
|
// Get snapshot URI from camera
|
||||||
@@ -1515,4 +1515,4 @@ func (c *CLI) captureAndDisplaySnapshot(ctx context.Context) {
|
|||||||
fmt.Printf("✅ Snapshot saved to %s\n", filename)
|
fmt.Printf("✅ Snapshot saved to %s\n", filename)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ func main() {
|
|||||||
|
|
||||||
func discoverCameras() {
|
func discoverCameras() {
|
||||||
reader := bufio.NewReader(os.Stdin)
|
reader := bufio.NewReader(os.Stdin)
|
||||||
|
|
||||||
fmt.Println("🔍 Discovering cameras on network...")
|
fmt.Println("🔍 Discovering cameras on network...")
|
||||||
|
|
||||||
// Ask if user wants to use a specific interface
|
// Ask if user wants to use a specific interface
|
||||||
@@ -150,7 +150,6 @@ func listNetworkInterfaces() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func connectAndShowInfo() {
|
func connectAndShowInfo() {
|
||||||
reader := bufio.NewReader(os.Stdin)
|
reader := bufio.NewReader(os.Stdin)
|
||||||
|
|
||||||
@@ -200,7 +199,7 @@ func connectAndShowInfo() {
|
|||||||
profiles, err := client.GetProfiles(ctx)
|
profiles, err := client.GetProfiles(ctx)
|
||||||
if err == nil && len(profiles) > 0 {
|
if err == nil && len(profiles) > 0 {
|
||||||
fmt.Printf("📺 %d profile(s) available\n", len(profiles))
|
fmt.Printf("📺 %d profile(s) available\n", len(profiles))
|
||||||
|
|
||||||
// Show first stream URL
|
// Show first stream URL
|
||||||
streamURI, err := client.GetStreamURI(ctx, profiles[0].Token)
|
streamURI, err := client.GetStreamURI(ctx, profiles[0].Token)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -228,7 +227,7 @@ func ptzDemo() {
|
|||||||
password = strings.TrimSpace(password)
|
password = strings.TrimSpace(password)
|
||||||
|
|
||||||
endpoint := fmt.Sprintf("http://%s/onvif/device_service", ip)
|
endpoint := fmt.Sprintf("http://%s/onvif/device_service", ip)
|
||||||
|
|
||||||
client, err := onvif.NewClient(
|
client, err := onvif.NewClient(
|
||||||
endpoint,
|
endpoint,
|
||||||
onvif.WithCredentials(username, password),
|
onvif.WithCredentials(username, password),
|
||||||
@@ -333,7 +332,7 @@ func getStreamURLs() {
|
|||||||
password = strings.TrimSpace(password)
|
password = strings.TrimSpace(password)
|
||||||
|
|
||||||
endpoint := fmt.Sprintf("http://%s/onvif/device_service", ip)
|
endpoint := fmt.Sprintf("http://%s/onvif/device_service", ip)
|
||||||
|
|
||||||
client, err := onvif.NewClient(
|
client, err := onvif.NewClient(
|
||||||
endpoint,
|
endpoint,
|
||||||
onvif.WithCredentials(username, password),
|
onvif.WithCredentials(username, password),
|
||||||
@@ -382,7 +381,7 @@ func getStreamURLs() {
|
|||||||
if profile.VideoEncoderConfiguration != nil {
|
if profile.VideoEncoderConfiguration != nil {
|
||||||
fmt.Printf(" 🎬 Encoding: %s", profile.VideoEncoderConfiguration.Encoding)
|
fmt.Printf(" 🎬 Encoding: %s", profile.VideoEncoderConfiguration.Encoding)
|
||||||
if profile.VideoEncoderConfiguration.Resolution != nil {
|
if profile.VideoEncoderConfiguration.Resolution != nil {
|
||||||
fmt.Printf(" (%dx%d)",
|
fmt.Printf(" (%dx%d)",
|
||||||
profile.VideoEncoderConfiguration.Resolution.Width,
|
profile.VideoEncoderConfiguration.Resolution.Width,
|
||||||
profile.VideoEncoderConfiguration.Resolution.Height)
|
profile.VideoEncoderConfiguration.Resolution.Height)
|
||||||
}
|
}
|
||||||
@@ -396,4 +395,4 @@ func getStreamURLs() {
|
|||||||
fmt.Println(" - Use VLC to open RTSP streams")
|
fmt.Println(" - Use VLC to open RTSP streams")
|
||||||
fmt.Println(" - Open snapshot URLs in a web browser")
|
fmt.Println(" - Open snapshot URLs in a web browser")
|
||||||
fmt.Println(" - Some cameras may require authentication in the URL")
|
fmt.Println(" - Some cameras may require authentication in the URL")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ func buildConfig(host string, port int, username, password, manufacturer, model,
|
|||||||
// Generate profiles
|
// Generate profiles
|
||||||
for i := 0; i < numProfiles; i++ {
|
for i := 0; i < numProfiles; i++ {
|
||||||
template := templates[i%len(templates)]
|
template := templates[i%len(templates)]
|
||||||
|
|
||||||
profile := server.ProfileConfig{
|
profile := server.ProfileConfig{
|
||||||
Token: fmt.Sprintf("profile_%d", i),
|
Token: fmt.Sprintf("profile_%d", i),
|
||||||
Name: template.name,
|
Name: template.name,
|
||||||
|
|||||||
@@ -1092,4 +1092,3 @@ func (c *Client) SetNetworkDefaultGateway(ctx context.Context, gateway *NetworkG
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -110,8 +110,8 @@ func (c *Client) GetDPAddresses(ctx context.Context) ([]NetworkHost, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type GetDPAddressesResponse struct {
|
type GetDPAddressesResponse struct {
|
||||||
XMLName xml.Name `xml:"GetDPAddressesResponse"`
|
XMLName xml.Name `xml:"GetDPAddressesResponse"`
|
||||||
DPAddress []NetworkHost `xml:"DPAddress"`
|
DPAddress []NetworkHost `xml:"DPAddress"`
|
||||||
}
|
}
|
||||||
|
|
||||||
request := GetDPAddressesBody{
|
request := GetDPAddressesBody{
|
||||||
@@ -171,8 +171,8 @@ func (c *Client) GetAccessPolicy(ctx context.Context) (*AccessPolicy, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type GetAccessPolicyResponse struct {
|
type GetAccessPolicyResponse struct {
|
||||||
XMLName xml.Name `xml:"GetAccessPolicyResponse"`
|
XMLName xml.Name `xml:"GetAccessPolicyResponse"`
|
||||||
PolicyFile *BinaryData `xml:"PolicyFile"`
|
PolicyFile *BinaryData `xml:"PolicyFile"`
|
||||||
}
|
}
|
||||||
|
|
||||||
request := GetAccessPolicyBody{
|
request := GetAccessPolicyBody{
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ func newMockDeviceAdditionalServer() *httptest.Server {
|
|||||||
</s:Envelope>`))
|
</s:Envelope>`))
|
||||||
|
|
||||||
case strings.Contains(bodyContent, "GetDPAddresses"):
|
case strings.Contains(bodyContent, "GetDPAddresses"):
|
||||||
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
||||||
<s:Body>
|
<s:Body>
|
||||||
<tds:GetDPAddressesResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl">
|
<tds:GetDPAddressesResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl">
|
||||||
@@ -71,7 +71,7 @@ func newMockDeviceAdditionalServer() *httptest.Server {
|
|||||||
</s:Envelope>`))
|
</s:Envelope>`))
|
||||||
|
|
||||||
case strings.Contains(bodyContent, "SetDPAddresses"):
|
case strings.Contains(bodyContent, "SetDPAddresses"):
|
||||||
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
||||||
<s:Body>
|
<s:Body>
|
||||||
<tds:SetDPAddressesResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl"/>
|
<tds:SetDPAddressesResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl"/>
|
||||||
@@ -79,7 +79,7 @@ func newMockDeviceAdditionalServer() *httptest.Server {
|
|||||||
</s:Envelope>`))
|
</s:Envelope>`))
|
||||||
|
|
||||||
case strings.Contains(bodyContent, "GetAccessPolicy"):
|
case strings.Contains(bodyContent, "GetAccessPolicy"):
|
||||||
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
||||||
<s:Body>
|
<s:Body>
|
||||||
<tds:GetAccessPolicyResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl">
|
<tds:GetAccessPolicyResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl">
|
||||||
@@ -92,7 +92,7 @@ func newMockDeviceAdditionalServer() *httptest.Server {
|
|||||||
</s:Envelope>`))
|
</s:Envelope>`))
|
||||||
|
|
||||||
case strings.Contains(bodyContent, "SetAccessPolicy"):
|
case strings.Contains(bodyContent, "SetAccessPolicy"):
|
||||||
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
||||||
<s:Body>
|
<s:Body>
|
||||||
<tds:SetAccessPolicyResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl"/>
|
<tds:SetAccessPolicyResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl"/>
|
||||||
@@ -100,7 +100,7 @@ func newMockDeviceAdditionalServer() *httptest.Server {
|
|||||||
</s:Envelope>`))
|
</s:Envelope>`))
|
||||||
|
|
||||||
case strings.Contains(bodyContent, "GetWsdlUrl"):
|
case strings.Contains(bodyContent, "GetWsdlUrl"):
|
||||||
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
||||||
<s:Body>
|
<s:Body>
|
||||||
<tds:GetWsdlUrlResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl">
|
<tds:GetWsdlUrlResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl">
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ func (c *Client) CreateCertificate(ctx context.Context, certificateID, subject s
|
|||||||
}
|
}
|
||||||
|
|
||||||
type CreateCertificateResponse struct {
|
type CreateCertificateResponse struct {
|
||||||
XMLName xml.Name `xml:"CreateCertificateResponse"`
|
XMLName xml.Name `xml:"CreateCertificateResponse"`
|
||||||
Certificate *Certificate `xml:"Certificate"`
|
Certificate *Certificate `xml:"Certificate"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,7 +204,7 @@ func (c *Client) GetCertificateInformation(ctx context.Context, certificateID st
|
|||||||
}
|
}
|
||||||
|
|
||||||
type GetCertificateInformationResponse struct {
|
type GetCertificateInformationResponse struct {
|
||||||
XMLName xml.Name `xml:"GetCertificateInformationResponse"`
|
XMLName xml.Name `xml:"GetCertificateInformationResponse"`
|
||||||
CertificateInformation *CertificateInformation `xml:"CertificateInformation"`
|
CertificateInformation *CertificateInformation `xml:"CertificateInformation"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,8 +296,8 @@ func (c *Client) GetPkcs10Request(ctx context.Context, certificateID, subject st
|
|||||||
}
|
}
|
||||||
|
|
||||||
type GetPkcs10RequestResponse struct {
|
type GetPkcs10RequestResponse struct {
|
||||||
XMLName xml.Name `xml:"GetPkcs10RequestResponse"`
|
XMLName xml.Name `xml:"GetPkcs10RequestResponse"`
|
||||||
Pkcs10Request *BinaryData `xml:"Pkcs10Request"`
|
Pkcs10Request *BinaryData `xml:"Pkcs10Request"`
|
||||||
}
|
}
|
||||||
|
|
||||||
request := GetPkcs10RequestBody{
|
request := GetPkcs10RequestBody{
|
||||||
@@ -323,8 +323,8 @@ func (c *Client) GetPkcs10Request(ctx context.Context, certificateID, subject st
|
|||||||
// ONVIF Specification: LoadCertificateWithPrivateKey operation
|
// ONVIF Specification: LoadCertificateWithPrivateKey operation
|
||||||
func (c *Client) LoadCertificateWithPrivateKey(ctx context.Context, certificates []*Certificate, privateKey []*BinaryData, certificateIDs []string) error {
|
func (c *Client) LoadCertificateWithPrivateKey(ctx context.Context, certificates []*Certificate, privateKey []*BinaryData, certificateIDs []string) error {
|
||||||
type LoadCertificateWithPrivateKeyBody struct {
|
type LoadCertificateWithPrivateKeyBody struct {
|
||||||
XMLName xml.Name `xml:"tds:LoadCertificateWithPrivateKey"`
|
XMLName xml.Name `xml:"tds:LoadCertificateWithPrivateKey"`
|
||||||
Xmlns string `xml:"xmlns:tds,attr"`
|
Xmlns string `xml:"xmlns:tds,attr"`
|
||||||
CertificateWithPrivateKey []struct {
|
CertificateWithPrivateKey []struct {
|
||||||
CertificateID string `xml:"CertificateID"`
|
CertificateID string `xml:"CertificateID"`
|
||||||
Certificate *Certificate `xml:"Certificate"`
|
Certificate *Certificate `xml:"Certificate"`
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ func newMockDeviceCertificatesServer() *httptest.Server {
|
|||||||
w.Header().Set("Content-Type", "application/soap+xml")
|
w.Header().Set("Content-Type", "application/soap+xml")
|
||||||
|
|
||||||
// Parse request to determine which operation
|
// Parse request to determine which operation
|
||||||
buf := make([]byte, r.ContentLength)
|
buf := make([]byte, r.ContentLength)
|
||||||
_, _ = r.Body.Read(buf)
|
_, _ = r.Body.Read(buf)
|
||||||
requestBody := string(buf)
|
requestBody := string(buf)
|
||||||
|
|
||||||
var response string
|
var response string
|
||||||
|
|||||||
+12
-12
@@ -131,7 +131,7 @@ func (c *Client) FixedGetSystemDateAndTime(ctx context.Context) (*SystemDateTime
|
|||||||
}
|
}
|
||||||
|
|
||||||
type GetSystemDateAndTimeResponse struct {
|
type GetSystemDateAndTimeResponse struct {
|
||||||
XMLName xml.Name `xml:"GetSystemDateAndTimeResponse"`
|
XMLName xml.Name `xml:"GetSystemDateAndTimeResponse"`
|
||||||
SystemDateAndTime struct {
|
SystemDateAndTime struct {
|
||||||
DateTimeType string `xml:"DateTimeType"`
|
DateTimeType string `xml:"DateTimeType"`
|
||||||
DaylightSavings bool `xml:"DaylightSavings"`
|
DaylightSavings bool `xml:"DaylightSavings"`
|
||||||
@@ -406,10 +406,10 @@ func (c *Client) GetRelayOutputs(ctx context.Context) ([]*RelayOutput, error) {
|
|||||||
// SetRelayOutputSettings sets the settings of a relay output
|
// SetRelayOutputSettings sets the settings of a relay output
|
||||||
func (c *Client) SetRelayOutputSettings(ctx context.Context, token string, settings *RelayOutputSettings) error {
|
func (c *Client) SetRelayOutputSettings(ctx context.Context, token string, settings *RelayOutputSettings) error {
|
||||||
type SetRelayOutputSettings struct {
|
type SetRelayOutputSettings struct {
|
||||||
XMLName xml.Name `xml:"tds:SetRelayOutputSettings"`
|
XMLName xml.Name `xml:"tds:SetRelayOutputSettings"`
|
||||||
Xmlns string `xml:"xmlns:tds,attr"`
|
Xmlns string `xml:"xmlns:tds,attr"`
|
||||||
RelayOutputToken string `xml:"tds:RelayOutputToken"`
|
RelayOutputToken string `xml:"tds:RelayOutputToken"`
|
||||||
Properties struct {
|
Properties struct {
|
||||||
Mode string `xml:"tt:Mode"`
|
Mode string `xml:"tt:Mode"`
|
||||||
DelayTime string `xml:"tt:DelayTime"`
|
DelayTime string `xml:"tt:DelayTime"`
|
||||||
IdleState string `xml:"tt:IdleState"`
|
IdleState string `xml:"tt:IdleState"`
|
||||||
@@ -417,7 +417,7 @@ func (c *Client) SetRelayOutputSettings(ctx context.Context, token string, setti
|
|||||||
}
|
}
|
||||||
|
|
||||||
req := SetRelayOutputSettings{
|
req := SetRelayOutputSettings{
|
||||||
Xmlns: deviceNamespace,
|
Xmlns: deviceNamespace,
|
||||||
RelayOutputToken: token,
|
RelayOutputToken: token,
|
||||||
}
|
}
|
||||||
req.Properties.Mode = string(settings.Mode)
|
req.Properties.Mode = string(settings.Mode)
|
||||||
@@ -437,16 +437,16 @@ func (c *Client) SetRelayOutputSettings(ctx context.Context, token string, setti
|
|||||||
// SetRelayOutputState sets the state of a relay output
|
// SetRelayOutputState sets the state of a relay output
|
||||||
func (c *Client) SetRelayOutputState(ctx context.Context, token string, state RelayLogicalState) error {
|
func (c *Client) SetRelayOutputState(ctx context.Context, token string, state RelayLogicalState) error {
|
||||||
type SetRelayOutputState struct {
|
type SetRelayOutputState struct {
|
||||||
XMLName xml.Name `xml:"tds:SetRelayOutputState"`
|
XMLName xml.Name `xml:"tds:SetRelayOutputState"`
|
||||||
Xmlns string `xml:"xmlns:tds,attr"`
|
Xmlns string `xml:"xmlns:tds,attr"`
|
||||||
RelayOutputToken string `xml:"tds:RelayOutputToken"`
|
RelayOutputToken string `xml:"tds:RelayOutputToken"`
|
||||||
LogicalState RelayLogicalState `xml:"tds:LogicalState"`
|
LogicalState RelayLogicalState `xml:"tds:LogicalState"`
|
||||||
}
|
}
|
||||||
|
|
||||||
req := SetRelayOutputState{
|
req := SetRelayOutputState{
|
||||||
Xmlns: deviceNamespace,
|
Xmlns: deviceNamespace,
|
||||||
RelayOutputToken: token,
|
RelayOutputToken: token,
|
||||||
LogicalState: state,
|
LogicalState: state,
|
||||||
}
|
}
|
||||||
|
|
||||||
username, password := c.GetCredentials()
|
username, password := c.GetCredentials()
|
||||||
@@ -628,8 +628,8 @@ func (c *Client) GetSystemUris(ctx context.Context) (*SystemLogUriList, string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
type GetSystemUrisResponse struct {
|
type GetSystemUrisResponse struct {
|
||||||
XMLName xml.Name `xml:"GetSystemUrisResponse"`
|
XMLName xml.Name `xml:"GetSystemUrisResponse"`
|
||||||
SystemLogUris *struct {
|
SystemLogUris *struct {
|
||||||
SystemLog []struct {
|
SystemLog []struct {
|
||||||
Type string `xml:"Type"`
|
Type string `xml:"Type"`
|
||||||
Uri string `xml:"Uri"`
|
Uri string `xml:"Uri"`
|
||||||
|
|||||||
+10
-10
@@ -24,7 +24,7 @@ func newMockDeviceExtendedServer() *httptest.Server {
|
|||||||
|
|
||||||
switch {
|
switch {
|
||||||
case strings.Contains(bodyContent, "AddScopes"):
|
case strings.Contains(bodyContent, "AddScopes"):
|
||||||
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
||||||
<s:Body>
|
<s:Body>
|
||||||
<tds:AddScopesResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl"/>
|
<tds:AddScopesResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl"/>
|
||||||
@@ -32,7 +32,7 @@ func newMockDeviceExtendedServer() *httptest.Server {
|
|||||||
</s:Envelope>`))
|
</s:Envelope>`))
|
||||||
|
|
||||||
case strings.Contains(bodyContent, "RemoveScopes"):
|
case strings.Contains(bodyContent, "RemoveScopes"):
|
||||||
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
||||||
<s:Body>
|
<s:Body>
|
||||||
<tds:RemoveScopesResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl">
|
<tds:RemoveScopesResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl">
|
||||||
@@ -42,7 +42,7 @@ func newMockDeviceExtendedServer() *httptest.Server {
|
|||||||
</s:Envelope>`))
|
</s:Envelope>`))
|
||||||
|
|
||||||
case strings.Contains(bodyContent, "SetScopes"):
|
case strings.Contains(bodyContent, "SetScopes"):
|
||||||
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
||||||
<s:Body>
|
<s:Body>
|
||||||
<tds:SetScopesResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl"/>
|
<tds:SetScopesResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl"/>
|
||||||
@@ -50,7 +50,7 @@ func newMockDeviceExtendedServer() *httptest.Server {
|
|||||||
</s:Envelope>`))
|
</s:Envelope>`))
|
||||||
|
|
||||||
case strings.Contains(bodyContent, "GetRelayOutputs"):
|
case strings.Contains(bodyContent, "GetRelayOutputs"):
|
||||||
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
||||||
<s:Body>
|
<s:Body>
|
||||||
<tds:GetRelayOutputsResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl">
|
<tds:GetRelayOutputsResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl">
|
||||||
@@ -66,7 +66,7 @@ func newMockDeviceExtendedServer() *httptest.Server {
|
|||||||
</s:Envelope>`))
|
</s:Envelope>`))
|
||||||
|
|
||||||
case strings.Contains(bodyContent, "SetRelayOutputSettings"):
|
case strings.Contains(bodyContent, "SetRelayOutputSettings"):
|
||||||
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
||||||
<s:Body>
|
<s:Body>
|
||||||
<tds:SetRelayOutputSettingsResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl"/>
|
<tds:SetRelayOutputSettingsResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl"/>
|
||||||
@@ -74,7 +74,7 @@ func newMockDeviceExtendedServer() *httptest.Server {
|
|||||||
</s:Envelope>`))
|
</s:Envelope>`))
|
||||||
|
|
||||||
case strings.Contains(bodyContent, "SetRelayOutputState"):
|
case strings.Contains(bodyContent, "SetRelayOutputState"):
|
||||||
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
||||||
<s:Body>
|
<s:Body>
|
||||||
<tds:SetRelayOutputStateResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl"/>
|
<tds:SetRelayOutputStateResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl"/>
|
||||||
@@ -82,7 +82,7 @@ func newMockDeviceExtendedServer() *httptest.Server {
|
|||||||
</s:Envelope>`))
|
</s:Envelope>`))
|
||||||
|
|
||||||
case strings.Contains(bodyContent, "SendAuxiliaryCommand"):
|
case strings.Contains(bodyContent, "SendAuxiliaryCommand"):
|
||||||
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
||||||
<s:Body>
|
<s:Body>
|
||||||
<tds:SendAuxiliaryCommandResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl">
|
<tds:SendAuxiliaryCommandResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl">
|
||||||
@@ -92,7 +92,7 @@ func newMockDeviceExtendedServer() *httptest.Server {
|
|||||||
</s:Envelope>`))
|
</s:Envelope>`))
|
||||||
|
|
||||||
case strings.Contains(bodyContent, "GetSystemLog"):
|
case strings.Contains(bodyContent, "GetSystemLog"):
|
||||||
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
||||||
<s:Body>
|
<s:Body>
|
||||||
<tds:GetSystemLogResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl">
|
<tds:GetSystemLogResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl">
|
||||||
@@ -104,7 +104,7 @@ func newMockDeviceExtendedServer() *httptest.Server {
|
|||||||
</s:Envelope>`))
|
</s:Envelope>`))
|
||||||
|
|
||||||
case strings.Contains(bodyContent, "SetSystemFactoryDefault"):
|
case strings.Contains(bodyContent, "SetSystemFactoryDefault"):
|
||||||
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
||||||
<s:Body>
|
<s:Body>
|
||||||
<tds:SetSystemFactoryDefaultResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl"/>
|
<tds:SetSystemFactoryDefaultResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl"/>
|
||||||
@@ -112,7 +112,7 @@ func newMockDeviceExtendedServer() *httptest.Server {
|
|||||||
</s:Envelope>`))
|
</s:Envelope>`))
|
||||||
|
|
||||||
case strings.Contains(bodyContent, "StartFirmwareUpgrade"):
|
case strings.Contains(bodyContent, "StartFirmwareUpgrade"):
|
||||||
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
||||||
<s:Body>
|
<s:Body>
|
||||||
<tds:StartFirmwareUpgradeResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl">
|
<tds:StartFirmwareUpgradeResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl">
|
||||||
|
|||||||
+8
-8
@@ -370,7 +370,7 @@ func (c *Client) GetDynamicDNS(ctx context.Context) (*DynamicDNSInformation, err
|
|||||||
}
|
}
|
||||||
|
|
||||||
type GetDynamicDNSResponse struct {
|
type GetDynamicDNSResponse struct {
|
||||||
XMLName xml.Name `xml:"GetDynamicDNSResponse"`
|
XMLName xml.Name `xml:"GetDynamicDNSResponse"`
|
||||||
DynamicDNSInformation struct {
|
DynamicDNSInformation struct {
|
||||||
Type string `xml:"Type"`
|
Type string `xml:"Type"`
|
||||||
Name string `xml:"Name"`
|
Name string `xml:"Name"`
|
||||||
@@ -431,13 +431,13 @@ func (c *Client) GetPasswordComplexityConfiguration(ctx context.Context) (*Passw
|
|||||||
}
|
}
|
||||||
|
|
||||||
type GetPasswordComplexityConfigurationResponse struct {
|
type GetPasswordComplexityConfigurationResponse struct {
|
||||||
XMLName xml.Name `xml:"GetPasswordComplexityConfigurationResponse"`
|
XMLName xml.Name `xml:"GetPasswordComplexityConfigurationResponse"`
|
||||||
MinLen int `xml:"MinLen"`
|
MinLen int `xml:"MinLen"`
|
||||||
Uppercase int `xml:"Uppercase"`
|
Uppercase int `xml:"Uppercase"`
|
||||||
Number int `xml:"Number"`
|
Number int `xml:"Number"`
|
||||||
SpecialChars int `xml:"SpecialChars"`
|
SpecialChars int `xml:"SpecialChars"`
|
||||||
BlockUsernameOccurrence bool `xml:"BlockUsernameOccurrence"`
|
BlockUsernameOccurrence bool `xml:"BlockUsernameOccurrence"`
|
||||||
PolicyConfigurationLocked bool `xml:"PolicyConfigurationLocked"`
|
PolicyConfigurationLocked bool `xml:"PolicyConfigurationLocked"`
|
||||||
}
|
}
|
||||||
|
|
||||||
req := GetPasswordComplexityConfiguration{
|
req := GetPasswordComplexityConfiguration{
|
||||||
|
|||||||
+15
-15
@@ -24,7 +24,7 @@ func newMockDeviceSecurityServer() *httptest.Server {
|
|||||||
|
|
||||||
switch {
|
switch {
|
||||||
case strings.Contains(bodyContent, "GetRemoteUser"):
|
case strings.Contains(bodyContent, "GetRemoteUser"):
|
||||||
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
||||||
<s:Body>
|
<s:Body>
|
||||||
<tds:GetRemoteUserResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl">
|
<tds:GetRemoteUserResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl">
|
||||||
@@ -38,7 +38,7 @@ func newMockDeviceSecurityServer() *httptest.Server {
|
|||||||
</s:Envelope>`))
|
</s:Envelope>`))
|
||||||
|
|
||||||
case strings.Contains(bodyContent, "SetRemoteUser"):
|
case strings.Contains(bodyContent, "SetRemoteUser"):
|
||||||
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
||||||
<s:Body>
|
<s:Body>
|
||||||
<tds:SetRemoteUserResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl"/>
|
<tds:SetRemoteUserResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl"/>
|
||||||
@@ -46,7 +46,7 @@ func newMockDeviceSecurityServer() *httptest.Server {
|
|||||||
</s:Envelope>`))
|
</s:Envelope>`))
|
||||||
|
|
||||||
case strings.Contains(bodyContent, "GetIPAddressFilter"):
|
case strings.Contains(bodyContent, "GetIPAddressFilter"):
|
||||||
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
||||||
<s:Body>
|
<s:Body>
|
||||||
<tds:GetIPAddressFilterResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl">
|
<tds:GetIPAddressFilterResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl">
|
||||||
@@ -61,10 +61,10 @@ func newMockDeviceSecurityServer() *httptest.Server {
|
|||||||
</s:Body>
|
</s:Body>
|
||||||
</s:Envelope>`))
|
</s:Envelope>`))
|
||||||
|
|
||||||
case strings.Contains(bodyContent, "SetIPAddressFilter"),
|
case strings.Contains(bodyContent, "SetIPAddressFilter"),
|
||||||
strings.Contains(bodyContent, "AddIPAddressFilter"),
|
strings.Contains(bodyContent, "AddIPAddressFilter"),
|
||||||
strings.Contains(bodyContent, "RemoveIPAddressFilter"):
|
strings.Contains(bodyContent, "RemoveIPAddressFilter"):
|
||||||
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
||||||
<s:Body>
|
<s:Body>
|
||||||
<tds:SetIPAddressFilterResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl"/>
|
<tds:SetIPAddressFilterResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl"/>
|
||||||
@@ -72,7 +72,7 @@ func newMockDeviceSecurityServer() *httptest.Server {
|
|||||||
</s:Envelope>`))
|
</s:Envelope>`))
|
||||||
|
|
||||||
case strings.Contains(bodyContent, "GetZeroConfiguration"):
|
case strings.Contains(bodyContent, "GetZeroConfiguration"):
|
||||||
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
||||||
<s:Body>
|
<s:Body>
|
||||||
<tds:GetZeroConfigurationResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl">
|
<tds:GetZeroConfigurationResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl">
|
||||||
@@ -86,7 +86,7 @@ func newMockDeviceSecurityServer() *httptest.Server {
|
|||||||
</s:Envelope>`))
|
</s:Envelope>`))
|
||||||
|
|
||||||
case strings.Contains(bodyContent, "SetZeroConfiguration"):
|
case strings.Contains(bodyContent, "SetZeroConfiguration"):
|
||||||
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
||||||
<s:Body>
|
<s:Body>
|
||||||
<tds:SetZeroConfigurationResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl"/>
|
<tds:SetZeroConfigurationResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl"/>
|
||||||
@@ -94,7 +94,7 @@ func newMockDeviceSecurityServer() *httptest.Server {
|
|||||||
</s:Envelope>`))
|
</s:Envelope>`))
|
||||||
|
|
||||||
case strings.Contains(bodyContent, "GetPasswordComplexityConfiguration"):
|
case strings.Contains(bodyContent, "GetPasswordComplexityConfiguration"):
|
||||||
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
||||||
<s:Body>
|
<s:Body>
|
||||||
<tds:GetPasswordComplexityConfigurationResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl">
|
<tds:GetPasswordComplexityConfigurationResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl">
|
||||||
@@ -109,7 +109,7 @@ func newMockDeviceSecurityServer() *httptest.Server {
|
|||||||
</s:Envelope>`))
|
</s:Envelope>`))
|
||||||
|
|
||||||
case strings.Contains(bodyContent, "SetPasswordComplexityConfiguration"):
|
case strings.Contains(bodyContent, "SetPasswordComplexityConfiguration"):
|
||||||
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
||||||
<s:Body>
|
<s:Body>
|
||||||
<tds:SetPasswordComplexityConfigurationResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl"/>
|
<tds:SetPasswordComplexityConfigurationResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl"/>
|
||||||
@@ -117,7 +117,7 @@ func newMockDeviceSecurityServer() *httptest.Server {
|
|||||||
</s:Envelope>`))
|
</s:Envelope>`))
|
||||||
|
|
||||||
case strings.Contains(bodyContent, "GetPasswordHistoryConfiguration"):
|
case strings.Contains(bodyContent, "GetPasswordHistoryConfiguration"):
|
||||||
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
||||||
<s:Body>
|
<s:Body>
|
||||||
<tds:GetPasswordHistoryConfigurationResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl">
|
<tds:GetPasswordHistoryConfigurationResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl">
|
||||||
@@ -128,7 +128,7 @@ func newMockDeviceSecurityServer() *httptest.Server {
|
|||||||
</s:Envelope>`))
|
</s:Envelope>`))
|
||||||
|
|
||||||
case strings.Contains(bodyContent, "SetPasswordHistoryConfiguration"):
|
case strings.Contains(bodyContent, "SetPasswordHistoryConfiguration"):
|
||||||
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
||||||
<s:Body>
|
<s:Body>
|
||||||
<tds:SetPasswordHistoryConfigurationResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl"/>
|
<tds:SetPasswordHistoryConfigurationResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl"/>
|
||||||
@@ -136,7 +136,7 @@ func newMockDeviceSecurityServer() *httptest.Server {
|
|||||||
</s:Envelope>`))
|
</s:Envelope>`))
|
||||||
|
|
||||||
case strings.Contains(bodyContent, "GetAuthFailureWarningConfiguration"):
|
case strings.Contains(bodyContent, "GetAuthFailureWarningConfiguration"):
|
||||||
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
||||||
<s:Body>
|
<s:Body>
|
||||||
<tds:GetAuthFailureWarningConfigurationResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl">
|
<tds:GetAuthFailureWarningConfigurationResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl">
|
||||||
@@ -148,7 +148,7 @@ func newMockDeviceSecurityServer() *httptest.Server {
|
|||||||
</s:Envelope>`))
|
</s:Envelope>`))
|
||||||
|
|
||||||
case strings.Contains(bodyContent, "SetAuthFailureWarningConfiguration"):
|
case strings.Contains(bodyContent, "SetAuthFailureWarningConfiguration"):
|
||||||
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
||||||
<s:Body>
|
<s:Body>
|
||||||
<tds:SetAuthFailureWarningConfigurationResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl"/>
|
<tds:SetAuthFailureWarningConfigurationResponse xmlns:tds="http://www.onvif.org/ver10/device/wsdl"/>
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ func newMockDeviceStorageServer() *httptest.Server {
|
|||||||
w.Header().Set("Content-Type", "application/soap+xml")
|
w.Header().Set("Content-Type", "application/soap+xml")
|
||||||
|
|
||||||
// Parse request to determine which operation
|
// Parse request to determine which operation
|
||||||
buf := make([]byte, r.ContentLength)
|
buf := make([]byte, r.ContentLength)
|
||||||
_, _ = r.Body.Read(buf)
|
_, _ = r.Body.Read(buf)
|
||||||
requestBody := string(buf)
|
requestBody := string(buf)
|
||||||
|
|
||||||
var response string
|
var response string
|
||||||
|
|||||||
+11
-11
@@ -18,7 +18,7 @@ func (c *Client) GetDot11Capabilities(ctx context.Context) (*Dot11Capabilities,
|
|||||||
}
|
}
|
||||||
|
|
||||||
type GetDot11CapabilitiesResponse struct {
|
type GetDot11CapabilitiesResponse struct {
|
||||||
XMLName xml.Name `xml:"GetDot11CapabilitiesResponse"`
|
XMLName xml.Name `xml:"GetDot11CapabilitiesResponse"`
|
||||||
Capabilities *Dot11Capabilities `xml:"Capabilities"`
|
Capabilities *Dot11Capabilities `xml:"Capabilities"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,14 +73,14 @@ func (c *Client) GetDot11Status(ctx context.Context, interfaceToken string) (*Do
|
|||||||
// ONVIF Specification: GetDot1XConfiguration operation
|
// ONVIF Specification: GetDot1XConfiguration operation
|
||||||
func (c *Client) GetDot1XConfiguration(ctx context.Context, configToken string) (*Dot1XConfiguration, error) {
|
func (c *Client) GetDot1XConfiguration(ctx context.Context, configToken string) (*Dot1XConfiguration, error) {
|
||||||
type GetDot1XConfigurationBody struct {
|
type GetDot1XConfigurationBody struct {
|
||||||
XMLName xml.Name `xml:"tds:GetDot1XConfiguration"`
|
XMLName xml.Name `xml:"tds:GetDot1XConfiguration"`
|
||||||
Xmlns string `xml:"xmlns:tds,attr"`
|
Xmlns string `xml:"xmlns:tds,attr"`
|
||||||
Dot1XConfigurationToken string `xml:"tds:Dot1XConfigurationToken"`
|
Dot1XConfigurationToken string `xml:"tds:Dot1XConfigurationToken"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetDot1XConfigurationResponse struct {
|
type GetDot1XConfigurationResponse struct {
|
||||||
XMLName xml.Name `xml:"GetDot1XConfigurationResponse"`
|
XMLName xml.Name `xml:"GetDot1XConfigurationResponse"`
|
||||||
Dot1XConfiguration *Dot1XConfiguration `xml:"Dot1XConfiguration"`
|
Dot1XConfiguration *Dot1XConfiguration `xml:"Dot1XConfiguration"`
|
||||||
}
|
}
|
||||||
|
|
||||||
request := GetDot1XConfigurationBody{
|
request := GetDot1XConfigurationBody{
|
||||||
@@ -109,8 +109,8 @@ func (c *Client) GetDot1XConfigurations(ctx context.Context) ([]*Dot1XConfigurat
|
|||||||
}
|
}
|
||||||
|
|
||||||
type GetDot1XConfigurationsResponse struct {
|
type GetDot1XConfigurationsResponse struct {
|
||||||
XMLName xml.Name `xml:"GetDot1XConfigurationsResponse"`
|
XMLName xml.Name `xml:"GetDot1XConfigurationsResponse"`
|
||||||
Dot1XConfiguration []*Dot1XConfiguration `xml:"Dot1XConfiguration"`
|
Dot1XConfiguration []*Dot1XConfiguration `xml:"Dot1XConfiguration"`
|
||||||
}
|
}
|
||||||
|
|
||||||
request := GetDot1XConfigurationsBody{
|
request := GetDot1XConfigurationsBody{
|
||||||
@@ -193,9 +193,9 @@ func (c *Client) CreateDot1XConfiguration(ctx context.Context, config *Dot1XConf
|
|||||||
// ONVIF Specification: DeleteDot1XConfiguration operation
|
// ONVIF Specification: DeleteDot1XConfiguration operation
|
||||||
func (c *Client) DeleteDot1XConfiguration(ctx context.Context, configToken string) error {
|
func (c *Client) DeleteDot1XConfiguration(ctx context.Context, configToken string) error {
|
||||||
type DeleteDot1XConfigurationBody struct {
|
type DeleteDot1XConfigurationBody struct {
|
||||||
XMLName xml.Name `xml:"tds:DeleteDot1XConfiguration"`
|
XMLName xml.Name `xml:"tds:DeleteDot1XConfiguration"`
|
||||||
Xmlns string `xml:"xmlns:tds,attr"`
|
Xmlns string `xml:"xmlns:tds,attr"`
|
||||||
Dot1XConfigurationToken string `xml:"tds:Dot1XConfigurationToken"`
|
Dot1XConfigurationToken string `xml:"tds:Dot1XConfigurationToken"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type DeleteDot1XConfigurationResponse struct {
|
type DeleteDot1XConfigurationResponse struct {
|
||||||
|
|||||||
+2
-2
@@ -13,8 +13,8 @@ func newMockDeviceWiFiServer() *httptest.Server {
|
|||||||
w.Header().Set("Content-Type", "application/soap+xml")
|
w.Header().Set("Content-Type", "application/soap+xml")
|
||||||
|
|
||||||
// Parse request to determine which operation
|
// Parse request to determine which operation
|
||||||
buf := make([]byte, r.ContentLength)
|
buf := make([]byte, r.ContentLength)
|
||||||
_, _ = r.Body.Read(buf)
|
_, _ = r.Body.Read(buf)
|
||||||
requestBody := string(buf)
|
requestBody := string(buf)
|
||||||
|
|
||||||
var response string
|
var response string
|
||||||
|
|||||||
+12
-12
@@ -12,7 +12,7 @@ import (
|
|||||||
const (
|
const (
|
||||||
// WS-Discovery multicast address
|
// WS-Discovery multicast address
|
||||||
multicastAddr = "239.255.255.250:3702"
|
multicastAddr = "239.255.255.250:3702"
|
||||||
|
|
||||||
// WS-Discovery probe message
|
// WS-Discovery probe message
|
||||||
probeTemplate = `<?xml version="1.0" encoding="UTF-8"?>
|
probeTemplate = `<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing">
|
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing">
|
||||||
@@ -36,16 +36,16 @@ const (
|
|||||||
type Device struct {
|
type Device struct {
|
||||||
// Device endpoint address
|
// Device endpoint address
|
||||||
EndpointRef string
|
EndpointRef string
|
||||||
|
|
||||||
// XAddrs contains the device service addresses
|
// XAddrs contains the device service addresses
|
||||||
XAddrs []string
|
XAddrs []string
|
||||||
|
|
||||||
// Types contains the device types
|
// Types contains the device types
|
||||||
Types []string
|
Types []string
|
||||||
|
|
||||||
// Scopes contains the device scopes (name, location, etc.)
|
// Scopes contains the device scopes (name, location, etc.)
|
||||||
Scopes []string
|
Scopes []string
|
||||||
|
|
||||||
// Metadata version
|
// Metadata version
|
||||||
MetadataVersion int
|
MetadataVersion int
|
||||||
}
|
}
|
||||||
@@ -62,8 +62,8 @@ type ProbeMatch struct {
|
|||||||
|
|
||||||
// ProbeMatches represents WS-Discovery probe matches
|
// ProbeMatches represents WS-Discovery probe matches
|
||||||
type ProbeMatches struct {
|
type ProbeMatches struct {
|
||||||
XMLName xml.Name `xml:"ProbeMatches"`
|
XMLName xml.Name `xml:"ProbeMatches"`
|
||||||
ProbeMatch []ProbeMatch `xml:"ProbeMatch"`
|
ProbeMatch []ProbeMatch `xml:"ProbeMatch"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DiscoverOptions contains options for device discovery
|
// DiscoverOptions contains options for device discovery
|
||||||
@@ -72,7 +72,7 @@ type DiscoverOptions struct {
|
|||||||
// If empty, the system will choose the default interface.
|
// If empty, the system will choose the default interface.
|
||||||
// Examples: "eth0", "wlan0", "192.168.1.100"
|
// Examples: "eth0", "wlan0", "192.168.1.100"
|
||||||
NetworkInterface string
|
NetworkInterface string
|
||||||
|
|
||||||
// Context and timeout are handled by the caller
|
// Context and timeout are handled by the caller
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -308,13 +308,13 @@ func ListNetworkInterfaces() ([]NetworkInterface, error) {
|
|||||||
type NetworkInterface struct {
|
type NetworkInterface struct {
|
||||||
// Name of the interface (e.g., "eth0", "wlan0")
|
// Name of the interface (e.g., "eth0", "wlan0")
|
||||||
Name string
|
Name string
|
||||||
|
|
||||||
// IP addresses assigned to this interface
|
// IP addresses assigned to this interface
|
||||||
Addresses []string
|
Addresses []string
|
||||||
|
|
||||||
// Up indicates if the interface is up
|
// Up indicates if the interface is up
|
||||||
Up bool
|
Up bool
|
||||||
|
|
||||||
// Multicast indicates if the interface supports multicast
|
// Multicast indicates if the interface supports multicast
|
||||||
Multicast bool
|
Multicast bool
|
||||||
}
|
}
|
||||||
@@ -324,7 +324,7 @@ func (d *Device) GetDeviceEndpoint() string {
|
|||||||
if len(d.XAddrs) == 0 {
|
if len(d.XAddrs) == 0 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the first XAddr
|
// Return the first XAddr
|
||||||
return d.XAddrs[0]
|
return d.XAddrs[0]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
fmt.Println("Discovering ONVIF devices on the network...")
|
fmt.Println("Discovering ONVIF devices on the network...")
|
||||||
|
|
||||||
// Create a context with timeout
|
// Create a context with timeout
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|||||||
@@ -100,15 +100,15 @@ func main() {
|
|||||||
|
|
||||||
// Modify some settings
|
// Modify some settings
|
||||||
fmt.Println("\n\nModifying imaging settings...")
|
fmt.Println("\n\nModifying imaging settings...")
|
||||||
|
|
||||||
// Increase brightness
|
// Increase brightness
|
||||||
newBrightness := 60.0
|
newBrightness := 60.0
|
||||||
settings.Brightness = &newBrightness
|
settings.Brightness = &newBrightness
|
||||||
|
|
||||||
// Increase contrast
|
// Increase contrast
|
||||||
newContrast := 55.0
|
newContrast := 55.0
|
||||||
settings.Contrast = &newContrast
|
settings.Contrast = &newContrast
|
||||||
|
|
||||||
// Set to auto exposure
|
// Set to auto exposure
|
||||||
if settings.Exposure != nil {
|
if settings.Exposure != nil {
|
||||||
settings.Exposure.Mode = "AUTO"
|
settings.Exposure.Mode = "AUTO"
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ func demonstratePTZ(ctx context.Context, client *onvif.Client, profileToken stri
|
|||||||
fmt.Println("Moving camera right...")
|
fmt.Println("Moving camera right...")
|
||||||
velocity := &onvif.PTZSpeed{
|
velocity := &onvif.PTZSpeed{
|
||||||
PanTilt: &onvif.Vector2D{
|
PanTilt: &onvif.Vector2D{
|
||||||
X: 0.5, // Move right
|
X: 0.5, // Move right
|
||||||
Y: 0.0,
|
Y: 0.0,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ func main() {
|
|||||||
for i, profile := range profiles {
|
for i, profile := range profiles {
|
||||||
fmt.Printf("\n Profile %d: %s\n", i+1, profile.Name)
|
fmt.Printf("\n Profile %d: %s\n", i+1, profile.Name)
|
||||||
fmt.Printf(" Token: %s\n", profile.Token)
|
fmt.Printf(" Token: %s\n", profile.Token)
|
||||||
|
|
||||||
if profile.VideoEncoderConfiguration != nil {
|
if profile.VideoEncoderConfiguration != nil {
|
||||||
fmt.Printf(" Video: %dx%d @ %s\n",
|
fmt.Printf(" Video: %dx%d @ %s\n",
|
||||||
profile.VideoEncoderConfiguration.Resolution.Width,
|
profile.VideoEncoderConfiguration.Resolution.Width,
|
||||||
@@ -98,7 +98,7 @@ func main() {
|
|||||||
// Test PTZ if available
|
// Test PTZ if available
|
||||||
if profile.PTZConfiguration != nil {
|
if profile.PTZConfiguration != nil {
|
||||||
fmt.Println(" PTZ: ✓ Enabled")
|
fmt.Println(" PTZ: ✓ Enabled")
|
||||||
|
|
||||||
// Get PTZ status
|
// Get PTZ status
|
||||||
status, err := client.GetStatus(ctx, profile.Token)
|
status, err := client.GetStatus(ctx, profile.Token)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -121,7 +121,7 @@ func main() {
|
|||||||
if len(profiles) > 0 && profiles[0].PTZConfiguration != nil {
|
if len(profiles) > 0 && profiles[0].PTZConfiguration != nil {
|
||||||
fmt.Println("🎮 Test 5: Testing PTZ Control...")
|
fmt.Println("🎮 Test 5: Testing PTZ Control...")
|
||||||
profileToken := profiles[0].Token
|
profileToken := profiles[0].Token
|
||||||
|
|
||||||
// Absolute move to home position
|
// Absolute move to home position
|
||||||
fmt.Println(" Moving to home position...")
|
fmt.Println(" Moving to home position...")
|
||||||
position := &onvif.PTZVector{
|
position := &onvif.PTZVector{
|
||||||
|
|||||||
@@ -63,18 +63,18 @@ func TestBuildEnvelope(t *testing.T) {
|
|||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "with authentication",
|
name: "with authentication",
|
||||||
body: &testRequest{Value: "test"},
|
body: &testRequest{Value: "test"},
|
||||||
username: "admin",
|
username: "admin",
|
||||||
password: "password",
|
password: "password",
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "without authentication",
|
name: "without authentication",
|
||||||
body: &testRequest{Value: "test"},
|
body: &testRequest{Value: "test"},
|
||||||
username: "",
|
username: "",
|
||||||
password: "",
|
password: "",
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
-12
@@ -45,10 +45,10 @@ type AnalyticsCapabilities struct {
|
|||||||
|
|
||||||
// DeviceCapabilities represents device service capabilities
|
// DeviceCapabilities represents device service capabilities
|
||||||
type DeviceCapabilities struct {
|
type DeviceCapabilities struct {
|
||||||
XAddr string `xml:"XAddr"`
|
XAddr string `xml:"XAddr"`
|
||||||
Network *NetworkCapabilities `xml:"Network,omitempty"`
|
Network *NetworkCapabilities `xml:"Network,omitempty"`
|
||||||
System *SystemCapabilities `xml:"System,omitempty"`
|
System *SystemCapabilities `xml:"System,omitempty"`
|
||||||
IO *IOCapabilities `xml:"IO,omitempty"`
|
IO *IOCapabilities `xml:"IO,omitempty"`
|
||||||
Security *SecurityCapabilities `xml:"Security,omitempty"`
|
Security *SecurityCapabilities `xml:"Security,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,12 +62,12 @@ type NetworkCapabilities struct {
|
|||||||
|
|
||||||
// SystemCapabilities represents system capabilities
|
// SystemCapabilities represents system capabilities
|
||||||
type SystemCapabilities struct {
|
type SystemCapabilities struct {
|
||||||
DiscoveryResolve bool `xml:"DiscoveryResolve,attr"`
|
DiscoveryResolve bool `xml:"DiscoveryResolve,attr"`
|
||||||
DiscoveryBye bool `xml:"DiscoveryBye,attr"`
|
DiscoveryBye bool `xml:"DiscoveryBye,attr"`
|
||||||
RemoteDiscovery bool `xml:"RemoteDiscovery,attr"`
|
RemoteDiscovery bool `xml:"RemoteDiscovery,attr"`
|
||||||
SystemBackup bool `xml:"SystemBackup,attr"`
|
SystemBackup bool `xml:"SystemBackup,attr"`
|
||||||
SystemLogging bool `xml:"SystemLogging,attr"`
|
SystemLogging bool `xml:"SystemLogging,attr"`
|
||||||
FirmwareUpgrade bool `xml:"FirmwareUpgrade,attr"`
|
FirmwareUpgrade bool `xml:"FirmwareUpgrade,attr"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// IOCapabilities represents I/O capabilities
|
// IOCapabilities represents I/O capabilities
|
||||||
@@ -127,8 +127,8 @@ type GetServicesResponse struct {
|
|||||||
|
|
||||||
// Service represents a service
|
// Service represents a service
|
||||||
type Service struct {
|
type Service struct {
|
||||||
Namespace string `xml:"Namespace"`
|
Namespace string `xml:"Namespace"`
|
||||||
XAddr string `xml:"XAddr"`
|
XAddr string `xml:"XAddr"`
|
||||||
Version Version `xml:"Version"`
|
Version Version `xml:"Version"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+20
-20
@@ -42,18 +42,18 @@ type BacklightCompensationSettings struct {
|
|||||||
|
|
||||||
// ExposureSettings20 represents exposure settings for ONVIF 2.0
|
// ExposureSettings20 represents exposure settings for ONVIF 2.0
|
||||||
type ExposureSettings20 struct {
|
type ExposureSettings20 struct {
|
||||||
Mode string `xml:"Mode"`
|
Mode string `xml:"Mode"`
|
||||||
Priority *string `xml:"Priority,omitempty"`
|
Priority *string `xml:"Priority,omitempty"`
|
||||||
Window *Rectangle `xml:"Window,omitempty"`
|
Window *Rectangle `xml:"Window,omitempty"`
|
||||||
MinExposureTime *float64 `xml:"MinExposureTime,omitempty"`
|
MinExposureTime *float64 `xml:"MinExposureTime,omitempty"`
|
||||||
MaxExposureTime *float64 `xml:"MaxExposureTime,omitempty"`
|
MaxExposureTime *float64 `xml:"MaxExposureTime,omitempty"`
|
||||||
MinGain *float64 `xml:"MinGain,omitempty"`
|
MinGain *float64 `xml:"MinGain,omitempty"`
|
||||||
MaxGain *float64 `xml:"MaxGain,omitempty"`
|
MaxGain *float64 `xml:"MaxGain,omitempty"`
|
||||||
MinIris *float64 `xml:"MinIris,omitempty"`
|
MinIris *float64 `xml:"MinIris,omitempty"`
|
||||||
MaxIris *float64 `xml:"MaxIris,omitempty"`
|
MaxIris *float64 `xml:"MaxIris,omitempty"`
|
||||||
ExposureTime *float64 `xml:"ExposureTime,omitempty"`
|
ExposureTime *float64 `xml:"ExposureTime,omitempty"`
|
||||||
Gain *float64 `xml:"Gain,omitempty"`
|
Gain *float64 `xml:"Gain,omitempty"`
|
||||||
Iris *float64 `xml:"Iris,omitempty"`
|
Iris *float64 `xml:"Iris,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// FocusConfiguration20 represents focus configuration for ONVIF 2.0
|
// FocusConfiguration20 represents focus configuration for ONVIF 2.0
|
||||||
@@ -168,15 +168,15 @@ type WhiteBalanceOptions struct {
|
|||||||
|
|
||||||
// MoveRequest represents Move (focus) request
|
// MoveRequest represents Move (focus) request
|
||||||
type MoveRequest struct {
|
type MoveRequest struct {
|
||||||
XMLName xml.Name `xml:"http://www.onvif.org/ver20/imaging/wsdl Move"`
|
XMLName xml.Name `xml:"http://www.onvif.org/ver20/imaging/wsdl Move"`
|
||||||
VideoSourceToken string `xml:"VideoSourceToken"`
|
VideoSourceToken string `xml:"VideoSourceToken"`
|
||||||
Focus *FocusMove `xml:"Focus"`
|
Focus *FocusMove `xml:"Focus"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// FocusMove represents focus move parameters
|
// FocusMove represents focus move parameters
|
||||||
type FocusMove struct {
|
type FocusMove struct {
|
||||||
Absolute *AbsoluteFocus `xml:"Absolute,omitempty"`
|
Absolute *AbsoluteFocus `xml:"Absolute,omitempty"`
|
||||||
Relative *RelativeFocus `xml:"Relative,omitempty"`
|
Relative *RelativeFocus `xml:"Relative,omitempty"`
|
||||||
Continuous *ContinuousFocus `xml:"Continuous,omitempty"`
|
Continuous *ContinuousFocus `xml:"Continuous,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,10 +342,10 @@ func (s *Server) HandleSetImagingSettings(body interface{}) (interface{}, error)
|
|||||||
func (s *Server) HandleGetOptions(body interface{}) (interface{}, error) {
|
func (s *Server) HandleGetOptions(body interface{}) (interface{}, error) {
|
||||||
// Return available imaging options/capabilities
|
// Return available imaging options/capabilities
|
||||||
options := &ImagingOptions{
|
options := &ImagingOptions{
|
||||||
Brightness: &FloatRange{Min: 0, Max: 100},
|
Brightness: &FloatRange{Min: 0, Max: 100},
|
||||||
ColorSaturation: &FloatRange{Min: 0, Max: 100},
|
ColorSaturation: &FloatRange{Min: 0, Max: 100},
|
||||||
Contrast: &FloatRange{Min: 0, Max: 100},
|
Contrast: &FloatRange{Min: 0, Max: 100},
|
||||||
Sharpness: &FloatRange{Min: 0, Max: 100},
|
Sharpness: &FloatRange{Min: 0, Max: 100},
|
||||||
IrCutFilterModes: []string{"ON", "OFF", "AUTO"},
|
IrCutFilterModes: []string{"ON", "OFF", "AUTO"},
|
||||||
BacklightCompensation: &BacklightCompensationOptions{
|
BacklightCompensation: &BacklightCompensationOptions{
|
||||||
Mode: []string{"OFF", "ON"},
|
Mode: []string{"OFF", "ON"},
|
||||||
|
|||||||
+11
-11
@@ -9,7 +9,7 @@ import (
|
|||||||
|
|
||||||
// GetProfilesResponse represents GetProfiles response
|
// GetProfilesResponse represents GetProfiles response
|
||||||
type GetProfilesResponse struct {
|
type GetProfilesResponse struct {
|
||||||
XMLName xml.Name `xml:"http://www.onvif.org/ver10/media/wsdl GetProfilesResponse"`
|
XMLName xml.Name `xml:"http://www.onvif.org/ver10/media/wsdl GetProfilesResponse"`
|
||||||
Profiles []MediaProfile `xml:"Profiles"`
|
Profiles []MediaProfile `xml:"Profiles"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,16 +46,16 @@ type AudioSourceConfiguration struct {
|
|||||||
|
|
||||||
// VideoEncoderConfiguration represents video encoder configuration
|
// VideoEncoderConfiguration represents video encoder configuration
|
||||||
type VideoEncoderConfiguration struct {
|
type VideoEncoderConfiguration struct {
|
||||||
Token string `xml:"token,attr"`
|
Token string `xml:"token,attr"`
|
||||||
Name string `xml:"Name"`
|
Name string `xml:"Name"`
|
||||||
UseCount int `xml:"UseCount"`
|
UseCount int `xml:"UseCount"`
|
||||||
Encoding string `xml:"Encoding"`
|
Encoding string `xml:"Encoding"`
|
||||||
Resolution VideoResolution `xml:"Resolution"`
|
Resolution VideoResolution `xml:"Resolution"`
|
||||||
Quality float64 `xml:"Quality"`
|
Quality float64 `xml:"Quality"`
|
||||||
RateControl *VideoRateControl `xml:"RateControl,omitempty"`
|
RateControl *VideoRateControl `xml:"RateControl,omitempty"`
|
||||||
H264 *H264Configuration `xml:"H264,omitempty"`
|
H264 *H264Configuration `xml:"H264,omitempty"`
|
||||||
Multicast *MulticastConfiguration `xml:"Multicast,omitempty"`
|
Multicast *MulticastConfiguration `xml:"Multicast,omitempty"`
|
||||||
SessionTimeout string `xml:"SessionTimeout"`
|
SessionTimeout string `xml:"SessionTimeout"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// AudioEncoderConfiguration represents audio encoder configuration
|
// AudioEncoderConfiguration represents audio encoder configuration
|
||||||
@@ -130,7 +130,7 @@ type MulticastConfiguration struct {
|
|||||||
|
|
||||||
// IPAddress represents an IP address
|
// IPAddress represents an IP address
|
||||||
type IPAddress struct {
|
type IPAddress struct {
|
||||||
Type string `xml:"Type"`
|
Type string `xml:"Type"`
|
||||||
IPv4Address string `xml:"IPv4Address,omitempty"`
|
IPv4Address string `xml:"IPv4Address,omitempty"`
|
||||||
IPv6Address string `xml:"IPv6Address,omitempty"`
|
IPv6Address string `xml:"IPv6Address,omitempty"`
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-9
@@ -75,9 +75,9 @@ type GetStatusResponse struct {
|
|||||||
|
|
||||||
// PTZStatus represents PTZ status
|
// PTZStatus represents PTZ status
|
||||||
type PTZStatus struct {
|
type PTZStatus struct {
|
||||||
Position PTZVector `xml:"Position"`
|
Position PTZVector `xml:"Position"`
|
||||||
MoveStatus PTZMoveStatus `xml:"MoveStatus"`
|
MoveStatus PTZMoveStatus `xml:"MoveStatus"`
|
||||||
UTCTime string `xml:"UtcTime"`
|
UTCTime string `xml:"UtcTime"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// PTZMoveStatus represents PTZ movement status
|
// PTZMoveStatus represents PTZ movement status
|
||||||
@@ -113,7 +113,7 @@ type GetPresetsRequest struct {
|
|||||||
|
|
||||||
// GetPresetsResponse represents GetPresets response
|
// GetPresetsResponse represents GetPresets response
|
||||||
type GetPresetsResponse struct {
|
type GetPresetsResponse struct {
|
||||||
XMLName xml.Name `xml:"http://www.onvif.org/ver20/ptz/wsdl GetPresetsResponse"`
|
XMLName xml.Name `xml:"http://www.onvif.org/ver20/ptz/wsdl GetPresetsResponse"`
|
||||||
Preset []PTZPreset `xml:"Preset"`
|
Preset []PTZPreset `xml:"Preset"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,16 +153,16 @@ type SetPresetResponse struct {
|
|||||||
|
|
||||||
// GetConfigurationsResponse represents GetConfigurations response
|
// GetConfigurationsResponse represents GetConfigurations response
|
||||||
type GetConfigurationsResponse struct {
|
type GetConfigurationsResponse struct {
|
||||||
XMLName xml.Name `xml:"http://www.onvif.org/ver20/ptz/wsdl GetConfigurationsResponse"`
|
XMLName xml.Name `xml:"http://www.onvif.org/ver20/ptz/wsdl GetConfigurationsResponse"`
|
||||||
PTZConfiguration []PTZConfigurationExt `xml:"PTZConfiguration"`
|
PTZConfiguration []PTZConfigurationExt `xml:"PTZConfiguration"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// PTZConfigurationExt represents PTZ configuration with extensions
|
// PTZConfigurationExt represents PTZ configuration with extensions
|
||||||
type PTZConfigurationExt struct {
|
type PTZConfigurationExt struct {
|
||||||
Token string `xml:"token,attr"`
|
Token string `xml:"token,attr"`
|
||||||
Name string `xml:"Name"`
|
Name string `xml:"Name"`
|
||||||
UseCount int `xml:"UseCount"`
|
UseCount int `xml:"UseCount"`
|
||||||
NodeToken string `xml:"NodeToken"`
|
NodeToken string `xml:"NodeToken"`
|
||||||
PanTiltLimits *PanTiltLimits `xml:"PanTiltLimits,omitempty"`
|
PanTiltLimits *PanTiltLimits `xml:"PanTiltLimits,omitempty"`
|
||||||
ZoomLimits *ZoomLimits `xml:"ZoomLimits,omitempty"`
|
ZoomLimits *ZoomLimits `xml:"ZoomLimits,omitempty"`
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-5
@@ -27,14 +27,14 @@ func New(config *Config) (*Server, error) {
|
|||||||
for i := range config.Profiles {
|
for i := range config.Profiles {
|
||||||
profile := &config.Profiles[i]
|
profile := &config.Profiles[i]
|
||||||
streamPath := fmt.Sprintf("/stream%d", i)
|
streamPath := fmt.Sprintf("/stream%d", i)
|
||||||
|
|
||||||
host := config.Host
|
host := config.Host
|
||||||
if host == "0.0.0.0" || host == "" {
|
if host == "0.0.0.0" || host == "" {
|
||||||
host = "localhost"
|
host = "localhost"
|
||||||
}
|
}
|
||||||
|
|
||||||
streamURI := fmt.Sprintf("rtsp://%s:8554%s", host, streamPath)
|
streamURI := fmt.Sprintf("rtsp://%s:8554%s", host, streamPath)
|
||||||
|
|
||||||
server.streams[profile.Token] = &StreamConfig{
|
server.streams[profile.Token] = &StreamConfig{
|
||||||
ProfileToken: profile.Token,
|
ProfileToken: profile.Token,
|
||||||
RTSPPath: streamPath,
|
RTSPPath: streamPath,
|
||||||
@@ -104,11 +104,11 @@ func (s *Server) Start(ctx context.Context) error {
|
|||||||
// Register service handlers
|
// Register service handlers
|
||||||
s.registerDeviceService(mux)
|
s.registerDeviceService(mux)
|
||||||
s.registerMediaService(mux)
|
s.registerMediaService(mux)
|
||||||
|
|
||||||
if s.config.SupportPTZ {
|
if s.config.SupportPTZ {
|
||||||
s.registerPTZService(mux)
|
s.registerPTZService(mux)
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.config.SupportImaging {
|
if s.config.SupportImaging {
|
||||||
s.registerImagingService(mux)
|
s.registerImagingService(mux)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ func (h *Handler) extractAction(bodyXML []byte) string {
|
|||||||
decoder := xml.NewDecoder(bytes.NewReader(bodyXML))
|
decoder := xml.NewDecoder(bytes.NewReader(bodyXML))
|
||||||
inBody := false
|
inBody := false
|
||||||
depth := 0
|
depth := 0
|
||||||
|
|
||||||
for {
|
for {
|
||||||
token, err := decoder.Token()
|
token, err := decoder.Token()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -241,17 +241,17 @@ type GetSystemDateAndTimeRequest struct {
|
|||||||
|
|
||||||
// GetSystemDateAndTimeResponse represents GetSystemDateAndTime response
|
// GetSystemDateAndTimeResponse represents GetSystemDateAndTime response
|
||||||
type GetSystemDateAndTimeResponse struct {
|
type GetSystemDateAndTimeResponse struct {
|
||||||
XMLName xml.Name `xml:"http://www.onvif.org/ver10/device/wsdl GetSystemDateAndTimeResponse"`
|
XMLName xml.Name `xml:"http://www.onvif.org/ver10/device/wsdl GetSystemDateAndTimeResponse"`
|
||||||
SystemDateAndTime SystemDateAndTime `xml:"SystemDateAndTime"`
|
SystemDateAndTime SystemDateAndTime `xml:"SystemDateAndTime"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SystemDateAndTime represents system date and time
|
// SystemDateAndTime represents system date and time
|
||||||
type SystemDateAndTime struct {
|
type SystemDateAndTime struct {
|
||||||
DateTimeType string `xml:"DateTimeType"`
|
DateTimeType string `xml:"DateTimeType"`
|
||||||
DaylightSavings bool `xml:"DaylightSavings"`
|
DaylightSavings bool `xml:"DaylightSavings"`
|
||||||
TimeZone TimeZone `xml:"TimeZone,omitempty"`
|
TimeZone TimeZone `xml:"TimeZone,omitempty"`
|
||||||
UTCDateTime DateTime `xml:"UTCDateTime,omitempty"`
|
UTCDateTime DateTime `xml:"UTCDateTime,omitempty"`
|
||||||
LocalDateTime DateTime `xml:"LocalDateTime,omitempty"`
|
LocalDateTime DateTime `xml:"LocalDateTime,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TimeZone represents timezone information
|
// TimeZone represents timezone information
|
||||||
|
|||||||
+10
-10
@@ -88,15 +88,15 @@ type AudioEncoderConfig struct {
|
|||||||
|
|
||||||
// PTZConfig represents PTZ configuration
|
// PTZConfig represents PTZ configuration
|
||||||
type PTZConfig struct {
|
type PTZConfig struct {
|
||||||
NodeToken string // PTZ node token
|
NodeToken string // PTZ node token
|
||||||
PanRange Range // Pan range in degrees
|
PanRange Range // Pan range in degrees
|
||||||
TiltRange Range // Tilt range in degrees
|
TiltRange Range // Tilt range in degrees
|
||||||
ZoomRange Range // Zoom range
|
ZoomRange Range // Zoom range
|
||||||
DefaultSpeed PTZSpeed // Default speed
|
DefaultSpeed PTZSpeed // Default speed
|
||||||
SupportsContinuous bool // Supports continuous move
|
SupportsContinuous bool // Supports continuous move
|
||||||
SupportsAbsolute bool // Supports absolute move
|
SupportsAbsolute bool // Supports absolute move
|
||||||
SupportsRelative bool // Supports relative move
|
SupportsRelative bool // Supports relative move
|
||||||
Presets []Preset // Predefined presets
|
Presets []Preset // Predefined presets
|
||||||
}
|
}
|
||||||
|
|
||||||
// SnapshotConfig represents snapshot configuration
|
// SnapshotConfig represents snapshot configuration
|
||||||
@@ -195,8 +195,8 @@ type BacklightCompensation struct {
|
|||||||
|
|
||||||
// ExposureSettings represents exposure settings
|
// ExposureSettings represents exposure settings
|
||||||
type ExposureSettings struct {
|
type ExposureSettings struct {
|
||||||
Mode string // AUTO, MANUAL
|
Mode string // AUTO, MANUAL
|
||||||
Priority string // LowNoise, FrameRate
|
Priority string // LowNoise, FrameRate
|
||||||
MinExposure float64
|
MinExposure float64
|
||||||
MaxExposure float64
|
MaxExposure float64
|
||||||
MinGain float64
|
MinGain float64
|
||||||
@@ -207,7 +207,7 @@ type ExposureSettings struct {
|
|||||||
|
|
||||||
// FocusSettings represents focus settings
|
// FocusSettings represents focus settings
|
||||||
type FocusSettings struct {
|
type FocusSettings struct {
|
||||||
AutoFocusMode string // AUTO, MANUAL
|
AutoFocusMode string // AUTO, MANUAL
|
||||||
DefaultSpeed float64
|
DefaultSpeed float64
|
||||||
NearLimit float64
|
NearLimit float64
|
||||||
FarLimit float64
|
FarLimit float64
|
||||||
@@ -216,7 +216,7 @@ type FocusSettings struct {
|
|||||||
|
|
||||||
// WhiteBalanceSettings represents white balance settings
|
// WhiteBalanceSettings represents white balance settings
|
||||||
type WhiteBalanceSettings struct {
|
type WhiteBalanceSettings struct {
|
||||||
Mode string // AUTO, MANUAL
|
Mode string // AUTO, MANUAL
|
||||||
CrGain float64
|
CrGain float64
|
||||||
CbGain float64
|
CbGain float64
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
package onvif
|
package onvif
|
||||||
package captures
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|||||||
@@ -872,9 +872,9 @@ const (
|
|||||||
|
|
||||||
// RemoteUser represents remote user configuration
|
// RemoteUser represents remote user configuration
|
||||||
type RemoteUser struct {
|
type RemoteUser struct {
|
||||||
Username string
|
Username string
|
||||||
Password string
|
Password string
|
||||||
UseDerivedPassword bool
|
UseDerivedPassword bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Certificate represents a certificate
|
// Certificate represents a certificate
|
||||||
@@ -917,17 +917,17 @@ type CertificateUsage struct {
|
|||||||
|
|
||||||
// DateTimeRange represents date/time range
|
// DateTimeRange represents date/time range
|
||||||
type DateTimeRange struct {
|
type DateTimeRange struct {
|
||||||
From time.Time
|
From time.Time
|
||||||
Until time.Time
|
Until time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dot11Capabilities represents 802.11 capabilities
|
// Dot11Capabilities represents 802.11 capabilities
|
||||||
type Dot11Capabilities struct {
|
type Dot11Capabilities struct {
|
||||||
TKIP bool
|
TKIP bool
|
||||||
ScanAvailableNetworks bool
|
ScanAvailableNetworks bool
|
||||||
MultipleConfiguration bool
|
MultipleConfiguration bool
|
||||||
AdHocStationMode bool
|
AdHocStationMode bool
|
||||||
WEP bool
|
WEP bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dot11Status represents 802.11 status
|
// Dot11Status represents 802.11 status
|
||||||
@@ -985,12 +985,12 @@ type TLSConfiguration struct {
|
|||||||
|
|
||||||
// Dot11AvailableNetworks represents available 802.11 networks
|
// Dot11AvailableNetworks represents available 802.11 networks
|
||||||
type Dot11AvailableNetworks struct {
|
type Dot11AvailableNetworks struct {
|
||||||
SSID string
|
SSID string
|
||||||
BSSID string
|
BSSID string
|
||||||
AuthAndMangementSuite []Dot11AuthAndMangementSuite
|
AuthAndMangementSuite []Dot11AuthAndMangementSuite
|
||||||
PairCipher []Dot11Cipher
|
PairCipher []Dot11Cipher
|
||||||
GroupCipher []Dot11Cipher
|
GroupCipher []Dot11Cipher
|
||||||
SignalStrength Dot11SignalStrength
|
SignalStrength Dot11SignalStrength
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dot11AuthAndMangementSuite represents auth suite
|
// Dot11AuthAndMangementSuite represents auth suite
|
||||||
@@ -1011,18 +1011,18 @@ type StorageConfiguration struct {
|
|||||||
|
|
||||||
// StorageConfigurationData represents storage configuration data
|
// StorageConfigurationData represents storage configuration data
|
||||||
type StorageConfigurationData struct {
|
type StorageConfigurationData struct {
|
||||||
Type string
|
Type string
|
||||||
LocalPath string
|
LocalPath string
|
||||||
StorageUri string
|
StorageUri string
|
||||||
User *UserCredential
|
User *UserCredential
|
||||||
CertPathValidationPolicyID string
|
CertPathValidationPolicyID string
|
||||||
}
|
}
|
||||||
|
|
||||||
// UserCredential represents user credentials
|
// UserCredential represents user credentials
|
||||||
type UserCredential struct {
|
type UserCredential struct {
|
||||||
UserName string
|
UserName string
|
||||||
Password string
|
Password string
|
||||||
Token string
|
Token string
|
||||||
}
|
}
|
||||||
|
|
||||||
// LocationEntity represents geo location
|
// LocationEntity represents geo location
|
||||||
@@ -1049,12 +1049,12 @@ type AccessPolicy struct {
|
|||||||
|
|
||||||
// PasswordComplexityConfiguration represents password complexity config
|
// PasswordComplexityConfiguration represents password complexity config
|
||||||
type PasswordComplexityConfiguration struct {
|
type PasswordComplexityConfiguration struct {
|
||||||
MinLen int
|
MinLen int
|
||||||
Uppercase int
|
Uppercase int
|
||||||
Number int
|
Number int
|
||||||
SpecialChars int
|
SpecialChars int
|
||||||
BlockUsernameOccurrence bool
|
BlockUsernameOccurrence bool
|
||||||
PolicyConfigurationLocked bool
|
PolicyConfigurationLocked bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// PasswordHistoryConfiguration represents password history config
|
// PasswordHistoryConfiguration represents password history config
|
||||||
|
|||||||
Reference in New Issue
Block a user