Add unified port configuration system
- Unified API and WebUI on single configurable port (default: 4567) - Added strix.yaml configuration file support (go2rtc-style format) - Environment variable STRIX_API_LISTEN overrides config file - Port validation and source logging - Relative URLs in frontend for automatic port detection - Removed separate server instances - Cleaned up temporary files and updated .gitignore - Updated documentation with configuration examples
This commit is contained in:
+104
-18
@@ -1,10 +1,15 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// Config holds application configuration
|
||||
@@ -17,8 +22,7 @@ type Config struct {
|
||||
|
||||
// ServerConfig contains HTTP server settings
|
||||
type ServerConfig struct {
|
||||
Host string
|
||||
Port string
|
||||
Listen string // Address to listen on (e.g., ":4567" or "0.0.0.0:4567")
|
||||
ReadTimeout time.Duration
|
||||
WriteTimeout time.Duration
|
||||
}
|
||||
@@ -35,17 +39,17 @@ type DatabaseConfig struct {
|
||||
|
||||
// ScannerConfig contains stream scanner settings
|
||||
type ScannerConfig struct {
|
||||
DefaultTimeout time.Duration
|
||||
MaxStreams int
|
||||
ModelSearchLimit int
|
||||
WorkerPoolSize int
|
||||
FFProbeTimeout time.Duration
|
||||
RetryAttempts int
|
||||
RetryDelay time.Duration
|
||||
DefaultTimeout time.Duration
|
||||
MaxStreams int
|
||||
ModelSearchLimit int
|
||||
WorkerPoolSize int
|
||||
FFProbeTimeout time.Duration
|
||||
RetryAttempts int
|
||||
RetryDelay time.Duration
|
||||
// Validation settings
|
||||
StrictValidation bool // Enable strict validation mode
|
||||
MinImageSize int // Minimum bytes for valid image (JPEG/PNG)
|
||||
MinVideoStreams int // Minimum video streams required
|
||||
StrictValidation bool // Enable strict validation mode
|
||||
MinImageSize int // Minimum bytes for valid image (JPEG/PNG)
|
||||
MinVideoStreams int // Minimum video streams required
|
||||
}
|
||||
|
||||
// LoggerConfig contains logging settings
|
||||
@@ -54,14 +58,20 @@ type LoggerConfig struct {
|
||||
Format string // "text" or "json"
|
||||
}
|
||||
|
||||
// yamlConfig represents the structure of strix.yaml
|
||||
type yamlConfig struct {
|
||||
API struct {
|
||||
Listen string `yaml:"listen"`
|
||||
} `yaml:"api"`
|
||||
}
|
||||
|
||||
// Load returns configuration with defaults
|
||||
func Load() *Config {
|
||||
dataPath := getEnv("STRIX_DATA_PATH", "./data")
|
||||
|
||||
return &Config{
|
||||
cfg := &Config{
|
||||
Server: ServerConfig{
|
||||
Host: getEnv("STRIX_HOST", "0.0.0.0"),
|
||||
Port: getEnv("STRIX_PORT", "8080"),
|
||||
Listen: ":4567", // Default listen address
|
||||
ReadTimeout: 30 * time.Second,
|
||||
WriteTimeout: 30 * time.Second,
|
||||
},
|
||||
@@ -83,14 +93,90 @@ func Load() *Config {
|
||||
RetryDelay: 500 * time.Millisecond,
|
||||
// Strict validation enabled by default
|
||||
StrictValidation: true,
|
||||
MinImageSize: 5120, // 5KB minimum for valid images
|
||||
MinVideoStreams: 1, // At least 1 video stream required
|
||||
MinImageSize: 5120, // 5KB minimum for valid images
|
||||
MinVideoStreams: 1, // At least 1 video stream required
|
||||
},
|
||||
Logger: LoggerConfig{
|
||||
Level: getEnv("STRIX_LOG_LEVEL", "info"),
|
||||
Format: getEnv("STRIX_LOG_FORMAT", "json"),
|
||||
},
|
||||
}
|
||||
|
||||
// Load from strix.yaml if exists
|
||||
configSource := "default"
|
||||
if err := loadYAML(cfg); err == nil {
|
||||
configSource = "strix.yaml"
|
||||
}
|
||||
|
||||
// Environment variable overrides everything
|
||||
if envListen := os.Getenv("STRIX_API_LISTEN"); envListen != "" {
|
||||
cfg.Server.Listen = envListen
|
||||
configSource = "environment variable STRIX_API_LISTEN"
|
||||
}
|
||||
|
||||
// Validate listen address
|
||||
if err := validateListen(cfg.Server.Listen); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "ERROR: Invalid listen address '%s': %v\n", cfg.Server.Listen, err)
|
||||
fmt.Fprintf(os.Stderr, "Using default: :4567\n")
|
||||
cfg.Server.Listen = ":4567"
|
||||
configSource = "default (validation failed)"
|
||||
}
|
||||
|
||||
// Log configuration source
|
||||
fmt.Printf("INFO: API listen address '%s' loaded from %s\n", cfg.Server.Listen, configSource)
|
||||
|
||||
return cfg
|
||||
}
|
||||
|
||||
// loadYAML attempts to load configuration from strix.yaml
|
||||
func loadYAML(cfg *Config) error {
|
||||
data, err := os.ReadFile("./strix.yaml")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var yamlCfg yamlConfig
|
||||
if err := yaml.Unmarshal(data, &yamlCfg); err != nil {
|
||||
return fmt.Errorf("failed to parse strix.yaml: %w", err)
|
||||
}
|
||||
|
||||
// Apply yaml configuration
|
||||
if yamlCfg.API.Listen != "" {
|
||||
cfg.Server.Listen = yamlCfg.API.Listen
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateListen validates the listen address format and port range
|
||||
func validateListen(listen string) error {
|
||||
if listen == "" {
|
||||
return fmt.Errorf("listen address cannot be empty")
|
||||
}
|
||||
|
||||
// Parse the listen address
|
||||
parts := strings.Split(listen, ":")
|
||||
if len(parts) < 2 {
|
||||
return fmt.Errorf("invalid format, expected ':port' or 'host:port', got '%s'", listen)
|
||||
}
|
||||
|
||||
// Get port (last part)
|
||||
portStr := parts[len(parts)-1]
|
||||
if portStr == "" {
|
||||
return fmt.Errorf("port cannot be empty")
|
||||
}
|
||||
|
||||
// Validate port number
|
||||
port, err := strconv.Atoi(portStr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid port number '%s': %w", portStr, err)
|
||||
}
|
||||
|
||||
if port < 1 || port > 65535 {
|
||||
return fmt.Errorf("port %d out of valid range (1-65535)", port)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetupLogger configures the global logger
|
||||
@@ -126,4 +212,4 @@ func getEnv(key, defaultValue string) string {
|
||||
return value
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user