diff --git a/cmd/main.go b/cmd/main.go index 07471fe..75f8265 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -114,7 +114,7 @@ func main() { authSvc := authentication.NewService(store, store, cfg.RefreshExpiry) userSvc := user.NewService(store, store, messengerSvc, cfg) - eventSvc := event.New(cfg.Bet365Token, store, *settingSvc, domain.MongoDBLogger) + eventSvc := event.New(cfg.Bet365Token, store, *settingSvc, domain.MongoDBLogger, cfg) oddsSvc := odds.New(store, cfg, eventSvc, logger, domain.MongoDBLogger) notificationRepo := repository.NewNotificationRepository(store) virtuaGamesRepo := repository.NewVirtualGameRepository(store) @@ -143,7 +143,7 @@ func main() { ticketSvc := ticket.NewService(store, eventSvc, *oddsSvc, domain.MongoDBLogger, *settingSvc, notificationSvc) betSvc := bet.NewService(store, eventSvc, *oddsSvc, *walletSvc, *branchSvc, *companySvc, *settingSvc, *userSvc, notificationSvc, logger, domain.MongoDBLogger) resultSvc := result.NewService(store, cfg, logger, domain.MongoDBLogger, *betSvc, *oddsSvc, eventSvc, leagueSvc, notificationSvc, messengerSvc, *userSvc) - bonusSvc := bonus.NewService(store, walletSvc, settingSvc, notificationSvc, domain.MongoDBLogger) + bonusSvc := bonus.NewService(store, walletSvc, settingSvc, notificationSvc, domain.MongoDBLogger) referalRepo := repository.NewReferralRepository(store) vitualGameRepo := repository.NewVirtualGameRepository(store) recommendationRepo := repository.NewRecommendationRepository(store) @@ -153,7 +153,7 @@ func main() { virtualGameSvc := virtualgameservice.New(vitualGameRepo, *walletSvc, store, cfg, logger) aleaService := alea.NewAleaPlayService(vitualGameRepo, *walletSvc, cfg, logger) veliCLient := veli.NewClient(cfg, walletSvc) - veliVirtualGameService := veli.New(virtualGameSvc, vitualGameRepo, veliCLient, walletSvc, wallet.TransferStore(store), domain.MongoDBLogger, cfg) + veliVirtualGameService := veli.New(virtualGameSvc, vitualGameRepo, veliCLient, walletSvc, wallet.TransferStore(store), domain.MongoDBLogger, cfg) atlasClient := atlas.NewClient(cfg, walletSvc) atlasVirtualGameService := atlas.New(virtualGameSvc, vitualGameRepo, atlasClient, walletSvc, wallet.TransferStore(store), cfg) recommendationSvc := recommendation.NewService(recommendationRepo) diff --git a/internal/domain/jsontypes.go b/internal/domain/jsontypes.go new file mode 100644 index 0000000..3e52375 --- /dev/null +++ b/internal/domain/jsontypes.go @@ -0,0 +1,27 @@ +package domain + +import ( + "encoding/json" + "fmt" +) + +// Custom type for fields that can be string or int +type StringOrNumber string + +func (s *StringOrNumber) UnmarshalJSON(data []byte) error { + // Try as string + var str string + if err := json.Unmarshal(data, &str); err == nil { + *s = StringOrNumber(str) + return nil + } + + // Try as number + var num json.Number + if err := json.Unmarshal(data, &num); err == nil { + *s = StringOrNumber(num.String()) + return nil + } + + return fmt.Errorf("StringOrNumber: cannot unmarshal %s", string(data)) +} diff --git a/internal/domain/oddres.go b/internal/domain/oddres.go index 266aa11..19c2cb2 100644 --- a/internal/domain/oddres.go +++ b/internal/domain/oddres.go @@ -27,7 +27,7 @@ type RawOdd struct { // The Market ID for the json data can be either string / int which is causing problems when UnMarshalling type OddsMarket struct { - ID ValidInt64 `json:"id"` + ID StringOrNumber `json:"id"` Name string `json:"name"` Odds []json.RawMessage `json:"odds"` Header string `json:"header,omitempty"` diff --git a/internal/domain/validtypes.go b/internal/domain/validtypes.go index c20f6c3..99ad794 100644 --- a/internal/domain/validtypes.go +++ b/internal/domain/validtypes.go @@ -31,6 +31,7 @@ func (n *ValidInt64) UnmarshalJSON(data []byte) error { } v, err := strconv.ParseInt(s, 10, 64) if err != nil { + fmt.Printf("Failed to parse the value of %v \n\n", s) return err } n.Value, n.Valid = v, true @@ -42,7 +43,7 @@ func (n *ValidInt64) UnmarshalJSON(data []byte) error { n.Value, n.Valid = v, true return nil } - + fmt.Printf("Failed to parse the value of %v", s) return fmt.Errorf("invalid int64 value: %s", string(data)) } diff --git a/internal/services/event/service.go b/internal/services/event/service.go index 798a925..13f9897 100644 --- a/internal/services/event/service.go +++ b/internal/services/event/service.go @@ -12,6 +12,7 @@ import ( "sync" "time" + "github.com/SamuelTariku/FortuneBet-Backend/internal/config" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/repository" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/settings" @@ -25,14 +26,16 @@ type service struct { store *repository.Store settingSvc settings.Service mongoLogger *zap.Logger + cfg *config.Config } -func New(token string, store *repository.Store, settingSvc settings.Service, mongoLogger *zap.Logger) Service { +func New(token string, store *repository.Store, settingSvc settings.Service, mongoLogger *zap.Logger, cfg *config.Config) Service { return &service{ token: token, store: store, settingSvc: settingSvc, mongoLogger: mongoLogger, + cfg: cfg, } } @@ -217,10 +220,18 @@ func (s *service) fetchUpcomingEventsFromProvider(ctx context.Context, source_ur s.mongoLogger.Error("Failed to fetch event data for page", zap.Error(err)) return } - const pageLimit int = 200 - sportIDs := []int{1, 18, 17, 3, 83, 15, 12, 19, 8, 16, 91} - // const pageLimit int = 1 - // sportIDs := []int{1} + + var pageLimit int + var sportIDs []int + + // Restricting the page to 1 on development, which drastically reduces the amount of events that is fetched + if s.cfg.Env == "development" { + pageLimit = 1 + sportIDs = []int{1} + } else { + pageLimit = 200 + sportIDs = []int{1, 18, 17, 3, 83, 15, 12, 19, 8, 16, 91} + } var skippedLeague []string var totalEvents = 0 diff --git a/internal/services/odds/service.go b/internal/services/odds/service.go index dff3fdd..b52bf0e 100644 --- a/internal/services/odds/service.go +++ b/internal/services/odds/service.go @@ -88,67 +88,49 @@ func (s *ServiceImpl) fetchBet365Odds(ctx context.Context) error { return err } - var errs []error - for index, event := range eventIDs { - log.Printf("📡 Fetching prematch odds for event ID: %v (%d/%d) ", event.ID, index, len(eventIDs)) + if s.config.Env == "development" { + log.Printf("📡 Fetching prematch odds for event ID: %v (%d/%d) ", event.ID, index, len(eventIDs)) + } + eventLogger := s.mongoLogger.With( + zap.String("eventID", event.ID), + zap.Int32("sportID", event.SportID), + ) oddsData, err := s.FetchNonLiveOddsByEventID(ctx, event.ID) if err != nil || oddsData.Success != 1 { - s.mongoLogger.Error( - "Failed to fetch prematch odds", - zap.String("eventID", event.ID), - zap.Error(err), - ) - errs = append(errs, fmt.Errorf("failed to fetch prematch odds for event %v: %w", event.ID, err)) + eventLogger.Error("Failed to fetch prematch odds", zap.Error(err)) continue } parsedOddSections, err := s.ParseOddSections(ctx, oddsData.Results[0], event.SportID) if err != nil { - s.mongoLogger.Error( - "Failed to parse odd section", - zap.String("eventID", event.ID), - zap.Int32("sportID", event.SportID), - zap.Error(err), - ) - errs = append(errs, fmt.Errorf("failed to parse odd section for event %v: %w", event.ID, err)) + eventLogger.Error("Failed to parse odd section", zap.Error(err)) continue } + parsedOddLogger := eventLogger.With( + zap.String("parsedOddSectionFI", parsedOddSections.EventFI), + zap.Int("main_sections_count", len(parsedOddSections.Sections)), + zap.Int("other_sections_count", len(parsedOddSections.OtherRes)), + ) + if parsedOddSections.EventFI == "" { - s.mongoLogger.Error( - "Skipping result with no valid Event FI field", - zap.String("FI", parsedOddSections.EventFI), - zap.String("eventID", event.ID), - zap.Int32("sportID", event.SportID), - zap.Error(err), - ) - errs = append(errs, errors.New("event FI is empty")) + parsedOddLogger.Error("Skipping result with no valid Event FI field", zap.Error(err)) continue } + if len(parsedOddSections.Sections) == 0 { + parsedOddLogger.Warn("Event has no odds in main sections", zap.Error(err)) + } for oddCategory, section := range parsedOddSections.Sections { if err := s.storeSection(ctx, event.ID, parsedOddSections.EventFI, oddCategory, section); err != nil { - s.mongoLogger.Error( - "Error storing odd section", - zap.String("eventID", event.ID), - zap.String("odd", oddCategory), - zap.Int32("sportID", event.SportID), - zap.Error(err), - ) - errs = append(errs, err) + parsedOddLogger.Error("Error storing odd section", zap.String("odd", oddCategory), zap.Error(err)) } } for _, section := range parsedOddSections.OtherRes { if err := s.storeSection(ctx, event.ID, parsedOddSections.EventFI, "others", section); err != nil { - s.mongoLogger.Error( - "Error storing odd other section", - zap.String("eventID", event.ID), - zap.Int32("sportID", event.SportID), - zap.Error(err), - ) - errs = append(errs, err) + parsedOddLogger.Error("Error storing odd other section", zap.Error(err)) continue } } @@ -157,10 +139,6 @@ func (s *ServiceImpl) fetchBet365Odds(ctx context.Context) error { } - for err := range errs { - log.Printf("❌ Error: %v", err) - } - return nil } @@ -345,6 +323,7 @@ func (s *ServiceImpl) ParseOddSections(ctx context.Context, res json.RawMessage, if err := json.Unmarshal(res, &footballRes); err != nil { s.mongoLogger.Error( "Failed to unmarshal football result", + zap.Error(err), ) return domain.ParseOddSectionsRes{}, err @@ -534,6 +513,10 @@ func (s *ServiceImpl) ParseOddSections(ctx context.Context, res json.RawMessage, func (s *ServiceImpl) storeSection(ctx context.Context, eventID, fi, sectionName string, section domain.OddsSection) error { if len(section.Sp) == 0 { + s.mongoLogger.Warn("Event Section is empty", + zap.String("eventID", eventID), + zap.String("sectionName", sectionName), + ) return nil } @@ -542,41 +525,36 @@ func (s *ServiceImpl) storeSection(ctx context.Context, eventID, fi, sectionName var errs []error for marketType, market := range section.Sp { + marketLogger := s.mongoLogger.With( + zap.String("eventID", eventID), + zap.String("sectionName", sectionName), + zap.String("market_id", string(market.ID)), + zap.String("marketType", marketType), + zap.String("marketName", market.Name), + ) if len(market.Odds) == 0 { + // marketLogger.Warn("Skipping market with no odds") continue } - // Check if the market id is a string - marketIDint := market.ID.Value - // if err != nil { - // s.mongoLogger.Error( - // "Invalid market id", - // zap.Int64("market_id", marketIDint), - // zap.String("market_name", market.Name), - // zap.String("eventID", eventID), - // zap.Error(err), - // ) - // continue - // } + marketIDint, err := strconv.ParseInt(string(market.ID), 10, 64) + if err != nil { + marketLogger.Warn("skipping market section where market_id is not int") + continue + } marketIDstr := strconv.FormatInt(marketIDint, 10) isSupported, ok := domain.SupportedMarkets[marketIDint] if !ok || !isSupported { - // s.logger.Info("Unsupported market_id", "marketID", marketIDint, "marketName", market.Name) + // marketLogger.Warn("skipping market that isn't supported", zap.Bool("is_market_found", ok)) continue } marketOdds, err := convertRawMessage(market.Odds) if err != nil { - s.mongoLogger.Error( - "failed to convert market.Odds to json.RawMessage to []map[string]interface{}", - zap.String("market_id", marketIDstr), - zap.String("market_name", market.Name), - zap.String("eventID", eventID), - zap.Error(err), - ) + marketLogger.Error("failed to convert market.Odds to json.RawMessage to []map[string]interface{}", zap.Error(err)) errs = append(errs, err) continue } @@ -593,25 +571,13 @@ func (s *ServiceImpl) storeSection(ctx context.Context, eventID, fi, sectionName } if err := s.CheckAndInsertOddHistory(ctx, marketRecord); err != nil { - s.mongoLogger.Error( - "failed to check and insert odd history", - zap.String("market_id", marketIDstr), - zap.String("market_name", market.Name), - zap.String("eventID", eventID), - zap.Error(err), - ) + marketLogger.Error("failed to check and insert odd history", zap.Error(err)) continue } err = s.store.SaveOddMarket(ctx, marketRecord) if err != nil { - s.mongoLogger.Error( - "failed to save market", - zap.String("market_id", marketIDstr), - zap.String("market_name", market.Name), - zap.String("eventID", eventID), - zap.Error(err), - ) + marketLogger.Error("failed to save market", zap.Error(err)) errs = append(errs, fmt.Errorf("market %v: %w", market.ID, err)) continue } diff --git a/internal/services/result/service.go b/internal/services/result/service.go index 4ae5bf3..cb19963 100644 --- a/internal/services/result/service.go +++ b/internal/services/result/service.go @@ -1007,17 +1007,17 @@ func (s *Service) GetResultsForEvent(ctx context.Context, eventID string) (json. outcomes := make([]domain.BetOutcome, 0) for _, section := range parsedOddSections.Sections { for _, market := range section.Sp { - marketIDint := market.ID.Value - // if err != nil { - // s.mongoLogger.Error( - // "Invalid market id", - // zap.Int64("market_id", marketIDint), - // zap.String("market_name", market.Name), - // zap.String("eventID", eventID), - // zap.Error(err), - // ) - // continue - // } + marketIDint, err := strconv.ParseInt(string(market.ID), 10, 64) + if err != nil { + s.mongoLogger.Warn( + "Invalid market id", + zap.Int64("market_id", marketIDint), + zap.String("market_name", market.Name), + zap.String("eventID", eventID), + zap.Error(err), + ) + continue + } isSupported, ok := domain.SupportedMarkets[marketIDint]