77 lines
2.1 KiB
Go
77 lines
2.1 KiB
Go
// main is the composition root for the application.
|
|
// It parses config, wires dependencies into an app struct, and delegates.
|
|
// Implementation details lives in internal/; cmd/ should be kept thin by
|
|
// deliberately operating only with high level concepts.
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"gitea.djmil.dev/go/template/internal/greeter"
|
|
"gitea.djmil.dev/go/template/pkg/logger"
|
|
"gitea.djmil.dev/go/template/pkg/result"
|
|
)
|
|
|
|
// app holds all wired dependencies for the lifetime of the process.
|
|
type app struct {
|
|
cfg *Config
|
|
log *logger.Logger
|
|
greeter *greeter.Service
|
|
}
|
|
|
|
func newApp(cfg *Config) *app {
|
|
// NewCLI auto-detects: human text on a terminal, JSON when piped.
|
|
// Pass -debug-log FILE to enable debug mode (writes full trace to file).
|
|
log := logger.NewCLI(cfg.Logger.Level, cfg.Logger.DebugFile).Expect("create logger")
|
|
log.Debug("config", "port", cfg.App.Port, "level", cfg.Logger.Level, "env", cfg.App.Env)
|
|
if cfg.App.Env == "dev" {
|
|
log.Warn("dev mode — not for production")
|
|
}
|
|
return &app{
|
|
cfg: cfg,
|
|
log: log,
|
|
greeter: greeter.New(log),
|
|
}
|
|
}
|
|
|
|
func main() {
|
|
conf := parseArgs()
|
|
|
|
app := newApp(conf)
|
|
app.log.WithFields(map[string]any{
|
|
"app": filepath.Base(os.Args[0]),
|
|
"env": conf.App.Env,
|
|
}).Info("starting up")
|
|
|
|
if err := result.Run(app.run); err != nil {
|
|
fmt.Fprintf(os.Stderr, "[failed] %v\n", err)
|
|
if stack := result.StackTrace(err); stack != "" {
|
|
fmt.Fprintf(os.Stderr, "%s\n", stack)
|
|
}
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func (a *app) run() {
|
|
defer a.log.Close()
|
|
|
|
// Warm up the greeter with a few names before the real call.
|
|
// In debug mode this produces repeated identical debug lines from the greeter,
|
|
// demonstrating how the deduplication counter collapses them in-place.
|
|
for _, name := range []string{"Alice", "Bob", "Carol", "Dave"} {
|
|
a.greeter.Greet(name)
|
|
}
|
|
|
|
a.showGreeting(a.cfg.Greeter.Name)
|
|
|
|
fmt.Printf("TODO: implement listening on port %d\n", a.cfg.App.Port)
|
|
}
|
|
|
|
func (a *app) showGreeting(name string) {
|
|
msg := a.greeter.Greet(name).Expect("greeting")
|
|
a.log.WithField("message", msg).Info("greeting complete")
|
|
fmt.Println(msg)
|
|
}
|