2023-03-19 22:03:12 +01:00
|
|
|
package config
|
|
|
|
|
|
|
|
import (
|
2023-05-04 23:49:25 +02:00
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
|
|
|
"time"
|
|
|
|
|
2023-05-01 23:09:36 +02:00
|
|
|
"git.dotya.ml/mirre-mt/pcmt/slogging"
|
2023-03-19 22:03:12 +01:00
|
|
|
"github.com/philandstuff/dhall-golang/v6"
|
2023-05-09 17:35:00 +02:00
|
|
|
"golang.org/x/exp/slog"
|
2023-03-19 22:03:12 +01:00
|
|
|
)
|
|
|
|
|
2023-05-05 19:31:43 +02:00
|
|
|
type session struct {
|
|
|
|
CookieName string
|
|
|
|
CookieSecret string
|
|
|
|
}
|
|
|
|
|
2023-03-19 22:03:12 +01:00
|
|
|
type Config struct {
|
2023-05-05 19:31:43 +02:00
|
|
|
Host string
|
|
|
|
Port int
|
|
|
|
AppName string
|
|
|
|
LiveMode bool
|
|
|
|
DevelMode bool
|
|
|
|
Session session
|
|
|
|
Registration struct{ Allowed bool }
|
|
|
|
Logger struct {
|
|
|
|
Json bool //nolint:revive
|
|
|
|
Fmt string
|
|
|
|
}
|
2023-03-19 22:03:12 +01:00
|
|
|
}
|
|
|
|
|
2023-05-12 23:29:16 +02:00
|
|
|
const schemaCompatibility = "0.0.0" //nolint:unused
|
|
|
|
|
2023-05-11 17:06:20 +02:00
|
|
|
var log slogging.Slogger
|
2023-05-09 17:35:00 +02:00
|
|
|
|
2023-05-13 19:44:32 +02:00
|
|
|
func Load(conf string, isPath bool) (*Config, error) {
|
2023-03-19 22:03:12 +01:00
|
|
|
var config Config
|
|
|
|
|
2023-05-04 23:49:25 +02:00
|
|
|
var err error
|
|
|
|
|
2023-05-11 17:06:20 +02:00
|
|
|
slogger := slogging.Logger()
|
2023-05-09 17:35:00 +02:00
|
|
|
// initialise if not already initialised.
|
|
|
|
if slogger == nil {
|
|
|
|
slogger = slogging.Init(true)
|
|
|
|
}
|
|
|
|
|
|
|
|
// have a local copy.
|
|
|
|
log = *slogger
|
|
|
|
// add attr to all statements made with the local copy.
|
|
|
|
log.Logger = log.Logger.With(
|
|
|
|
slog.Group("pcmt extra", slog.String("module", "config")),
|
|
|
|
)
|
|
|
|
|
|
|
|
switch {
|
|
|
|
case isPath:
|
|
|
|
log.Debug("config from file")
|
2023-05-04 23:49:25 +02:00
|
|
|
|
|
|
|
err = dhall.UnmarshalFile(conf, &config)
|
2023-05-09 17:35:00 +02:00
|
|
|
case !isPath:
|
|
|
|
log.Debug("config raw from cmdline")
|
2023-05-04 23:49:25 +02:00
|
|
|
|
|
|
|
err = dhall.Unmarshal([]byte(conf), &config)
|
|
|
|
}
|
|
|
|
|
2023-05-09 17:35:00 +02:00
|
|
|
if !config.Logger.Json {
|
|
|
|
slogger = slogging.Init(false)
|
|
|
|
log.Logger = slogger.Logger.With(
|
|
|
|
slog.Group("pcmt extra", slog.String("module", "config")),
|
|
|
|
)
|
2023-03-19 22:03:12 +01:00
|
|
|
}
|
|
|
|
|
2023-05-12 23:22:48 +02:00
|
|
|
if config.DevelMode && os.Getenv("PCMT_DEVEL") != "False" {
|
2023-05-09 17:35:00 +02:00
|
|
|
log.Debug("set DEBUG level based on config value")
|
|
|
|
|
|
|
|
slogger = slogging.SetLevel(slogging.LevelDebug)
|
|
|
|
log.Logger = slogger.Logger.With(
|
|
|
|
slog.Group("pcmt extra", slog.String("module", "config")),
|
|
|
|
)
|
2023-05-04 23:49:25 +02:00
|
|
|
|
2023-05-09 17:35:00 +02:00
|
|
|
log.Debugf("parsed config: %+v", config)
|
2023-05-04 23:49:25 +02:00
|
|
|
|
|
|
|
if dhallCmdExists() {
|
|
|
|
_ = prettyPrintConfig(conf, isPath)
|
|
|
|
}
|
|
|
|
}
|
2023-04-13 00:07:08 +02:00
|
|
|
|
2023-05-13 21:33:55 +02:00
|
|
|
// only return now (if err), after we've had the chance to print the loaded
|
|
|
|
// config, as would be the case if the config *did* adhere to the schema imported
|
|
|
|
// but app's Config type definition above didn't - "don't know how to
|
|
|
|
// decode <nil> into ..." is the most likely outcome in that case and it
|
|
|
|
// could be the product of (at least) three things:
|
|
|
|
// * completely wrong config not following the schema
|
|
|
|
// * config is following a newer schema than the app supports
|
|
|
|
// * config is following an older schema than the app supports
|
|
|
|
//
|
|
|
|
// NOTE: for the most part the only thing checked above would be adherence
|
|
|
|
// to config schema (apart from *some* value validation).
|
2023-05-09 17:35:00 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-03-19 22:03:12 +01:00
|
|
|
return &config, nil
|
|
|
|
}
|
2023-05-04 23:49:25 +02:00
|
|
|
|
|
|
|
func prettyPrintConfig(conf string, isPath bool) error {
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
var cmd *exec.Cmd
|
|
|
|
if isPath {
|
|
|
|
cmd = exec.CommandContext(ctx, "/bin/sh", "-c", "dhall --file "+conf) //nolint:gosec
|
|
|
|
} else {
|
|
|
|
cmd = exec.CommandContext(ctx, "/bin/sh", "-c", "dhall <<< \""+conf+"\"") //nolint:gosec
|
|
|
|
}
|
|
|
|
|
|
|
|
output, err := cmd.CombinedOutput()
|
|
|
|
if err != nil {
|
2023-05-09 17:35:00 +02:00
|
|
|
log.Debug("could not pretty-print config", "error", err)
|
2023-05-04 23:49:25 +02:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if isPath {
|
|
|
|
fmt.Fprintln(os.Stderr, "\n"+conf+":\n"+string(output))
|
|
|
|
} else {
|
|
|
|
fmt.Fprintln(os.Stderr, "\nconfig:\n"+string(output))
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func dhallCmdExists() bool {
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
if err := exec.CommandContext(ctx, "/bin/sh", "-c", "command -v dhall").Run(); err != nil {
|
2023-05-09 17:35:00 +02:00
|
|
|
log.Debug("no command dhall")
|
2023-05-04 23:49:25 +02:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|