Files
transmission-telegram/internal/config/config.go

127 lines
3.2 KiB
Go

package config
import (
"flag"
"fmt"
"net/url"
"os"
"strings"
"time"
)
// Config holds all application configuration
type Config struct {
BotToken string
Masters []string
RPCURL string
Username string
Password string
LogFile string
TransLogFile string
NoLive bool
Interval time.Duration
Duration int
}
// LoadConfig loads configuration from flags and environment variables
func LoadConfig() (*Config, error) {
cfg := &Config{
Interval: DefaultUpdateInterval,
Duration: DefaultUpdateDuration,
}
var masters masterSlice
flag.StringVar(&cfg.BotToken, "token", "", "Telegram bot token, Can be passed via environment variable 'TT_BOTT'")
flag.Var(&masters, "master", "Your telegram handler, So the bot will only respond to you. Can specify more than one")
flag.StringVar(&cfg.RPCURL, "url", DefaultRPCURL, "Transmission RPC URL")
flag.StringVar(&cfg.Username, "username", "", "Transmission username")
flag.StringVar(&cfg.Password, "password", "", "Transmission password")
flag.StringVar(&cfg.LogFile, "logfile", "", "Send logs to a file")
flag.StringVar(&cfg.TransLogFile, "transmission-logfile", "", "Open transmission logfile to monitor torrents completion")
flag.BoolVar(&cfg.NoLive, "no-live", false, "Don't edit and update info after sending")
flag.Usage = func() {
fmt.Fprint(os.Stderr, "Usage: transmission-telegram <-token=TOKEN> <-master=@tuser> [-master=@yuser2] [-url=http://] [-username=user] [-password=pass]\n\n")
flag.PrintDefaults()
}
flag.Parse()
// Check environment variable for bot token
if cfg.BotToken == "" {
if token := os.Getenv("TT_BOTT"); len(token) > 1 {
cfg.BotToken = token
}
}
// Check environment variable for Transmission auth
if cfg.Username == "" {
if values := strings.Split(os.Getenv("TR_AUTH"), ":"); len(values) > 1 {
cfg.Username, cfg.Password = values[0], values[1]
}
}
// Convert masters slice
cfg.Masters = []string(masters)
for i := range cfg.Masters {
cfg.Masters[i] = strings.ReplaceAll(cfg.Masters[i], "@", "")
cfg.Masters[i] = strings.ToLower(cfg.Masters[i])
}
// Validate configuration
if err := cfg.Validate(); err != nil {
return nil, err
}
return cfg, nil
}
// Validate checks if configuration is valid
func (c *Config) Validate() error {
if c.BotToken == "" {
return fmt.Errorf("bot token is required (use -token flag or TT_BOTT environment variable)")
}
if len(c.Masters) < 1 {
return fmt.Errorf("at least one master is required (use -master flag)")
}
if c.RPCURL != "" {
if _, err := url.Parse(c.RPCURL); err != nil {
return fmt.Errorf("invalid RPC URL: %w", err)
}
}
return nil
}
// IsMaster checks if username is in masters list
func (c *Config) IsMaster(username string) bool {
username = strings.ToLower(username)
for _, master := range c.Masters {
if master == username {
return true
}
}
return false
}
// PrintUsage prints usage information
func PrintUsage() {
flag.Usage()
}
// masterSlice is a custom type for flag parsing
type masterSlice []string
func (masters *masterSlice) String() string {
return fmt.Sprintf("%s", *masters)
}
func (masters *masterSlice) Set(master string) error {
*masters = append(*masters, strings.ToLower(master))
return nil
}