138 lines
3.4 KiB
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: "/mnt/recordings",
|
|
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
|
|
}
|