You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

217 lines
5.3 KiB
Go

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)
}
}