fix odd filtering
This commit is contained in:
parent
252bf04b1e
commit
8e271559ae
|
|
@ -69,7 +69,7 @@ func main() {
|
|||
userSvc := user.NewService(store, store, mockSms, mockEmail)
|
||||
|
||||
eventSvc := event.New(cfg.Bet365Token, store)
|
||||
oddsSvc := odds.New(cfg.Bet365Token, store)
|
||||
oddsSvc := odds.New(store, cfg, logger)
|
||||
resultSvc := result.NewService(store, cfg, logger)
|
||||
ticketSvc := ticket.NewService(store)
|
||||
betSvc := bet.NewService(store)
|
||||
|
|
|
|||
50
internal/domain/oddres.go
Normal file
50
internal/domain/oddres.go
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
package domain
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
type BaseNonLiveOddResponse struct {
|
||||
Success int `json:"success"`
|
||||
Results []json.RawMessage `json:"results"`
|
||||
}
|
||||
|
||||
type OddsSection struct {
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
Sp map[string]OddsMarket `json:"sp"`
|
||||
}
|
||||
|
||||
type OddsMarket struct {
|
||||
ID json.Number `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Odds []json.RawMessage `json:"odds"`
|
||||
Header string `json:"header,omitempty"`
|
||||
Handicap string `json:"handicap,omitempty"`
|
||||
Open int64 `json:"open,omitempty"`
|
||||
}
|
||||
|
||||
type FootballOddsResponse struct {
|
||||
EventID string `json:"event_id"`
|
||||
FI string `json:"FI"`
|
||||
Main OddsSection `json:"main"`
|
||||
AsianLines OddsSection `json:"asian_lines"`
|
||||
Goals OddsSection `json:"goals"`
|
||||
Half OddsSection `json:"half"`
|
||||
}
|
||||
|
||||
type BasketballOddsResponse struct {
|
||||
EventID string `json:"event_id"`
|
||||
FI string `json:"FI"`
|
||||
Main OddsSection `json:"main"`
|
||||
HalfProps OddsSection `json:"half_props"`
|
||||
QuarterProps OddsSection `json:"quarter_props"`
|
||||
TeamProps OddsSection `json:"team_props"`
|
||||
Others []OddsSection `json:"others"`
|
||||
}
|
||||
|
||||
type IceHockeyOddsResponse struct {
|
||||
EventID string `json:"event_id"`
|
||||
FI string `json:"FI"`
|
||||
Main OddsSection `json:"main"`
|
||||
Main2 OddsSection `json:"main_2"`
|
||||
FirstPeriod OddsSection `json:"1st_period"`
|
||||
Others []OddsSection `json:"others"`
|
||||
}
|
||||
|
|
@ -1,185 +1,9 @@
|
|||
package domain
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
)
|
||||
|
||||
type BaseResultResponse struct {
|
||||
Success int `json:"success"`
|
||||
Results []json.RawMessage `json:"results"`
|
||||
}
|
||||
type FootballResultResponse struct {
|
||||
ID string `json:"id"`
|
||||
SportID string `json:"sport_id"`
|
||||
Time string `json:"time"`
|
||||
TimeStatus string `json:"time_status"`
|
||||
League struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
CC string `json:"cc"`
|
||||
} `json:"league"`
|
||||
Home struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
ImageID string `json:"image_id"`
|
||||
CC string `json:"cc"`
|
||||
} `json:"home"`
|
||||
Away struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
ImageID string `json:"image_id"`
|
||||
CC string `json:"cc"`
|
||||
} `json:"away"`
|
||||
SS string `json:"ss"`
|
||||
Scores struct {
|
||||
FirstHalf Score `json:"1"`
|
||||
SecondHalf Score `json:"2"`
|
||||
} `json:"scores"`
|
||||
Stats struct {
|
||||
Attacks []string `json:"attacks"`
|
||||
Corners []string `json:"corners"`
|
||||
DangerousAttacks []string `json:"dangerous_attacks"`
|
||||
Goals []string `json:"goals"`
|
||||
OffTarget []string `json:"off_target"`
|
||||
OnTarget []string `json:"on_target"`
|
||||
Penalties []string `json:"penalties"`
|
||||
PossessionRT []string `json:"possession_rt"`
|
||||
RedCards []string `json:"redcards"`
|
||||
Substitutions []string `json:"substitutions"`
|
||||
YellowCards []string `json:"yellowcards"`
|
||||
} `json:"stats"`
|
||||
Extra struct {
|
||||
HomePos string `json:"home_pos"`
|
||||
AwayPos string `json:"away_pos"`
|
||||
StadiumData map[string]string `json:"stadium_data"`
|
||||
Round string `json:"round"`
|
||||
} `json:"extra"`
|
||||
Events []map[string]string `json:"events"`
|
||||
HasLineup int `json:"has_lineup"`
|
||||
ConfirmedAt string `json:"confirmed_at"`
|
||||
Bet365ID string `json:"bet365_id"`
|
||||
}
|
||||
|
||||
type BasketballResultResponse struct {
|
||||
ID string `json:"id"`
|
||||
SportID string `json:"sport_id"`
|
||||
Time string `json:"time"`
|
||||
TimeStatus string `json:"time_status"`
|
||||
League struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
CC string `json:"cc"`
|
||||
} `json:"league"`
|
||||
Home struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
ImageID string `json:"image_id"`
|
||||
CC string `json:"cc"`
|
||||
} `json:"home"`
|
||||
Away struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
ImageID string `json:"image_id"`
|
||||
CC string `json:"cc"`
|
||||
} `json:"away"`
|
||||
SS string `json:"ss"`
|
||||
Scores struct {
|
||||
FirstQuarter Score `json:"1"`
|
||||
SecondQuarter Score `json:"2"`
|
||||
FirstHalf Score `json:"3"`
|
||||
ThirdQuarter Score `json:"4"`
|
||||
FourthQuarter Score `json:"5"`
|
||||
TotalScore Score `json:"7"`
|
||||
} `json:"scores"`
|
||||
Stats struct {
|
||||
TwoPoints []string `json:"2points"`
|
||||
ThreePoints []string `json:"3points"`
|
||||
BiggestLead []string `json:"biggest_lead"`
|
||||
Fouls []string `json:"fouls"`
|
||||
FreeThrows []string `json:"free_throws"`
|
||||
FreeThrowRate []string `json:"free_throws_rate"`
|
||||
LeadChanges []string `json:"lead_changes"`
|
||||
MaxpointsInarow []string `json:"maxpoints_inarow"`
|
||||
Possession []string `json:"possession"`
|
||||
SuccessAttempts []string `json:"success_attempts"`
|
||||
TimeSpendInLead []string `json:"timespent_inlead"`
|
||||
Timeuts []string `json:"time_outs"`
|
||||
} `json:"stats"`
|
||||
Extra struct {
|
||||
HomePos string `json:"home_pos"`
|
||||
AwayPos string `json:"away_pos"`
|
||||
AwayManager map[string]string `json:"away_manager"`
|
||||
HomeManager map[string]string `json:"home_manager"`
|
||||
NumberOfPeriods string `json:"numberofperiods"`
|
||||
PeriodLength string `json:"periodlength"`
|
||||
StadiumData map[string]string `json:"stadium_data"`
|
||||
Length string `json:"length"`
|
||||
Round string `json:"round"`
|
||||
} `json:"extra"`
|
||||
Events []map[string]string `json:"events"`
|
||||
HasLineup int `json:"has_lineup"`
|
||||
ConfirmedAt string `json:"confirmed_at"`
|
||||
Bet365ID string `json:"bet365_id"`
|
||||
}
|
||||
type IceHockeyResultResponse struct {
|
||||
ID string `json:"id"`
|
||||
SportID string `json:"sport_id"`
|
||||
Time string `json:"time"`
|
||||
TimeStatus string `json:"time_status"`
|
||||
League struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
CC string `json:"cc"`
|
||||
} `json:"league"`
|
||||
Home struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
ImageID string `json:"image_id"`
|
||||
CC string `json:"cc"`
|
||||
} `json:"home"`
|
||||
Away struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
ImageID string `json:"image_id"`
|
||||
CC string `json:"cc"`
|
||||
} `json:"away"`
|
||||
SS string `json:"ss"`
|
||||
Scores struct {
|
||||
FirstPeriod Score `json:"1"`
|
||||
SecondPeriod Score `json:"2"`
|
||||
ThirdPeriod Score `json:"3"`
|
||||
TotalScore Score `json:"5"`
|
||||
} `json:"scores"`
|
||||
|
||||
Stats struct {
|
||||
Shots []string `json:"shots"`
|
||||
Penalties []string `json:"penalties"`
|
||||
GoalsOnPowerPlay []string `json:"goals_on_power_play"`
|
||||
SSeven []string `json:"s7"`
|
||||
} `json:"stats"`
|
||||
Extra struct {
|
||||
HomePos string `json:"home_pos"`
|
||||
AwayPos string `json:"away_pos"`
|
||||
AwayManager map[string]string `json:"away_manager"`
|
||||
HomeManager map[string]string `json:"home_manager"`
|
||||
NumberOfPeriods string `json:"numberofperiods"`
|
||||
PeriodLength string `json:"periodlength"`
|
||||
StadiumData map[string]string `json:"stadium_data"`
|
||||
Length string `json:"length"`
|
||||
Round string `json:"round"`
|
||||
} `json:"extra"`
|
||||
Events []map[string]string `json:"events"`
|
||||
HasLineup int `json:"has_lineup"`
|
||||
ConfirmedAt string `json:"confirmed_at"`
|
||||
Bet365ID string `json:"bet365_id"`
|
||||
}
|
||||
|
||||
type Score struct {
|
||||
Home string `json:"home"`
|
||||
Away string `json:"away"`
|
||||
}
|
||||
|
||||
type MarketConfig struct {
|
||||
Sport string
|
||||
MarketCategories map[string]bool
|
||||
|
|
|
|||
152
internal/domain/resultres.go
Normal file
152
internal/domain/resultres.go
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
package domain
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
type BaseResultResponse struct {
|
||||
Success int `json:"success"`
|
||||
Results []json.RawMessage `json:"results"`
|
||||
}
|
||||
|
||||
type League struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
CC string `json:"cc"`
|
||||
}
|
||||
|
||||
type Team struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
ImageID string `json:"image_id"`
|
||||
CC string `json:"cc"`
|
||||
}
|
||||
|
||||
type Score struct {
|
||||
Home string `json:"home"`
|
||||
Away string `json:"away"`
|
||||
}
|
||||
|
||||
type FootballResultResponse struct {
|
||||
ID string `json:"id"`
|
||||
SportID string `json:"sport_id"`
|
||||
Time string `json:"time"`
|
||||
TimeStatus string `json:"time_status"`
|
||||
League League `json:"league"`
|
||||
Home Team `json:"home"`
|
||||
Away Team `json:"away"`
|
||||
SS string `json:"ss"`
|
||||
Scores struct {
|
||||
FirstHalf Score `json:"1"`
|
||||
SecondHalf Score `json:"2"`
|
||||
} `json:"scores"`
|
||||
Stats struct {
|
||||
Attacks []string `json:"attacks"`
|
||||
Corners []string `json:"corners"`
|
||||
DangerousAttacks []string `json:"dangerous_attacks"`
|
||||
Goals []string `json:"goals"`
|
||||
OffTarget []string `json:"off_target"`
|
||||
OnTarget []string `json:"on_target"`
|
||||
Penalties []string `json:"penalties"`
|
||||
PossessionRT []string `json:"possession_rt"`
|
||||
RedCards []string `json:"redcards"`
|
||||
Substitutions []string `json:"substitutions"`
|
||||
YellowCards []string `json:"yellowcards"`
|
||||
} `json:"stats"`
|
||||
Extra struct {
|
||||
HomePos string `json:"home_pos"`
|
||||
AwayPos string `json:"away_pos"`
|
||||
StadiumData map[string]string `json:"stadium_data"`
|
||||
Round string `json:"round"`
|
||||
} `json:"extra"`
|
||||
Events []map[string]string `json:"events"`
|
||||
HasLineup int `json:"has_lineup"`
|
||||
ConfirmedAt string `json:"confirmed_at"`
|
||||
Bet365ID string `json:"bet365_id"`
|
||||
}
|
||||
|
||||
type BasketballResultResponse struct {
|
||||
ID string `json:"id"`
|
||||
SportID string `json:"sport_id"`
|
||||
Time string `json:"time"`
|
||||
TimeStatus string `json:"time_status"`
|
||||
League League `json:"league"`
|
||||
Home Team `json:"home"`
|
||||
Away Team `json:"away"`
|
||||
SS string `json:"ss"`
|
||||
Scores struct {
|
||||
FirstQuarter Score `json:"1"`
|
||||
SecondQuarter Score `json:"2"`
|
||||
FirstHalf Score `json:"3"`
|
||||
ThirdQuarter Score `json:"4"`
|
||||
FourthQuarter Score `json:"5"`
|
||||
TotalScore Score `json:"7"`
|
||||
} `json:"scores"`
|
||||
Stats struct {
|
||||
TwoPoints []string `json:"2points"`
|
||||
ThreePoints []string `json:"3points"`
|
||||
BiggestLead []string `json:"biggest_lead"`
|
||||
Fouls []string `json:"fouls"`
|
||||
FreeThrows []string `json:"free_throws"`
|
||||
FreeThrowRate []string `json:"free_throws_rate"`
|
||||
LeadChanges []string `json:"lead_changes"`
|
||||
MaxpointsInarow []string `json:"maxpoints_inarow"`
|
||||
Possession []string `json:"possession"`
|
||||
SuccessAttempts []string `json:"success_attempts"`
|
||||
TimeSpendInLead []string `json:"timespent_inlead"`
|
||||
Timeuts []string `json:"time_outs"`
|
||||
} `json:"stats"`
|
||||
Extra struct {
|
||||
HomePos string `json:"home_pos"`
|
||||
AwayPos string `json:"away_pos"`
|
||||
AwayManager map[string]string `json:"away_manager"`
|
||||
HomeManager map[string]string `json:"home_manager"`
|
||||
NumberOfPeriods string `json:"numberofperiods"`
|
||||
PeriodLength string `json:"periodlength"`
|
||||
StadiumData map[string]string `json:"stadium_data"`
|
||||
Length string `json:"length"`
|
||||
Round string `json:"round"`
|
||||
} `json:"extra"`
|
||||
Events []map[string]string `json:"events"`
|
||||
HasLineup int `json:"has_lineup"`
|
||||
ConfirmedAt string `json:"confirmed_at"`
|
||||
Bet365ID string `json:"bet365_id"`
|
||||
}
|
||||
type IceHockeyResultResponse struct {
|
||||
ID string `json:"id"`
|
||||
SportID string `json:"sport_id"`
|
||||
Time string `json:"time"`
|
||||
TimeStatus string `json:"time_status"`
|
||||
League League `json:"league"`
|
||||
Home Team `json:"home"`
|
||||
Away Team `json:"away"`
|
||||
SS string `json:"ss"`
|
||||
Scores struct {
|
||||
FirstPeriod Score `json:"1"`
|
||||
SecondPeriod Score `json:"2"`
|
||||
ThirdPeriod Score `json:"3"`
|
||||
TotalScore Score `json:"5"`
|
||||
} `json:"scores"`
|
||||
|
||||
Stats struct {
|
||||
Shots []string `json:"shots"`
|
||||
Penalties []string `json:"penalties"`
|
||||
GoalsOnPowerPlay []string `json:"goals_on_power_play"`
|
||||
SSeven []string `json:"s7"`
|
||||
} `json:"stats"`
|
||||
Extra struct {
|
||||
HomePos string `json:"home_pos"`
|
||||
AwayPos string `json:"away_pos"`
|
||||
AwayManager map[string]string `json:"away_manager"`
|
||||
HomeManager map[string]string `json:"home_manager"`
|
||||
NumberOfPeriods string `json:"numberofperiods"`
|
||||
PeriodLength string `json:"periodlength"`
|
||||
StadiumData map[string]string `json:"stadium_data"`
|
||||
Length string `json:"length"`
|
||||
Round string `json:"round"`
|
||||
} `json:"extra"`
|
||||
Events []map[string]string `json:"events"`
|
||||
HasLineup int `json:"has_lineup"`
|
||||
ConfirmedAt string `json:"confirmed_at"`
|
||||
Bet365ID string `json:"bet365_id"`
|
||||
}
|
||||
|
|
@ -3,26 +3,37 @@ package odds
|
|||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/config"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/repository"
|
||||
)
|
||||
|
||||
type ServiceImpl struct {
|
||||
token string
|
||||
store *repository.Store
|
||||
store *repository.Store
|
||||
config *config.Config
|
||||
logger *slog.Logger
|
||||
client *http.Client
|
||||
}
|
||||
|
||||
func New(token string, store *repository.Store) *ServiceImpl {
|
||||
return &ServiceImpl{token: token, store: store}
|
||||
func New(store *repository.Store, cfg *config.Config, logger *slog.Logger) *ServiceImpl {
|
||||
return &ServiceImpl{
|
||||
store: store,
|
||||
config: cfg,
|
||||
logger: logger,
|
||||
client: &http.Client{Timeout: 10 * time.Second},
|
||||
}
|
||||
}
|
||||
|
||||
// TODO this is only getting the main odds, this must be fixed
|
||||
// TODO Add the optimization to get 10 events at the same time
|
||||
func (s *ServiceImpl) FetchNonLiveOdds(ctx context.Context) error {
|
||||
eventIDs, err := s.store.GetAllUpcomingEvents(ctx)
|
||||
if err != nil {
|
||||
|
|
@ -30,60 +41,208 @@ func (s *ServiceImpl) FetchNonLiveOdds(ctx context.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
var errs []error
|
||||
|
||||
for _, event := range eventIDs {
|
||||
// time.Sleep(3 * time.Second) //This will restrict the fetching to 1200 requests per hour
|
||||
|
||||
eventID := event.ID
|
||||
prematchURL := "https://api.b365api.com/v3/bet365/prematch?token=" + s.token + "&FI=" + eventID
|
||||
log.Printf("📡 Fetching prematch odds for event ID: %s", eventID)
|
||||
resp, err := http.Get(prematchURL)
|
||||
eventID, err := strconv.ParseInt(event.ID, 10, 64)
|
||||
if err != nil {
|
||||
log.Printf("❌ Failed to fetch prematch odds for event %s: %v", eventID, err)
|
||||
s.logger.Error("Failed to parse event id")
|
||||
return err
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("https://api.b365api.com/v3/bet365/prematch?token=%s&FI=%d", s.config.Bet365Token, eventID)
|
||||
|
||||
log.Printf("📡 Fetching prematch odds for event ID: %d", eventID)
|
||||
|
||||
resp, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
log.Printf("❌ Failed to fetch prematch odds for event %d: %v", eventID, err)
|
||||
continue
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
var oddsData struct {
|
||||
Success int `json:"success"`
|
||||
Results []struct {
|
||||
EventID string `json:"event_id"`
|
||||
FI string `json:"FI"`
|
||||
Main OddsSection `json:"main"`
|
||||
} `json:"results"`
|
||||
}
|
||||
var oddsData domain.BaseNonLiveOddResponse
|
||||
|
||||
if err := json.Unmarshal(body, &oddsData); err != nil || oddsData.Success != 1 || len(oddsData.Results) == 0 {
|
||||
log.Printf("❌ Invalid prematch data for event %s", eventID)
|
||||
log.Printf("❌ Invalid prematch data for event %d", eventID)
|
||||
continue
|
||||
}
|
||||
|
||||
result := oddsData.Results[0]
|
||||
finalID := result.EventID
|
||||
if finalID == "" {
|
||||
finalID = result.FI
|
||||
sportID, err := strconv.ParseInt(event.SportID, 10, 64)
|
||||
|
||||
switch sportID {
|
||||
case domain.FOOTBALL:
|
||||
if err := s.parseFootball(ctx, oddsData.Results[0]); err != nil {
|
||||
s.logger.Error("Failed to insert football odd")
|
||||
errs = append(errs, err)
|
||||
}
|
||||
case domain.BASKETBALL:
|
||||
if err := s.parseBasketball(ctx, oddsData.Results[0]); err != nil {
|
||||
s.logger.Error("Failed to insert basketball odd")
|
||||
errs = append(errs, err)
|
||||
}
|
||||
case domain.ICE_HOCKEY:
|
||||
if err := s.parseIceHockey(ctx, oddsData.Results[0]); err != nil {
|
||||
s.logger.Error("Failed to insert ice hockey odd")
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
}
|
||||
if finalID == "" {
|
||||
log.Printf("⚠️ Skipping event %s with no valid ID", eventID)
|
||||
continue
|
||||
}
|
||||
s.storeSection(ctx, finalID, result.FI, "main", result.Main)
|
||||
|
||||
// result := oddsData.Results[0]
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ServiceImpl) storeSection(ctx context.Context, eventID, fi, sectionName string, section OddsSection) {
|
||||
func (s *ServiceImpl) parseFootball(ctx context.Context, res json.RawMessage) error {
|
||||
var footballRes domain.FootballOddsResponse
|
||||
if err := json.Unmarshal(res, &footballRes); err != nil {
|
||||
s.logger.Error("Failed to unmarshal football result", "error", err)
|
||||
return err
|
||||
}
|
||||
if footballRes.EventID == "" && footballRes.FI == "" {
|
||||
s.logger.Error("Skipping result with no valid Event ID")
|
||||
return fmt.Errorf("Skipping result with no valid Event ID")
|
||||
}
|
||||
sections := map[string]domain.OddsSection{
|
||||
"main": footballRes.Main,
|
||||
"asian_lines": footballRes.AsianLines,
|
||||
"goals": footballRes.Goals,
|
||||
"half": footballRes.Half,
|
||||
}
|
||||
|
||||
var errs []error
|
||||
|
||||
for oddCategory, section := range sections {
|
||||
if err := s.storeSection(ctx, footballRes.EventID, footballRes.FI, oddCategory, section); err != nil {
|
||||
s.logger.Error("Skipping result with no valid Event ID")
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ServiceImpl) parseBasketball(ctx context.Context, res json.RawMessage) error {
|
||||
var basketballRes domain.BasketballOddsResponse
|
||||
if err := json.Unmarshal(res, &basketballRes); err != nil {
|
||||
s.logger.Error("Failed to unmarshal football result", "error", err)
|
||||
return err
|
||||
}
|
||||
if basketballRes.EventID == "" && basketballRes.FI == "" {
|
||||
s.logger.Error("Skipping result with no valid Event ID")
|
||||
return fmt.Errorf("Skipping result with no valid Event ID")
|
||||
}
|
||||
sections := map[string]domain.OddsSection{
|
||||
"main": basketballRes.Main,
|
||||
"half_props": basketballRes.HalfProps,
|
||||
"quarter_props": basketballRes.QuarterProps,
|
||||
"team_props": basketballRes.TeamProps,
|
||||
}
|
||||
|
||||
var errs []error
|
||||
|
||||
for oddCategory, section := range sections {
|
||||
if err := s.storeSection(ctx, basketballRes.EventID, basketballRes.FI, oddCategory, section); err != nil {
|
||||
s.logger.Error("Skipping result with no valid Event ID")
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
for _, section := range basketballRes.Others {
|
||||
if err := s.storeSection(ctx, basketballRes.EventID, basketballRes.FI, "others", section); err != nil {
|
||||
s.logger.Error("Skipping result with no valid Event ID")
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
func (s *ServiceImpl) parseIceHockey(ctx context.Context, res json.RawMessage) error {
|
||||
var iceHockeyRes domain.IceHockeyOddsResponse
|
||||
if err := json.Unmarshal(res, &iceHockeyRes); err != nil {
|
||||
s.logger.Error("Failed to unmarshal football result", "error", err)
|
||||
return err
|
||||
}
|
||||
if iceHockeyRes.EventID == "" && iceHockeyRes.FI == "" {
|
||||
s.logger.Error("Skipping result with no valid Event ID")
|
||||
return fmt.Errorf("Skipping result with no valid Event ID")
|
||||
}
|
||||
sections := map[string]domain.OddsSection{
|
||||
"main": iceHockeyRes.Main,
|
||||
"main_2": iceHockeyRes.Main2,
|
||||
"1st_period": iceHockeyRes.FirstPeriod,
|
||||
}
|
||||
|
||||
var errs []error
|
||||
|
||||
for oddCategory, section := range sections {
|
||||
if err := s.storeSection(ctx, iceHockeyRes.EventID, iceHockeyRes.FI, oddCategory, section); err != nil {
|
||||
s.logger.Error("Skipping result with no valid Event ID")
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
for _, section := range iceHockeyRes.Others {
|
||||
if err := s.storeSection(ctx, iceHockeyRes.EventID, iceHockeyRes.FI, "others", section); err != nil {
|
||||
s.logger.Error("Skipping result with no valid Event ID")
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ServiceImpl) storeSection(ctx context.Context, eventID, fi, sectionName string, section domain.OddsSection) error {
|
||||
if len(section.Sp) == 0 {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
updatedAtUnix, _ := strconv.ParseInt(section.UpdatedAt, 10, 64)
|
||||
updatedAt := time.Unix(updatedAtUnix, 0)
|
||||
|
||||
var errs []error
|
||||
for marketType, market := range section.Sp {
|
||||
if len(market.Odds) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
marketID, err := market.ID.Int64()
|
||||
if err != nil {
|
||||
s.logger.Error("Invalid market id", "marketID", marketID)
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
|
||||
isSupported, ok := domain.SupportedMarkets[marketID]
|
||||
|
||||
if !ok || !isSupported {
|
||||
s.logger.Info("Unsupported market_id", "marketID", marketID)
|
||||
continue
|
||||
}
|
||||
|
||||
marketRecord := domain.Market{
|
||||
EventID: eventID,
|
||||
FI: fi,
|
||||
|
|
@ -95,21 +254,18 @@ func (s *ServiceImpl) storeSection(ctx context.Context, eventID, fi, sectionName
|
|||
Odds: market.Odds,
|
||||
}
|
||||
|
||||
_ = s.store.SaveNonLiveMarket(ctx, marketRecord)
|
||||
err = s.store.SaveNonLiveMarket(ctx, marketRecord)
|
||||
if err != nil {
|
||||
s.logger.Error("failed to save market", "market_id", market.ID, "error", err)
|
||||
errs = append(errs, fmt.Errorf("market %s: %w", market.ID, err))
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type OddsMarket struct {
|
||||
ID json.Number `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Odds []json.RawMessage `json:"odds"`
|
||||
Header string `json:"header,omitempty"`
|
||||
Handicap string `json:"handicap,omitempty"`
|
||||
}
|
||||
|
||||
type OddsSection struct {
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
Sp map[string]OddsMarket `json:"sp"`
|
||||
if len(errs) > 0 {
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ServiceImpl) GetPrematchOdds(ctx context.Context, eventID string) ([]domain.Odd, error) {
|
||||
|
|
|
|||
|
|
@ -66,7 +66,6 @@ func (s *Service) FetchAndProcessResults(ctx context.Context) error {
|
|||
s.logger.Error("Sport ID is invalid", "event_id", outcome.EventID, "error", err)
|
||||
continue
|
||||
}
|
||||
|
||||
result, err := s.fetchResult(ctx, outcome.EventID, outcome.OddID, outcome.MarketID, sportID, outcome)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to fetch result", "event_id", outcome.EventID, "error", err)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user