NextNVR/config.go

138 lines
3.4 KiB
Go

// NextNVR — MIT License
// Copyright (c) 2026 NextNVR Contributors
// SPDX-License-Identifier: MIT
//
// config.go — JSON configuration management. Zero external dependencies.
package main
import (
"encoding/json"
"fmt"
"os"
)
// Config represents the top-level application configuration.
type Config struct {
Server ServerConfig `json:"server"`
Storage StorageConfig `json:"storage"`
Auth AuthConfig `json:"auth"`
Cameras []CameraConfig `json:"cameras"`
Go2RTC Go2RTCConfig `json:"go2rtc"`
}
type ServerConfig struct {
Port string `json:"port"`
BindHost string `json:"bind_host"`
ViewerPort string `json:"viewer_port"`
}
type StorageConfig struct {
RecordingsPath string `json:"recordings_path"`
RetentionDays int `json:"retention_days"`
CleanupIntervalMins int `json:"cleanup_interval_mins"`
}
type CameraConfig struct {
ID string `json:"id"`
Name string `json:"name"`
IP string `json:"ip"`
Username string `json:"username"`
Password string `json:"password"`
ONVIFPort int `json:"onvif_port,string"`
RTSPMain string `json:"rtsp_main"`
RTSPSub string `json:"rtsp_sub"`
Description string `json:"description"`
Enabled bool `json:"enabled"`
Record bool `json:"record"`
}
type Go2RTCConfig struct {
Enabled bool `json:"enabled"`
Port string `json:"port"`
Binary string `json:"binary"`
}
type AuthConfig struct {
Enabled bool `json:"enabled"`
Master UserConfig `json:"master"`
Viewer UserConfig `json:"viewer"`
}
type UserConfig struct {
Username string `json:"username"`
Password string `json:"password"`
Enabled bool `json:"enabled"`
}
// 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",
ViewerPort: ":8090",
},
Storage: StorageConfig{
RecordingsPath: "/home/master/nvr_data",
RetentionDays: 7,
CleanupIntervalMins: 60,
},
Auth: AuthConfig{
Enabled: false,
Viewer: UserConfig{Enabled: true},
},
Go2RTC: Go2RTCConfig{
Enabled: true,
Port: ":1984",
Binary: "/opt/nextnvr/go2rtc",
},
}
}
// LoadConfig reads and parses a JSON configuration file.
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 := json.Unmarshal(data, &cfg); err != nil {
return cfg, fmt.Errorf("parsing config: %w", err)
}
return cfg, nil
}
// SaveConfig writes the configuration to a JSON file.
func SaveConfig(cfg Config, path string) error {
data, err := json.MarshalIndent(&cfg, "", " ")
if err != nil {
return fmt.Errorf("marshaling config: %w", err)
}
data = append(data, '\n')
if err := os.WriteFile(path, data, 0600); err != nil {
return fmt.Errorf("writing config: %w", err)
}
return nil
}