package config
import (
"cmp"
"errors"
"log/slog"
"os"
"os/exec"
"strconv"
"strings"
)
var log = slog.New(slog.NewJSONHandler(os.Stdout, nil))
type Config struct {
AddrPort string `json:"addr_port"`
Keys map[string]string `json:"keys"`
Speaker string `json:"speaker"`
Conn string `json:"conn"`
SessionLengthMax int `json:"session_length_max"`
IntervalImmediate int `json:"interval_immediate"`
IntervalInvestigate int `json:"interval_investigate"`
SkipVoicing bool `json:"skip_voicing"`
SeedAlert bool `json:"seed_alert"`
}
func die(err error, str string) {
if err == nil {
return
}
log.Error(str, "err", err)
os.Exit(1)
}
func Must() Config {
cfg := Config{
AddrPort: os.Getenv("CICADA_ADDRPORT"),
Speaker: cmp.Or(os.Getenv("CICADA_SPEAKER"), "espeak"),
Conn: os.Getenv("CICADA_CONN"),
SkipVoicing: os.Getenv("CICADA_SKIP_VOICING") == "true",
SeedAlert: os.Getenv("CICADA_SEED_ALERT") == "true",
SessionLengthMax: 86400 * 365,
IntervalImmediate: 60 * 5,
IntervalInvestigate: 60 * 60,
}
if !cfg.SkipVoicing {
die(exec.Command("which", cfg.Speaker).Run(), "could not find speech command")
}
keysEnv := os.Getenv("CICADA_KEYS")
if keysEnv == "" {
die(errors.New("must pass CICADA_KEYS"), "bad config")
}
keys := strings.Split(keysEnv, ",")
keysMap := map[string]string{}
foundAdmin := false
for i, key := range keys {
username, _, hasUsername := strings.Cut(key, "_")
if !hasUsername {
die(errors.New("key must have username"), "bad username in position "+strconv.Itoa(i))
}
keysMap[key] = username
if username == "admin" {
foundAdmin = true
if !foundAdmin {
}
}
}
cfg.Keys = keysMap
if !foundAdmin {
die(errors.New("no admin found"), "must supply an admin in keys")
}
return cfg
}