Initial implementation
This commit is contained in:
144
internal/config/config.go
Normal file
144
internal/config/config.go
Normal file
@@ -0,0 +1,144 @@
|
||||
// Package config handles loading and validation of application configuration.
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
// Config holds all application configuration.
|
||||
type Config struct {
|
||||
Server ServerConfig
|
||||
Calendar CalendarConfig
|
||||
Diary DiaryConfig
|
||||
CalDAV CalDAVConfig
|
||||
Photos PhotosConfig
|
||||
}
|
||||
|
||||
// ServerConfig holds HTTP server settings.
|
||||
type ServerConfig struct {
|
||||
Port int
|
||||
}
|
||||
|
||||
// CalendarConfig holds calendar ICS file settings.
|
||||
type CalendarConfig struct {
|
||||
LocalICS string
|
||||
}
|
||||
|
||||
// DiaryConfig holds diary ICS file settings.
|
||||
type DiaryConfig struct {
|
||||
ICSFile string
|
||||
}
|
||||
|
||||
// CalDAVConfig holds CalDAV remote calendar settings.
|
||||
type CalDAVConfig struct {
|
||||
Enabled bool
|
||||
URL string
|
||||
Username string
|
||||
Password string
|
||||
}
|
||||
|
||||
// PhotosConfig holds photo storage settings.
|
||||
type PhotosConfig struct {
|
||||
RootFolder string
|
||||
}
|
||||
|
||||
// Load reads configuration from the specified INI file.
|
||||
func Load(path string) (*Config, error) {
|
||||
cfg, err := ini.Load(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load config file: %w", err)
|
||||
}
|
||||
|
||||
config := &Config{
|
||||
Server: ServerConfig{
|
||||
Port: cfg.Section("server").Key("port").MustInt(8080),
|
||||
},
|
||||
Calendar: CalendarConfig{
|
||||
LocalICS: cfg.Section("calendar").Key("local_ics").String(),
|
||||
},
|
||||
Diary: DiaryConfig{
|
||||
ICSFile: cfg.Section("diary").Key("ics_file").String(),
|
||||
},
|
||||
CalDAV: CalDAVConfig{
|
||||
Enabled: cfg.Section("caldav").Key("enabled").MustBool(false),
|
||||
URL: cfg.Section("caldav").Key("url").String(),
|
||||
Username: cfg.Section("caldav").Key("username").String(),
|
||||
Password: cfg.Section("caldav").Key("password").String(),
|
||||
},
|
||||
Photos: PhotosConfig{
|
||||
RootFolder: cfg.Section("photos").Key("root_folder").String(),
|
||||
},
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// Validate checks that all required configuration values are set and valid.
|
||||
func (c *Config) Validate() error {
|
||||
if c.Server.Port <= 0 || c.Server.Port > 65535 {
|
||||
return fmt.Errorf("invalid server port: %d", c.Server.Port)
|
||||
}
|
||||
|
||||
// Validate calendar ICS path if specified
|
||||
if c.Calendar.LocalICS != "" {
|
||||
if err := validateFileReadable(c.Calendar.LocalICS); err != nil {
|
||||
return fmt.Errorf("calendar ICS file: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Validate diary ICS path if specified
|
||||
if c.Diary.ICSFile != "" {
|
||||
dir := filepath.Dir(c.Diary.ICSFile)
|
||||
if err := validateDirExists(dir); err != nil {
|
||||
return fmt.Errorf("diary ICS directory: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Validate CalDAV settings if enabled
|
||||
if c.CalDAV.Enabled {
|
||||
if c.CalDAV.URL == "" {
|
||||
return fmt.Errorf("caldav URL is required when caldav is enabled")
|
||||
}
|
||||
}
|
||||
|
||||
// Validate photos folder if specified
|
||||
if c.Photos.RootFolder != "" {
|
||||
if err := validateDirExists(c.Photos.RootFolder); err != nil {
|
||||
return fmt.Errorf("photos root folder: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateFileReadable(path string) error {
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return fmt.Errorf("file does not exist: %s", path)
|
||||
}
|
||||
return fmt.Errorf("cannot access file: %w", err)
|
||||
}
|
||||
if info.IsDir() {
|
||||
return fmt.Errorf("path is a directory, not a file: %s", path)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateDirExists(path string) error {
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return fmt.Errorf("directory does not exist: %s", path)
|
||||
}
|
||||
return fmt.Errorf("cannot access directory: %w", err)
|
||||
}
|
||||
if !info.IsDir() {
|
||||
return fmt.Errorf("path is not a directory: %s", path)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user