399 lines
12 KiB
Go
399 lines
12 KiB
Go
package handlers
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"log"
|
|
"strings"
|
|
|
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
|
"github.com/gofiber/fiber/v2"
|
|
)
|
|
|
|
// InitAtlasGame godoc
|
|
// @Summary Start an Atlas virtual game session
|
|
// @Description Initializes a game session for the given player using Atlas virtual game provider
|
|
// @Tags Virtual Games - Atlas
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body domain.AtlasGameInitRequest true "Start game input"
|
|
// @Success 200 {object} domain.Response{data=domain.AtlasGameInitResponse}
|
|
// @Failure 400 {object} domain.ErrorResponse
|
|
// @Failure 502 {object} domain.ErrorResponse
|
|
// @Router /api/v1/atlas/init-game [post]
|
|
func (h *Handler) InitAtlasGame(c *fiber.Ctx) error {
|
|
// Retrieve user ID from context
|
|
userId, ok := c.Locals("user_id").(int64)
|
|
if !ok {
|
|
return c.Status(fiber.StatusUnauthorized).JSON(domain.ErrorResponse{
|
|
Error: "missing user id",
|
|
Message: "Unauthorized",
|
|
})
|
|
}
|
|
|
|
var req domain.AtlasGameInitRequest
|
|
if err := c.BodyParser(&req); err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid request body",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
// Attach user ID to request
|
|
req.PlayerID = fmt.Sprintf("%d", userId)
|
|
|
|
// Default language if not provided
|
|
if req.Language == "" {
|
|
req.Language = "en"
|
|
}
|
|
|
|
// Default currency if not provided
|
|
if req.Currency == "" {
|
|
req.Currency = "USD"
|
|
}
|
|
|
|
// Call the service
|
|
res, err := h.atlasVirtualGameSvc.InitGame(context.Background(), req)
|
|
if err != nil {
|
|
log.Println("InitAtlasGame error:", err)
|
|
|
|
return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{
|
|
Message: "Failed to initialize Atlas game",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
return c.Status(fiber.StatusOK).JSON(domain.Response{
|
|
Message: "Game initialized successfully",
|
|
Data: res,
|
|
StatusCode: fiber.StatusOK,
|
|
Success: true,
|
|
})
|
|
}
|
|
|
|
// AtlasGetUserDataCallback godoc
|
|
// @Summary Atlas Get User Data callback
|
|
// @Description Callback endpoint for Atlas game server to fetch player balance
|
|
// @Tags Virtual Games - Atlas
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body domain.AtlasGetUserDataRequest true "Get user data input"
|
|
// @Success 200 {object} domain.AtlasGetUserDataResponse
|
|
// @Failure 400 {object} domain.ErrorResponse
|
|
// @Failure 502 {object} domain.ErrorResponse
|
|
// @Router /account [post]
|
|
func (h *Handler) AtlasGetUserDataCallback(c *fiber.Ctx) error {
|
|
var req domain.AtlasGetUserDataRequest
|
|
if err := c.BodyParser(&req); err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid request body",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
// Optional: validate casino_id matches your configured Atlas casino
|
|
if req.CasinoID != h.Cfg.Atlas.CasinoID {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid casino_id",
|
|
Error: "unauthorized request",
|
|
})
|
|
}
|
|
|
|
// Call service to get player data
|
|
res, err := h.atlasVirtualGameSvc.GetUserData(c.Context(), req)
|
|
if err != nil {
|
|
log.Println("AtlasGetUserDataCallback error:", err)
|
|
return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{
|
|
Message: "Failed to fetch user data",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
// Return Atlas expected response
|
|
return c.JSON(res)
|
|
}
|
|
|
|
// HandleAtlasBetWin godoc
|
|
// @Summary Atlas BetWin callback
|
|
// @Description Processes a Bet and Win request from Atlas provider
|
|
// @Tags Virtual Games - Atlas
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body domain.AtlasBetWinRequest true "Atlas BetWin input"
|
|
// @Success 200 {object} domain.AtlasBetWinResponse
|
|
// @Failure 400 {object} domain.ErrorResponse
|
|
// @Failure 502 {object} domain.ErrorResponse
|
|
// @Router /betwin [post]
|
|
func (h *Handler) HandleAtlasBetWin(c *fiber.Ctx) error {
|
|
body := c.Body()
|
|
if len(body) == 0 {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Empty request body",
|
|
Error: "Request body cannot be empty",
|
|
})
|
|
}
|
|
|
|
var req domain.AtlasBetWinRequest
|
|
if err := json.Unmarshal(body, &req); err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid Atlas BetWin request",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
res, err := h.atlasVirtualGameSvc.ProcessBetWin(c.Context(), req)
|
|
if err != nil {
|
|
// Handle known errors specifically
|
|
code := fiber.StatusInternalServerError
|
|
errMsg := err.Error()
|
|
|
|
switch {
|
|
case errors.Is(err, domain.ErrInsufficientBalance):
|
|
code = fiber.StatusBadRequest
|
|
errMsg = "INSUFFICIENT_BALANCE"
|
|
case strings.Contains(err.Error(), "invalid casino_id"):
|
|
code = fiber.StatusBadRequest
|
|
case strings.Contains(err.Error(), "invalid playerID"):
|
|
code = fiber.StatusBadRequest
|
|
}
|
|
|
|
return c.Status(code).JSON(domain.ErrorResponse{
|
|
Message: "Failed to process Atlas BetWin",
|
|
Error: errMsg,
|
|
})
|
|
}
|
|
|
|
return c.Status(fiber.StatusOK).JSON(res)
|
|
}
|
|
|
|
// HandleRoundResult godoc
|
|
// @Summary Atlas Round Result callback
|
|
// @Description Processes a round result from Atlas or other providers
|
|
// @Tags Virtual Games - Atlas
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body domain.RoundResultRequest true "Round result input"
|
|
// @Success 200 {object} domain.RoundResultResponse
|
|
// @Failure 400 {object} domain.ErrorResponse
|
|
// @Failure 502 {object} domain.ErrorResponse
|
|
// @Router /result [post]
|
|
func (h *Handler) HandleRoundResult(c *fiber.Ctx) error {
|
|
body := c.Body()
|
|
if len(body) == 0 {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Empty request body",
|
|
Error: "Request body cannot be empty",
|
|
})
|
|
}
|
|
|
|
var req domain.RoundResultRequest
|
|
if err := json.Unmarshal(body, &req); err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid RoundResult request",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
res, err := h.atlasVirtualGameSvc.ProcessRoundResult(c.Context(), req)
|
|
if err != nil {
|
|
code := fiber.StatusInternalServerError
|
|
errMsg := err.Error()
|
|
|
|
// Validation errors
|
|
if strings.Contains(err.Error(), "missing player_id") || strings.Contains(err.Error(), "missing transaction_id") {
|
|
code = fiber.StatusBadRequest
|
|
}
|
|
|
|
return c.Status(code).JSON(domain.ErrorResponse{
|
|
Message: "Failed to process round result",
|
|
Error: errMsg,
|
|
})
|
|
}
|
|
|
|
return c.Status(fiber.StatusOK).JSON(res)
|
|
}
|
|
|
|
// HandleRollback godoc
|
|
// @Summary Atlas Rollback callback
|
|
// @Description Processes a rollback request from Atlas or other providers
|
|
// @Tags Virtual Games - Atlas
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body domain.RollbackRequest true "Rollback request input"
|
|
// @Success 200 {object} domain.RollbackResponse
|
|
// @Failure 400 {object} domain.ErrorResponse
|
|
// @Failure 502 {object} domain.ErrorResponse
|
|
// @Router /rollback [post]
|
|
func (h *Handler) HandleRollback(c *fiber.Ctx) error {
|
|
body := c.Body()
|
|
if len(body) == 0 {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Empty request body",
|
|
Error: "Request body cannot be empty",
|
|
})
|
|
}
|
|
|
|
var req domain.RollbackRequest
|
|
if err := json.Unmarshal(body, &req); err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid Rollback request",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
res, err := h.atlasVirtualGameSvc.ProcessRollBack(c.Context(), req)
|
|
if err != nil {
|
|
code := fiber.StatusInternalServerError
|
|
errMsg := err.Error()
|
|
|
|
// Validation errors
|
|
if strings.Contains(err.Error(), "missing player_id") || strings.Contains(err.Error(), "missing transaction_id") {
|
|
code = fiber.StatusBadRequest
|
|
}
|
|
|
|
return c.Status(code).JSON(domain.ErrorResponse{
|
|
Message: "Failed to process rollback",
|
|
Error: errMsg,
|
|
})
|
|
}
|
|
|
|
return c.Status(fiber.StatusOK).JSON(res)
|
|
}
|
|
|
|
// CreateFreeSpin godoc
|
|
// @Summary Create free spins for a player
|
|
// @Description Sends a request to Atlas to create free spins/bets for a given player
|
|
// @Tags Virtual Games - Atlas
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body domain.FreeSpinRequest true "Free spin input"
|
|
// @Success 200 {object} domain.Response{data=domain.FreeSpinResponse}
|
|
// @Failure 400 {object} domain.ErrorResponse
|
|
// @Failure 502 {object} domain.ErrorResponse
|
|
// @Router /api/v1/atlas/freespin [post]
|
|
func (h *Handler) CreateFreeSpin(c *fiber.Ctx) error {
|
|
// Get the authenticated user ID
|
|
userId, ok := c.Locals("user_id").(int64)
|
|
if !ok {
|
|
return c.Status(fiber.StatusUnauthorized).JSON(domain.ErrorResponse{
|
|
Error: "missing user id",
|
|
Message: "Unauthorized",
|
|
})
|
|
}
|
|
|
|
var req domain.FreeSpinRequest
|
|
if err := c.BodyParser(&req); err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid request body",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
// Attach player ID from authenticated user
|
|
req.PlayerID = fmt.Sprintf("%d", userId)
|
|
|
|
res, err := h.atlasVirtualGameSvc.CreateFreeSpin(c.Context(), req)
|
|
if err != nil {
|
|
log.Println("CreateFreeSpin error:", err)
|
|
return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{
|
|
Message: "Failed to create free spins",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
return c.Status(fiber.StatusOK).JSON(domain.Response{
|
|
Message: "Free spins created successfully",
|
|
Data: res,
|
|
StatusCode: fiber.StatusOK,
|
|
Success: true,
|
|
})
|
|
}
|
|
|
|
// FreeSpinResultCallback godoc
|
|
// @Summary Free Spin/Bet result callback
|
|
// @Description Handles the result of a free spin/bet from the game server
|
|
// @Tags Virtual Games - Atlas
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body domain.FreeSpinResultRequest true "Free spin result input"
|
|
// @Success 200 {object} domain.FreeSpinResultResponse
|
|
// @Failure 400 {object} domain.ErrorResponse
|
|
// @Failure 502 {object} domain.ErrorResponse
|
|
// @Router /freespin [post]
|
|
func (h *Handler) FreeSpinResultCallback(c *fiber.Ctx) error {
|
|
// Read raw request body
|
|
body := c.Body()
|
|
if len(body) == 0 {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Empty request body",
|
|
Error: "Request body cannot be empty",
|
|
})
|
|
}
|
|
|
|
// Unmarshal into FreeSpinResultRequest
|
|
var req domain.FreeSpinResultRequest
|
|
if err := json.Unmarshal(body, &req); err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid free spin result request",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
// Process the free spin result
|
|
res, err := h.atlasVirtualGameSvc.ProcessFreeSpinResult(c.Context(), req)
|
|
if err != nil {
|
|
log.Println("FreeSpinResultCallback error:", err)
|
|
return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{
|
|
Message: "Failed to process free spin result",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
return c.Status(fiber.StatusOK).JSON(res)
|
|
}
|
|
|
|
// JackpotCallback godoc
|
|
// @Summary Jackpot result callback
|
|
// @Description Handles the jackpot result from the game server
|
|
// @Tags Virtual Games - Atlas
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body domain.JackpotRequest true "Jackpot result input"
|
|
// @Success 200 {object} domain.JackpotResponse
|
|
// @Failure 400 {object} domain.ErrorResponse
|
|
// @Failure 502 {object} domain.ErrorResponse
|
|
// @Router /jackpot [post]
|
|
func (h *Handler) JackpotCallback(c *fiber.Ctx) error {
|
|
// Read raw request body
|
|
body := c.Body()
|
|
if len(body) == 0 {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Empty request body",
|
|
Error: "Request body cannot be empty",
|
|
})
|
|
}
|
|
|
|
// Unmarshal into JackpotRequest
|
|
var req domain.JackpotRequest
|
|
if err := json.Unmarshal(body, &req); err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid jackpot request",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
// Process the jackpot
|
|
res, err := h.atlasVirtualGameSvc.ProcessJackPot(c.Context(), req)
|
|
if err != nil {
|
|
log.Println("JackpotCallback error:", err)
|
|
return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{
|
|
Message: "Failed to process jackpot",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
return c.Status(fiber.StatusOK).JSON(res)
|
|
}
|