package main import ( "context" "log" "os" "os/signal" "strings" "syscall" "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/cors" "github.com/gofiber/fiber/v2/middleware/logger" "knowfoolery/backend/shared/auth" "knowfoolery/backend/shared/database" "knowfoolery/backend/shared/utils" "knowfoolery/backend/services/game-service/internal/services" ) func main() { app := fiber.New(fiber.Config{ AppName: "Know Foolery Game Service v1.0.0", ServerHeader: "Game Service", }) // Initialize database connection databaseURL := utils.GetEnvOrDefault("DATABASE_URL", "sqlite://./game_service.db") var dbConfig database.Config if strings.HasPrefix(databaseURL, "postgres") { dbConfig = database.Config{ Driver: "postgres", Host: utils.GetEnvOrDefault("DB_HOST", "localhost"), Port: utils.GetEnvOrDefaultInt("DB_PORT", 5432), User: utils.GetEnvOrDefault("DB_USER", "knowfoolery"), Password: utils.GetEnvOrDefault("DB_PASSWORD", "dev-password-2024"), Database: utils.GetEnvOrDefault("DB_NAME", "knowfoolery"), SSLMode: utils.GetEnvOrDefault("DB_SSLMODE", "disable"), } } else { dbConfig = database.Config{ Driver: "sqlite3", Database: utils.GetEnvOrDefault("SQLITE_PATH", "./game_service.db"), } } db, err := database.NewClient(dbConfig) if err != nil { log.Fatal("Failed to connect to database:", err) } defer db.Close() // Create tables if they don't exist if err := db.CreateTables(context.Background()); err != nil { log.Fatal("Failed to create database tables:", err) } log.Println("Database connected successfully") // Initialize services gameService := services.NewGameService(db) // Initialize mock auth service authService, err := auth.NewMockAuthService("knowfoolery-game-service") if err != nil { log.Fatal("Failed to create auth service:", err) } middleware := auth.NewJWTMiddleware(authService) // Create mock tokens for testing mockTokens := authService.CreateMockUsers() log.Printf("Mock tokens created:") for user, token := range mockTokens { log.Printf(" %s: Bearer %s", user, token) } // Middleware app.Use(logger.New(logger.Config{ Format: "[${time}] ${status} - ${method} ${path} ${latency}\n", })) app.Use(cors.New()) // Health endpoint (no auth required) app.Get("/health", func(c *fiber.Ctx) error { return c.JSON(fiber.Map{ "status": "healthy", "service": "game-service", "version": "1.0.0", }) }) // Auth endpoints app.Post("/auth/tokens", func(c *fiber.Ctx) error { tokens := authService.CreateMockUsers() return c.JSON(fiber.Map{ "message": "Mock tokens for development", "tokens": tokens, }) }) // Protected API routes api := app.Group("/api/v1") api.Use(middleware.Optional()) // Optional auth for most endpoints api.Get("/games", func(c *fiber.Ctx) error { user, err := auth.GetUserFromContext(c) if err != nil { // Not authenticated, return public info return c.JSON(fiber.Map{ "message": "Game service endpoint", "games": []string{}, "user": "anonymous", }) } // Authenticated, return user-specific info return c.JSON(fiber.Map{ "message": "Game service endpoint", "games": []string{}, "user": user.Username, "roles": user.Roles, }) }) // Database test endpoints api.Get("/questions/random", func(c *fiber.Ctx) error { theme := c.Query("theme") difficulty := c.Query("difficulty") question, err := gameService.GetRandomQuestion(c.Context(), theme, difficulty) if err != nil { return c.Status(500).JSON(fiber.Map{ "error": err.Error(), }) } return c.JSON(fiber.Map{ "question": question, }) }) api.Post("/sessions", func(c *fiber.Ctx) error { var req struct { PlayerName string `json:"player_name"` } if err := c.BodyParser(&req); err != nil { return c.Status(400).JSON(fiber.Map{ "error": "Invalid request body", }) } // Get user ID if authenticated var userID *string if user, err := auth.GetUserFromContext(c); err == nil { userID = &user.UserID } session, err := gameService.CreateSession(c.Context(), req.PlayerName, userID) if err != nil { return c.Status(500).JSON(fiber.Map{ "error": err.Error(), }) } return c.JSON(fiber.Map{ "session": session, }) }) api.Get("/sessions/:id", func(c *fiber.Ctx) error { sessionID := c.Params("id") session, err := gameService.GetSessionByID(c.Context(), sessionID) if err != nil { return c.Status(404).JSON(fiber.Map{ "error": err.Error(), }) } return c.JSON(fiber.Map{ "session": session, }) }) // Admin-only endpoints adminAPI := api.Group("/admin") adminAPI.Use(middleware.Authenticate()) adminAPI.Use(middleware.RequireRole("admin")) adminAPI.Get("/stats", func(c *fiber.Ctx) error { user, _ := auth.GetUserFromContext(c) return c.JSON(fiber.Map{ "message": "Admin stats endpoint", "admin_user": user.Username, "total_games": 42, "active_users": 15, }) }) // Graceful shutdown c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, syscall.SIGTERM) go func() { <-c log.Println("Gracefully shutting down Game Service...") _ = app.Shutdown() }() port := utils.GetEnvOrDefault("PORT", "3001") log.Printf("Game Service starting on port %s", port) if err := app.Listen(":" + port); err != nil { log.Printf("Error starting server: %v", err) } }