adding upcoming
This commit is contained in:
parent
ed0d107f1a
commit
1726cfd63b
|
|
@ -33,6 +33,35 @@ ON CONFLICT (id) DO UPDATE SET
|
||||||
is_live = EXCLUDED.is_live,
|
is_live = EXCLUDED.is_live,
|
||||||
status = EXCLUDED.status,
|
status = EXCLUDED.status,
|
||||||
fetched_at = now();
|
fetched_at = now();
|
||||||
|
-- name: InsertUpcomingEvent :exec
|
||||||
|
INSERT INTO events (
|
||||||
|
id, sport_id, match_name, home_team, away_team,
|
||||||
|
home_team_id, away_team_id, home_kit_image, away_kit_image,
|
||||||
|
league_id, league_name, league_cc, start_time,
|
||||||
|
is_live, status
|
||||||
|
) VALUES (
|
||||||
|
$1, $2, $3, $4, $5,
|
||||||
|
$6, $7, $8, $9,
|
||||||
|
$10, $11, $12, $13,
|
||||||
|
false, 'upcoming'
|
||||||
|
)
|
||||||
|
ON CONFLICT (id) DO UPDATE SET
|
||||||
|
sport_id = EXCLUDED.sport_id,
|
||||||
|
match_name = EXCLUDED.match_name,
|
||||||
|
home_team = EXCLUDED.home_team,
|
||||||
|
away_team = EXCLUDED.away_team,
|
||||||
|
home_team_id = EXCLUDED.home_team_id,
|
||||||
|
away_team_id = EXCLUDED.away_team_id,
|
||||||
|
home_kit_image = EXCLUDED.home_kit_image,
|
||||||
|
away_kit_image = EXCLUDED.away_kit_image,
|
||||||
|
league_id = EXCLUDED.league_id,
|
||||||
|
league_name = EXCLUDED.league_name,
|
||||||
|
league_cc = EXCLUDED.league_cc,
|
||||||
|
start_time = EXCLUDED.start_time,
|
||||||
|
is_live = false,
|
||||||
|
status = 'upcoming',
|
||||||
|
fetched_at = now();
|
||||||
|
|
||||||
|
|
||||||
-- name: ListLiveEvents :many
|
-- name: ListLiveEvents :many
|
||||||
SELECT id FROM events WHERE is_live = true;
|
SELECT id FROM events WHERE is_live = true;
|
||||||
|
|
@ -97,6 +97,71 @@ func (q *Queries) InsertEvent(ctx context.Context, arg InsertEventParams) error
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const InsertUpcomingEvent = `-- name: InsertUpcomingEvent :exec
|
||||||
|
INSERT INTO events (
|
||||||
|
id, sport_id, match_name, home_team, away_team,
|
||||||
|
home_team_id, away_team_id, home_kit_image, away_kit_image,
|
||||||
|
league_id, league_name, league_cc, start_time,
|
||||||
|
is_live, status
|
||||||
|
) VALUES (
|
||||||
|
$1, $2, $3, $4, $5,
|
||||||
|
$6, $7, $8, $9,
|
||||||
|
$10, $11, $12, $13,
|
||||||
|
false, 'upcoming'
|
||||||
|
)
|
||||||
|
ON CONFLICT (id) DO UPDATE SET
|
||||||
|
sport_id = EXCLUDED.sport_id,
|
||||||
|
match_name = EXCLUDED.match_name,
|
||||||
|
home_team = EXCLUDED.home_team,
|
||||||
|
away_team = EXCLUDED.away_team,
|
||||||
|
home_team_id = EXCLUDED.home_team_id,
|
||||||
|
away_team_id = EXCLUDED.away_team_id,
|
||||||
|
home_kit_image = EXCLUDED.home_kit_image,
|
||||||
|
away_kit_image = EXCLUDED.away_kit_image,
|
||||||
|
league_id = EXCLUDED.league_id,
|
||||||
|
league_name = EXCLUDED.league_name,
|
||||||
|
league_cc = EXCLUDED.league_cc,
|
||||||
|
start_time = EXCLUDED.start_time,
|
||||||
|
is_live = false,
|
||||||
|
status = 'upcoming',
|
||||||
|
fetched_at = now()
|
||||||
|
`
|
||||||
|
|
||||||
|
type InsertUpcomingEventParams struct {
|
||||||
|
ID string
|
||||||
|
SportID pgtype.Text
|
||||||
|
MatchName pgtype.Text
|
||||||
|
HomeTeam pgtype.Text
|
||||||
|
AwayTeam pgtype.Text
|
||||||
|
HomeTeamID pgtype.Text
|
||||||
|
AwayTeamID pgtype.Text
|
||||||
|
HomeKitImage pgtype.Text
|
||||||
|
AwayKitImage pgtype.Text
|
||||||
|
LeagueID pgtype.Text
|
||||||
|
LeagueName pgtype.Text
|
||||||
|
LeagueCc pgtype.Text
|
||||||
|
StartTime pgtype.Timestamp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) InsertUpcomingEvent(ctx context.Context, arg InsertUpcomingEventParams) error {
|
||||||
|
_, err := q.db.Exec(ctx, InsertUpcomingEvent,
|
||||||
|
arg.ID,
|
||||||
|
arg.SportID,
|
||||||
|
arg.MatchName,
|
||||||
|
arg.HomeTeam,
|
||||||
|
arg.AwayTeam,
|
||||||
|
arg.HomeTeamID,
|
||||||
|
arg.AwayTeamID,
|
||||||
|
arg.HomeKitImage,
|
||||||
|
arg.AwayKitImage,
|
||||||
|
arg.LeagueID,
|
||||||
|
arg.LeagueName,
|
||||||
|
arg.LeagueCc,
|
||||||
|
arg.StartTime,
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
const ListLiveEvents = `-- name: ListLiveEvents :many
|
const ListLiveEvents = `-- name: ListLiveEvents :many
|
||||||
SELECT id FROM events WHERE is_live = true
|
SELECT id FROM events WHERE is_live = true
|
||||||
`
|
`
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
package domain
|
package domain
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
type Event struct {
|
type Event struct {
|
||||||
ID string
|
ID string
|
||||||
SportID string
|
SportID string
|
||||||
|
|
@ -21,3 +24,18 @@ type Event struct {
|
||||||
IsLive bool
|
IsLive bool
|
||||||
Status string
|
Status string
|
||||||
}
|
}
|
||||||
|
type UpcomingEvent struct {
|
||||||
|
ID string // Event ID
|
||||||
|
SportID string // Sport ID
|
||||||
|
MatchName string // Match or event name
|
||||||
|
HomeTeam string // Home team name (if available)
|
||||||
|
AwayTeam string // Away team name (can be empty/null)
|
||||||
|
HomeTeamID string // Home team ID
|
||||||
|
AwayTeamID string // Away team ID (can be empty/null)
|
||||||
|
HomeKitImage string // Kit or image for home team (optional)
|
||||||
|
AwayKitImage string // Kit or image for away team (optional)
|
||||||
|
LeagueID string // League ID
|
||||||
|
LeagueName string // League name
|
||||||
|
LeagueCC string // League country code
|
||||||
|
StartTime time.Time // Converted from "time" field in UNIX format
|
||||||
|
}
|
||||||
|
|
@ -38,6 +38,23 @@ func (s *Store) SaveEvent(ctx context.Context, e domain.Event) error {
|
||||||
Status: pgtype.Text{String: e.Status, Valid: true},
|
Status: pgtype.Text{String: e.Status, Valid: true},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
func (s *Store) SaveUpcomingEvent(ctx context.Context, e domain.UpcomingEvent) error {
|
||||||
|
return s.queries.InsertUpcomingEvent(ctx, dbgen.InsertUpcomingEventParams{
|
||||||
|
ID: e.ID,
|
||||||
|
SportID: pgtype.Text{String: e.SportID, Valid: true},
|
||||||
|
MatchName: pgtype.Text{String: e.MatchName, Valid: true},
|
||||||
|
HomeTeam: pgtype.Text{String: e.HomeTeam, Valid: true},
|
||||||
|
AwayTeam: pgtype.Text{String: e.AwayTeam, Valid: true},
|
||||||
|
HomeTeamID: pgtype.Text{String: e.HomeTeamID, Valid: true},
|
||||||
|
AwayTeamID: pgtype.Text{String: e.AwayTeamID, Valid: true},
|
||||||
|
HomeKitImage: pgtype.Text{String: e.HomeKitImage, Valid: true},
|
||||||
|
AwayKitImage: pgtype.Text{String: e.AwayKitImage, Valid: true},
|
||||||
|
LeagueID: pgtype.Text{String: e.LeagueID, Valid: true},
|
||||||
|
LeagueName: pgtype.Text{String: e.LeagueName, Valid: true},
|
||||||
|
LeagueCc: pgtype.Text{String: e.LeagueCC, Valid: true},
|
||||||
|
StartTime: pgtype.Timestamp{Time: e.StartTime, Valid: true},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Store) GetLiveEventIDs(ctx context.Context) ([]string, error) {
|
func (s *Store) GetLiveEventIDs(ctx context.Context) ([]string, error) {
|
||||||
return s.queries.ListLiveEvents(ctx)
|
return s.queries.ListLiveEvents(ctx)
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -96,65 +97,66 @@ func (s *service) FetchLiveEvents(ctx context.Context) error {
|
||||||
|
|
||||||
func (s *service) FetchUpcomingEvents(ctx context.Context) error {
|
func (s *service) FetchUpcomingEvents(ctx context.Context) error {
|
||||||
sportIDs := []int{1, 13, 78, 18, 91, 16, 17, 14, 12, 3, 2, 4, 83, 15, 92, 94, 8, 19, 36, 66, 9, 75, 90, 95, 110, 107, 151, 162, 148}
|
sportIDs := []int{1, 13, 78, 18, 91, 16, 17, 14, 12, 3, 2, 4, 83, 15, 92, 94, 8, 19, 36, 66, 9, 75, 90, 95, 110, 107, 151, 162, 148}
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
|
|
||||||
for _, sportID := range sportIDs {
|
for _, sportID := range sportIDs {
|
||||||
wg.Add(1)
|
|
||||||
go func(sportID int) {
|
|
||||||
defer wg.Done()
|
|
||||||
|
|
||||||
url := fmt.Sprintf("https://api.b365api.com/v1/bet365/upcoming?sport_id=%d&token=%s", sportID, s.token)
|
url := fmt.Sprintf("https://api.b365api.com/v1/bet365/upcoming?sport_id=%d&token=%s", sportID, s.token)
|
||||||
resp, err := http.Get(url)
|
resp, err := http.Get(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf(" Failed request for upcoming sport_id=%d: %v\n", sportID, err)
|
continue
|
||||||
return
|
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
body, _ := io.ReadAll(resp.Body)
|
body, _ := io.ReadAll(resp.Body)
|
||||||
|
|
||||||
var data struct {
|
var data struct {
|
||||||
Success int `json:"success"`
|
Success int `json:"success"`
|
||||||
Results [][]map[string]interface{} `json:"results"`
|
Results []struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
SportID string `json:"sport_id"`
|
||||||
|
Time string `json:"time"`
|
||||||
|
League struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
} `json:"league"`
|
||||||
|
Home struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
} `json:"home"`
|
||||||
|
Away *struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
} `json:"away"`
|
||||||
|
} `json:"results"`
|
||||||
}
|
}
|
||||||
if err := json.Unmarshal(body, &data); err != nil || data.Success != 1 {
|
if err := json.Unmarshal(body, &data); err != nil || data.Success != 1 {
|
||||||
fmt.Printf(" Decode failed for upcoming sport_id=%d\nRaw: %s\n", sportID, string(body))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, group := range data.Results {
|
|
||||||
for _, ev := range group {
|
|
||||||
if getString(ev["type"]) != "EV" {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
event := domain.Event{
|
for _, ev := range data.Results {
|
||||||
ID: getString(ev["ID"]),
|
startUnix, _ := strconv.ParseInt(ev.Time, 10, 64)
|
||||||
SportID: fmt.Sprintf("%d", sportID),
|
event := domain.UpcomingEvent{
|
||||||
MatchName: getString(ev["NA"]),
|
ID: ev.ID,
|
||||||
HomeTeamID: getString(ev["HT"]),
|
SportID: ev.SportID,
|
||||||
AwayTeamID: getString(ev["AT"]),
|
MatchName: ev.Home.Name,
|
||||||
HomeKitImage: getString(ev["K1"]),
|
HomeTeam: ev.Home.Name,
|
||||||
AwayKitImage: getString(ev["K2"]),
|
AwayTeam: "", // handle nil safely
|
||||||
LeagueID: getString(ev["C2"]),
|
HomeTeamID: ev.Home.ID,
|
||||||
LeagueName: getString(ev["CT"]),
|
AwayTeamID: "",
|
||||||
LeagueCC: getString(ev["CB"]),
|
HomeKitImage: "",
|
||||||
StartTime: time.Now().UTC().Format(time.RFC3339),
|
AwayKitImage: "",
|
||||||
IsLive: false,
|
LeagueID: ev.League.ID,
|
||||||
Status: "upcoming",
|
LeagueName: ev.League.Name,
|
||||||
|
LeagueCC: "",
|
||||||
|
StartTime: time.Unix(startUnix, 0).UTC(),
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.store.SaveEvent(ctx, event); err != nil {
|
if ev.Away != nil {
|
||||||
fmt.Printf(" Could not store upcoming event [id=%s]: %v\n", event.ID, err)
|
event.AwayTeam = ev.Away.Name
|
||||||
}
|
event.AwayTeamID = ev.Away.ID
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}(sportID)
|
_ = s.store.SaveUpcomingEvent(ctx, event)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wg.Wait()
|
|
||||||
fmt.Println(" All upcoming events fetched and stored.")
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.S
|
||||||
}{
|
}{
|
||||||
|
|
||||||
{
|
{
|
||||||
spec: "0 0 * * * *", // Every hour
|
spec: "*/5 * * * * *", // Every 5 seconds
|
||||||
task: func() {
|
task: func() {
|
||||||
if err := eventService.FetchUpcomingEvents(context.Background()); err != nil {
|
if err := eventService.FetchUpcomingEvents(context.Background()); err != nil {
|
||||||
log.Printf("FetchUpcomingEvents error: %v", err)
|
log.Printf("FetchUpcomingEvents error: %v", err)
|
||||||
|
|
@ -27,6 +27,7 @@ func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.S
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
spec: "*/5 * * * * *", // Every 5 seconds
|
spec: "*/5 * * * * *", // Every 5 seconds
|
||||||
task: func() {
|
task: func() {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user