Files
comicverse/editor/cmd/cmd.go

129 lines
3.3 KiB
Go

package main
import (
"context"
"errors"
"flag"
"fmt"
"log/slog"
"net/http"
"os"
"os/signal"
"syscall"
"code.capytal.cc/capytal/comicverse/editor"
"code.capytal.cc/capytal/comicverse/editor/assets"
"code.capytal.cc/capytal/comicverse/editor/router"
"code.capytal.cc/capytal/comicverse/editor/storage"
"code.capytal.cc/capytal/comicverse/editor/template"
"code.capytal.cc/loreddev/x/tinyssert"
)
var (
hostname = flag.String("hostname", "localhost", "Host to listen to")
port = flag.Uint("port", 8080, "Port to be used for the server.")
verbose = flag.Bool("verbose", false, "Print debug information on logs")
dev = flag.Bool("dev", false, "Run the server in debug mode.")
)
var (
storageDir = getEnv("EDITOR_PUBLICATIONS_DIR", ".publications") // TODO: Use XDG_STATE_HOME as default
assetsDir = getEnv("EDITOR_ASSETS_DIR", "assets") // TODO: Use XDG_CONFIG_HOME as default
templatesDir = getEnv("EDITOR_TEMPLATES_DIR", "template") // TODO: Use XDG_CONFIG_HOME as default
)
func getEnv(key string, d string) string {
v := os.Getenv(key)
if v == "" {
return d
}
return v
}
func init() {
flag.Parse()
}
func main() {
ctx := context.Background()
log := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{}))
assert := tinyssert.New(tinyssert.WithLogger(log))
assets := assets.New()
templater, err := template.New()
if err != nil {
log.Error("Unable to initiate templater due to error", slog.String("error", err.Error()))
os.Exit(1)
return
}
if *dev {
assets = os.DirFS(assetsDir)
log = slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug}))
assert = tinyssert.New(tinyssert.WithPanic(), tinyssert.WithLogger(log.WithGroup("assertions")))
templater, err = template.Dev(os.DirFS(templatesDir))
if err != nil {
log.Error("Unable to initiate dev templater due to error", slog.String("error", err.Error()))
os.Exit(1)
return
}
}
err = os.MkdirAll(storageDir, os.ModePerm)
if err != nil {
log.Error("Unable to create storage directory due to error", slog.String("error", err.Error()))
os.Exit(1)
return
}
root, err := os.OpenRoot(storageDir)
if err != nil {
log.Error("Unable to open storage directory due to error", slog.String("error", err.Error()))
os.Exit(1)
return
}
storage := storage.Newlocal(root, log)
editor := editor.New(storage, log.WithGroup("editor"), assert)
router := router.New(router.Config{
Assets: assets,
Editor: editor,
Templater: templater,
Logger: log.WithGroup("router"),
})
srv := &http.Server{
Addr: fmt.Sprintf("%s:%d", *hostname, *port),
Handler: router,
}
c, stop := signal.NotifyContext(ctx, syscall.SIGINT, syscall.SIGTERM)
defer stop()
go func() {
log.Info("Starting application",
slog.String("host", *hostname),
slog.Uint64("port", uint64(*port)),
slog.Bool("verbose", *verbose),
slog.Bool("development", *dev))
if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
log.Error("Failed to start application server", slog.String("error", err.Error()))
os.Exit(1)
}
}()
<-c.Done()
log.Info("Stopping application gracefully")
if err := srv.Shutdown(c); err != nil {
log.Error("Failed to stop application server gracefully", slog.String("error", err.Error()))
os.Exit(1)
}
log.Info("FINAL")
os.Exit(0)
}