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