// Command server serves the player HTTP API and the web front end. package main import ( "context" "flag" "log" "net/http" "os" "halcyon/api" "halcyon/config" "halcyon/store" "halcyon/web" ) func main() { dsn := flag.String("db", config.DatabaseURL(), "sqlite: or postgres:// URL (default: $DATABASE_URL)") addr := flag.String("addr", ":8080", "listen address") manual := flag.String("manual-pdf", envOr("MANUAL_PDF", "docs/generated/manual.pdf"), "rendered PDF manual to serve (default: $MANUAL_PDF)") cfg, err := config.Bind(flag.CommandLine) if err != nil { log.Fatal(err) } flag.Parse() if err := cfg.Validate(); err != nil { log.Fatal(err) } st, err := store.Open(*dsn) if err != nil { log.Fatal(err) } defer st.Close() if err := st.Migrate(context.Background()); err != nil { log.Fatal(err) } adminPassword := os.Getenv("HALCYON_ADMIN_PASSWORD") switch { case adminPassword == "": log.Print("admin interface is OFF: set HALCYON_ADMIN_PASSWORD to turn it on at /admin") case len(adminPassword) < 12: log.Print("admin interface is on at /admin, but its password is short: use at least 12 characters") default: log.Print("admin interface is on at /admin") } mux := api.New(st, *cfg, api.WithAdminPassword(adminPassword)) mux.Handle("/", web.Handler(*manual)) // the site; API routes are more specific and win log.Printf("listening on %s", *addr) log.Fatal(http.ListenAndServe(*addr, mux)) } func envOr(key, def string) string { if v := os.Getenv(key); v != "" { return v } return def }