154 lines
3.6 KiB
Go
154 lines
3.6 KiB
Go
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"regexp"
|
|
|
|
"github.com/BurntSushi/toml"
|
|
)
|
|
|
|
var timeFormatRe = regexp.MustCompile(`^\d{2}:\d{2}$`)
|
|
|
|
type Config struct {
|
|
Memos MemosConfig `toml:"memos"`
|
|
Database DatabaseConfig `toml:"database"`
|
|
Search SearchConfig `toml:"search"`
|
|
Telegram TelegramConfig `toml:"telegram"`
|
|
Web WebConfig `toml:"web"`
|
|
General GeneralConfig `toml:"general"`
|
|
}
|
|
|
|
type MemosConfig struct {
|
|
URL string `toml:"url"`
|
|
Token string `toml:"token"`
|
|
PublicURL string `toml:"public_url"`
|
|
}
|
|
|
|
type DatabaseConfig struct {
|
|
Path string `toml:"path"`
|
|
}
|
|
|
|
type SearchConfig struct {
|
|
CooldownDays int `toml:"cooldown_days"`
|
|
RelaxedCooldownDays int `toml:"relaxed_cooldown_days"`
|
|
PageSize int `toml:"page_size"`
|
|
MaxYearsBack int `toml:"max_years_back"`
|
|
PreferOlder bool `toml:"prefer_older"`
|
|
TierWeights TierWeights `toml:"tier_weights"`
|
|
}
|
|
|
|
type TierWeights struct {
|
|
Tier1 int `toml:"tier1"`
|
|
Tier2 int `toml:"tier2"`
|
|
Tier3 int `toml:"tier3"`
|
|
Tier4 int `toml:"tier4"`
|
|
Tier5 int `toml:"tier5"`
|
|
Tier6 int `toml:"tier6"`
|
|
Tier7 int `toml:"tier7"`
|
|
}
|
|
|
|
func (tw TierWeights) Sum() int {
|
|
return tw.Tier1 + tw.Tier2 + tw.Tier3 + tw.Tier4 + tw.Tier5 + tw.Tier6 + tw.Tier7
|
|
}
|
|
|
|
func (tw TierWeights) AsSlice() [7]int {
|
|
return [7]int{tw.Tier1, tw.Tier2, tw.Tier3, tw.Tier4, tw.Tier5, tw.Tier6, tw.Tier7}
|
|
}
|
|
|
|
type TelegramConfig struct {
|
|
Enabled bool `toml:"enabled"`
|
|
Token string `toml:"token"`
|
|
ChatID int64 `toml:"chat_id"`
|
|
SendAt string `toml:"send_at"`
|
|
}
|
|
|
|
type WebConfig struct {
|
|
Listen string `toml:"listen"`
|
|
}
|
|
|
|
type GeneralConfig struct {
|
|
Timezone string `toml:"timezone"`
|
|
LogLevel string `toml:"log_level"`
|
|
}
|
|
|
|
func Load(path string) (*Config, error) {
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("read config: %w", err)
|
|
}
|
|
|
|
var cfg Config
|
|
if err := toml.Unmarshal(data, &cfg); err != nil {
|
|
return nil, fmt.Errorf("parse config: %w", err)
|
|
}
|
|
|
|
setDefaults(&cfg)
|
|
|
|
if err := validate(&cfg); err != nil {
|
|
return nil, fmt.Errorf("validate config: %w", err)
|
|
}
|
|
|
|
return &cfg, nil
|
|
}
|
|
|
|
func setDefaults(cfg *Config) {
|
|
if cfg.Database.Path == "" {
|
|
cfg.Database.Path = "remembos.db"
|
|
}
|
|
if cfg.Search.CooldownDays == 0 {
|
|
cfg.Search.CooldownDays = 90
|
|
}
|
|
if cfg.Search.RelaxedCooldownDays == 0 {
|
|
cfg.Search.RelaxedCooldownDays = 30
|
|
}
|
|
if cfg.Search.PageSize == 0 {
|
|
cfg.Search.PageSize = 50
|
|
}
|
|
if cfg.Search.MaxYearsBack == 0 {
|
|
cfg.Search.MaxYearsBack = 10
|
|
}
|
|
if cfg.Search.TierWeights.Sum() == 0 {
|
|
cfg.Search.TierWeights = TierWeights{
|
|
Tier1: 35, Tier2: 15, Tier3: 15,
|
|
Tier4: 12, Tier5: 10, Tier6: 5, Tier7: 8,
|
|
}
|
|
}
|
|
if cfg.Web.Listen == "" {
|
|
cfg.Web.Listen = "127.0.0.1:8080"
|
|
}
|
|
if cfg.General.Timezone == "" {
|
|
cfg.General.Timezone = "Europe/Moscow"
|
|
}
|
|
if cfg.General.LogLevel == "" {
|
|
cfg.General.LogLevel = "info"
|
|
}
|
|
if cfg.Telegram.SendAt == "" {
|
|
cfg.Telegram.SendAt = "09:00"
|
|
}
|
|
}
|
|
|
|
func validate(cfg *Config) error {
|
|
if cfg.Memos.URL == "" {
|
|
return fmt.Errorf("memos.url is required")
|
|
}
|
|
if cfg.Memos.Token == "" {
|
|
return fmt.Errorf("memos.token is required")
|
|
}
|
|
if sum := cfg.Search.TierWeights.Sum(); sum != 100 {
|
|
return fmt.Errorf("search.tier_weights must sum to 100, got %d", sum)
|
|
}
|
|
if cfg.Telegram.Enabled {
|
|
if cfg.Telegram.Token == "" {
|
|
return fmt.Errorf("telegram.token is required when telegram.enabled = true")
|
|
}
|
|
if cfg.Telegram.ChatID == 0 {
|
|
return fmt.Errorf("telegram.chat_id is required when telegram.enabled = true")
|
|
}
|
|
if !timeFormatRe.MatchString(cfg.Telegram.SendAt) {
|
|
return fmt.Errorf("telegram.send_at must be in HH:MM format, got %q", cfg.Telegram.SendAt)
|
|
}
|
|
}
|
|
return nil
|
|
}
|