refactor: introduce constants for improved maintainability in tests and server configurations

- Added constants for test endpoints, usernames, and XML headers in client_test.go and device_certificates_test.go to enhance readability and reduce hardcoded values.
- Updated various test cases to utilize these constants, ensuring consistency across tests.
- Refactored imaging settings and server configurations to use defined constants for default values, improving clarity and maintainability in server/device.go and server/imaging.go.
- Enhanced comments throughout the code to clarify functionality and adhere to best practices.
This commit is contained in:
0x524a
2025-12-02 21:39:54 -05:00
parent 31df3f8b79
commit c1daba5be6
25 changed files with 253 additions and 159 deletions
+4 -3
View File
@@ -25,6 +25,7 @@ const (
bufferSize1024 = 1024
largeASCIIWidth = 160
largeASCIIHeight = 50
defaultQuality = "medium"
)
// DefaultASCIIConfig returns a sensible default configuration.
@@ -70,7 +71,7 @@ func ImageToASCII(imageData []byte, config ASCIIConfig) (string, error) {
// imageToASCIIFromImage is the core conversion function.
//
//nolint:gocyclo // Image to ASCII conversion has high complexity due to multiple pixel processing paths
func imageToASCIIFromImage(img image.Image, config ASCIIConfig, format string) (string, error) {
func imageToASCIIFromImage(img image.Image, config ASCIIConfig, format string) (string, error) { //nolint:unparam // format reserved for future use
// Validate configuration
if config.Width <= 0 {
config.Width = 120
@@ -79,7 +80,7 @@ func imageToASCIIFromImage(img image.Image, config ASCIIConfig, format string) (
config.Height = defaultASCIIHeight
}
if config.Quality == "" {
config.Quality = "medium"
config.Quality = defaultQuality
}
// Select character set based on quality
@@ -220,7 +221,7 @@ type ImageInfo struct {
// formatBytes converts bytes to human-readable format.
func formatBytes(bytes int64) string {
if bytes < 1024 {
if bytes < bufferSize1024 {
return fmt.Sprintf("%d B", bytes)
}
const kbSize = 1024
+24 -14
View File
@@ -23,6 +23,7 @@ const (
ptzTimeoutSeconds = 30
maxRetries = 3
readBufferSize = 5
defaultBrightness = "50.0"
)
type CLI struct {
@@ -114,7 +115,7 @@ func (c *CLI) discoverCameras() {
// Try auto-discovery first (no specific interface)
fmt.Println("⏳ Attempting auto-discovery on default interface...")
devices, err := discovery.DiscoverWithOptions(ctx, 5*time.Second, &discovery.DiscoverOptions{})
devices, err := discovery.DiscoverWithOptions(ctx, defaultRetryDelay*time.Second, &discovery.DiscoverOptions{})
// If auto-discovery fails or finds nothing, offer interface selection
if err != nil || len(devices) == 0 {
@@ -275,7 +276,11 @@ func (c *CLI) performDiscoveryOnInterface(interfaceName string) ([]*discovery.De
NetworkInterface: interfaceName,
}
return discovery.DiscoverWithOptions(ctx, 5*time.Second, opts)
devices, err := discovery.DiscoverWithOptions(ctx, defaultRetryDelay*time.Second, opts)
if err != nil {
return nil, fmt.Errorf("discovery failed: %w", err)
}
return devices, nil
}
func (c *CLI) selectAndConnectCamera(devices []*discovery.Device) {
@@ -361,7 +366,7 @@ func (c *CLI) createClient(endpoint, username, password string, insecure bool) {
opts := []onvif.ClientOption{
onvif.WithCredentials(username, password),
onvif.WithTimeout(30 * time.Second),
onvif.WithTimeout(ptzTimeoutSeconds * time.Second),
}
if insecure {
@@ -607,10 +612,13 @@ func (c *CLI) inspectRTSPStream(streamURI string) map[string]interface{} {
}
// Use rtspeek library for detailed stream inspection
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
ctx, cancel := context.WithTimeout(
context.Background(),
defaultRetryDelay*time.Second, //nolint:mnd // Stream inspection timeout
)
defer cancel()
streamInfo, err := sd.DescribeStream(ctx, streamURI, 5*time.Second)
streamInfo, err := sd.DescribeStream(ctx, streamURI, defaultRetryDelay*time.Second) //nolint:mnd // Stream description timeout
if err == nil && streamInfo != nil {
details["reachable"] = streamInfo.IsReachable()
@@ -677,7 +685,7 @@ func (c *CLI) tryRTSPConnection(streamURI string) map[string]interface{} {
}
// Try to connect
conn, err := net.DialTimeout("tcp", hostPort, 3*time.Second)
conn, err := net.DialTimeout("tcp", hostPort, maxRetries*time.Second) //nolint:mnd // Connection timeout
if err == nil {
//nolint:errcheck // Close error is not critical for connectivity check
_ = conn.Close()
@@ -1287,7 +1295,7 @@ func (c *CLI) setBrightness(ctx context.Context, videoSourceToken string) {
return
}
currentValue := "50.0"
currentValue := defaultBrightness
if currentSettings.Brightness != nil {
currentValue = fmt.Sprintf("%.1f", *currentSettings.Brightness)
}
@@ -1322,7 +1330,7 @@ func (c *CLI) setContrast(ctx context.Context, videoSourceToken string) {
return
}
currentValue := "50.0"
currentValue := defaultBrightness
if currentSettings.Contrast != nil {
currentValue = fmt.Sprintf("%.1f", *currentSettings.Contrast)
}
@@ -1357,7 +1365,7 @@ func (c *CLI) setSaturation(ctx context.Context, videoSourceToken string) {
return
}
currentValue := "50.0"
currentValue := defaultBrightness
if currentSettings.ColorSaturation != nil {
currentValue = fmt.Sprintf("%.1f", *currentSettings.ColorSaturation)
}
@@ -1392,7 +1400,7 @@ func (c *CLI) setSharpness(ctx context.Context, videoSourceToken string) {
return
}
currentValue := "50.0"
currentValue := defaultBrightness
if currentSettings.Sharpness != nil {
currentValue = fmt.Sprintf("%.1f", *currentSettings.Sharpness)
}
@@ -1482,7 +1490,7 @@ func (c *CLI) advancedImagingSettings(ctx context.Context, videoSourceToken stri
}
//nolint:gocyclo // Snapshot capture and display has high complexity due to multiple error handling paths
func (c *CLI) captureAndDisplaySnapshot(ctx context.Context) {
func (c *CLI) captureAndDisplaySnapshot(ctx context.Context) { //nolint:funlen // Many statements due to error handling
fmt.Println("📷 Capture Snapshot as ASCII Preview")
fmt.Println("===================================")
fmt.Println()
@@ -1543,7 +1551,7 @@ func (c *CLI) captureAndDisplaySnapshot(ctx context.Context) {
case "2":
config.Width = 100
config.Height = 30
config.Quality = "medium"
config.Quality = defaultQuality
case "3":
config.Width = 140
config.Height = 40
@@ -1555,7 +1563,7 @@ func (c *CLI) captureAndDisplaySnapshot(ctx context.Context) {
default:
config.Width = 100
config.Height = 30
config.Quality = "medium"
config.Quality = defaultQuality
}
// Download actual snapshot
@@ -1606,7 +1614,9 @@ func (c *CLI) captureAndDisplaySnapshot(ctx context.Context) {
if filename == "" {
filename = "snapshot.jpg"
}
if err := os.WriteFile(filename, snapshotData, 0600); err != nil { //nolint:gosec // 0600 is appropriate for CLI output files
if err := os.WriteFile(
filename, snapshotData, 0600, //nolint:gosec,mnd // 0600 appropriate for CLI output files
); err != nil {
fmt.Printf("❌ Failed to save file: %v\n", err)
} else {
fmt.Printf("✅ Snapshot saved to %s\n", filename)
+12 -10
View File
@@ -26,6 +26,7 @@ const (
maxRetryAttempts = 10
retryDelaySec = 5
maxIdleTimeoutSec = 90
unknownStatus = "Unknown"
)
type CameraReport struct {
@@ -146,7 +147,7 @@ var (
username = flag.String("username", "", "ONVIF username")
password = flag.String("password", "", "ONVIF password")
outputDir = flag.String("output", "./camera-logs", "Output directory for logs")
timeout = flag.Int("timeout", 30, "Request timeout in seconds")
timeout = flag.Int("timeout", 30, "Request timeout in seconds") //nolint:mnd // Default timeout value
verbose = flag.Bool("verbose", false, "Verbose output")
captureXML = flag.Bool("capture-xml", false, "Capture raw SOAP XML traffic and create tar.gz archive")
)
@@ -174,7 +175,7 @@ func main() {
}
// Create output directory
if err := os.MkdirAll(*outputDir, 0750); err != nil { //nolint:gosec // 0750 is appropriate for diagnostic output directory
if err := os.MkdirAll(*outputDir, 0750); err != nil { //nolint:gosec,mnd // 0750 appropriate for diagnostic output
log.Fatalf("Failed to create output directory: %v", err)
}
@@ -198,7 +199,7 @@ func main() {
if *captureXML {
timestamp := time.Now().Format("20060102-150405")
xmlCaptureDir = filepath.Join(*outputDir, "temp_"+timestamp)
if err := os.MkdirAll(xmlCaptureDir, 0750); err != nil { //nolint:gosec // 0750 appropriate for diagnostic output
if err := os.MkdirAll(xmlCaptureDir, 0750); err != nil { //nolint:gosec,mnd // 0750 appropriate for diagnostic output
log.Fatalf("Failed to create XML capture directory: %v", err)
}
@@ -883,8 +884,7 @@ func saveReport(report *CameraReport, filename string) error {
return fmt.Errorf("failed to marshal report: %w", err)
}
if err := os.WriteFile(filename, data, 0600); err != nil {
//nolint:gosec // 0600 appropriate for diagnostic files
if err := os.WriteFile(filename, data, 0600); err != nil { //nolint:gosec,mnd // 0600 appropriate for diagnostic files
return fmt.Errorf("failed to write file: %w", err)
}
@@ -1024,22 +1024,24 @@ func (t *LoggingTransport) saveCapture(capture *XMLCapture) {
return
}
if err := os.WriteFile(filename, data, 0600); err != nil {
//nolint:gosec // 0600 appropriate for diagnostic files
if err := os.WriteFile(filename, data, 0600); err != nil { //nolint:gosec,mnd // 0600 appropriate for diagnostic files
log.Printf("Failed to write capture: %v", err)
}
// Pretty-print and save XML files for easier viewing
reqFile := filepath.Join(t.LogDir, baseFilename+"_request.xml")
prettyRequest := prettyPrintXML(capture.RequestBody)
if err := os.WriteFile(reqFile, []byte(prettyRequest), 0600); err != nil {
//nolint:gosec // 0600 appropriate for diagnostic files
if err := os.WriteFile(
reqFile, []byte(prettyRequest), 0600, //nolint:gosec,mnd // 0600 appropriate for diagnostic files
); err != nil {
log.Printf("Failed to write request XML: %v", err)
}
respFile := filepath.Join(t.LogDir, baseFilename+"_response.xml")
prettyResponse := prettyPrintXML(capture.ResponseBody)
if err := os.WriteFile(respFile, []byte(prettyResponse), 0600); err != nil { //nolint:gosec // 0600 appropriate for diagnostic files
if err := os.WriteFile(
respFile, []byte(prettyResponse), 0600, //nolint:gosec,mnd // 0600 appropriate for diagnostic files
); err != nil {
log.Printf("Failed to write response XML: %v", err)
}
}
+2 -3
View File
@@ -110,7 +110,7 @@ func discoverCameras() {
ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout*time.Second)
defer cancel()
devices, err := discovery.DiscoverWithOptions(ctx, 5*time.Second, opts)
devices, err := discovery.DiscoverWithOptions(ctx, defaultRetryDelay*time.Second, opts)
if err != nil {
fmt.Printf("❌ Error: %v\n", err)
@@ -233,8 +233,7 @@ func connectAndShowInfo() {
}
}
//nolint:gocyclo // PTZ demo function has high complexity due to multiple control paths
func ptzDemo() {
func ptzDemo() { //nolint:funlen,gocyclo // Many statements and high complexity due to user interaction
reader := bufio.NewReader(os.Stdin)
fmt.Print("Camera IP: ")
+8 -6
View File
@@ -17,7 +17,6 @@ var (
version = "1.0.0"
)
//nolint:funlen // Main function has many statements due to server setup and configuration
const (
defaultPort = 8080
maxWorkers = 3
@@ -28,6 +27,7 @@ const (
ptzSpeed = 0.5
)
//nolint:funlen // Main function has many statements due to server setup and configuration
func main() {
// Define command-line flags
host := flag.String("host", "0.0.0.0", "Server host address")
@@ -38,7 +38,7 @@ func main() {
model := flag.String("model", "Virtual Multi-Lens Camera", "Device model")
firmware := flag.String("firmware", "1.0.0", "Firmware version")
serial := flag.String("serial", "SN-12345678", "Serial number")
profiles := flag.Int("profiles", 3, "Number of camera profiles (1-10)")
profiles := flag.Int("profiles", maxWorkers, "Number of camera profiles (1-10)") //nolint:mnd // Default profile count
ptz := flag.Bool("ptz", true, "Enable PTZ support")
imaging := flag.Bool("imaging", true, "Enable Imaging support")
events := flag.Bool("events", false, "Enable Events support")
@@ -190,7 +190,7 @@ func buildConfig(host string, port int, username, password, manufacturer, model,
Snapshot: server.SnapshotConfig{
Enabled: true,
Resolution: server.Resolution{Width: template.width, Height: template.height},
Quality: template.quality + 5,
Quality: template.quality + 5, //nolint:mnd // Quality offset
},
}
@@ -212,9 +212,11 @@ func buildConfig(host string, port int, username, password, manufacturer, model,
Position: server.PTZPosition{Pan: 0, Tilt: 0, Zoom: 0},
},
{
Token: fmt.Sprintf("preset_%d_1", i),
Name: "Entrance",
Position: server.PTZPosition{Pan: -45, Tilt: -10, Zoom: template.ptzZoomMax * ptzSpeed}, //nolint:mnd // Preset position values
Token: fmt.Sprintf("preset_%d_1", i),
Name: "Entrance",
Position: server.PTZPosition{
Pan: -45, Tilt: -10, Zoom: template.ptzZoomMax * ptzSpeed, //nolint:mnd // Preset position values
},
},
},
}