Merge remote-tracking branch 'refs/remotes/origin/auth' into auth
This commit is contained in:
commit
e7e87a4511
|
|
@ -44,13 +44,13 @@ import (
|
||||||
func main() {
|
func main() {
|
||||||
cfg, err := config.NewConfig()
|
cfg, err := config.NewConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("❌ Config error:", "err", err)
|
slog.Error(" Config error:", "err", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
db, _, err := repository.OpenDB(cfg.DbUrl)
|
db, _, err := repository.OpenDB(cfg.DbUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("❌ Database error:", err)
|
fmt.Println(" Database error:", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,4 +56,37 @@ SELECT
|
||||||
source,
|
source,
|
||||||
is_active
|
is_active
|
||||||
FROM odds
|
FROM odds
|
||||||
WHERE event_id = $1 AND is_active = true AND source = 'b365api';
|
WHERE event_id = $1 AND is_active = true AND source = 'b365api';
|
||||||
|
|
||||||
|
-- name: GetALLPrematchOdds :many
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
event_id,
|
||||||
|
fi,
|
||||||
|
market_type,
|
||||||
|
market_name,
|
||||||
|
market_category,
|
||||||
|
market_id,
|
||||||
|
name,
|
||||||
|
handicap,
|
||||||
|
odds_value,
|
||||||
|
section,
|
||||||
|
category,
|
||||||
|
raw_odds,
|
||||||
|
fetched_at,
|
||||||
|
source,
|
||||||
|
is_active
|
||||||
|
FROM odds
|
||||||
|
WHERE is_active = true AND source = 'b365api';
|
||||||
|
-- name: GetRawOddsByID :one
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
event_id,
|
||||||
|
raw_odds,
|
||||||
|
fetched_at
|
||||||
|
FROM odds
|
||||||
|
WHERE
|
||||||
|
raw_odds @> $1::jsonb AND
|
||||||
|
is_active = true AND
|
||||||
|
source = 'b365api'
|
||||||
|
LIMIT 1;
|
||||||
102
docs/docs.go
102
docs/docs.go
|
|
@ -1246,6 +1246,82 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/prematch/odds": {
|
||||||
|
"get": {
|
||||||
|
"description": "Retrieve all prematch odds from the database",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"prematch"
|
||||||
|
],
|
||||||
|
"summary": "Retrieve all prematch odds",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/domain.Odd"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/prematch/odds/raw/{raw_odds_id}": {
|
||||||
|
"get": {
|
||||||
|
"description": "Retrieve raw odds by raw odds ID",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"prematch"
|
||||||
|
],
|
||||||
|
"summary": "Retrieve raw odds by ID",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Raw Odds ID",
|
||||||
|
"name": "raw_odds_id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/domain.RawOddsByID"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/prematch/odds/{event_id}": {
|
"/prematch/odds/{event_id}": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Retrieve prematch odds for a specific event by event ID",
|
"description": "Retrieve prematch odds for a specific event by event ID",
|
||||||
|
|
@ -2413,9 +2489,6 @@ const docTemplate = `{
|
||||||
"handicap": {
|
"handicap": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"header": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"id": {
|
"id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
|
@ -2432,17 +2505,16 @@ const docTemplate = `{
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"market_type": {
|
"market_type": {
|
||||||
|
"description": "RawEventID string ` + "`" + `json:\"raw_event_id\"` + "`" + `",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
|
"description": "Header string ` + "`" + `json:\"header\"` + "`" + `",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"odds_value": {
|
"odds_value": {
|
||||||
"type": "number"
|
"type": "number"
|
||||||
},
|
},
|
||||||
"raw_event_id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"raw_odds": {
|
"raw_odds": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {}
|
"items": {}
|
||||||
|
|
@ -2470,6 +2542,24 @@ const docTemplate = `{
|
||||||
"BANK"
|
"BANK"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"domain.RawOddsByID": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"event_id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"fetched_at": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"raw_odds": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"domain.Role": {
|
"domain.Role": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": [
|
||||||
|
|
|
||||||
|
|
@ -1238,6 +1238,82 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/prematch/odds": {
|
||||||
|
"get": {
|
||||||
|
"description": "Retrieve all prematch odds from the database",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"prematch"
|
||||||
|
],
|
||||||
|
"summary": "Retrieve all prematch odds",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/domain.Odd"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/prematch/odds/raw/{raw_odds_id}": {
|
||||||
|
"get": {
|
||||||
|
"description": "Retrieve raw odds by raw odds ID",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"prematch"
|
||||||
|
],
|
||||||
|
"summary": "Retrieve raw odds by ID",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Raw Odds ID",
|
||||||
|
"name": "raw_odds_id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/domain.RawOddsByID"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/prematch/odds/{event_id}": {
|
"/prematch/odds/{event_id}": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Retrieve prematch odds for a specific event by event ID",
|
"description": "Retrieve prematch odds for a specific event by event ID",
|
||||||
|
|
@ -2405,9 +2481,6 @@
|
||||||
"handicap": {
|
"handicap": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"header": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"id": {
|
"id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
|
@ -2424,17 +2497,16 @@
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"market_type": {
|
"market_type": {
|
||||||
|
"description": "RawEventID string `json:\"raw_event_id\"`",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
|
"description": "Header string `json:\"header\"`",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"odds_value": {
|
"odds_value": {
|
||||||
"type": "number"
|
"type": "number"
|
||||||
},
|
},
|
||||||
"raw_event_id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"raw_odds": {
|
"raw_odds": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {}
|
"items": {}
|
||||||
|
|
@ -2462,6 +2534,24 @@
|
||||||
"BANK"
|
"BANK"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"domain.RawOddsByID": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"event_id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"fetched_at": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"raw_odds": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"domain.Role": {
|
"domain.Role": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": [
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,6 @@ definitions:
|
||||||
type: string
|
type: string
|
||||||
handicap:
|
handicap:
|
||||||
type: string
|
type: string
|
||||||
header:
|
|
||||||
type: string
|
|
||||||
id:
|
id:
|
||||||
type: integer
|
type: integer
|
||||||
is_active:
|
is_active:
|
||||||
|
|
@ -47,13 +45,13 @@ definitions:
|
||||||
market_name:
|
market_name:
|
||||||
type: string
|
type: string
|
||||||
market_type:
|
market_type:
|
||||||
|
description: RawEventID string `json:"raw_event_id"`
|
||||||
type: string
|
type: string
|
||||||
name:
|
name:
|
||||||
|
description: Header string `json:"header"`
|
||||||
type: string
|
type: string
|
||||||
odds_value:
|
odds_value:
|
||||||
type: number
|
type: number
|
||||||
raw_event_id:
|
|
||||||
type: string
|
|
||||||
raw_odds:
|
raw_odds:
|
||||||
items: {}
|
items: {}
|
||||||
type: array
|
type: array
|
||||||
|
|
@ -74,6 +72,18 @@ definitions:
|
||||||
- TELEBIRR_TRANSACTION
|
- TELEBIRR_TRANSACTION
|
||||||
- ARIFPAY_TRANSACTION
|
- ARIFPAY_TRANSACTION
|
||||||
- BANK
|
- BANK
|
||||||
|
domain.RawOddsByID:
|
||||||
|
properties:
|
||||||
|
event_id:
|
||||||
|
type: string
|
||||||
|
fetched_at:
|
||||||
|
type: string
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
raw_odds:
|
||||||
|
items: {}
|
||||||
|
type: array
|
||||||
|
type: object
|
||||||
domain.Role:
|
domain.Role:
|
||||||
enum:
|
enum:
|
||||||
- super_admin
|
- super_admin
|
||||||
|
|
@ -1535,6 +1545,27 @@ paths:
|
||||||
summary: Create a operation
|
summary: Create a operation
|
||||||
tags:
|
tags:
|
||||||
- branch
|
- branch
|
||||||
|
/prematch/odds:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: Retrieve all prematch odds from the database
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/domain.Odd'
|
||||||
|
type: array
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.APIResponse'
|
||||||
|
summary: Retrieve all prematch odds
|
||||||
|
tags:
|
||||||
|
- prematch
|
||||||
/prematch/odds/{event_id}:
|
/prematch/odds/{event_id}:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
|
|
@ -1566,6 +1597,35 @@ paths:
|
||||||
summary: Retrieve prematch odds for an event
|
summary: Retrieve prematch odds for an event
|
||||||
tags:
|
tags:
|
||||||
- prematch
|
- prematch
|
||||||
|
/prematch/odds/raw/{raw_odds_id}:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: Retrieve raw odds by raw odds ID
|
||||||
|
parameters:
|
||||||
|
- description: Raw Odds ID
|
||||||
|
in: path
|
||||||
|
name: raw_odds_id
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/domain.RawOddsByID'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.APIResponse'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.APIResponse'
|
||||||
|
summary: Retrieve raw odds by ID
|
||||||
|
tags:
|
||||||
|
- prematch
|
||||||
/search/branch:
|
/search/branch:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,84 @@ import (
|
||||||
"github.com/jackc/pgx/v5/pgtype"
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const GetALLPrematchOdds = `-- name: GetALLPrematchOdds :many
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
event_id,
|
||||||
|
fi,
|
||||||
|
market_type,
|
||||||
|
market_name,
|
||||||
|
market_category,
|
||||||
|
market_id,
|
||||||
|
name,
|
||||||
|
handicap,
|
||||||
|
odds_value,
|
||||||
|
section,
|
||||||
|
category,
|
||||||
|
raw_odds,
|
||||||
|
fetched_at,
|
||||||
|
source,
|
||||||
|
is_active
|
||||||
|
FROM odds
|
||||||
|
WHERE is_active = true AND source = 'b365api'
|
||||||
|
`
|
||||||
|
|
||||||
|
type GetALLPrematchOddsRow struct {
|
||||||
|
ID int32
|
||||||
|
EventID pgtype.Text
|
||||||
|
Fi pgtype.Text
|
||||||
|
MarketType string
|
||||||
|
MarketName pgtype.Text
|
||||||
|
MarketCategory pgtype.Text
|
||||||
|
MarketID pgtype.Text
|
||||||
|
Name pgtype.Text
|
||||||
|
Handicap pgtype.Text
|
||||||
|
OddsValue pgtype.Float8
|
||||||
|
Section string
|
||||||
|
Category pgtype.Text
|
||||||
|
RawOdds []byte
|
||||||
|
FetchedAt pgtype.Timestamp
|
||||||
|
Source pgtype.Text
|
||||||
|
IsActive pgtype.Bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetALLPrematchOdds(ctx context.Context) ([]GetALLPrematchOddsRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, GetALLPrematchOdds)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []GetALLPrematchOddsRow
|
||||||
|
for rows.Next() {
|
||||||
|
var i GetALLPrematchOddsRow
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.EventID,
|
||||||
|
&i.Fi,
|
||||||
|
&i.MarketType,
|
||||||
|
&i.MarketName,
|
||||||
|
&i.MarketCategory,
|
||||||
|
&i.MarketID,
|
||||||
|
&i.Name,
|
||||||
|
&i.Handicap,
|
||||||
|
&i.OddsValue,
|
||||||
|
&i.Section,
|
||||||
|
&i.Category,
|
||||||
|
&i.RawOdds,
|
||||||
|
&i.FetchedAt,
|
||||||
|
&i.Source,
|
||||||
|
&i.IsActive,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
const GetPrematchOdds = `-- name: GetPrematchOdds :many
|
const GetPrematchOdds = `-- name: GetPrematchOdds :many
|
||||||
SELECT
|
SELECT
|
||||||
id,
|
id,
|
||||||
|
|
@ -74,6 +152,39 @@ func (q *Queries) GetPrematchOdds(ctx context.Context, eventID pgtype.Text) ([]O
|
||||||
return items, nil
|
return items, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const GetRawOddsByID = `-- name: GetRawOddsByID :one
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
event_id,
|
||||||
|
raw_odds,
|
||||||
|
fetched_at
|
||||||
|
FROM odds
|
||||||
|
WHERE
|
||||||
|
raw_odds @> $1::jsonb AND
|
||||||
|
is_active = true AND
|
||||||
|
source = 'b365api'
|
||||||
|
LIMIT 1
|
||||||
|
`
|
||||||
|
|
||||||
|
type GetRawOddsByIDRow struct {
|
||||||
|
ID int32
|
||||||
|
EventID pgtype.Text
|
||||||
|
RawOdds []byte
|
||||||
|
FetchedAt pgtype.Timestamp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetRawOddsByID(ctx context.Context, dollar_1 []byte) (GetRawOddsByIDRow, error) {
|
||||||
|
row := q.db.QueryRow(ctx, GetRawOddsByID, dollar_1)
|
||||||
|
var i GetRawOddsByIDRow
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.EventID,
|
||||||
|
&i.RawOdds,
|
||||||
|
&i.FetchedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
const InsertNonLiveOdd = `-- name: InsertNonLiveOdd :exec
|
const InsertNonLiveOdd = `-- name: InsertNonLiveOdd :exec
|
||||||
INSERT INTO odds (
|
INSERT INTO odds (
|
||||||
event_id,
|
event_id,
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
)
|
)
|
||||||
type RawMessage interface{} // Change from json.RawMessage to interface{}
|
type RawMessage interface{}
|
||||||
|
|
||||||
type Market struct {
|
type Market struct {
|
||||||
EventID string
|
EventID string
|
||||||
|
|
@ -27,12 +27,12 @@ type Odd struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
EventID string `json:"event_id"`
|
EventID string `json:"event_id"`
|
||||||
Fi string `json:"fi"`
|
Fi string `json:"fi"`
|
||||||
RawEventID string `json:"raw_event_id"`
|
// RawEventID string `json:"raw_event_id"`
|
||||||
MarketType string `json:"market_type"`
|
MarketType string `json:"market_type"`
|
||||||
MarketName string `json:"market_name"`
|
MarketName string `json:"market_name"`
|
||||||
MarketCategory string `json:"market_category"`
|
MarketCategory string `json:"market_category"`
|
||||||
MarketID string `json:"market_id"`
|
MarketID string `json:"market_id"`
|
||||||
Header string `json:"header"`
|
// Header string `json:"header"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Handicap string `json:"handicap"`
|
Handicap string `json:"handicap"`
|
||||||
OddsValue float64 `json:"odds_value"`
|
OddsValue float64 `json:"odds_value"`
|
||||||
|
|
@ -42,4 +42,10 @@ type Odd struct {
|
||||||
FetchedAt time.Time `json:"fetched_at"`
|
FetchedAt time.Time `json:"fetched_at"`
|
||||||
Source string `json:"source"`
|
Source string `json:"source"`
|
||||||
IsActive bool `json:"is_active"`
|
IsActive bool `json:"is_active"`
|
||||||
|
}
|
||||||
|
type RawOddsByID struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
EventID string `json:"event_id"`
|
||||||
|
RawOdds []RawMessage `json:"raw_odds"`
|
||||||
|
FetchedAt time.Time `json:"fetched_at"`
|
||||||
}
|
}
|
||||||
|
|
@ -1,112 +1,105 @@
|
||||||
package repository
|
package repository
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"os"
|
||||||
"os"
|
"strconv"
|
||||||
"strconv"
|
"time"
|
||||||
"time"
|
|
||||||
|
|
||||||
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
"github.com/jackc/pgx/v5/pgtype"
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Store) SaveNonLiveMarket(ctx context.Context, m domain.Market) error {
|
func (s *Store) SaveNonLiveMarket(ctx context.Context, m domain.Market) error {
|
||||||
if len(m.Odds) == 0 {
|
if len(m.Odds) == 0 {
|
||||||
fmt.Printf(" Market has no odds: %s (%s)\n", m.MarketType, m.EventID)
|
return nil
|
||||||
return nil
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for _, raw := range m.Odds {
|
for _, raw := range m.Odds {
|
||||||
var item map[string]interface{}
|
var item map[string]interface{}
|
||||||
if err := json.Unmarshal(raw, &item); err != nil {
|
if err := json.Unmarshal(raw, &item); err != nil {
|
||||||
fmt.Printf(" Invalid odd JSON for %s (%s): %v\n", m.MarketType, m.EventID, err)
|
continue
|
||||||
continue
|
}
|
||||||
}
|
|
||||||
|
|
||||||
header := getString(item["header"])
|
header := getString(item["header"])
|
||||||
name := getString(item["name"])
|
name := getString(item["name"])
|
||||||
handicap := getString(item["handicap"])
|
handicap := getString(item["handicap"])
|
||||||
oddsVal := getFloat(item["odds"])
|
oddsVal := getFloat(item["odds"])
|
||||||
|
|
||||||
rawOddsBytes, _ := json.Marshal(m.Odds)
|
rawOddsBytes, _ := json.Marshal(m.Odds)
|
||||||
|
|
||||||
params := dbgen.InsertNonLiveOddParams{
|
params := dbgen.InsertNonLiveOddParams{
|
||||||
EventID: pgtype.Text{String: m.EventID, Valid: m.EventID != ""},
|
EventID: pgtype.Text{String: m.EventID, Valid: m.EventID != ""},
|
||||||
Fi: pgtype.Text{String: m.FI, Valid: m.FI != ""},
|
Fi: pgtype.Text{String: m.FI, Valid: m.FI != ""},
|
||||||
RawEventID: pgtype.Text{String: m.EventID, Valid: m.EventID != ""},
|
RawEventID: pgtype.Text{String: m.EventID, Valid: m.EventID != ""},
|
||||||
MarketType: m.MarketType,
|
MarketType: m.MarketType,
|
||||||
MarketName: pgtype.Text{String: m.MarketName, Valid: m.MarketName != ""},
|
MarketName: pgtype.Text{String: m.MarketName, Valid: m.MarketName != ""},
|
||||||
MarketCategory: pgtype.Text{String: m.MarketCategory, Valid: m.MarketCategory != ""},
|
MarketCategory: pgtype.Text{String: m.MarketCategory, Valid: m.MarketCategory != ""},
|
||||||
MarketID: pgtype.Text{String: m.MarketID, Valid: m.MarketID != ""},
|
MarketID: pgtype.Text{String: m.MarketID, Valid: m.MarketID != ""},
|
||||||
Header: pgtype.Text{String: header, Valid: header != ""},
|
Header: pgtype.Text{String: header, Valid: header != ""},
|
||||||
Name: pgtype.Text{String: name, Valid: name != ""},
|
Name: pgtype.Text{String: name, Valid: name != ""},
|
||||||
Handicap: pgtype.Text{String: handicap, Valid: handicap != ""},
|
Handicap: pgtype.Text{String: handicap, Valid: handicap != ""},
|
||||||
OddsValue: pgtype.Float8{Float64: oddsVal, Valid: oddsVal != 0},
|
OddsValue: pgtype.Float8{Float64: oddsVal, Valid: oddsVal != 0},
|
||||||
Section: m.MarketCategory,
|
Section: m.MarketCategory,
|
||||||
Category: pgtype.Text{Valid: false},
|
Category: pgtype.Text{Valid: false},
|
||||||
RawOdds: rawOddsBytes,
|
RawOdds: rawOddsBytes,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := s.queries.InsertNonLiveOdd(ctx, params)
|
err := s.queries.InsertNonLiveOdd(ctx, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf(" Failed to insert odd for market %s (%s): %v\n", m.MarketType, m.EventID, err)
|
_ = writeFailedMarketLog(m, err)
|
||||||
_ = writeFailedMarketLog(m, err)
|
continue
|
||||||
continue
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
fmt.Printf("Inserted odd: %s | type=%s | header=%s | name=%s\n", m.EventID, m.MarketType, header, name)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func writeFailedMarketLog(m domain.Market, err error) error {
|
func writeFailedMarketLog(m domain.Market, err error) error {
|
||||||
logDir := "logs"
|
logDir := "logs"
|
||||||
logFile := logDir + "/failed_markets.log"
|
logFile := logDir + "/failed_markets.log"
|
||||||
|
|
||||||
if mkErr := os.MkdirAll(logDir, 0755); mkErr != nil {
|
if mkErr := os.MkdirAll(logDir, 0755); mkErr != nil {
|
||||||
return mkErr
|
return mkErr
|
||||||
}
|
}
|
||||||
|
|
||||||
f, fileErr := os.OpenFile(logFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
f, fileErr := os.OpenFile(logFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||||
if fileErr != nil {
|
if fileErr != nil {
|
||||||
return fileErr
|
return fileErr
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
entry := struct {
|
entry := struct {
|
||||||
Time string `json:"time"`
|
Time string `json:"time"`
|
||||||
Error string `json:"error"`
|
Error string `json:"error"`
|
||||||
Record domain.Market `json:"record"`
|
Record domain.Market `json:"record"`
|
||||||
}{
|
}{
|
||||||
Time: time.Now().Format(time.RFC3339),
|
Time: time.Now().Format(time.RFC3339),
|
||||||
Error: err.Error(),
|
Error: err.Error(),
|
||||||
Record: m,
|
Record: m,
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonData, _ := json.MarshalIndent(entry, "", " ")
|
jsonData, _ := json.MarshalIndent(entry, "", " ")
|
||||||
_, writeErr := f.WriteString(string(jsonData) + "\n\n")
|
_, writeErr := f.WriteString(string(jsonData) + "\n\n")
|
||||||
return writeErr
|
return writeErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func getString(v interface{}) string {
|
func getString(v interface{}) string {
|
||||||
if s, ok := v.(string); ok {
|
if s, ok := v.(string); ok {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func getFloat(v interface{}) float64 {
|
func getFloat(v interface{}) float64 {
|
||||||
if s, ok := v.(string); ok {
|
if s, ok := v.(string); ok {
|
||||||
f, err := strconv.ParseFloat(s, 64)
|
f, err := strconv.ParseFloat(s, 64)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) GetPrematchOdds(ctx context.Context, eventID string) ([]domain.Odd, error) {
|
func (s *Store) GetPrematchOdds(ctx context.Context, eventID string) ([]domain.Odd, error) {
|
||||||
|
|
@ -120,32 +113,96 @@ func (s *Store) GetPrematchOdds(ctx context.Context, eventID string) ([]domain.O
|
||||||
domainOdds := make([]domain.Odd, len(odds))
|
domainOdds := make([]domain.Odd, len(odds))
|
||||||
for i, odd := range odds {
|
for i, odd := range odds {
|
||||||
domainOdds[i] = domain.Odd{
|
domainOdds[i] = domain.Odd{
|
||||||
ID: int64(odd.ID), // Cast int32 to int64
|
ID: int64(odd.ID),
|
||||||
EventID: odd.EventID.String, // Extract the String value
|
EventID: odd.EventID.String,
|
||||||
Fi: odd.Fi.String, // Extract the String value
|
Fi: odd.Fi.String,
|
||||||
RawEventID: odd.RawEventID.String, // Extract the String value
|
// RawEventID: odd.RawEventID.String,
|
||||||
MarketType: odd.MarketType, // Direct assignment
|
MarketType: odd.MarketType,
|
||||||
MarketName: odd.MarketName.String, // Extract the String value
|
MarketName: odd.MarketName.String,
|
||||||
MarketCategory: odd.MarketCategory.String, // Extract the String value
|
MarketCategory: odd.MarketCategory.String,
|
||||||
MarketID: odd.MarketID.String, // Extract the String value
|
MarketID: odd.MarketID.String,
|
||||||
Header: odd.Header.String, // Extract the String value
|
// Header: odd.Header.String,
|
||||||
Name: odd.Name.String, // Extract the String value
|
Name: odd.Name.String,
|
||||||
Handicap: odd.Handicap.String, // Extract the String value
|
Handicap: odd.Handicap.String,
|
||||||
OddsValue: odd.OddsValue.Float64, // Extract the Float64 value
|
OddsValue: odd.OddsValue.Float64,
|
||||||
Section: odd.Section, // Direct assignment
|
Section: odd.Section,
|
||||||
Category: odd.Category.String, // Extract the String value
|
Category: odd.Category.String,
|
||||||
RawOdds: func() []domain.RawMessage {
|
RawOdds: func() []domain.RawMessage {
|
||||||
var rawOdds []domain.RawMessage
|
var rawOdds []domain.RawMessage
|
||||||
if err := json.Unmarshal(odd.RawOdds, &rawOdds); err != nil {
|
if err := json.Unmarshal(odd.RawOdds, &rawOdds); err != nil {
|
||||||
rawOdds = nil
|
rawOdds = nil
|
||||||
}
|
}
|
||||||
return rawOdds
|
return rawOdds
|
||||||
}(),
|
}(),
|
||||||
FetchedAt: odd.FetchedAt.Time, // Extract the Time value
|
FetchedAt: odd.FetchedAt.Time,
|
||||||
Source: odd.Source.String, // Extract the String value
|
Source: odd.Source.String,
|
||||||
IsActive: odd.IsActive.Bool, // Extract the Bool value
|
IsActive: odd.IsActive.Bool,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return domainOdds, nil
|
return domainOdds, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetALLPrematchOdds(ctx context.Context) ([]domain.Odd, error) {
|
||||||
|
rows, err := s.queries.GetALLPrematchOdds(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
domainOdds := make([]domain.Odd, len(rows))
|
||||||
|
for i, row := range rows {
|
||||||
|
domainOdds[i] = domain.Odd{
|
||||||
|
ID: int64(row.ID),
|
||||||
|
EventID: row.EventID.String,
|
||||||
|
Fi: row.Fi.String,
|
||||||
|
MarketType: row.MarketType,
|
||||||
|
MarketName: row.MarketName.String,
|
||||||
|
MarketCategory: row.MarketCategory.String,
|
||||||
|
MarketID: row.MarketID.String,
|
||||||
|
Name: row.Name.String,
|
||||||
|
Handicap: row.Handicap.String,
|
||||||
|
OddsValue: row.OddsValue.Float64,
|
||||||
|
Section: row.Section,
|
||||||
|
Category: row.Category.String,
|
||||||
|
RawOdds: func() []domain.RawMessage {
|
||||||
|
var rawOdds []domain.RawMessage
|
||||||
|
if err := json.Unmarshal(row.RawOdds, &rawOdds); err != nil {
|
||||||
|
rawOdds = nil
|
||||||
|
}
|
||||||
|
return rawOdds
|
||||||
|
}(),
|
||||||
|
FetchedAt: row.FetchedAt.Time,
|
||||||
|
Source: row.Source.String,
|
||||||
|
IsActive: row.IsActive.Bool,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return domainOdds, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetRawOddsByID(ctx context.Context, rawOddsID string) (domain.RawOddsByID, error) {
|
||||||
|
jsonFilter := `[{"id":"` + rawOddsID + `"}]`
|
||||||
|
|
||||||
|
odd, err := s.queries.GetRawOddsByID(ctx, []byte(jsonFilter))
|
||||||
|
if err != nil {
|
||||||
|
return domain.RawOddsByID{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var rawOdds []json.RawMessage
|
||||||
|
if err := json.Unmarshal(odd.RawOdds, &rawOdds); err != nil {
|
||||||
|
return domain.RawOddsByID{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return domain.RawOddsByID{
|
||||||
|
ID: int64(odd.ID),
|
||||||
|
EventID: odd.EventID.String,
|
||||||
|
RawOdds: func() []domain.RawMessage {
|
||||||
|
converted := make([]domain.RawMessage, len(rawOdds))
|
||||||
|
for i, r := range rawOdds {
|
||||||
|
converted[i] = domain.RawMessage(r)
|
||||||
|
}
|
||||||
|
return converted
|
||||||
|
}(),
|
||||||
|
FetchedAt: odd.FetchedAt.Time,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
@ -170,4 +170,4 @@ func getInt(v interface{}) int {
|
||||||
return int(f)
|
return int(f)
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
@ -9,6 +9,8 @@ import (
|
||||||
type Service interface {
|
type Service interface {
|
||||||
FetchNonLiveOdds(ctx context.Context) error
|
FetchNonLiveOdds(ctx context.Context) error
|
||||||
GetPrematchOdds(ctx context.Context, eventID string) ([]domain.Odd, error)
|
GetPrematchOdds(ctx context.Context, eventID string) ([]domain.Odd, error)
|
||||||
|
GetALLPrematchOdds(ctx context.Context) ([]domain.Odd, error)
|
||||||
|
GetRawOddsByID(ctx context.Context, rawOddsID string) ([]domain.RawOddsByID, error)
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ package odds
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
@ -23,79 +22,70 @@ func New(token string, store *repository.Store) *ServiceImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ServiceImpl) FetchNonLiveOdds(ctx context.Context) error {
|
func (s *ServiceImpl) FetchNonLiveOdds(ctx context.Context) error {
|
||||||
fmt.Println("Starting FetchNonLiveOdds...")
|
sportIDs := []int{
|
||||||
|
1, 13, 78, 18, 91, 16, 17, 14, 12, 3, 2, 4,
|
||||||
sportID := 1
|
83, 15, 92, 94, 8, 19, 36, 66, 9, 75, 90,
|
||||||
upcomingURL := fmt.Sprintf("https://api.b365api.com/v1/bet365/upcoming?sport_id=%d&token=%s", sportID, s.token)
|
95, 110, 107, 151, 162, 148,
|
||||||
resp, err := http.Get(upcomingURL)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Failed to fetch upcoming: %v\n", err)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
for _, sportID := range sportIDs {
|
||||||
|
upcomingURL := "https://api.b365api.com/v1/bet365/upcoming?sport_id=" + strconv.Itoa(sportID) + "&token=" + s.token
|
||||||
body, _ := io.ReadAll(resp.Body)
|
resp, err := http.Get(upcomingURL)
|
||||||
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 {
|
if err != nil {
|
||||||
fmt.Printf(" Odds fetch failed for event_id=%s: %v\n", eventID, err)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
defer oddsResp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
oddsBody, _ := io.ReadAll(oddsResp.Body)
|
body, _ := io.ReadAll(resp.Body)
|
||||||
fmt.Printf(" Raw odds response for event_id=%s: %.300s...\n", eventID, string(oddsBody))
|
var upcomingData struct {
|
||||||
|
|
||||||
var oddsData struct {
|
|
||||||
Success int `json:"success"`
|
Success int `json:"success"`
|
||||||
Results []struct {
|
Results []struct {
|
||||||
EventID string `json:"event_id"`
|
ID string `json:"id"`
|
||||||
FI string `json:"FI"`
|
|
||||||
Main OddsSection `json:"main"`
|
|
||||||
} `json:"results"`
|
} `json:"results"`
|
||||||
}
|
}
|
||||||
if err := json.Unmarshal(oddsBody, &oddsData); err != nil || oddsData.Success != 1 || len(oddsData.Results) == 0 {
|
if err := json.Unmarshal(body, &upcomingData); err != nil || upcomingData.Success != 1 {
|
||||||
fmt.Printf(" Failed odds decode for event_id=%s\nRaw: %s\n", eventID, string(oddsBody))
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
result := oddsData.Results[0]
|
for _, ev := range upcomingData.Results {
|
||||||
finalID := result.EventID
|
eventID := ev.ID
|
||||||
if finalID == "" {
|
prematchURL := "https://api.b365api.com/v3/bet365/prematch?token=" + s.token + "&FI=" + eventID
|
||||||
finalID = result.FI
|
oddsResp, err := http.Get(prematchURL)
|
||||||
}
|
if err != nil {
|
||||||
if finalID == "" {
|
continue
|
||||||
fmt.Println(" Skipping event with missing final ID.")
|
}
|
||||||
continue
|
defer oddsResp.Body.Close()
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("🗂 Saving prematch odds for event_id=%s\n", finalID)
|
oddsBody, _ := io.ReadAll(oddsResp.Body)
|
||||||
s.storeSection(ctx, finalID, result.FI, "main", result.Main)
|
var oddsData struct {
|
||||||
fmt.Printf(" Finished storing prematch odds for event_id=%s\n", finalID)
|
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 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
result := oddsData.Results[0]
|
||||||
|
finalID := result.EventID
|
||||||
|
if finalID == "" {
|
||||||
|
finalID = result.FI
|
||||||
|
}
|
||||||
|
if finalID == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
s.storeSection(ctx, finalID, result.FI, "main", result.Main)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(" All prematch odds fetched and stored.")
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ServiceImpl) storeSection(ctx context.Context, eventID, fi, sectionName string, section OddsSection) {
|
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 {
|
if len(section.Sp) == 0 {
|
||||||
fmt.Printf(" No odds in section '%s' for event_id=%s\n", sectionName, eventID)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -103,9 +93,7 @@ func (s *ServiceImpl) storeSection(ctx context.Context, eventID, fi, sectionName
|
||||||
updatedAt := time.Unix(updatedAtUnix, 0)
|
updatedAt := time.Unix(updatedAtUnix, 0)
|
||||||
|
|
||||||
for marketType, market := range section.Sp {
|
for marketType, market := range section.Sp {
|
||||||
fmt.Printf(" Processing market: %s (%s)\n", marketType, market.ID)
|
|
||||||
if len(market.Odds) == 0 {
|
if len(market.Odds) == 0 {
|
||||||
fmt.Printf(" Empty odds for marketType=%s in section=%s\n", marketType, sectionName)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -120,23 +108,16 @@ func (s *ServiceImpl) storeSection(ctx context.Context, eventID, fi, sectionName
|
||||||
Odds: market.Odds,
|
Odds: market.Odds,
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf(" Saving market to DB: %s (%s)\n", marketType, market.ID)
|
_ = s.store.SaveNonLiveMarket(ctx, marketRecord)
|
||||||
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 {
|
type OddsMarket struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Odds []json.RawMessage `json:"odds"`
|
Odds []json.RawMessage `json:"odds"`
|
||||||
Header string `json:"header,omitempty"`
|
Header string `json:"header,omitempty"`
|
||||||
Handicap string `json:"handicap,omitempty"`
|
Handicap string `json:"handicap,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type OddsSection struct {
|
type OddsSection struct {
|
||||||
|
|
@ -144,22 +125,20 @@ type OddsSection struct {
|
||||||
Sp map[string]OddsMarket `json:"sp"`
|
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) {
|
func (s *ServiceImpl) GetPrematchOdds(ctx context.Context, eventID string) ([]domain.Odd, error) {
|
||||||
fmt.Printf("Retrieving prematch odds for event_id=%s\n", eventID)
|
return s.store.GetPrematchOdds(ctx, eventID)
|
||||||
|
}
|
||||||
|
|
||||||
odds, err := s.store.GetPrematchOdds(ctx, eventID)
|
func (s *ServiceImpl) GetALLPrematchOdds(ctx context.Context) ([]domain.Odd, error) {
|
||||||
|
return s.store.GetALLPrematchOdds(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ServiceImpl) GetRawOddsByID(ctx context.Context, rawOddsID string) ([]domain.RawOddsByID, error) {
|
||||||
|
rawOdds, err := s.store.GetRawOddsByID(ctx, rawOddsID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf(" Failed to retrieve odds for event_id=%s: %v\n", eventID, err)
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
return []domain.RawOddsByID{rawOdds}, nil
|
||||||
fmt.Printf(" Retrieved %d odds entries for event_id=%s\n", len(odds), eventID)
|
}
|
||||||
return odds, nil
|
|
||||||
}
|
|
||||||
|
|
@ -33,7 +33,7 @@ func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.S
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
spec: "*/5 * * * * *", // Every 5 seconds
|
spec: "0 */5 * * * *", // Every 5 minutes
|
||||||
task: func() {
|
task: func() {
|
||||||
if err := oddsService.FetchNonLiveOdds(context.Background()); err != nil {
|
if err := oddsService.FetchNonLiveOdds(context.Background()); err != nil {
|
||||||
log.Printf(" FetchNonLiveOdds error: %v", err)
|
log.Printf(" FetchNonLiveOdds error: %v", err)
|
||||||
|
|
@ -41,6 +41,8 @@ func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.S
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, job := range schedule {
|
for _, job := range schedule {
|
||||||
|
|
|
||||||
|
|
@ -22,16 +22,59 @@ func GetPrematchOdds(logger *slog.Logger, prematchSvc *odds.ServiceImpl) fiber.H
|
||||||
return func(c *fiber.Ctx) error {
|
return func(c *fiber.Ctx) error {
|
||||||
eventID := c.Params("event_id")
|
eventID := c.Params("event_id")
|
||||||
if eventID == "" {
|
if eventID == "" {
|
||||||
logger.Error("GetPrematchOdds failed: missing event_id")
|
|
||||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Missing event_id", nil, nil)
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Missing event_id", nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
odds, err := prematchSvc.GetPrematchOdds(c.Context(), eventID)
|
odds, err := prematchSvc.GetPrematchOdds(c.Context(), eventID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("GetPrematchOdds failed", "error", err)
|
|
||||||
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve odds", nil, nil)
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve odds", nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Prematch odds retrieved successfully", odds, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "Prematch odds retrieved successfully", odds, nil)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
//GetALLPrematchOdds
|
||||||
|
// @Summary Retrieve all prematch odds
|
||||||
|
// @Description Retrieve all prematch odds from the database
|
||||||
|
// @Tags prematch
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {array} domain.Odd
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /prematch/odds [get]
|
||||||
|
func GetALLPrematchOdds(logger *slog.Logger, prematchSvc *odds.ServiceImpl) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
odds, err := prematchSvc.GetALLPrematchOdds(c.Context())
|
||||||
|
if err != nil {
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve all prematch odds", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "All prematch odds retrieved successfully", odds, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// GetRawOddsByID
|
||||||
|
// @Summary Retrieve raw odds by ID
|
||||||
|
// @Description Retrieve raw odds by raw odds ID
|
||||||
|
// @Tags prematch
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param raw_odds_id path string true "Raw Odds ID"
|
||||||
|
// @Success 200 {object} domain.RawOddsByID
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /prematch/odds/raw/{raw_odds_id} [get]
|
||||||
|
func GetRawOddsByID(logger *slog.Logger, prematchSvc *odds.ServiceImpl) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
rawOddsID := c.Params("raw_odds_id")
|
||||||
|
if rawOddsID == "" {
|
||||||
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Missing raw_odds_id", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
rawOdds, err := prematchSvc.GetRawOddsByID(c.Context(), rawOddsID)
|
||||||
|
if err != nil {
|
||||||
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve raw odds", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "Raw odds retrieved successfully", rawOdds, nil)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -59,7 +59,8 @@ func (a *App) initAppRoutes() {
|
||||||
|
|
||||||
|
|
||||||
a.fiber.Get("/prematch/odds/:event_id", handlers.GetPrematchOdds(a.logger, a.prematchSvc))
|
a.fiber.Get("/prematch/odds/:event_id", handlers.GetPrematchOdds(a.logger, a.prematchSvc))
|
||||||
|
a.fiber.Get("/prematch/odds", handlers.GetALLPrematchOdds(a.logger, a.prematchSvc))
|
||||||
|
a.fiber.Get("/prematch/odds/raw/:raw_odds_id", handlers.GetRawOddsByID(a.logger, a.prematchSvc))
|
||||||
// Swagger
|
// Swagger
|
||||||
a.fiber.Get("/swagger/*", fiberSwagger.FiberWrapHandler())
|
a.fiber.Get("/swagger/*", fiberSwagger.FiberWrapHandler())
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user