132 lines
3.8 KiB
Go
132 lines
3.8 KiB
Go
// NextNVR v0.1.0 — Configuration management
|
|
// Handles config.yaml parsing with sensible defaults
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
// Config represents the top-level application configuration.
|
|
type Config struct {
|
|
Server ServerConfig `yaml:"server" json:"server"`
|
|
Storage StorageConfig `yaml:"storage" json:"storage"`
|
|
Cameras []CameraConfig `yaml:"cameras" json:"cameras"`
|
|
Go2RTC Go2RTCConfig `yaml:"go2rtc" json:"go2rtc"`
|
|
}
|
|
|
|
// ServerConfig holds HTTP server settings.
|
|
type ServerConfig struct {
|
|
Port string `yaml:"port" json:"port"`
|
|
BindHost string `yaml:"bind_host" json:"bind_host"`
|
|
}
|
|
|
|
// StorageConfig holds recording and retention settings.
|
|
type StorageConfig struct {
|
|
RecordingsPath string `yaml:"recordings_path" json:"recordings_path"`
|
|
RetentionDays int `yaml:"retention_days" json:"retention_days"`
|
|
CleanupIntervalMins int `yaml:"cleanup_interval_mins" json:"cleanup_interval_mins"`
|
|
}
|
|
|
|
// CameraConfig represents a single camera's configuration.
|
|
type CameraConfig struct {
|
|
ID string `yaml:"id" json:"id"`
|
|
Name string `yaml:"name" json:"name"`
|
|
IP string `yaml:"ip" json:"ip"`
|
|
Username string `yaml:"username" json:"username"`
|
|
Password string `yaml:"password" json:"password"`
|
|
ONVIFPort int `yaml:"onvif_port" json:"onvif_port,string"`
|
|
RTSPMain string `yaml:"rtsp_main" json:"rtsp_main"`
|
|
RTSPSub string `yaml:"rtsp_sub" json:"rtsp_sub"`
|
|
Description string `yaml:"description" json:"description"`
|
|
Enabled bool `yaml:"enabled" json:"enabled"`
|
|
Record bool `yaml:"record" json:"record"`
|
|
}
|
|
|
|
// Go2RTCConfig holds go2rtc child process settings.
|
|
type Go2RTCConfig struct {
|
|
Enabled bool `yaml:"enabled" json:"enabled"`
|
|
Port string `yaml:"port" json:"port"`
|
|
Binary string `yaml:"binary" json:"binary"`
|
|
}
|
|
|
|
// APIResponse wraps all JSON API responses.
|
|
type APIResponse struct {
|
|
Success bool `json:"success"`
|
|
Data interface{} `json:"data,omitempty"`
|
|
Error string `json:"error,omitempty"`
|
|
}
|
|
|
|
// CameraStatus extends CameraConfig with runtime information.
|
|
type CameraStatus struct {
|
|
CameraConfig
|
|
Online bool `json:"online"`
|
|
Uptime string `json:"uptime"`
|
|
Streams int `json:"streams"`
|
|
}
|
|
|
|
// DefaultConfig returns a Config with sensible defaults.
|
|
func DefaultConfig() Config {
|
|
return Config{
|
|
Server: ServerConfig{
|
|
Port: ":8080",
|
|
BindHost: "0.0.0.0",
|
|
},
|
|
Storage: StorageConfig{
|
|
RecordingsPath: "/mnt/recordings",
|
|
RetentionDays: 18,
|
|
CleanupIntervalMins: 60,
|
|
},
|
|
Go2RTC: Go2RTCConfig{
|
|
Enabled: true,
|
|
Port: ":1984",
|
|
Binary: "go2rtc",
|
|
},
|
|
}
|
|
}
|
|
|
|
// LoadConfig reads and parses a YAML configuration file.
|
|
// If the file does not exist, it returns DefaultConfig().
|
|
func LoadConfig(path string) (Config, error) {
|
|
cfg := DefaultConfig()
|
|
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return cfg, fmt.Errorf("config file not found: %s", path)
|
|
}
|
|
return cfg, fmt.Errorf("reading config: %w", err)
|
|
}
|
|
|
|
if err := yaml.Unmarshal(data, &cfg); err != nil {
|
|
return cfg, fmt.Errorf("parsing config: %w", err)
|
|
}
|
|
|
|
// Apply path defaults relative to config file location.
|
|
configDir := filepath.Dir(path)
|
|
if cfg.Storage.RecordingsPath == "" {
|
|
cfg.Storage.RecordingsPath = "/mnt/recordings"
|
|
}
|
|
_ = configDir // reserved for relative path resolution
|
|
|
|
return cfg, nil
|
|
}
|
|
|
|
// SaveConfig writes the configuration to a YAML file.
|
|
func SaveConfig(cfg Config, path string) error {
|
|
data, err := yaml.Marshal(&cfg)
|
|
if err != nil {
|
|
return fmt.Errorf("marshaling config: %w", err)
|
|
}
|
|
|
|
header := []byte("# NextNVR Configuration\n# Generated by NextNVR setup\n\n")
|
|
out := append(header, data...)
|
|
|
|
if err := os.WriteFile(path, out, 0644); err != nil {
|
|
return fmt.Errorf("writing config: %w", err)
|
|
}
|
|
return nil
|
|
}
|