musiclink/pkg/config/config.go

65 lines
1.8 KiB
Go

// Package config handles configuration loading and validation.
package config
import (
"fmt"
"os"
"github.com/BurntSushi/toml"
)
// Config holds the complete application configuration.
type Config struct {
Matrix MatrixConfig `toml:"matrix"`
}
// MatrixConfig holds Matrix-native bot settings.
type MatrixConfig struct {
Shadow bool `toml:"shadow"` // Shadow mode (log only)
HealthAddr string `toml:"healthAddr"` // Health server listen address
Server string `toml:"server"` // Homeserver base URL
AccessToken string `toml:"accessToken"` // Access token for bot user
UserID string `toml:"userId"` // Full Matrix user ID
Rooms []string `toml:"rooms"` // Allowlisted room IDs
StateStorePath string `toml:"stateStorePath"` // Path to state store (sync token/dedupe)
}
// Load reads and parses a TOML configuration file.
func Load(path string) (*Config, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("reading config file: %w", err)
}
var cfg Config
if err := toml.Unmarshal(data, &cfg); err != nil {
return nil, fmt.Errorf("parsing config file: %w", err)
}
if err := cfg.Validate(); err != nil {
return nil, fmt.Errorf("validating config: %w", err)
}
return &cfg, nil
}
// Validate checks that required configuration fields are set.
func (c *Config) Validate() error {
if c.Matrix.Server == "" {
return fmt.Errorf("matrix.server is required")
}
if c.Matrix.AccessToken == "" {
return fmt.Errorf("matrix.accessToken is required")
}
if c.Matrix.UserID == "" {
return fmt.Errorf("matrix.userId is required")
}
if len(c.Matrix.Rooms) == 0 {
return fmt.Errorf("matrix.rooms must include at least one room")
}
if c.Matrix.StateStorePath == "" {
c.Matrix.StateStorePath = "data/matrix-state.db"
}
return nil
}