atlas gaming + veli credit balance route
This commit is contained in:
parent
fc49eefe40
commit
ea986b538e
|
|
@ -57,6 +57,7 @@ import (
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/user"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/user"
|
||||||
virtualgameservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame"
|
virtualgameservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame"
|
||||||
alea "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/Alea"
|
alea "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/Alea"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/atlas"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/veli"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/veli"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet/monitor"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet/monitor"
|
||||||
|
|
@ -153,7 +154,9 @@ func main() {
|
||||||
virtualGameSvc := virtualgameservice.New(vitualGameRepo, *walletSvc, store, cfg, logger)
|
virtualGameSvc := virtualgameservice.New(vitualGameRepo, *walletSvc, store, cfg, logger)
|
||||||
aleaService := alea.NewAleaPlayService(vitualGameRepo, *walletSvc, cfg, logger)
|
aleaService := alea.NewAleaPlayService(vitualGameRepo, *walletSvc, cfg, logger)
|
||||||
veliCLient := veli.NewClient(cfg, walletSvc)
|
veliCLient := veli.NewClient(cfg, walletSvc)
|
||||||
veliVirtualGameService := veli.New(virtualGameSvc,vitualGameRepo, veliCLient, walletSvc, wallet.TransferStore(store), cfg)
|
veliVirtualGameService := veli.New(virtualGameSvc, vitualGameRepo, veliCLient, walletSvc, wallet.TransferStore(store), cfg)
|
||||||
|
atlasClient := atlas.NewClient(cfg, walletSvc)
|
||||||
|
atlasVirtualGameService := atlas.New(virtualGameSvc, vitualGameRepo, atlasClient, walletSvc, wallet.TransferStore(store), cfg)
|
||||||
recommendationSvc := recommendation.NewService(recommendationRepo)
|
recommendationSvc := recommendation.NewService(recommendationRepo)
|
||||||
chapaClient := chapa.NewClient(cfg.CHAPA_BASE_URL, cfg.CHAPA_SECRET_KEY)
|
chapaClient := chapa.NewClient(cfg.CHAPA_BASE_URL, cfg.CHAPA_SECRET_KEY)
|
||||||
|
|
||||||
|
|
@ -244,6 +247,7 @@ func main() {
|
||||||
|
|
||||||
// Initialize and start HTTP server
|
// Initialize and start HTTP server
|
||||||
app := httpserver.NewApp(
|
app := httpserver.NewApp(
|
||||||
|
atlasVirtualGameService,
|
||||||
veliVirtualGameService,
|
veliVirtualGameService,
|
||||||
telebirrSvc,
|
telebirrSvc,
|
||||||
arifpaySvc,
|
arifpaySvc,
|
||||||
|
|
|
||||||
3779
docs/docs.go
3779
docs/docs.go
File diff suppressed because it is too large
Load Diff
3779
docs/swagger.json
3779
docs/swagger.json
File diff suppressed because it is too large
Load Diff
2540
docs/swagger.yaml
2540
docs/swagger.yaml
File diff suppressed because it is too large
Load Diff
|
|
@ -59,6 +59,14 @@ type VeliConfig struct {
|
||||||
Enabled bool `mapstructure:"Enabled"`
|
Enabled bool `mapstructure:"Enabled"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AtlasConfig struct {
|
||||||
|
BaseURL string `mapstructure:"ATLAS_BASE_URL"`
|
||||||
|
SecretKey string `mapstructure:"ATLAS_SECRET_KEY"`
|
||||||
|
OperatorID string `mapstructure:"ATLAS_OPERATOR_ID"`
|
||||||
|
CasinoID string `mapstructure:"ATLAS_BRAND_ID"`
|
||||||
|
PartnerID string `mapstructure:"ATLAS_PARTNER_ID"`
|
||||||
|
}
|
||||||
|
|
||||||
type ARIFPAYConfig struct {
|
type ARIFPAYConfig struct {
|
||||||
APIKey string `mapstructure:"ARIFPAY_API_KEY"`
|
APIKey string `mapstructure:"ARIFPAY_API_KEY"`
|
||||||
BaseURL string `mapstructure:"ARIFPAY_BASE_URL"`
|
BaseURL string `mapstructure:"ARIFPAY_BASE_URL"`
|
||||||
|
|
@ -126,6 +134,7 @@ type Config struct {
|
||||||
Bet365Token string
|
Bet365Token string
|
||||||
PopOK domain.PopOKConfig
|
PopOK domain.PopOKConfig
|
||||||
AleaPlay AleaPlayConfig `mapstructure:"alea_play"`
|
AleaPlay AleaPlayConfig `mapstructure:"alea_play"`
|
||||||
|
Atlas AtlasConfig `mapstructure:"atlas"`
|
||||||
VeliGames VeliConfig `mapstructure:"veli_games"`
|
VeliGames VeliConfig `mapstructure:"veli_games"`
|
||||||
ARIFPAY ARIFPAYConfig `mapstructure:"arifpay_config"`
|
ARIFPAY ARIFPAYConfig `mapstructure:"arifpay_config"`
|
||||||
SANTIMPAY SANTIMPAYConfig `mapstructure:"santimpay_config"`
|
SANTIMPAY SANTIMPAYConfig `mapstructure:"santimpay_config"`
|
||||||
|
|
|
||||||
151
internal/domain/atlas.go
Normal file
151
internal/domain/atlas.go
Normal file
|
|
@ -0,0 +1,151 @@
|
||||||
|
package domain
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
type AtlasGameInitRequest struct {
|
||||||
|
Game string `json:"game"`
|
||||||
|
PlayerID string `json:"player_id"`
|
||||||
|
Language string `json:"language"`
|
||||||
|
Currency string `json:"currency"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AtlasGameInitResponse struct {
|
||||||
|
URL string `json:"url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AtlasGetUserDataRequest struct {
|
||||||
|
Game string `json:"game"`
|
||||||
|
CasinoID string `json:"casino_id"`
|
||||||
|
PlayerID string `json:"player_id"`
|
||||||
|
SessionID string `json:"session_id"`
|
||||||
|
// timestamp and hash will also be included in the incoming JSON
|
||||||
|
}
|
||||||
|
|
||||||
|
type AtlasGetUserDataResponse struct {
|
||||||
|
PlayerID string `json:"player_id"`
|
||||||
|
Balance float64 `json:"balance"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AtlasBetRequest struct {
|
||||||
|
Game string `json:"game"`
|
||||||
|
CasinoID string `json:"casino_id"`
|
||||||
|
PlayerID string `json:"player_id"`
|
||||||
|
SessionID string `json:"session_id"`
|
||||||
|
Amount float64 `json:"amount"`
|
||||||
|
Currency string `json:"currency"`
|
||||||
|
RoundID int64 `json:"round_id"`
|
||||||
|
TransactionID string `json:"transaction_id"`
|
||||||
|
Details string `json:"details"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AtlasBetResponse struct {
|
||||||
|
PlayerID string `json:"player_id"`
|
||||||
|
Balance float64 `json:"balance"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AtlasBetWinRequest struct {
|
||||||
|
Game string `json:"game"`
|
||||||
|
CasinoID string `json:"casino_id"`
|
||||||
|
RoundID int64 `json:"round_id"`
|
||||||
|
PlayerID string `json:"player_id"`
|
||||||
|
SessionID string `json:"session_id"`
|
||||||
|
BetAmount float64 `json:"betAmount"`
|
||||||
|
WinAmount float64 `json:"winAmount"`
|
||||||
|
Currency string `json:"currency"`
|
||||||
|
TransactionID string `json:"transaction_id"`
|
||||||
|
Timestamp string `json:"timestamp"`
|
||||||
|
Hash string `json:"hash"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AtlasBetWinResponse struct {
|
||||||
|
PlayerID string `json:"player_id"`
|
||||||
|
Balance float64 `json:"balance"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RoundResultRequest struct {
|
||||||
|
Game string `json:"game"`
|
||||||
|
RoundID int64 `json:"round_id"`
|
||||||
|
CasinoID string `json:"casino_id"`
|
||||||
|
PlayerID string `json:"player_id"`
|
||||||
|
Amount float64 `json:"amount"` // win amount
|
||||||
|
Currency string `json:"currency"`
|
||||||
|
TransactionID string `json:"transaction_id"` // new transaction id
|
||||||
|
BetTransactionID string `json:"bet_transaction_id"` // from BET request
|
||||||
|
SessionID string `json:"session_id"`
|
||||||
|
Timestamp string `json:"timestamp"`
|
||||||
|
Hash string `json:"hash"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RoundResultResponse struct {
|
||||||
|
Success bool `json:"success"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RollbackRequest struct {
|
||||||
|
Game string `json:"game"`
|
||||||
|
RoundID int64 `json:"round_id"`
|
||||||
|
CasinoID string `json:"casino_id"`
|
||||||
|
PlayerID string `json:"player_id"`
|
||||||
|
BetTransactionID string `json:"bet_transaction_id"`
|
||||||
|
SessionID string `json:"session_id"`
|
||||||
|
Timestamp string `json:"timestamp"`
|
||||||
|
Hash string `json:"hash"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RollbackResponse struct {
|
||||||
|
Success bool `json:"success"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FreeSpinRequest struct {
|
||||||
|
CasinoID string `json:"casino_id"`
|
||||||
|
PlayerID string `json:"player_id"`
|
||||||
|
EndDate string `json:"end_date"` // "yyyy-mm-ddTHH:MM:SS+00:00"
|
||||||
|
FreeSpinsCount int `json:"freespins_count"` // count of free spins/bets
|
||||||
|
Timestamp string `json:"timestamp"`
|
||||||
|
Hash string `json:"hash"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FreeSpinResponse struct {
|
||||||
|
Success bool `json:"success"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FreeSpinResultRequest struct {
|
||||||
|
Game string `json:"game"`
|
||||||
|
RoundID int64 `json:"round_id"`
|
||||||
|
CasinoID string `json:"casino_id"`
|
||||||
|
PlayerID string `json:"player_id"`
|
||||||
|
Amount float64 `json:"amount"` // win amount
|
||||||
|
Currency string `json:"currency"`
|
||||||
|
TransactionID string `json:"transaction_id"`
|
||||||
|
SessionID string `json:"session_id"`
|
||||||
|
Timestamp string `json:"timestamp"`
|
||||||
|
Hash string `json:"hash"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FreeSpinResultResponse struct {
|
||||||
|
Success bool `json:"success"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type JackpotRequest struct {
|
||||||
|
Game string `json:"game"`
|
||||||
|
CasinoID string `json:"casino_id"`
|
||||||
|
PlayerID string `json:"player_id"`
|
||||||
|
SessionID string `json:"session_id"`
|
||||||
|
Amount float64 `json:"amount"` // jackpot win
|
||||||
|
Currency string `json:"currency"`
|
||||||
|
RoundID int64 `json:"round_id"`
|
||||||
|
TransactionID string `json:"transaction_id"`
|
||||||
|
Details string `json:"details,omitempty"`
|
||||||
|
Timestamp string `json:"timestamp"`
|
||||||
|
Hash string `json:"hash"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type JackpotResponse struct {
|
||||||
|
Success bool `json:"success"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrPlayerNotFound = errors.New("PLAYER_NOT_FOUND")
|
||||||
|
ErrSessionExpired = errors.New("SESSION_EXPIRED")
|
||||||
|
ErrWalletsNotFound = errors.New("WALLETS_NOT_FOUND")
|
||||||
|
ErrDuplicateTransaction = errors.New("DUPLICATE_TRANSACTION")
|
||||||
|
)
|
||||||
|
|
@ -61,14 +61,14 @@ type CreateOddMarketSettings struct {
|
||||||
CustomRawOdds []map[string]interface{}
|
CustomRawOdds []map[string]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// type RawOddsByMarketID struct {
|
type RawOddsByMarketID struct {
|
||||||
// ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
// MarketName string `json:"market_name"`
|
MarketName string `json:"market_name"`
|
||||||
// Handicap string `json:"handicap"`
|
Handicap string `json:"handicap"`
|
||||||
// RawOdds []json.RawMessage `json:"raw_odds"`
|
RawOdds []map[string]interface{} `json:"raw_odds"`
|
||||||
// FetchedAt time.Time `json:"fetched_at"`
|
FetchedAt time.Time `json:"fetched_at"`
|
||||||
// ExpiresAt time.Time `json:"expires_at"`
|
ExpiresAt time.Time `json:"expires_at"`
|
||||||
// }
|
}
|
||||||
|
|
||||||
type OddMarketFilter struct {
|
type OddMarketFilter struct {
|
||||||
Limit ValidInt32
|
Limit ValidInt32
|
||||||
|
|
|
||||||
|
|
@ -136,7 +136,7 @@ type CancelRequest struct {
|
||||||
CorrelationID string `json:"correlationId,omitempty"`
|
CorrelationID string `json:"correlationId,omitempty"`
|
||||||
ProviderID string `json:"providerId"`
|
ProviderID string `json:"providerId"`
|
||||||
BrandID string `json:"brandId"`
|
BrandID string `json:"brandId"`
|
||||||
IsAdjustment bool `json:"isAdjustment,omitempty"`
|
IsAdjustment bool `json:"isAdjustment,omitempty"`
|
||||||
AdjustmentRefund *struct {
|
AdjustmentRefund *struct {
|
||||||
Amount float64 `json:"amount"`
|
Amount float64 `json:"amount"`
|
||||||
Currency string `json:"currency"`
|
Currency string `json:"currency"`
|
||||||
|
|
@ -254,3 +254,9 @@ type HugeWinItem struct {
|
||||||
CreatedAt string `json:"createdAt"`
|
CreatedAt string `json:"createdAt"`
|
||||||
Reason string `json:"reason"`
|
Reason string `json:"reason"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CreditBalance struct {
|
||||||
|
Currency string `json:"currency"`
|
||||||
|
Balance float64 `json:"balance"`
|
||||||
|
Threshold float64 `json:"threshold"`
|
||||||
|
}
|
||||||
|
|
|
||||||
89
internal/services/virtualGame/atlas/client.go
Normal file
89
internal/services/virtualGame/atlas/client.go
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
package atlas
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"crypto/sha1"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/config"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
http *http.Client
|
||||||
|
BaseURL string
|
||||||
|
PrivateKey string
|
||||||
|
CasinoID string
|
||||||
|
PartnerID string
|
||||||
|
walletSvc *wallet.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewClient(cfg *config.Config, walletSvc *wallet.Service) *Client {
|
||||||
|
return &Client{
|
||||||
|
http: &http.Client{Timeout: 10 * time.Second},
|
||||||
|
BaseURL: cfg.Atlas.BaseURL,
|
||||||
|
PrivateKey: cfg.Atlas.SecretKey, // PRIVATE_KEY from Atlas
|
||||||
|
CasinoID: cfg.Atlas.CasinoID, // provided by Atlas
|
||||||
|
PartnerID: cfg.Atlas.PartnerID, // aggregator/casino partner_id
|
||||||
|
walletSvc: walletSvc,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate timestamp in ms
|
||||||
|
func nowTimestamp() string {
|
||||||
|
return fmt.Sprintf("%d", time.Now().UnixMilli())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Signature generator: sha1 hex of (REQUEST_BODY + PRIVATE_KEY + timestamp)
|
||||||
|
func (c *Client) generateHash(body []byte, timestamp string) string {
|
||||||
|
plain := string(body) + c.PrivateKey + timestamp
|
||||||
|
h := sha1.New()
|
||||||
|
h.Write([]byte(plain))
|
||||||
|
return hex.EncodeToString(h.Sum(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST helper
|
||||||
|
func (c *Client) post(ctx context.Context, path string, body map[string]any, result any) error {
|
||||||
|
// Add timestamp first
|
||||||
|
timestamp := nowTimestamp()
|
||||||
|
body["timestamp"] = timestamp
|
||||||
|
|
||||||
|
// Marshal without hash first
|
||||||
|
tmp, _ := json.Marshal(body)
|
||||||
|
|
||||||
|
// Generate hash using original body
|
||||||
|
hash := c.generateHash(tmp, timestamp)
|
||||||
|
body["hash"] = hash
|
||||||
|
|
||||||
|
// Marshal final body
|
||||||
|
data, _ := json.Marshal(body)
|
||||||
|
|
||||||
|
req, _ := http.NewRequestWithContext(ctx, "POST", c.BaseURL+path, bytes.NewReader(data))
|
||||||
|
req.Header.Set("Content-Type", "text/javascript")
|
||||||
|
|
||||||
|
// Debug
|
||||||
|
fmt.Println("Request URL:", c.BaseURL+path)
|
||||||
|
fmt.Println("Request Body:", string(data))
|
||||||
|
|
||||||
|
// Send request
|
||||||
|
res, err := c.http.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
b, _ := io.ReadAll(res.Body)
|
||||||
|
if res.StatusCode >= 400 {
|
||||||
|
return fmt.Errorf("error: %s", string(b))
|
||||||
|
}
|
||||||
|
if result != nil {
|
||||||
|
return json.Unmarshal(b, result)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
20
internal/services/virtualGame/atlas/port.go
Normal file
20
internal/services/virtualGame/atlas/port.go
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
// services/veli/service.go
|
||||||
|
package atlas
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AtlasVirtualGameService interface {
|
||||||
|
InitGame(ctx context.Context, req domain.AtlasGameInitRequest) (*domain.AtlasGameInitResponse, error)
|
||||||
|
GetUserData(ctx context.Context, req domain.AtlasGetUserDataRequest) (*domain.AtlasGetUserDataResponse, error)
|
||||||
|
ProcessBet(ctx context.Context, req domain.AtlasBetRequest) (*domain.AtlasBetResponse, error)
|
||||||
|
ProcessBetWin(ctx context.Context, req domain.AtlasBetWinRequest) (*domain.AtlasBetWinResponse, error)
|
||||||
|
ProcessRoundResult(ctx context.Context, req domain.RoundResultRequest) (*domain.RoundResultResponse, error)
|
||||||
|
ProcessRollBack(ctx context.Context, req domain.RollbackRequest) (*domain.RollbackResponse, error)
|
||||||
|
CreateFreeSpin(ctx context.Context, req domain.FreeSpinRequest) (*domain.FreeSpinResponse, error)
|
||||||
|
ProcessFreeSpinResult(ctx context.Context, req domain.FreeSpinResultRequest) (*domain.FreeSpinResultResponse, error)
|
||||||
|
ProcessJackPot(ctx context.Context, req domain.JackpotRequest) (*domain.JackpotResponse, error)
|
||||||
|
}
|
||||||
323
internal/services/virtualGame/atlas/service.go
Normal file
323
internal/services/virtualGame/atlas/service.go
Normal file
|
|
@ -0,0 +1,323 @@
|
||||||
|
package atlas
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/config"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/repository"
|
||||||
|
virtualgameservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
virtualGameSvc virtualgameservice.VirtualGameService
|
||||||
|
repo repository.VirtualGameRepository
|
||||||
|
client *Client
|
||||||
|
walletSvc *wallet.Service
|
||||||
|
transfetStore wallet.TransferStore
|
||||||
|
cfg *config.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(virtualGameSvc virtualgameservice.VirtualGameService, repo repository.VirtualGameRepository, client *Client, walletSvc *wallet.Service, transferStore wallet.TransferStore, cfg *config.Config) *Service {
|
||||||
|
return &Service{
|
||||||
|
virtualGameSvc: virtualGameSvc,
|
||||||
|
repo: repo,
|
||||||
|
client: client,
|
||||||
|
walletSvc: walletSvc,
|
||||||
|
transfetStore: transferStore,
|
||||||
|
cfg: cfg,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) InitGame(ctx context.Context, req domain.AtlasGameInitRequest) (*domain.AtlasGameInitResponse, error) {
|
||||||
|
|
||||||
|
body := map[string]any{
|
||||||
|
"game": req.Game,
|
||||||
|
"partner_id": s.client.PartnerID,
|
||||||
|
"casino_id": s.client.CasinoID,
|
||||||
|
"language": req.Language,
|
||||||
|
"currency": req.Currency,
|
||||||
|
"player_id": req.PlayerID,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Call the Atlas client
|
||||||
|
var res domain.AtlasGameInitResponse
|
||||||
|
if err := s.client.post(ctx, "/init", body, &res); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to initialize game: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetUserData(ctx context.Context, req domain.AtlasGetUserDataRequest) (*domain.AtlasGetUserDataResponse, error) {
|
||||||
|
// 1. Validate casino_id and hash if needed
|
||||||
|
if req.CasinoID != s.client.CasinoID {
|
||||||
|
return nil, fmt.Errorf("invalid casino_id")
|
||||||
|
}
|
||||||
|
// 2. Fetch player from DB
|
||||||
|
playerIDInt, err := strconv.ParseInt(req.PlayerID, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid playerID: %w", err)
|
||||||
|
}
|
||||||
|
wallet, err := s.walletSvc.GetCustomerWallet(ctx, playerIDInt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to fetch walllets for player %d: %w", playerIDInt, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Build response
|
||||||
|
res := &domain.AtlasGetUserDataResponse{
|
||||||
|
PlayerID: req.PlayerID,
|
||||||
|
Balance: float64(wallet.RegularBalance),
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) ProcessBet(ctx context.Context, req domain.AtlasBetRequest) (*domain.AtlasBetResponse, error) {
|
||||||
|
if req.CasinoID != s.client.CasinoID {
|
||||||
|
return nil, fmt.Errorf("invalid casino_id")
|
||||||
|
}
|
||||||
|
|
||||||
|
playerIDInt, err := strconv.ParseInt(req.PlayerID, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid playerID: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
wallet, err := s.walletSvc.GetCustomerWallet(ctx, playerIDInt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to fetch walllets for player %d: %w", playerIDInt, err)
|
||||||
|
}
|
||||||
|
// if player == nil {
|
||||||
|
// return nil, ErrPlayerNotFound
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 3. Check for duplicate transaction
|
||||||
|
// exists, err := s.repo.TransactionExists(ctx, req.TransactionID)
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, fmt.Errorf("failed to check transaction: %w", err)
|
||||||
|
// }
|
||||||
|
// if exists {
|
||||||
|
// return nil, ErrDuplicateTransaction
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 4. Get current balance
|
||||||
|
// balance, err := s.walletSvc.GetBalance(ctx, req.PlayerID)
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, fmt.Errorf("failed to fetch wallet balance: %w", err)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 5. Ensure sufficient balance
|
||||||
|
if float64(wallet.RegularBalance) < req.Amount {
|
||||||
|
return nil, domain.ErrInsufficientBalance
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. Deduct amount from wallet (record transaction)
|
||||||
|
_, err = s.walletSvc.DeductFromWallet(ctx, wallet.ID, domain.Currency(req.Amount), domain.ValidInt64{}, domain.PaymentMethod(domain.DEPOSIT), "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to debit wallet: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. Save transaction record to DB (optional but recommended)
|
||||||
|
// if err := s.repo.SaveBetTransaction(ctx, req); err != nil {
|
||||||
|
// // log warning but don’t fail response to Atlas
|
||||||
|
// fmt.Printf("warning: failed to save bet transaction: %v\n", err)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 8. Build response
|
||||||
|
res := &domain.AtlasBetResponse{
|
||||||
|
PlayerID: req.PlayerID,
|
||||||
|
Balance: float64(wallet.RegularBalance) - req.Amount,
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) ProcessBetWin(ctx context.Context, req domain.AtlasBetWinRequest) (*domain.AtlasBetWinResponse, error) {
|
||||||
|
if req.CasinoID != s.client.CasinoID {
|
||||||
|
return nil, fmt.Errorf("invalid casino_id")
|
||||||
|
}
|
||||||
|
|
||||||
|
playerIDInt, err := strconv.ParseInt(req.PlayerID, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid playerID: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
wallet, err := s.walletSvc.GetCustomerWallet(ctx, playerIDInt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to fetch walllets for player %d: %w", playerIDInt, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. Ensure sufficient balance
|
||||||
|
if float64(wallet.RegularBalance) < req.BetAmount {
|
||||||
|
return nil, domain.ErrInsufficientBalance
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. Deduct amount from wallet (record transaction)
|
||||||
|
_, err = s.walletSvc.DeductFromWallet(ctx, wallet.ID, domain.Currency(req.BetAmount), domain.ValidInt64{}, domain.PaymentMethod(domain.DEPOSIT), "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to debit wallet: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.WinAmount > 0 {
|
||||||
|
_, err = s.walletSvc.AddToWallet(ctx, wallet.ID, domain.Currency(req.WinAmount), domain.ValidInt64{}, domain.PaymentMethod(domain.DEPOSIT), domain.PaymentDetails{}, "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to credit wallet: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 8. Build response
|
||||||
|
res := &domain.AtlasBetWinResponse{
|
||||||
|
PlayerID: req.PlayerID,
|
||||||
|
Balance: float64(wallet.RegularBalance) - req.BetAmount + req.WinAmount,
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) ProcessRoundResult(ctx context.Context, req domain.RoundResultRequest) (*domain.RoundResultResponse, error) {
|
||||||
|
if req.PlayerID == "" || req.TransactionID == "" {
|
||||||
|
return nil, errors.New("missing player_id or transaction_id")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Credit player with win amount if > 0
|
||||||
|
if req.Amount > 0 {
|
||||||
|
// This will credit player's balance
|
||||||
|
playerIDInt, err := strconv.ParseInt(req.PlayerID, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid playerID: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
wallet, err := s.walletSvc.GetCustomerWallet(ctx, playerIDInt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to fetch walllets for player %d: %w", playerIDInt, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = s.walletSvc.AddToWallet(ctx, wallet.ID, domain.Currency(req.Amount), domain.ValidInt64{}, domain.PaymentMethod(domain.DEPOSIT), domain.PaymentDetails{}, "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to credit wallet: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return &domain.RoundResultResponse{Success: true}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) ProcessRollBack(ctx context.Context, req domain.RollbackRequest) (*domain.RollbackResponse, error) {
|
||||||
|
if req.PlayerID == "" || req.BetTransactionID == "" {
|
||||||
|
return nil, errors.New("missing player_id or transaction_id")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Credit player with win amount if > 0
|
||||||
|
// This will credit player's balance
|
||||||
|
playerIDInt, err := strconv.ParseInt(req.PlayerID, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid playerID: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
wallet, err := s.walletSvc.GetCustomerWallet(ctx, playerIDInt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to fetch walllets for player %d: %w", playerIDInt, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
transfer, err := s.transfetStore.GetTransferByReference(ctx, req.BetTransactionID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to fetch transfer for reference %s: %w", req.BetTransactionID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = s.walletSvc.AddToWallet(ctx, wallet.ID, domain.Currency(transfer.Amount), domain.ValidInt64{}, domain.PaymentMethod(domain.DEPOSIT), domain.PaymentDetails{}, "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to credit wallet: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = s.transfetStore.UpdateTransferStatus(ctx, transfer.ID, string(domain.STATUS_CANCELLED))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to update transfer status: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = s.transfetStore.UpdateTransferVerification(ctx, transfer.ID, true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to update transfer verification: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &domain.RollbackResponse{Success: true}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) CreateFreeSpin(ctx context.Context, req domain.FreeSpinRequest) (*domain.FreeSpinResponse, error) {
|
||||||
|
|
||||||
|
body := map[string]any{
|
||||||
|
"casino_id": s.client.CasinoID,
|
||||||
|
"freespins_count": req.FreeSpinsCount,
|
||||||
|
"end_date": req.EndDate,
|
||||||
|
"player_id": req.PlayerID,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Call the Atlas client
|
||||||
|
var res domain.FreeSpinResponse
|
||||||
|
if err := s.client.post(ctx, "/freespin", body, &res); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create free spin: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) ProcessFreeSpinResult(ctx context.Context, req domain.FreeSpinResultRequest) (*domain.FreeSpinResultResponse, error) {
|
||||||
|
|
||||||
|
if req.PlayerID == "" || req.TransactionID == "" {
|
||||||
|
return nil, errors.New("missing player_id or transaction_id")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Credit player with win amount if > 0
|
||||||
|
if req.Amount > 0 {
|
||||||
|
// This will credit player's balance
|
||||||
|
playerIDInt, err := strconv.ParseInt(req.PlayerID, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid playerID: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
wallet, err := s.walletSvc.GetCustomerWallet(ctx, playerIDInt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to fetch walllets for player %d: %w", playerIDInt, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = s.walletSvc.AddToWallet(ctx, wallet.ID, domain.Currency(req.Amount), domain.ValidInt64{}, domain.PaymentMethod(domain.DEPOSIT), domain.PaymentDetails{}, "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to credit wallet: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return &domain.FreeSpinResultResponse{Success: true}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) ProcessJackPot(ctx context.Context, req domain.JackpotRequest) (*domain.JackpotResponse, error) {
|
||||||
|
|
||||||
|
if req.PlayerID == "" || req.TransactionID == "" {
|
||||||
|
return nil, errors.New("missing player_id or transaction_id")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Credit player with win amount if > 0
|
||||||
|
if req.Amount > 0 {
|
||||||
|
// This will credit player's balance
|
||||||
|
playerIDInt, err := strconv.ParseInt(req.PlayerID, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid playerID: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
wallet, err := s.walletSvc.GetCustomerWallet(ctx, playerIDInt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to fetch walllets for player %d: %w", playerIDInt, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = s.walletSvc.AddToWallet(ctx, wallet.ID, domain.Currency(req.Amount), domain.ValidInt64{}, domain.PaymentMethod(domain.DEPOSIT), domain.PaymentDetails{}, "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to credit wallet: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return &domain.JackpotResponse{Success: true}, nil
|
||||||
|
}
|
||||||
|
|
@ -22,4 +22,5 @@ type VeliVirtualGameService interface {
|
||||||
ProcessCancel(ctx context.Context, req domain.CancelRequest) (*domain.CancelResponse, error)
|
ProcessCancel(ctx context.Context, req domain.CancelRequest) (*domain.CancelResponse, error)
|
||||||
GetGamingActivity(ctx context.Context, req domain.GamingActivityRequest) (*domain.GamingActivityResponse, error)
|
GetGamingActivity(ctx context.Context, req domain.GamingActivityRequest) (*domain.GamingActivityResponse, error)
|
||||||
GetHugeWins(ctx context.Context, req domain.HugeWinsRequest) (*domain.HugeWinsResponse, error)
|
GetHugeWins(ctx context.Context, req domain.HugeWinsRequest) (*domain.HugeWinsResponse, error)
|
||||||
|
GetCreditBalances(ctx context.Context, brandID string) ([]domain.CreditBalance, error)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,23 +22,23 @@ var (
|
||||||
|
|
||||||
type Service struct {
|
type Service struct {
|
||||||
virtualGameSvc virtualgameservice.VirtualGameService
|
virtualGameSvc virtualgameservice.VirtualGameService
|
||||||
repo repository.VirtualGameRepository
|
repo repository.VirtualGameRepository
|
||||||
client *Client
|
client *Client
|
||||||
walletSvc *wallet.Service
|
walletSvc *wallet.Service
|
||||||
transfetStore wallet.TransferStore
|
transfetStore wallet.TransferStore
|
||||||
cfg *config.Config
|
cfg *config.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(virtualGameSvc virtualgameservice.VirtualGameService,repo repository.VirtualGameRepository,client *Client, walletSvc *wallet.Service, transferStore wallet.TransferStore, cfg *config.Config) *Service {
|
func New(virtualGameSvc virtualgameservice.VirtualGameService, repo repository.VirtualGameRepository, client *Client, walletSvc *wallet.Service, transferStore wallet.TransferStore, cfg *config.Config) *Service {
|
||||||
return &Service{
|
return &Service{
|
||||||
virtualGameSvc: virtualGameSvc,
|
virtualGameSvc: virtualGameSvc,
|
||||||
repo: repo,
|
repo: repo,
|
||||||
client: client,
|
client: client,
|
||||||
walletSvc: walletSvc,
|
walletSvc: walletSvc,
|
||||||
transfetStore: transferStore,
|
transfetStore: transferStore,
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) GetProviders(ctx context.Context, req domain.ProviderRequest) (*domain.ProviderResponse, error) {
|
func (s *Service) GetProviders(ctx context.Context, req domain.ProviderRequest) (*domain.ProviderResponse, error) {
|
||||||
// Always mirror request body fields into sigParams
|
// Always mirror request body fields into sigParams
|
||||||
|
|
@ -128,7 +128,6 @@ func (s *Service) StartGame(ctx context.Context, req domain.GameStartRequest) (*
|
||||||
return &res, nil
|
return &res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (s *Service) StartDemoGame(ctx context.Context, req domain.DemoGameRequest) (*domain.GameStartResponse, error) {
|
func (s *Service) StartDemoGame(ctx context.Context, req domain.DemoGameRequest) (*domain.GameStartResponse, error) {
|
||||||
// 1. Check if provider is enabled in DB
|
// 1. Check if provider is enabled in DB
|
||||||
provider, err := s.repo.GetVirtualGameProviderByID(ctx, req.ProviderID)
|
provider, err := s.repo.GetVirtualGameProviderByID(ctx, req.ProviderID)
|
||||||
|
|
@ -160,7 +159,6 @@ func (s *Service) StartDemoGame(ctx context.Context, req domain.DemoGameRequest)
|
||||||
return &res, nil
|
return &res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (s *Service) GetBalance(ctx context.Context, req domain.BalanceRequest) (*domain.BalanceResponse, error) {
|
func (s *Service) GetBalance(ctx context.Context, req domain.BalanceRequest) (*domain.BalanceResponse, error) {
|
||||||
// Retrieve player's real balance from wallet Service
|
// Retrieve player's real balance from wallet Service
|
||||||
playerIDInt64, err := strconv.ParseInt(req.PlayerID, 10, 64)
|
playerIDInt64, err := strconv.ParseInt(req.PlayerID, 10, 64)
|
||||||
|
|
@ -595,3 +593,25 @@ func (s *Service) GetHugeWins(ctx context.Context, req domain.HugeWinsRequest) (
|
||||||
|
|
||||||
return &res, nil
|
return &res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetCreditBalances(ctx context.Context, brandID string) ([]domain.CreditBalance, error) {
|
||||||
|
if brandID == "" {
|
||||||
|
return nil, fmt.Errorf("brandID cannot be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare request body
|
||||||
|
body := map[string]any{
|
||||||
|
"brandId": brandID,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call the VeliGames API
|
||||||
|
var res struct {
|
||||||
|
Credits []domain.CreditBalance `json:"credits"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.client.post(ctx, "/report-api/public/credit/balances", body, nil, &res); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to fetch credit balances: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.Credits, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import (
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/user"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/user"
|
||||||
virtualgameservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame"
|
virtualgameservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame"
|
||||||
alea "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/Alea"
|
alea "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/Alea"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/atlas"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/veli"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/veli"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet"
|
||||||
jwtutil "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/jwt"
|
jwtutil "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/jwt"
|
||||||
|
|
@ -43,45 +44,47 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type App struct {
|
type App struct {
|
||||||
veliVirtualGameService veli.VeliVirtualGameService
|
atlasVirtualGameService atlas.AtlasVirtualGameService
|
||||||
telebirrSvc *telebirr.TelebirrService
|
veliVirtualGameService veli.VeliVirtualGameService
|
||||||
arifpaySvc *arifpay.ArifpayService
|
telebirrSvc *telebirr.TelebirrService
|
||||||
santimpaySvc *santimpay.SantimPayService
|
arifpaySvc *arifpay.ArifpayService
|
||||||
issueReportingSvc *issuereporting.Service
|
santimpaySvc *santimpay.SantimPayService
|
||||||
instSvc *institutions.Service
|
issueReportingSvc *issuereporting.Service
|
||||||
currSvc *currency.Service
|
instSvc *institutions.Service
|
||||||
fiber *fiber.App
|
currSvc *currency.Service
|
||||||
aleaVirtualGameService alea.AleaVirtualGameService
|
fiber *fiber.App
|
||||||
recommendationSvc recommendation.RecommendationService
|
aleaVirtualGameService alea.AleaVirtualGameService
|
||||||
cfg *config.Config
|
recommendationSvc recommendation.RecommendationService
|
||||||
logger *slog.Logger
|
cfg *config.Config
|
||||||
NotidicationStore *notificationservice.Service
|
logger *slog.Logger
|
||||||
referralSvc referralservice.ReferralStore
|
NotidicationStore *notificationservice.Service
|
||||||
bonusSvc *bonus.Service
|
referralSvc referralservice.ReferralStore
|
||||||
port int
|
bonusSvc *bonus.Service
|
||||||
settingSvc *settings.Service
|
port int
|
||||||
authSvc *authentication.Service
|
settingSvc *settings.Service
|
||||||
userSvc *user.Service
|
authSvc *authentication.Service
|
||||||
betSvc *bet.Service
|
userSvc *user.Service
|
||||||
virtualGameSvc virtualgameservice.VirtualGameService
|
betSvc *bet.Service
|
||||||
reportSvc *report.Service
|
virtualGameSvc virtualgameservice.VirtualGameService
|
||||||
chapaSvc *chapa.Service
|
reportSvc *report.Service
|
||||||
walletSvc *wallet.Service
|
chapaSvc *chapa.Service
|
||||||
transactionSvc *transaction.Service
|
walletSvc *wallet.Service
|
||||||
ticketSvc *ticket.Service
|
transactionSvc *transaction.Service
|
||||||
branchSvc *branch.Service
|
ticketSvc *ticket.Service
|
||||||
companySvc *company.Service
|
branchSvc *branch.Service
|
||||||
validator *customvalidator.CustomValidator
|
companySvc *company.Service
|
||||||
JwtConfig jwtutil.JwtConfig
|
validator *customvalidator.CustomValidator
|
||||||
Logger *slog.Logger
|
JwtConfig jwtutil.JwtConfig
|
||||||
prematchSvc *odds.ServiceImpl
|
Logger *slog.Logger
|
||||||
eventSvc event.Service
|
prematchSvc *odds.ServiceImpl
|
||||||
leagueSvc league.Service
|
eventSvc event.Service
|
||||||
resultSvc *result.Service
|
leagueSvc league.Service
|
||||||
mongoLoggerSvc *zap.Logger
|
resultSvc *result.Service
|
||||||
|
mongoLoggerSvc *zap.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewApp(
|
func NewApp(
|
||||||
|
atlasVirtualGameService atlas.AtlasVirtualGameService,
|
||||||
veliVirtualGameService veli.VeliVirtualGameService,
|
veliVirtualGameService veli.VeliVirtualGameService,
|
||||||
telebirrSvc *telebirr.TelebirrService,
|
telebirrSvc *telebirr.TelebirrService,
|
||||||
arifpaySvc *arifpay.ArifpayService,
|
arifpaySvc *arifpay.ArifpayService,
|
||||||
|
|
@ -132,15 +135,16 @@ func NewApp(
|
||||||
}))
|
}))
|
||||||
|
|
||||||
s := &App{
|
s := &App{
|
||||||
|
atlasVirtualGameService: atlasVirtualGameService,
|
||||||
veliVirtualGameService: veliVirtualGameService,
|
veliVirtualGameService: veliVirtualGameService,
|
||||||
telebirrSvc: telebirrSvc,
|
telebirrSvc: telebirrSvc,
|
||||||
arifpaySvc: arifpaySvc,
|
arifpaySvc: arifpaySvc,
|
||||||
santimpaySvc: santimpaySvc,
|
santimpaySvc: santimpaySvc,
|
||||||
issueReportingSvc: issueReportingSvc,
|
issueReportingSvc: issueReportingSvc,
|
||||||
instSvc: instSvc,
|
instSvc: instSvc,
|
||||||
currSvc: currSvc,
|
currSvc: currSvc,
|
||||||
fiber: app,
|
fiber: app,
|
||||||
port: port,
|
port: port,
|
||||||
|
|
||||||
settingSvc: settingSvc,
|
settingSvc: settingSvc,
|
||||||
authSvc: authSvc,
|
authSvc: authSvc,
|
||||||
|
|
|
||||||
398
internal/web_server/handlers/atlas.go
Normal file
398
internal/web_server/handlers/atlas.go
Normal file
|
|
@ -0,0 +1,398 @@
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
@ -30,6 +30,7 @@ import (
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/user"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/user"
|
||||||
virtualgameservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame"
|
virtualgameservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame"
|
||||||
alea "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/Alea"
|
alea "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/Alea"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/atlas"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/veli"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/veli"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet"
|
||||||
jwtutil "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/jwt"
|
jwtutil "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/jwt"
|
||||||
|
|
@ -38,39 +39,40 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Handler struct {
|
type Handler struct {
|
||||||
telebirrSvc *telebirr.TelebirrService
|
telebirrSvc *telebirr.TelebirrService
|
||||||
arifpaySvc *arifpay.ArifpayService
|
arifpaySvc *arifpay.ArifpayService
|
||||||
santimpaySvc *santimpay.SantimPayService
|
santimpaySvc *santimpay.SantimPayService
|
||||||
issueReportingSvc *issuereporting.Service
|
issueReportingSvc *issuereporting.Service
|
||||||
instSvc *institutions.Service
|
instSvc *institutions.Service
|
||||||
currSvc *currency.Service
|
currSvc *currency.Service
|
||||||
logger *slog.Logger
|
logger *slog.Logger
|
||||||
settingSvc *settings.Service
|
settingSvc *settings.Service
|
||||||
notificationSvc *notificationservice.Service
|
notificationSvc *notificationservice.Service
|
||||||
userSvc *user.Service
|
userSvc *user.Service
|
||||||
referralSvc referralservice.ReferralStore
|
referralSvc referralservice.ReferralStore
|
||||||
bonusSvc *bonus.Service
|
bonusSvc *bonus.Service
|
||||||
reportSvc report.ReportStore
|
reportSvc report.ReportStore
|
||||||
chapaSvc *chapa.Service
|
chapaSvc *chapa.Service
|
||||||
walletSvc *wallet.Service
|
walletSvc *wallet.Service
|
||||||
transactionSvc *transaction.Service
|
transactionSvc *transaction.Service
|
||||||
ticketSvc *ticket.Service
|
ticketSvc *ticket.Service
|
||||||
betSvc *bet.Service
|
betSvc *bet.Service
|
||||||
branchSvc *branch.Service
|
branchSvc *branch.Service
|
||||||
companySvc *company.Service
|
companySvc *company.Service
|
||||||
prematchSvc *odds.ServiceImpl
|
prematchSvc *odds.ServiceImpl
|
||||||
eventSvc event.Service
|
eventSvc event.Service
|
||||||
leagueSvc league.Service
|
leagueSvc league.Service
|
||||||
virtualGameSvc virtualgameservice.VirtualGameService
|
virtualGameSvc virtualgameservice.VirtualGameService
|
||||||
aleaVirtualGameSvc alea.AleaVirtualGameService
|
aleaVirtualGameSvc alea.AleaVirtualGameService
|
||||||
veliVirtualGameSvc veli.VeliVirtualGameService
|
veliVirtualGameSvc veli.VeliVirtualGameService
|
||||||
recommendationSvc recommendation.RecommendationService
|
atlasVirtualGameSvc atlas.AtlasVirtualGameService
|
||||||
authSvc *authentication.Service
|
recommendationSvc recommendation.RecommendationService
|
||||||
resultSvc result.Service
|
authSvc *authentication.Service
|
||||||
jwtConfig jwtutil.JwtConfig
|
resultSvc result.Service
|
||||||
validator *customvalidator.CustomValidator
|
jwtConfig jwtutil.JwtConfig
|
||||||
Cfg *config.Config
|
validator *customvalidator.CustomValidator
|
||||||
mongoLoggerSvc *zap.Logger
|
Cfg *config.Config
|
||||||
|
mongoLoggerSvc *zap.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(
|
func New(
|
||||||
|
|
@ -92,6 +94,7 @@ func New(
|
||||||
virtualGameSvc virtualgameservice.VirtualGameService,
|
virtualGameSvc virtualgameservice.VirtualGameService,
|
||||||
aleaVirtualGameSvc alea.AleaVirtualGameService,
|
aleaVirtualGameSvc alea.AleaVirtualGameService,
|
||||||
veliVirtualGameSvc veli.VeliVirtualGameService,
|
veliVirtualGameSvc veli.VeliVirtualGameService,
|
||||||
|
atlasVirtualGameSvc atlas.AtlasVirtualGameService,
|
||||||
recommendationSvc recommendation.RecommendationService,
|
recommendationSvc recommendation.RecommendationService,
|
||||||
userSvc *user.Service,
|
userSvc *user.Service,
|
||||||
transactionSvc *transaction.Service,
|
transactionSvc *transaction.Service,
|
||||||
|
|
@ -109,38 +112,39 @@ func New(
|
||||||
mongoLoggerSvc *zap.Logger,
|
mongoLoggerSvc *zap.Logger,
|
||||||
) *Handler {
|
) *Handler {
|
||||||
return &Handler{
|
return &Handler{
|
||||||
telebirrSvc: telebirrSvc,
|
telebirrSvc: telebirrSvc,
|
||||||
arifpaySvc: arifpaySvc,
|
arifpaySvc: arifpaySvc,
|
||||||
santimpaySvc: santimpaySvc,
|
santimpaySvc: santimpaySvc,
|
||||||
issueReportingSvc: issueReportingSvc,
|
issueReportingSvc: issueReportingSvc,
|
||||||
instSvc: instSvc,
|
instSvc: instSvc,
|
||||||
currSvc: currSvc,
|
currSvc: currSvc,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
settingSvc: settingSvc,
|
settingSvc: settingSvc,
|
||||||
notificationSvc: notificationSvc,
|
notificationSvc: notificationSvc,
|
||||||
reportSvc: reportSvc,
|
reportSvc: reportSvc,
|
||||||
chapaSvc: chapaSvc,
|
chapaSvc: chapaSvc,
|
||||||
walletSvc: walletSvc,
|
walletSvc: walletSvc,
|
||||||
referralSvc: referralSvc,
|
referralSvc: referralSvc,
|
||||||
bonusSvc: bonusSvc,
|
bonusSvc: bonusSvc,
|
||||||
validator: validator,
|
validator: validator,
|
||||||
userSvc: userSvc,
|
userSvc: userSvc,
|
||||||
transactionSvc: transactionSvc,
|
transactionSvc: transactionSvc,
|
||||||
ticketSvc: ticketSvc,
|
ticketSvc: ticketSvc,
|
||||||
betSvc: betSvc,
|
betSvc: betSvc,
|
||||||
branchSvc: branchSvc,
|
branchSvc: branchSvc,
|
||||||
companySvc: companySvc,
|
companySvc: companySvc,
|
||||||
prematchSvc: prematchSvc,
|
prematchSvc: prematchSvc,
|
||||||
eventSvc: eventSvc,
|
eventSvc: eventSvc,
|
||||||
leagueSvc: leagueSvc,
|
leagueSvc: leagueSvc,
|
||||||
virtualGameSvc: virtualGameSvc,
|
virtualGameSvc: virtualGameSvc,
|
||||||
aleaVirtualGameSvc: aleaVirtualGameSvc,
|
aleaVirtualGameSvc: aleaVirtualGameSvc,
|
||||||
veliVirtualGameSvc: veliVirtualGameSvc,
|
veliVirtualGameSvc: veliVirtualGameSvc,
|
||||||
recommendationSvc: recommendationSvc,
|
atlasVirtualGameSvc: atlasVirtualGameSvc,
|
||||||
authSvc: authSvc,
|
recommendationSvc: recommendationSvc,
|
||||||
resultSvc: resultSvc,
|
authSvc: authSvc,
|
||||||
jwtConfig: jwtConfig,
|
resultSvc: resultSvc,
|
||||||
Cfg: cfg,
|
jwtConfig: jwtConfig,
|
||||||
mongoLoggerSvc: mongoLoggerSvc,
|
Cfg: cfg,
|
||||||
|
mongoLoggerSvc: mongoLoggerSvc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import (
|
||||||
// @Tags prematch
|
// @Tags prematch
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {array} domain.Odd
|
// @Success 200 {array} domain.OddMarketFilter
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /api/v1/odds [get]
|
// @Router /api/v1/odds [get]
|
||||||
func (h *Handler) GetAllOdds(c *fiber.Ctx) error {
|
func (h *Handler) GetAllOdds(c *fiber.Ctx) error {
|
||||||
|
|
@ -59,7 +59,7 @@ func (h *Handler) GetAllOdds(c *fiber.Ctx) error {
|
||||||
// @Tags prematch
|
// @Tags prematch
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {array} domain.Odd
|
// @Success 200 {array} domain.OddMarketFilter
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /api/v1/{tenant_slug}/odds [get]
|
// @Router /api/v1/{tenant_slug}/odds [get]
|
||||||
func (h *Handler) GetAllTenantOdds(c *fiber.Ctx) error {
|
func (h *Handler) GetAllTenantOdds(c *fiber.Ctx) error {
|
||||||
|
|
@ -201,7 +201,7 @@ func (h *Handler) GetTenantOddsByMarketID(c *fiber.Ctx) error {
|
||||||
// @Param upcoming_id path string true "Upcoming Event ID (FI)"
|
// @Param upcoming_id path string true "Upcoming Event ID (FI)"
|
||||||
// @Param limit query int false "Number of results to return (default: 10)"
|
// @Param limit query int false "Number of results to return (default: 10)"
|
||||||
// @Param offset query int false "Number of results to skip (default: 0)"
|
// @Param offset query int false "Number of results to skip (default: 0)"
|
||||||
// @Success 200 {array} domain.Odd
|
// @Success 200 {array} domain.OddMarketWithEventFilter
|
||||||
// @Failure 400 {object} response.APIResponse
|
// @Failure 400 {object} response.APIResponse
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /api/v1/odds/upcoming/{upcoming_id} [get]
|
// @Router /api/v1/odds/upcoming/{upcoming_id} [get]
|
||||||
|
|
@ -252,7 +252,7 @@ func (h *Handler) GetOddsByUpcomingID(c *fiber.Ctx) error {
|
||||||
// @Param upcoming_id path string true "Upcoming Event ID (FI)"
|
// @Param upcoming_id path string true "Upcoming Event ID (FI)"
|
||||||
// @Param limit query int false "Number of results to return (default: 10)"
|
// @Param limit query int false "Number of results to return (default: 10)"
|
||||||
// @Param offset query int false "Number of results to skip (default: 0)"
|
// @Param offset query int false "Number of results to skip (default: 0)"
|
||||||
// @Success 200 {array} domain.Odd
|
// @Success 200 {array} domain.OddMarketFilter
|
||||||
// @Failure 400 {object} response.APIResponse
|
// @Failure 400 {object} response.APIResponse
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /api/v1/{tenant_slug}/odds/upcoming/{upcoming_id} [get]
|
// @Router /api/v1/{tenant_slug}/odds/upcoming/{upcoming_id} [get]
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,6 @@ func (h *Handler) GetGamesByProvider(c *fiber.Ctx) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// StartGame godoc
|
// StartGame godoc
|
||||||
// @Summary Start a real game session
|
// @Summary Start a real game session
|
||||||
// @Description Starts a real VeliGames session with the given player and game info
|
// @Description Starts a real VeliGames session with the given player and game info
|
||||||
|
|
@ -167,7 +166,6 @@ func (h *Handler) StartGame(c *fiber.Ctx) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// StartDemoGame godoc
|
// StartDemoGame godoc
|
||||||
// @Summary Start a demo game session
|
// @Summary Start a demo game session
|
||||||
// @Description Starts a demo session of the specified game (must support demo mode)
|
// @Description Starts a demo session of the specified game (must support demo mode)
|
||||||
|
|
@ -220,7 +218,6 @@ func (h *Handler) StartDemoGame(c *fiber.Ctx) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (h *Handler) GetBalance(c *fiber.Ctx) error {
|
func (h *Handler) GetBalance(c *fiber.Ctx) error {
|
||||||
var req domain.BalanceRequest
|
var req domain.BalanceRequest
|
||||||
if err := c.BodyParser(&req); err != nil {
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
|
@ -395,3 +392,41 @@ func (h *Handler) GetHugeWins(c *fiber.Ctx) error {
|
||||||
Success: true,
|
Success: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetCreditBalances godoc
|
||||||
|
// @Summary Get VeliGames credit balances for a brand
|
||||||
|
// @Description Fetches current credit balances per currency for the specified brand
|
||||||
|
// @Tags Virtual Games - VeliGames
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param brandId query string true "Brand ID"
|
||||||
|
// @Success 200 {object} domain.Response{data=[]domain.CreditBalance}
|
||||||
|
// @Failure 400 {object} domain.ErrorResponse
|
||||||
|
// @Failure 502 {object} domain.ErrorResponse
|
||||||
|
// @Router /api/v1/veli/credit-balances [get]
|
||||||
|
func (h *Handler) GetCreditBalances(c *fiber.Ctx) error {
|
||||||
|
brandID := c.Query("brandId", h.Cfg.VeliGames.BrandID) // Default brand if not provided
|
||||||
|
|
||||||
|
if brandID == "" {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
||||||
|
Message: "Brand ID is required",
|
||||||
|
Error: "missing brandId",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := h.veliVirtualGameSvc.GetCreditBalances(c.Context(), brandID)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("GetCreditBalances error:", err)
|
||||||
|
return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{
|
||||||
|
Message: "Failed to fetch credit balances",
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Status(fiber.StatusOK).JSON(domain.Response{
|
||||||
|
Message: "Credit balances fetched successfully",
|
||||||
|
Data: res,
|
||||||
|
StatusCode: fiber.StatusOK,
|
||||||
|
Success: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -255,11 +255,26 @@ func (h *Handler) HandleBet(c *fiber.Ctx) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try parsing as Veli bet request
|
// Identify the provider based on request structure
|
||||||
var veliReq domain.BetRequest
|
provider, err := IdentifyBetProvider(body)
|
||||||
if err := json.Unmarshal(body, &veliReq); err == nil && veliReq.SessionID != "" && veliReq.BrandID != "" {
|
if err != nil {
|
||||||
// Process as Veli
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
||||||
res, err := h.veliVirtualGameSvc.ProcessBet(c.Context(), veliReq)
|
Message: "Unrecognized request format",
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
switch provider {
|
||||||
|
case "veli":
|
||||||
|
var req domain.BetRequest
|
||||||
|
if err := json.Unmarshal(body, &req); err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
||||||
|
Message: "Invalid Veli bet request",
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := h.veliVirtualGameSvc.ProcessBet(c.Context(), req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, veli.ErrDuplicateTransaction) {
|
if errors.Is(err, veli.ErrDuplicateTransaction) {
|
||||||
return c.Status(fiber.StatusConflict).JSON(domain.ErrorResponse{
|
return c.Status(fiber.StatusConflict).JSON(domain.ErrorResponse{
|
||||||
|
|
@ -267,19 +282,23 @@ func (h *Handler) HandleBet(c *fiber.Ctx) error {
|
||||||
Error: "DUPLICATE_TRANSACTION",
|
Error: "DUPLICATE_TRANSACTION",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
||||||
Message: "Veli bet processing failed",
|
Message: "Veli bet processing failed",
|
||||||
Error: err.Error(),
|
Error: err.Error(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return c.JSON(res)
|
return c.JSON(res)
|
||||||
}
|
|
||||||
|
|
||||||
// Try parsing as PopOK bet request
|
case "popok":
|
||||||
var popokReq domain.PopOKBetRequest
|
var req domain.PopOKBetRequest
|
||||||
if err := json.Unmarshal(body, &popokReq); err == nil && popokReq.ExternalToken != "" {
|
if err := json.Unmarshal(body, &req); err != nil {
|
||||||
// Process as PopOK
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
||||||
resp, err := h.virtualGameSvc.ProcessBet(c.Context(), &popokReq)
|
Message: "Invalid PopOK bet request",
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := h.virtualGameSvc.ProcessBet(c.Context(), &req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
code := fiber.StatusInternalServerError
|
code := fiber.StatusInternalServerError
|
||||||
switch err.Error() {
|
switch err.Error() {
|
||||||
|
|
@ -294,13 +313,35 @@ func (h *Handler) HandleBet(c *fiber.Ctx) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return c.JSON(resp)
|
return c.JSON(resp)
|
||||||
}
|
|
||||||
|
|
||||||
// If neither works
|
case "atlas":
|
||||||
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
var req domain.AtlasBetRequest
|
||||||
Message: "Unsupported provider",
|
if err := json.Unmarshal(body, &req); err != nil {
|
||||||
Error: "Request format doesn't match any supported provider",
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
||||||
})
|
Message: "Invalid Atlas bet request",
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := h.atlasVirtualGameSvc.ProcessBet(c.Context(), req)
|
||||||
|
if err != nil {
|
||||||
|
// code := fiber.StatusInternalServerError
|
||||||
|
// if errors.Is(err, ErrDuplicateTransaction) {
|
||||||
|
// code = fiber.StatusConflict
|
||||||
|
// }
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
||||||
|
Message: "Atlas bet processing failed",
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return c.JSON(resp)
|
||||||
|
|
||||||
|
default:
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
||||||
|
Message: "Unsupported provider",
|
||||||
|
Error: "Request format doesn't match any supported provider",
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// identifyProvider examines the request body to determine the provider
|
// identifyProvider examines the request body to determine the provider
|
||||||
|
|
@ -653,6 +694,17 @@ func IdentifyBetProvider(body []byte) (string, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var atlasCheck struct {
|
||||||
|
CasinoID string `json:"casino_id"`
|
||||||
|
SessionID string `json:"session_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if json.Unmarshal(body, &atlasCheck) == nil {
|
||||||
|
if atlasCheck.CasinoID != "" && atlasCheck.SessionID != "" {
|
||||||
|
return "atlas", nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return "", fmt.Errorf("could not identify provider from request structure")
|
return "", fmt.Errorf("could not identify provider from request structure")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ func (a *App) initAppRoutes() {
|
||||||
a.virtualGameSvc,
|
a.virtualGameSvc,
|
||||||
a.aleaVirtualGameService,
|
a.aleaVirtualGameService,
|
||||||
a.veliVirtualGameService,
|
a.veliVirtualGameService,
|
||||||
|
a.atlasVirtualGameService,
|
||||||
a.recommendationSvc,
|
a.recommendationSvc,
|
||||||
a.userSvc,
|
a.userSvc,
|
||||||
a.transactionSvc,
|
a.transactionSvc,
|
||||||
|
|
@ -306,6 +307,17 @@ func (a *App) initAppRoutes() {
|
||||||
a.fiber.Post("/balance", h.GetBalance)
|
a.fiber.Post("/balance", h.GetBalance)
|
||||||
groupV1.Post("/veli/gaming-activity", a.authMiddleware, h.GetGamingActivity)
|
groupV1.Post("/veli/gaming-activity", a.authMiddleware, h.GetGamingActivity)
|
||||||
groupV1.Post("/veli/huge-wins", a.authMiddleware, h.GetHugeWins)
|
groupV1.Post("/veli/huge-wins", a.authMiddleware, h.GetHugeWins)
|
||||||
|
groupV1.Post("/veli/credit-balances", a.authMiddleware, h.GetCreditBalances)
|
||||||
|
|
||||||
|
//Atlas Virtual Game Routes
|
||||||
|
groupV1.Post("/atlas/init-game", a.authMiddleware, h.InitAtlasGame)
|
||||||
|
a.fiber.Post("/account", h.AtlasGetUserDataCallback)
|
||||||
|
a.fiber.Post("/betwin", h.HandleAtlasBetWin)
|
||||||
|
a.fiber.Post("/result", h.HandleRoundResult)
|
||||||
|
a.fiber.Post("/rollback", h.HandleRollback)
|
||||||
|
a.fiber.Post("/freespin", h.FreeSpinResultCallback)
|
||||||
|
a.fiber.Post("/jackpot", h.JackpotCallback)
|
||||||
|
groupV1.Post("/atlas/freespin", a.authMiddleware, h.CreateFreeSpin)
|
||||||
|
|
||||||
//mongoDB logs
|
//mongoDB logs
|
||||||
groupV1.Get("/logs", a.authMiddleware, a.SuperAdminOnly, handlers.GetLogsHandler(context.Background()))
|
groupV1.Get("/logs", a.authMiddleware, a.SuperAdminOnly, handlers.GetLogsHandler(context.Background()))
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user