package main import ( "flag" "fmt" "log" "os" "os/signal" "path/filepath" "syscall" "dk/internal/models/babble" "dk/internal/models/control" "dk/internal/models/drops" "dk/internal/models/fights" "dk/internal/models/forum" "dk/internal/models/items" "dk/internal/models/monsters" "dk/internal/models/news" "dk/internal/models/spells" "dk/internal/models/towns" "dk/internal/models/users" "dk/internal/routes" "dk/internal/template" nigiri "git.sharkk.net/Sharkk/Nigiri" sushi "git.sharkk.net/Sharkk/Sushi" "git.sharkk.net/Sharkk/Sushi/auth" "git.sharkk.net/Sharkk/Sushi/csrf" "git.sharkk.net/Sharkk/Sushi/session" "git.sharkk.net/Sharkk/Sushi/timing" ) func main() { var port string flag.StringVar(&port, "p", "3000", "Port to run server on") if len(os.Args) < 2 { startServer(port) return } switch os.Args[1] { case "serve": flag.CommandLine.Parse(os.Args[2:]) startServer(port) default: fmt.Fprintf(os.Stderr, "Unknown command: %s\n", os.Args[1]) fmt.Fprintln(os.Stderr, "Available commands:") fmt.Fprintln(os.Stderr, " serve - Start the server") fmt.Fprintln(os.Stderr, " (no command) - Start the server") os.Exit(1) } } func startServer(port string) { fmt.Println("Starting Dragon Knight server...") if err := start(port); err != nil { log.Fatalf("Server failed: %v", err) } } func start(port string) error { cwd, err := os.Getwd() if err != nil { return fmt.Errorf("failed to get current working directory: %w", err) } template.InitializeCache(cwd) db := nigiri.NewCollection(filepath.Join(cwd, "data")) if err := setupStores(db); err != nil { return fmt.Errorf("failed to setup Nigiri stores: %w", err) } app := sushi.New() sushi.InitSessions(filepath.Join(cwd, "data/_sessions.json")) app.Use(session.Middleware()) app.Use(auth.Middleware(getUserByID)) app.Use(csrf.Middleware()) app.Use(timing.Middleware()) app.Get("/", routes.Index) protected := app.Group("") protected.Use(auth.RequireAuth("/login")) protected.Get("/explore", routes.Explore) protected.Post("/move", routes.Move) protected.Get("/teleport/:to", routes.Teleport) routes.RegisterAuthRoutes(app) routes.RegisterTownRoutes(app) routes.RegisterFightRoutes(app) app.Get("/assets/*path", sushi.Static(cwd)) addr := ":" + port log.Printf("Server starting on %s", addr) c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, syscall.SIGTERM) go func() { app.Listen(addr) }() <-c log.Println("\nReceived shutdown signal, shutting down gracefully...") log.Println("Saving database...") if err := db.Save(); err != nil { log.Printf("Error saving database: %v", err) } log.Println("Saving sessions...") sushi.SaveSessions() log.Println("Server stopped") return nil } func setupStores(db *nigiri.Collection) error { users.Init(db) towns.Init(db) spells.Init(db) news.Init(db) monsters.Init(db) items.Init(db) forum.Init(db) drops.Init(db) babble.Init(db) fights.Init(db) control.Init(db) db.Add("users", users.GetStore()) db.Add("towns", towns.GetStore()) db.Add("spells", spells.GetStore()) db.Add("news", news.GetStore()) db.Add("monsters", monsters.GetStore()) db.Add("items", items.GetStore()) db.Add("forum", forum.GetStore()) db.Add("drops", drops.GetStore()) db.Add("babble", babble.GetStore()) db.Add("fights", fights.GetStore()) return nil } func getUserByID(userID int) any { return users.GetByID(userID) }