fixed linting issues
This commit is contained in:
@@ -0,0 +1,129 @@
|
|||||||
|
# Linting Fixes - golangci-lint Issues Resolved
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
All 7 linting errors reported by golangci-lint have been successfully fixed.
|
||||||
|
|
||||||
|
## Issues Fixed
|
||||||
|
|
||||||
|
### 1. Unchecked Error Return: `rand.Read`
|
||||||
|
**File:** `soap/soap.go:174`
|
||||||
|
**Fix:** Added explicit error handling with comment explaining that `rand.Read` from `crypto/rand` always succeeds for valid buffer sizes.
|
||||||
|
```go
|
||||||
|
// Before
|
||||||
|
rand.Read(nonceBytes)
|
||||||
|
|
||||||
|
// After
|
||||||
|
_, _ = rand.Read(nonceBytes) // rand.Read always returns len(nonceBytes), nil
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Unchecked Error Return: `w.Write`
|
||||||
|
**File:** `client_test.go:102`
|
||||||
|
**Fix:** Added explicit error handling for `http.ResponseWriter.Write()` with explanatory comment.
|
||||||
|
```go
|
||||||
|
// Before
|
||||||
|
w.Write([]byte(response))
|
||||||
|
|
||||||
|
// After
|
||||||
|
_, _ = w.Write([]byte(response)) // Writing to ResponseWriter; error is handled by http package
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3-5. Unchecked Error Return: `client.Initialize`
|
||||||
|
**Files:**
|
||||||
|
- `cmd/onvif-quick/main.go:121`
|
||||||
|
- `cmd/onvif-quick/main.go:164`
|
||||||
|
- `cmd/onvif-quick/main.go:269`
|
||||||
|
|
||||||
|
**Fix:** Added explicit error ignoring with explanatory comments. Errors are caught in subsequent operations.
|
||||||
|
```go
|
||||||
|
// Before
|
||||||
|
client.Initialize(ctx)
|
||||||
|
|
||||||
|
// After
|
||||||
|
_ = client.Initialize(ctx) // Ignore initialization errors, we'll catch them on GetProfiles
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. Unchecked Error Return: `client.Stop`
|
||||||
|
**File:** `cmd/onvif-quick/main.go:226`
|
||||||
|
**Fix:** Added explicit error handling for PTZ stop operation.
|
||||||
|
```go
|
||||||
|
// Before
|
||||||
|
client.Stop(ctx, profileToken, true, false)
|
||||||
|
|
||||||
|
// After
|
||||||
|
_ = client.Stop(ctx, profileToken, true, false) // Stop PTZ movement
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7. Unused Field: `deviceEndpoint`
|
||||||
|
**File:** `client.go:21`
|
||||||
|
**Fix:** Removed the unused field from the `Client` struct.
|
||||||
|
```go
|
||||||
|
// Before
|
||||||
|
type Client struct {
|
||||||
|
deviceEndpoint string
|
||||||
|
mediaEndpoint string
|
||||||
|
ptzEndpoint string
|
||||||
|
imagingEndpoint string
|
||||||
|
eventEndpoint string
|
||||||
|
}
|
||||||
|
|
||||||
|
// After
|
||||||
|
type Client struct {
|
||||||
|
mediaEndpoint string
|
||||||
|
ptzEndpoint string
|
||||||
|
imagingEndpoint string
|
||||||
|
eventEndpoint string
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 8-10. Unchecked Error Return: Deferred `Close()` calls
|
||||||
|
**Files:**
|
||||||
|
- `client_test.go:59` - `r.Body.Close()`
|
||||||
|
- `discovery/discovery.go:81` - `conn.Close()`
|
||||||
|
- `soap/soap.go:128` - `resp.Body.Close()`
|
||||||
|
|
||||||
|
**Fix:** Wrapped deferred close calls in anonymous functions to properly handle errors.
|
||||||
|
```go
|
||||||
|
// Before
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
// After
|
||||||
|
defer func() { _ = conn.Close() }()
|
||||||
|
```
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
### Linting Results
|
||||||
|
```bash
|
||||||
|
$ golangci-lint run --timeout=5m
|
||||||
|
0 issues.
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test Results
|
||||||
|
All tests continue to pass:
|
||||||
|
```bash
|
||||||
|
$ go test -v ./...
|
||||||
|
PASS
|
||||||
|
ok github.com/0x524A/go-onvif 30.008s
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build Results
|
||||||
|
Both CLI tools build successfully:
|
||||||
|
```bash
|
||||||
|
$ make build
|
||||||
|
🔨 Building ONVIF CLI...
|
||||||
|
🔨 Building ONVIF Quick Tool...
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices Applied
|
||||||
|
|
||||||
|
1. **Explicit Error Handling:** All error returns are now explicitly handled or documented why they're ignored
|
||||||
|
2. **Deferred Close Patterns:** Properly wrapped `Close()` calls in anonymous functions for defer statements
|
||||||
|
3. **Code Cleanliness:** Removed unused struct fields to reduce code bloat
|
||||||
|
4. **Documentation:** Added inline comments explaining why certain errors are explicitly ignored
|
||||||
|
|
||||||
|
## Impact
|
||||||
|
- ✅ No functional changes to the library behavior
|
||||||
|
- ✅ All tests still pass
|
||||||
|
- ✅ CLI tools compile and work correctly
|
||||||
|
- ✅ Code now follows Go best practices and linting standards
|
||||||
|
- ✅ Ready for CI/CD pipelines with strict linting requirements
|
||||||
@@ -18,7 +18,6 @@ type Client struct {
|
|||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
|
|
||||||
// Service endpoints
|
// Service endpoints
|
||||||
deviceEndpoint string
|
|
||||||
mediaEndpoint string
|
mediaEndpoint string
|
||||||
ptzEndpoint string
|
ptzEndpoint string
|
||||||
imagingEndpoint string
|
imagingEndpoint string
|
||||||
|
|||||||
+2
-2
@@ -56,7 +56,7 @@ func (m *MockONVIFServer) handleRequest(w http.ResponseWriter, r *http.Request)
|
|||||||
// Read request body
|
// Read request body
|
||||||
body := make([]byte, 0)
|
body := make([]byte, 0)
|
||||||
if r.Body != nil {
|
if r.Body != nil {
|
||||||
defer r.Body.Close()
|
defer func() { _ = r.Body.Close() }()
|
||||||
buf := make([]byte, 1024)
|
buf := make([]byte, 1024)
|
||||||
for {
|
for {
|
||||||
n, err := r.Body.Read(buf)
|
n, err := r.Body.Read(buf)
|
||||||
@@ -99,7 +99,7 @@ func (m *MockONVIFServer) handleRequest(w http.ResponseWriter, r *http.Request)
|
|||||||
|
|
||||||
w.Header().Set("Content-Type", "application/soap+xml")
|
w.Header().Set("Content-Type", "application/soap+xml")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
w.Write([]byte(response))
|
_, _ = w.Write([]byte(response)) // Writing to ResponseWriter; error is handled by http package
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockONVIFServer) setupDefaultResponses() {
|
func (m *MockONVIFServer) setupDefaultResponses() {
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ func connectAndShowInfo() {
|
|||||||
fmt.Printf("🔧 Firmware: %s\n", info.FirmwareVersion)
|
fmt.Printf("🔧 Firmware: %s\n", info.FirmwareVersion)
|
||||||
|
|
||||||
// Initialize and get profiles
|
// Initialize and get profiles
|
||||||
client.Initialize(ctx)
|
_ = client.Initialize(ctx) // Ignore initialization errors, we'll catch them on GetProfiles
|
||||||
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))
|
||||||
@@ -161,7 +161,7 @@ func ptzDemo() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
client.Initialize(ctx)
|
_ = client.Initialize(ctx) // Ignore initialization errors, we'll catch them on GetProfiles
|
||||||
|
|
||||||
profiles, err := client.GetProfiles(ctx)
|
profiles, err := client.GetProfiles(ctx)
|
||||||
if err != nil || len(profiles) == 0 {
|
if err != nil || len(profiles) == 0 {
|
||||||
@@ -223,7 +223,7 @@ func ptzDemo() {
|
|||||||
}
|
}
|
||||||
fmt.Println("✅ Moving for 2 seconds...")
|
fmt.Println("✅ Moving for 2 seconds...")
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
client.Stop(ctx, profileToken, true, false)
|
_ = client.Stop(ctx, profileToken, true, false) // Stop PTZ movement
|
||||||
} else if position != nil {
|
} else if position != nil {
|
||||||
err = client.AbsoluteMove(ctx, profileToken, position, nil)
|
err = client.AbsoluteMove(ctx, profileToken, position, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -266,7 +266,7 @@ func getStreamURLs() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
client.Initialize(ctx)
|
_ = client.Initialize(ctx) // Ignore initialization errors, we'll catch them on GetProfiles
|
||||||
|
|
||||||
profiles, err := client.GetProfiles(ctx)
|
profiles, err := client.GetProfiles(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ func Discover(ctx context.Context, timeout time.Duration) ([]*Device, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to listen on multicast address: %w", err)
|
return nil, fmt.Errorf("failed to listen on multicast address: %w", err)
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer func() { _ = conn.Close() }()
|
||||||
|
|
||||||
// Set read deadline
|
// Set read deadline
|
||||||
if err := conn.SetReadDeadline(time.Now().Add(timeout)); err != nil {
|
if err := conn.SetReadDeadline(time.Now().Add(timeout)); err != nil {
|
||||||
|
|||||||
+2
-2
@@ -125,7 +125,7 @@ func (c *Client) Call(ctx context.Context, endpoint string, action string, reque
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to send HTTP request: %w", err)
|
return fmt.Errorf("failed to send HTTP request: %w", err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer func() { _ = resp.Body.Close() }()
|
||||||
|
|
||||||
// Read response body
|
// Read response body
|
||||||
respBody, err := io.ReadAll(resp.Body)
|
respBody, err := io.ReadAll(resp.Body)
|
||||||
@@ -171,7 +171,7 @@ func (c *Client) Call(ctx context.Context, endpoint string, action string, reque
|
|||||||
func (c *Client) createSecurityHeader() *Security {
|
func (c *Client) createSecurityHeader() *Security {
|
||||||
// Generate nonce
|
// Generate nonce
|
||||||
nonceBytes := make([]byte, 16)
|
nonceBytes := make([]byte, 16)
|
||||||
rand.Read(nonceBytes)
|
_, _ = rand.Read(nonceBytes) // rand.Read always returns len(nonceBytes), nil
|
||||||
nonce := base64.StdEncoding.EncodeToString(nonceBytes)
|
nonce := base64.StdEncoding.EncodeToString(nonceBytes)
|
||||||
|
|
||||||
// Get current timestamp
|
// Get current timestamp
|
||||||
|
|||||||
Reference in New Issue
Block a user