166 lines
4.7 KiB
Go
166 lines
4.7 KiB
Go
package odds
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/repository"
|
|
)
|
|
|
|
type ServiceImpl struct {
|
|
token string
|
|
store *repository.Store
|
|
}
|
|
|
|
func New(token string, store *repository.Store) *ServiceImpl {
|
|
return &ServiceImpl{token: token, store: store}
|
|
}
|
|
|
|
func (s *ServiceImpl) FetchNonLiveOdds(ctx context.Context) error {
|
|
fmt.Println("Starting FetchNonLiveOdds...")
|
|
|
|
sportID := 1
|
|
upcomingURL := fmt.Sprintf("https://api.b365api.com/v1/bet365/upcoming?sport_id=%d&token=%s", sportID, s.token)
|
|
resp, err := http.Get(upcomingURL)
|
|
if err != nil {
|
|
fmt.Printf("Failed to fetch upcoming: %v\n", err)
|
|
return err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
body, _ := io.ReadAll(resp.Body)
|
|
var upcomingData struct {
|
|
Success int `json:"success"`
|
|
Results []struct {
|
|
ID string `json:"id"`
|
|
} `json:"results"`
|
|
}
|
|
if err := json.Unmarshal(body, &upcomingData); err != nil || upcomingData.Success != 1 {
|
|
fmt.Printf("Failed to decode upcoming response\nRaw: %s\n", string(body))
|
|
return err
|
|
}
|
|
|
|
for _, ev := range upcomingData.Results {
|
|
eventID := ev.ID
|
|
fmt.Printf("Fetching prematch odds for event_id=%s\n", eventID)
|
|
prematchURL := fmt.Sprintf("https://api.b365api.com/v3/bet365/prematch?token=%s&FI=%s", s.token, eventID)
|
|
oddsResp, err := http.Get(prematchURL)
|
|
if err != nil {
|
|
fmt.Printf(" Odds fetch failed for event_id=%s: %v\n", eventID, err)
|
|
continue
|
|
}
|
|
defer oddsResp.Body.Close()
|
|
|
|
oddsBody, _ := io.ReadAll(oddsResp.Body)
|
|
fmt.Printf(" Raw odds response for event_id=%s: %.300s...\n", eventID, string(oddsBody))
|
|
|
|
var oddsData struct {
|
|
Success int `json:"success"`
|
|
Results []struct {
|
|
EventID string `json:"event_id"`
|
|
FI string `json:"FI"`
|
|
Main OddsSection `json:"main"`
|
|
} `json:"results"`
|
|
}
|
|
if err := json.Unmarshal(oddsBody, &oddsData); err != nil || oddsData.Success != 1 || len(oddsData.Results) == 0 {
|
|
fmt.Printf(" Failed odds decode for event_id=%s\nRaw: %s\n", eventID, string(oddsBody))
|
|
continue
|
|
}
|
|
|
|
result := oddsData.Results[0]
|
|
finalID := result.EventID
|
|
if finalID == "" {
|
|
finalID = result.FI
|
|
}
|
|
if finalID == "" {
|
|
fmt.Println(" Skipping event with missing final ID.")
|
|
continue
|
|
}
|
|
|
|
fmt.Printf("🗂 Saving prematch odds for event_id=%s\n", finalID)
|
|
s.storeSection(ctx, finalID, result.FI, "main", result.Main)
|
|
fmt.Printf(" Finished storing prematch odds for event_id=%s\n", finalID)
|
|
}
|
|
|
|
fmt.Println(" All prematch odds fetched and stored.")
|
|
return nil
|
|
}
|
|
|
|
func (s *ServiceImpl) storeSection(ctx context.Context, eventID, fi, sectionName string, section OddsSection) {
|
|
fmt.Printf(" Processing section '%s' for event_id=%s\n", sectionName, eventID)
|
|
if len(section.Sp) == 0 {
|
|
fmt.Printf(" No odds in section '%s' for event_id=%s\n", sectionName, eventID)
|
|
return
|
|
}
|
|
|
|
updatedAtUnix, _ := strconv.ParseInt(section.UpdatedAt, 10, 64)
|
|
updatedAt := time.Unix(updatedAtUnix, 0)
|
|
|
|
for marketType, market := range section.Sp {
|
|
fmt.Printf(" Processing market: %s (%s)\n", marketType, market.ID)
|
|
if len(market.Odds) == 0 {
|
|
fmt.Printf(" Empty odds for marketType=%s in section=%s\n", marketType, sectionName)
|
|
continue
|
|
}
|
|
|
|
marketRecord := domain.Market{
|
|
EventID: eventID,
|
|
FI: fi,
|
|
MarketCategory: sectionName,
|
|
MarketType: marketType,
|
|
MarketName: market.Name,
|
|
MarketID: market.ID,
|
|
UpdatedAt: updatedAt,
|
|
Odds: market.Odds,
|
|
}
|
|
|
|
fmt.Printf(" Saving market to DB: %s (%s)\n", marketType, market.ID)
|
|
err := s.store.SaveNonLiveMarket(ctx, marketRecord)
|
|
if err != nil {
|
|
fmt.Printf(" Save failed for market %s (%s): %v\n", marketType, eventID, err)
|
|
} else {
|
|
fmt.Printf(" Successfully stored market: %s (%s)\n", marketType, eventID)
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
type OddsMarket struct {
|
|
ID string `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"`
|
|
}
|
|
|
|
func getString(v interface{}) string {
|
|
if str, ok := v.(string); ok {
|
|
return str
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func (s *ServiceImpl) GetPrematchOdds(ctx context.Context, eventID string) ([]domain.Odd, error) {
|
|
fmt.Printf("Retrieving prematch odds for event_id=%s\n", eventID)
|
|
|
|
odds, err := s.store.GetPrematchOdds(ctx, eventID)
|
|
if err != nil {
|
|
fmt.Printf(" Failed to retrieve odds for event_id=%s: %v\n", eventID, err)
|
|
return nil, err
|
|
}
|
|
|
|
fmt.Printf(" Retrieved %d odds entries for event_id=%s\n", len(odds), eventID)
|
|
return odds, nil
|
|
}
|