Initial commit
This commit is contained in:
125
internal/config/config.go
Normal file
125
internal/config/config.go
Normal file
@@ -0,0 +1,125 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Server ServerConfig `toml:"server"`
|
||||
Security SecurityConfig `toml:"security"`
|
||||
Apify ApifyConfig `toml:"apify"`
|
||||
Ntfy NtfyConfig `toml:"ntfy"`
|
||||
Scheduler SchedulerConfig `toml:"scheduler"`
|
||||
}
|
||||
|
||||
type ServerConfig struct {
|
||||
Port int `toml:"port"`
|
||||
DBPath string `toml:"db_path"`
|
||||
}
|
||||
|
||||
type SecurityConfig struct {
|
||||
SessionSecret string `toml:"session_secret"`
|
||||
EncryptionKey string `toml:"encryption_key"`
|
||||
}
|
||||
|
||||
type ApifyConfig struct {
|
||||
APIKey string `toml:"api_key"`
|
||||
Actors ActorConfig `toml:"actors"`
|
||||
Proxy ProxyConfig `toml:"proxy"`
|
||||
}
|
||||
|
||||
// ProxyConfig controls the proxyConfiguration block passed to apify actors
|
||||
// that scrape sites which block datacenter IPs (e.g. eBay returns 403 without
|
||||
// a residential proxy).
|
||||
type ProxyConfig struct {
|
||||
UseApifyProxy bool `toml:"use_apify_proxy"`
|
||||
Groups []string `toml:"groups"`
|
||||
Country string `toml:"country"`
|
||||
}
|
||||
|
||||
type ActorConfig struct {
|
||||
ActiveListings string `toml:"active_listings"`
|
||||
SoldListings string `toml:"sold_listings"`
|
||||
PriceComparison string `toml:"price_comparison"`
|
||||
YahooAuctionsJP string `toml:"yahoo_auctions_jp"`
|
||||
YahooAuctionsJPSold string `toml:"yahoo_auctions_jp_sold"`
|
||||
MercariJP string `toml:"mercari_jp"`
|
||||
}
|
||||
|
||||
type NtfyConfig struct {
|
||||
BaseURL string `toml:"base_url"`
|
||||
DefaultTopic string `toml:"default_topic"`
|
||||
}
|
||||
|
||||
type SchedulerConfig struct {
|
||||
GlobalPollIntervalMinutes int `toml:"global_poll_interval_minutes"`
|
||||
MatchConfidenceThreshold float64 `toml:"match_confidence_threshold"`
|
||||
}
|
||||
|
||||
func Load(path string) (*Config, error) {
|
||||
if _, err := os.Stat(path); errors.Is(err, os.ErrNotExist) {
|
||||
return nil, fmt.Errorf("config file not found at %s. Copy config.toml.example to that path and fill it in", path)
|
||||
} else if err != nil {
|
||||
return nil, fmt.Errorf("stat config: %w", err)
|
||||
}
|
||||
|
||||
var c Config
|
||||
if _, err := toml.DecodeFile(path, &c); err != nil {
|
||||
return nil, fmt.Errorf("parse config: %w", err)
|
||||
}
|
||||
|
||||
if err := c.validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &c, nil
|
||||
}
|
||||
|
||||
func (c *Config) validate() error {
|
||||
if len(c.Security.SessionSecret) < 32 {
|
||||
return errors.New("security.session_secret must be at least 32 bytes")
|
||||
}
|
||||
if len(c.Security.EncryptionKey) < 32 {
|
||||
return errors.New("security.encryption_key must be at least 32 bytes")
|
||||
}
|
||||
if c.Security.SessionSecret == c.Security.EncryptionKey {
|
||||
return errors.New("security.session_secret and security.encryption_key must not be equal")
|
||||
}
|
||||
if c.Server.DBPath == "" {
|
||||
return errors.New("server.db_path must be set")
|
||||
}
|
||||
dir := filepath.Dir(c.Server.DBPath)
|
||||
if dir == "" {
|
||||
dir = "."
|
||||
}
|
||||
if err := checkWritable(dir); err != nil {
|
||||
return fmt.Errorf("server.db_path directory %s not writable: %w", dir, err)
|
||||
}
|
||||
if c.Server.Port == 0 {
|
||||
c.Server.Port = 8080
|
||||
}
|
||||
if c.Scheduler.GlobalPollIntervalMinutes == 0 {
|
||||
c.Scheduler.GlobalPollIntervalMinutes = 60
|
||||
}
|
||||
if c.Scheduler.MatchConfidenceThreshold == 0 {
|
||||
c.Scheduler.MatchConfidenceThreshold = 0.6
|
||||
}
|
||||
if c.Ntfy.DefaultTopic == "" {
|
||||
c.Ntfy.DefaultTopic = "veola"
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkWritable(dir string) error {
|
||||
f, err := os.CreateTemp(dir, ".veola-write-test-*")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
name := f.Name()
|
||||
f.Close()
|
||||
return os.Remove(name)
|
||||
}
|
||||
Reference in New Issue
Block a user