From 7a76a4a9482c7a9053b12188c8686720ac6a2998 Mon Sep 17 00:00:00 2001 From: Guillermo Mugnaini Date: Sat, 5 Aug 2023 18:38:42 -0300 Subject: [PATCH 01/26] feat(pvo-344): make pipes sync. add nodeID. fixture on odds change --- .idea/.gitignore | 8 ++++++++ .idea/go-uof-sdk.iml | 10 ++++++++++ .idea/misc.xml | 6 ++++++ .idea/modules.xml | 8 ++++++++ .idea/vcs.xml | 6 ++++++ api/api.go | 19 ++++++++++--------- cmd/client/main.go | 2 +- message.go | 7 ++++++- pipe/fixture.go | 24 ++++++++++++++---------- pipe/market.go | 2 +- pipe/player.go | 2 +- pipe/recovery.go | 12 +++++++----- queue/queue.go | 36 +++++++++++++++++++++--------------- sdk/sdk.go | 8 +++++--- 14 files changed, 104 insertions(+), 46 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/go-uof-sdk.iml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/go-uof-sdk.iml b/.idea/go-uof-sdk.iml new file mode 100644 index 0000000..25ed3f6 --- /dev/null +++ b/.idea/go-uof-sdk.iml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..639900d --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..822147f --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/api/api.go b/api/api.go index debf8e5..a55f64f 100644 --- a/api/api.go +++ b/api/api.go @@ -88,28 +88,28 @@ func client() *retryablehttp.Client { } const ( - recovery = "/v1/{{.Producer}}/recovery/initiate_request?after={{.Timestamp}}&request_id={{.RequestID}}" - fullRecovery = "/v1/{{.Producer}}/recovery/initiate_request?request_id={{.RequestID}}" + recovery = "/v1/{{.Producer}}/recovery/initiate_request?after={{.Timestamp}}&request_id={{.RequestID}}&node_id={{.NodeID}}" + fullRecovery = "/v1/{{.Producer}}/recovery/initiate_request?request_id={{.RequestID}}&node_id={{.NodeID}}" ping = "/v1/users/whoami.xml" ) -func (a *API) RequestRecovery(producer uof.Producer, timestamp int, requestID int) error { +func (a *API) RequestRecovery(producer uof.Producer, timestamp, requestID, nodeID int) error { if timestamp <= 0 { - return a.RequestFullOddsRecovery(producer, requestID) + return a.RequestFullOddsRecovery(producer, requestID, nodeID) } - return a.RequestRecoverySinceTimestamp(producer, timestamp, requestID) + return a.RequestRecoverySinceTimestamp(producer, timestamp, requestID, nodeID) } // RequestRecoverySinceTimestamp does recovery of odds and stateful messages // over the feed since after timestamp. Subscribes client to feed messages. -func (a *API) RequestRecoverySinceTimestamp(producer uof.Producer, timestamp int, requestID int) error { - return a.post(recovery, ¶ms{Producer: producer, Timestamp: timestamp, RequestID: requestID}) +func (a *API) RequestRecoverySinceTimestamp(producer uof.Producer, timestamp, requestID, nodeID int) error { + return a.post(recovery, ¶ms{Producer: producer, Timestamp: timestamp, RequestID: requestID, NodeID: nodeID}) } // RequestFullOddsRecovery does recovery of odds over the feed. Subscribes // client to feed messages. -func (a *API) RequestFullOddsRecovery(producer uof.Producer, requestID int) error { - return a.post(fullRecovery, ¶ms{Producer: producer, RequestID: requestID}) +func (a *API) RequestFullOddsRecovery(producer uof.Producer, requestID, nodeID int) error { + return a.post(fullRecovery, ¶ms{Producer: producer, RequestID: requestID, NodeID: nodeID}) } // // RecoverSportEvent requests to resend all odds for all markets for a sport @@ -207,6 +207,7 @@ type params struct { UseReplayTimestamp bool Lang uof.Lang Producer uof.Producer + NodeID int } func runTemplate(def string, p *params) string { diff --git a/cmd/client/main.go b/cmd/client/main.go index 35dfca0..d1d6c8a 100644 --- a/cmd/client/main.go +++ b/cmd/client/main.go @@ -71,7 +71,7 @@ func main() { pc.Add(uof.ProducerLiveOdds, timestamp) err := sdk.Run(exitSignal(), - sdk.Credentials(bookmakerID, token), + sdk.Credentials(bookmakerID, token, 123), sdk.Staging(), sdk.Recovery(pc), sdk.Fixtures(preloadTo), diff --git a/message.go b/message.go index e0f491a..fa3151c 100644 --- a/message.go +++ b/message.go @@ -23,6 +23,7 @@ type Header struct { RequestedAt int `json:"requestedAt,omitempty"` Producer Producer `json:"producer,omitempty"` Timestamp int `json:"timestamp,omitempty"` + NodeID int `json:"nodeID,omitempty"` } type Body struct { @@ -108,7 +109,11 @@ func (m *Message) parseRoutingKey(routingKey string) error { sportID := part(4) eventURN := part(5) eventID := part(6) - //nodeID := part(7) // currently unused + nodeID := part(7) // currently unused + + if nodeID != "" { + m.NodeID, _ = strconv.Atoi(nodeID) + } m.Priority.Parse(priority) m.Type.Parse(messageType) diff --git a/pipe/fixture.go b/pipe/fixture.go index 73bedae..03c563d 100644 --- a/pipe/fixture.go +++ b/pipe/fixture.go @@ -38,12 +38,12 @@ func Fixture(api fixtureAPI, languages []uof.Lang, preloadTo time.Time) InnerSta } // Na sto sve pazim ovdje: -// * na pocetku napravim preload -// * za vrijeme preload-a ne pokrecem pojedinacne -// * za vrijeme preload-a za zaustavljam lanaca, saljem dalje in -> out -// * nakon sto zavrsi preload napravim one koje preload nije ubacio -// * ne radim request cesce od svakih x (bitno za replay, da ne proizvedem puno requesta) -// * kada radim scenario replay htio bi da samo jednom opali, dok je neki in process da na pokrece isti +// - na pocetku napravim preload +// - za vrijeme preload-a ne pokrecem pojedinacne +// - za vrijeme preload-a za zaustavljam lanaca, saljem dalje in -> out +// - nakon sto zavrsi preload napravim one koje preload nije ubacio +// - ne radim request cesce od svakih x (bitno za replay, da ne proizvedem puno requesta) +// - kada radim scenario replay htio bi da samo jednom opali, dok je neki in process da na pokrece isti func (f *fixture) loop(in <-chan *uof.Message, out chan<- *uof.Message, errc chan<- error) *sync.WaitGroup { f.errc, f.out = errc, out @@ -51,16 +51,19 @@ func (f *fixture) loop(in <-chan *uof.Message, out chan<- *uof.Message, errc cha f.getFixture(u, uof.CurrentTimestamp(), true) } for m := range in { - out <- m if u := f.eventURN(m); u != uof.NoURN { f.getFixture(u, m.ReceivedAt, false) } + out <- m } return f.subProcs } func (f *fixture) eventURN(m *uof.Message) uof.URN { + if m.Type == uof.MessageTypeOddsChange && m.OddsChange != nil { + return m.OddsChange.EventURN + } if m.Type != uof.MessageTypeFixtureChange || m.FixtureChange == nil { return uof.NoURN } @@ -72,7 +75,7 @@ func (f *fixture) preloadLoop(in <-chan *uof.Message) []uof.URN { done := make(chan struct{}) f.subProcs.Add(1) - go func() { + func() { defer f.subProcs.Done() f.preload() close(done) @@ -102,7 +105,7 @@ func (f *fixture) preload() { var wg sync.WaitGroup wg.Add(len(f.languages)) for _, lang := range f.languages { - go func(lang uof.Lang) { + func(lang uof.Lang) { defer wg.Done() in, errc := f.api.Fixtures(lang, f.preloadTo) for x := range in { @@ -120,7 +123,7 @@ func (f *fixture) preload() { func (f *fixture) getFixture(eventURN uof.URN, receivedAt int, isPreload bool) { f.subProcs.Add(len(f.languages)) for _, lang := range f.languages { - go func(lang uof.Lang) { + func(lang uof.Lang) { defer f.subProcs.Done() f.rateLimit <- struct{}{} defer func() { <-f.rateLimit }() @@ -134,6 +137,7 @@ func (f *fixture) getFixture(eventURN uof.URN, receivedAt int, isPreload bool) { f.errc <- err return } + m, err := uof.NewFixtureMessageFromBuf(lang, buf, receivedAt) if err != nil { f.errc <- err diff --git a/pipe/market.go b/pipe/market.go index a40d48f..3a342a9 100644 --- a/pipe/market.go +++ b/pipe/market.go @@ -41,12 +41,12 @@ func (s *markets) loop(in <-chan *uof.Message, out chan<- *uof.Message, errc cha s.getAll() for m := range in { - out <- m if m.Is(uof.MessageTypeOddsChange) { m.OddsChange.EachVariantMarket(func(marketID int, variant string) { s.variantMarket(marketID, variant, m.ReceivedAt) }) } + out <- m } return s.subProcs } diff --git a/pipe/player.go b/pipe/player.go index 6de6421..1342a97 100644 --- a/pipe/player.go +++ b/pipe/player.go @@ -36,12 +36,12 @@ func (p *player) loop(in <-chan *uof.Message, out chan<- *uof.Message, errc chan p.errc, p.out = errc, out for m := range in { - out <- m if m.Is(uof.MessageTypeOddsChange) { m.OddsChange.EachPlayer(func(playerID int) { p.get(playerID, m.ReceivedAt) }) } + out <- m } return p.subProcs } diff --git a/pipe/recovery.go b/pipe/recovery.go index 80987c0..46f8344 100644 --- a/pipe/recovery.go +++ b/pipe/recovery.go @@ -57,19 +57,21 @@ func (p *recoveryProducer) recoveryTimestamp() int { type recovery struct { api recoveryAPI requestID int + nodeID int producers []*recoveryProducer errc chan<- error subProcs *sync.WaitGroup } type recoveryAPI interface { - RequestRecovery(producer uof.Producer, timestamp int, requestID int) error + RequestRecovery(producer uof.Producer, timestamp, requestID, nodeID int) error } -func newRecovery(api recoveryAPI, producers uof.ProducersChange) *recovery { +func newRecovery(api recoveryAPI, producers uof.ProducersChange, nodeID int) *recovery { r := &recovery{ api: api, subProcs: &sync.WaitGroup{}, + nodeID: nodeID, } ct := uof.CurrentTimestamp() for _, p := range producers { @@ -114,7 +116,7 @@ func (r *recovery) requestRecovery(p *recoveryProducer) { for { op := fmt.Sprintf("recovery for %s, timestamp: %d, requestID: %d", producer.Code(), timestamp, requestID) r.log(fmt.Errorf("starting %s", op)) - err := r.api.RequestRecovery(producer, timestamp, requestID) + err := r.api.RequestRecovery(producer, timestamp, requestID, r.nodeID) if err == nil { return } @@ -244,7 +246,7 @@ func (r *recovery) producersChangeMessage() *uof.Message { return uof.NewProducersChangeMessage(psc) } -func Recovery(api recoveryAPI, producers uof.ProducersChange) InnerStage { - r := newRecovery(api, producers) +func Recovery(api recoveryAPI, producers uof.ProducersChange, nodeID int) InnerStage { + r := newRecovery(api, producers, nodeID) return StageWithSubProcesses(r.loop) } diff --git a/queue/queue.go b/queue/queue.go index 4c78ad2..22076a1 100644 --- a/queue/queue.go +++ b/queue/queue.go @@ -24,39 +24,39 @@ const ( ) // Dial connects to the queue chosen by environment -func Dial(ctx context.Context, env uof.Environment, bookmakerID, token string) (*Connection, error) { +func Dial(ctx context.Context, env uof.Environment, bookmakerID, token string, nodeID int) (*Connection, error) { switch env { case uof.Replay: - return DialReplay(ctx, bookmakerID, token) + return DialReplay(ctx, bookmakerID, token, nodeID) case uof.Staging: - return DialStaging(ctx, bookmakerID, token) + return DialStaging(ctx, bookmakerID, token, nodeID) case uof.Production: - return DialProduction(ctx, bookmakerID, token) + return DialProduction(ctx, bookmakerID, token, nodeID) case uof.ProductionGlobal: - return DialProductionGlobal(ctx, bookmakerID, token) + return DialProductionGlobal(ctx, bookmakerID, token, nodeID) default: return nil, uof.Notice("queue dial", fmt.Errorf("unknown environment %d", env)) } } // Dial connects to the production queue -func DialProduction(ctx context.Context, bookmakerID, token string) (*Connection, error) { - return dial(ctx, productionServer, bookmakerID, token) +func DialProduction(ctx context.Context, bookmakerID, token string, nodeID int) (*Connection, error) { + return dial(ctx, productionServer, bookmakerID, token, nodeID) } // Dial connects to the production queue -func DialProductionGlobal(ctx context.Context, bookmakerID, token string) (*Connection, error) { - return dial(ctx, productionServerGlobal, bookmakerID, token) +func DialProductionGlobal(ctx context.Context, bookmakerID, token string, nodeID int) (*Connection, error) { + return dial(ctx, productionServerGlobal, bookmakerID, token, nodeID) } // DialStaging connects to the staging queue -func DialStaging(ctx context.Context, bookmakerID, token string) (*Connection, error) { - return dial(ctx, stagingServer, bookmakerID, token) +func DialStaging(ctx context.Context, bookmakerID, token string, nodeID int) (*Connection, error) { + return dial(ctx, stagingServer, bookmakerID, token, nodeID) } // DialReplay connects to the replay server -func DialReplay(ctx context.Context, bookmakerID, token string) (*Connection, error) { - return dial(ctx, replayServer, bookmakerID, token) +func DialReplay(ctx context.Context, bookmakerID, token string, nodeID int) (*Connection, error) { + return dial(ctx, replayServer, bookmakerID, token, nodeID) } type Connection struct { @@ -71,6 +71,7 @@ type ConnectionInfo struct { local string network string tlsVersion uint16 + nodeID int } func (c *Connection) Listen() (<-chan *uof.Message, <-chan error) { @@ -101,12 +102,16 @@ func (c *Connection) drain(out chan<- *uof.Message, errc chan<- error) { errc <- uof.Notice("conn.DeliveryParse", err) continue } + // ignores messages that are of no interest to the current session + if m.NodeID != 0 && m.NodeID != c.info.nodeID { + return + } out <- m } <-errsDone } -func dial(ctx context.Context, server, bookmakerID, token string) (*Connection, error) { +func dial(ctx context.Context, server, bookmakerID, token string, nodeID int) (*Connection, error) { addr := fmt.Sprintf("amqps://%s:@%s//unifiedfeed/%s", token, server, bookmakerID) tls := &tls.Config{ @@ -168,13 +173,14 @@ func dial(ctx context.Context, server, bookmakerID, token string) (*Connection, msgs: msgs, errs: errs, reDial: func() (*Connection, error) { - return dial(ctx, server, bookmakerID, token) + return dial(ctx, server, bookmakerID, token, nodeID) }, info: ConnectionInfo{ server: server, local: conn.LocalAddr().String(), network: conn.LocalAddr().Network(), tlsVersion: conn.ConnectionState().Version, + nodeID: nodeID, }, } diff --git a/sdk/sdk.go b/sdk/sdk.go index 8681385..b7193ed 100644 --- a/sdk/sdk.go +++ b/sdk/sdk.go @@ -19,6 +19,7 @@ type ErrorListenerFunc func(err error) type Config struct { BookmakerID string Token string + NodeID int Fixtures time.Time Recovery []uof.ProducerChange Stages []pipe.InnerStage @@ -59,7 +60,7 @@ func Run(ctx context.Context, options ...Option) error { pipe.BetStop(), } if len(c.Recovery) > 0 { - stages = append(stages, pipe.Recovery(apiConn, c.Recovery)) + stages = append(stages, pipe.Recovery(apiConn, c.Recovery, c.NodeID)) } stages = append(stages, c.Stages...) @@ -97,7 +98,7 @@ func config(options ...Option) Config { // connect to the queue and api func connect(ctx context.Context, c Config) (*queue.Connection, *api.API, error) { - conn, err := queue.Dial(ctx, c.Env, c.BookmakerID, c.Token) + conn, err := queue.Dial(ctx, c.Env, c.BookmakerID, c.Token, c.NodeID) if err != nil { return nil, nil, err } @@ -109,10 +110,11 @@ func connect(ctx context.Context, c Config) (*queue.Connection, *api.API, error) } // Credentials for establishing connection to the uof queue and api. -func Credentials(bookmakerID, token string) Option { +func Credentials(bookmakerID, token string, nodeID int) Option { return func(c *Config) { c.BookmakerID = bookmakerID c.Token = token + c.NodeID = nodeID } } From c1c510730b3f17e3598b6afba16744217c5ab531 Mon Sep 17 00:00:00 2001 From: Guillermo Mugnaini Date: Sat, 5 Aug 2023 18:40:00 -0300 Subject: [PATCH 02/26] feat(pvo-344): remove idea. gitignore --- .idea/.gitignore | 8 -------- .idea/go-uof-sdk.iml | 10 ---------- .idea/misc.xml | 6 ------ .idea/modules.xml | 8 -------- .idea/vcs.xml | 6 ------ 5 files changed, 38 deletions(-) delete mode 100644 .idea/.gitignore delete mode 100644 .idea/go-uof-sdk.iml delete mode 100644 .idea/misc.xml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/vcs.xml diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 13566b8..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Editor-based HTTP Client requests -/httpRequests/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml diff --git a/.idea/go-uof-sdk.iml b/.idea/go-uof-sdk.iml deleted file mode 100644 index 25ed3f6..0000000 --- a/.idea/go-uof-sdk.iml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 639900d..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 822147f..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1dd..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file From ce6706b91d6c498715c843683a58155620a22d70 Mon Sep 17 00:00:00 2001 From: Guillermo Mugnaini Date: Sat, 5 Aug 2023 18:40:11 -0300 Subject: [PATCH 03/26] feat(pvo-344): remove idea. gitignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index dfea7a2..35cb207 100644 --- a/.gitignore +++ b/.gitignore @@ -13,5 +13,5 @@ coverage.html .vscode - +.idea From 3e510c14bdd997f0800b3d72b734de6ecb8920b6 Mon Sep 17 00:00:00 2001 From: Guillermo Mugnaini Date: Sat, 5 Aug 2023 19:20:00 -0300 Subject: [PATCH 04/26] feat(pvo-344): change imports and go.mod --- .travis.yml | 2 +- api/api.go | 2 +- api/api_test.go | 2 +- api/replay.go | 2 +- api/sports.go | 2 +- cmd/client/main.go | 6 +- cmd/replay/main.go | 10 +- go.mod | 21 ++-- go.sum | 218 +++--------------------------------------- pipe/bet_stop.go | 2 +- pipe/bet_stop_test.go | 2 +- pipe/fixture.go | 2 +- pipe/fixture_test.go | 2 +- pipe/market.go | 2 +- pipe/market_test.go | 2 +- pipe/pipe.go | 2 +- pipe/player.go | 2 +- pipe/player_test.go | 2 +- pipe/recovery.go | 2 +- pipe/recovery_test.go | 2 +- pipe/store.go | 2 +- queue/queue.go | 2 +- queue/reconnect.go | 2 +- sdk/sdk.go | 8 +- 24 files changed, 60 insertions(+), 241 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2ce216d..3494f9a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: go -go_import_path: github.com/minus5/go-uof-sdk +go_import_path: github.com/pvotal-tech/go-uof-sdk os: - linux - osx diff --git a/api/api.go b/api/api.go index a55f64f..8de48f0 100644 --- a/api/api.go +++ b/api/api.go @@ -11,7 +11,7 @@ import ( "time" "github.com/hashicorp/go-retryablehttp" - "github.com/minus5/go-uof-sdk" + "github.com/pvotal-tech/go-uof-sdk" ) const ( diff --git a/api/api_test.go b/api/api_test.go index 6196edd..ddf10bf 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -9,7 +9,7 @@ import ( "testing" "time" - "github.com/minus5/go-uof-sdk" + "github.com/pvotal-tech/go-uof-sdk" "github.com/stretchr/testify/assert" ) diff --git a/api/replay.go b/api/replay.go index 31b8035..a60ca93 100644 --- a/api/replay.go +++ b/api/replay.go @@ -3,7 +3,7 @@ package api import ( "context" - "github.com/minus5/go-uof-sdk" + "github.com/pvotal-tech/go-uof-sdk" ) // replay api paths diff --git a/api/sports.go b/api/sports.go index d060138..329b558 100644 --- a/api/sports.go +++ b/api/sports.go @@ -4,7 +4,7 @@ import ( "encoding/xml" "time" - "github.com/minus5/go-uof-sdk" + "github.com/pvotal-tech/go-uof-sdk" ) const ( diff --git a/cmd/client/main.go b/cmd/client/main.go index d1d6c8a..c5561dc 100644 --- a/cmd/client/main.go +++ b/cmd/client/main.go @@ -14,9 +14,9 @@ import ( "syscall" "time" - "github.com/minus5/go-uof-sdk" - "github.com/minus5/go-uof-sdk/pipe" - "github.com/minus5/go-uof-sdk/sdk" + "github.com/pvotal-tech/go-uof-sdk" + "github.com/pvotal-tech/go-uof-sdk/pipe" + "github.com/pvotal-tech/go-uof-sdk/sdk" ) const ( diff --git a/cmd/replay/main.go b/cmd/replay/main.go index c421517..035cd59 100644 --- a/cmd/replay/main.go +++ b/cmd/replay/main.go @@ -12,10 +12,10 @@ import ( "net/http" _ "net/http/pprof" - "github.com/minus5/go-uof-sdk" - "github.com/minus5/go-uof-sdk/api" - "github.com/minus5/go-uof-sdk/pipe" - "github.com/minus5/go-uof-sdk/sdk" + "github.com/pvotal-tech/go-uof-sdk" + "github.com/pvotal-tech/go-uof-sdk/api" + "github.com/pvotal-tech/go-uof-sdk/pipe" + "github.com/pvotal-tech/go-uof-sdk/sdk" ) const ( @@ -84,7 +84,7 @@ func main() { go debugHTTP() err := sdk.Run(exitSignal(), - sdk.Credentials(bookmakerID, token), + sdk.Credentials(bookmakerID, token, 123), sdk.Languages(uof.Languages("en,de,hr")), sdk.BufferedConsumer(pipe.FileStore(outputFolder), 1024), sdk.Callback(progress), diff --git a/go.mod b/go.mod index 0b1be28..f727354 100644 --- a/go.mod +++ b/go.mod @@ -1,11 +1,18 @@ -module github.com/minus5/go-uof-sdk +module github.com/pvotal-tech/go-uof-sdk -go 1.13 +go 1.20 require ( - github.com/cenkalti/backoff/v3 v3.0.0 - github.com/hashicorp/go-retryablehttp v0.7.0 - github.com/pkg/errors v0.8.1 - github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271 - github.com/stretchr/testify v1.3.0 + github.com/cenkalti/backoff/v3 v3.2.2 + github.com/hashicorp/go-retryablehttp v0.7.4 + github.com/pkg/errors v0.9.1 + github.com/streadway/amqp v1.1.0 + github.com/stretchr/testify v1.8.4 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 36e473c..bc4c14b 100644 --- a/go.sum +++ b/go.sum @@ -1,211 +1,23 @@ -code.gitea.io/git v0.0.0-20161201150107-214cb0f5ed1f/go.mod h1:QxW8xSkZtRc3m0XXCWT5Kx0Jqfzj92Id6ZFd9mOLs5c= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/NaySoftware/go-fcm v0.0.0-20190516140123-808e978ddcd2/go.mod h1:3qVrdgWvoMZMoRG+/nusrCNrcP4RYU4MWGv467XjqLI= -github.com/PuerkitoBio/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg= -github.com/Unix4ever/statsd v0.0.0-20160120230120-a8219f1fb9d8/go.mod h1:flll3wbNf1Qxq2GxIDF5x0IEnv0BvkBSbPSEsnW9I4Q= -github.com/Unknwon/com v0.0.0-20151008135407-28b053d5a292/go.mod h1:KYCjqMOeHpNuTOiFQU6WEcTG7poCJrUs0YgyHNtn1no= -github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= -github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go v1.19.40/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/benbjohnson/clock v0.0.0-20161215174838-7dc76406b6d3/go.mod h1:UMqtWQTnOe4byzwe7Zhwh8f8s+36uszN51sJrSIZlTE= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= -github.com/cactus/go-statsd-client/statsd v0.0.0-20190302225832-f5dd73501f04/go.mod h1:3/sdo8I67TaOslRGJ6FqQC/ynu+wg7H6IE4WYtr51hk= -github.com/cenk/backoff v2.1.1+incompatible/go.mod h1:7FtoeaSnHoZnmZzz47cM35Y9nSW7tNyaidugnHTaFDE= -github.com/cenkalti/backoff v2.1.1+incompatible h1:tKJnvO2kl0zmb/jA5UKAt4VoEVw1qxKWjE/Bpp46npY= -github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= -github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= -github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= -github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c= -github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= +github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/structs v0.0.0-20181010231757-878a968ab225/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= -github.com/fatih/structtag v1.0.0/go.mod h1:IKitwq45uXL/yqi5mYghiD3w9H6eTOvI9vnk8tXMphA= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/gavv/httpexpect v0.0.0-20190508062428-fe291071476b/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= -github.com/gljubojevic/gocron v0.0.0-20180316141728-8dbbdbc711a8/go.mod h1:BAGn1nVfGKiOXBa74k9OGyABkSOX8/JXXZpqRskotyI= -github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= -github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= -github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/ws v1.0.0/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/hashicorp/consul v1.4.4/go.mod h1:mFrjN1mfidgJfYP1xrJCF+AfRhr6Eaqhb2+sfyn/OOI= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-retryablehttp v0.7.0 h1:eu1EI/mbirUgP5C8hVsTNaGZreBDlYiwC1FZWkvQPQ4= -github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= -github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= -github.com/jasonlvhit/gocron v0.0.0-20190528055910-f996a843b48d/go.mod h1:rwi/esz/h+4oWLhbWWK7f6dtmgLzxeZhnwGr7MCsTNk= -github.com/jlaffaye/ftp v0.0.0-20161124134916-988909ab2823/go.mod h1:lli8NYPQOFy3O++YmYbqVgOcQ1JPCwdOy+5zSjKJ9qY= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/juju/ansiterm v0.0.0-20161107204639-35c59b9e0fe2/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU= -github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= -github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/koding/websocketproxy v0.0.0-20181220232114-7ed82d81a28c/go.mod h1:Nn5wlyECw3iJrzi0AhIWg+AJUb4PlRQVW4/3XHH1LZA= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lib/pq v0.0.0-20170810061220-e42267488fe3/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lunixbochs/vtclean v0.0.0-20170504063817-d14193dfc626/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= -github.com/lusis/go-slackbot v0.0.0-20180109053408-401027ccfef5/go.mod h1:c2mYKRyMb1BPkO5St0c/ps62L4S0W2NAkaTXj9qEI+0= -github.com/lusis/slack-test v0.0.0-20190426140909-c40012f20018/go.mod h1:sFlOUpQL1YcjhFVXhg1CG8ZASEs/Mf1oVb6H75JL/zg= -github.com/manifoldco/promptui v0.0.0-20171212205406-abacd3cb3a43/go.mod h1:zoCNXiJnyM03LlBgTsWv8mq28s7aTC71UgKasqRJHww= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75/go.mod h1:76rfSfYPWj01Z85hUf/ituArm797mNKcvINh1OlsZKo= -github.com/mhale/smtpd v0.0.0-20181125220505-3c4c908952b8/go.mod h1:qqKwvL5sfYgFxcMy96Kjx3TCorMfDaQBvmEL2nvdidc= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.6/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/minus5/go-simplejson v0.5.1-0.20190518182223-8af509724a86 h1:bsm6+lQ2ea4dD6ZzGCz6GHXxmfU0ludQ4Cjxm7h/D9o= -github.com/minus5/go-simplejson v0.5.1-0.20190518182223-8af509724a86/go.mod h1:eBPLk8FJ9uc035DnbHAWvINeYXIIVduZe5EILao6s7o= -github.com/minus5/gofreetds v0.0.0-20180326091651-052917677671/go.mod h1:WvwUDnIBzwSEfXYkuvWQ+mKYt7Ja7I2uI1o5WoAotk4= -github.com/minus5/nsqm v0.0.0-20180124131437-bb786a0943ff/go.mod h1:f4aunz6tiHF4wpOnciBu470/Fk8X6omiODKCJKwGnpg= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= -github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/moul/http2curl v0.0.0-20181227153905-faeffb355356/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= -github.com/nlopes/slack v0.5.0/go.mod h1:jVI4BBK3lSktibKahxBF74txcK2vyvkza1z/+rRnVAM= -github.com/nranchev/go-libGeoIP v0.0.0-20170629073846-d6d4a9a4c7e8/go.mod h1:CSS25pAr1pT+qxFdpFZIJFHraF4zZfZYeFirlVvLXb4= -github.com/nsqio/go-nsq v1.0.7/go.mod h1:XP5zaUs3pqf+Q71EqUJs3HYfBIqfK6G83WQMdNN+Ito= -github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ= -github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= -github.com/peterbourgon/g2s v0.0.0-20170223122336-d4e7ad98afea/go.mod h1:1VcHEd3ro4QMoHfiNl/j7Jkln9+KQuorp0PItHMJYNg= -github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ= -github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.8.3/go.mod h1:NxmoDg/QLVWluQDUYG7XBZTLUpKeFa8e3aMf1BfjyHk= +github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA= +github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/quipo/statsd v0.0.0-20180118161217-3d6a5565f314/go.mod h1:1COUodqytMiv/GkAVUGhc0CA6e8xak5U4551TY7iEe0= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/smira/go-statsd v1.2.1/go.mod h1:EeOJShgQdCLKihNKZrhYf9918MStmI2ueQ4I1kVSTFA= -github.com/streadway/amqp v0.0.0-20161224082040-63795daa9a44/go.mod h1:1WNBiOZtZQLpVAyu0iTduoJL9hEsMloAK5XWrtW0xdY= -github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271 h1:WhxRHzgeVGETMlmVfqhRn8RIeeNoPr2Czh33I4Zdccw= -github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/streadway/amqp v1.1.0 h1:py12iX8XSyI7aN/3dUT8DFIDJazNJsVJdxNVEpnQTZM= +github.com/streadway/amqp v1.1.0/go.mod h1:WYSrTEYHOXHd0nwFeUXAe2G2hRnQT+deZJJf88uS9Bg= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stvp/go-toml-config v0.0.0-20170523163211-314328849d78/go.mod h1:mSfXi8twSmH/vUuE3J+HRfI2fp8XmWxVhYsV+V6W1JY= -github.com/tinylib/msgp v1.1.0 h1:9fQd+ICuRIu/ue4vxJZu6/LzxN0HwMds2nq/0cFvxHU= -github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= -github.com/tv42/topic v0.0.0-20130729201830-aa72cbe81b48/go.mod h1:b4JA15yUof03YRQ6IiKevPk2syaMBMJb92x9PeyU+Xc= -github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v0.0.0-20190506155449-f544170d6384/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk8LWSxF3s= -github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v0.0.0-20190423132807-354ad34c2300/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= -github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= -github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= -github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= -github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190611141213-3f473d35a33a h1:+KkCgOMgnKSgenxTBoiwkMqTiouMIy/3o8RLdmSbGoY= -golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190322080309-f49334f85ddc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -gopkg.in/alexcesaro/statsd.v2 v2.0.0/go.mod h1:i0ubccKGzBVNBpdGV5MocxyA/XlLUJzA7SLonnE4drU= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/mcuadros/go-syslog.v2 v2.2.1/go.mod h1:l5LPIyOOyIdQquNg+oU6Z3524YwrcqEm0aKH+5zpt2U= -gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -mvdan.cc/xurls/v2 v2.0.0/go.mod h1:2/webFPYOXN9jp/lzuj0zuAVlF+9g4KPFJANH1oJhRU= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/pipe/bet_stop.go b/pipe/bet_stop.go index e4eb4d1..ec10f05 100644 --- a/pipe/bet_stop.go +++ b/pipe/bet_stop.go @@ -5,7 +5,7 @@ import ( "math" "sort" - "github.com/minus5/go-uof-sdk" + "github.com/pvotal-tech/go-uof-sdk" ) func marketGroups() map[string][]int { diff --git a/pipe/bet_stop_test.go b/pipe/bet_stop_test.go index a49f00e..111ac74 100644 --- a/pipe/bet_stop_test.go +++ b/pipe/bet_stop_test.go @@ -3,7 +3,7 @@ package pipe import ( "testing" - "github.com/minus5/go-uof-sdk" + "github.com/pvotal-tech/go-uof-sdk" "github.com/stretchr/testify/assert" ) diff --git a/pipe/fixture.go b/pipe/fixture.go index 03c563d..56f8987 100644 --- a/pipe/fixture.go +++ b/pipe/fixture.go @@ -4,7 +4,7 @@ import ( "sync" "time" - "github.com/minus5/go-uof-sdk" + "github.com/pvotal-tech/go-uof-sdk" ) type fixtureAPI interface { diff --git a/pipe/fixture_test.go b/pipe/fixture_test.go index cb9542b..e9705af 100644 --- a/pipe/fixture_test.go +++ b/pipe/fixture_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "github.com/minus5/go-uof-sdk" + "github.com/pvotal-tech/go-uof-sdk" "github.com/stretchr/testify/assert" ) diff --git a/pipe/market.go b/pipe/market.go index 3a342a9..f84359e 100644 --- a/pipe/market.go +++ b/pipe/market.go @@ -5,7 +5,7 @@ import ( "sync" "time" - "github.com/minus5/go-uof-sdk" + "github.com/pvotal-tech/go-uof-sdk" ) type marketsAPI interface { diff --git a/pipe/market_test.go b/pipe/market_test.go index cd8e34d..c458820 100644 --- a/pipe/market_test.go +++ b/pipe/market_test.go @@ -5,7 +5,7 @@ import ( "sync" "testing" - "github.com/minus5/go-uof-sdk" + "github.com/pvotal-tech/go-uof-sdk" "github.com/stretchr/testify/assert" ) diff --git a/pipe/pipe.go b/pipe/pipe.go index 0ff0c60..9d4f14c 100644 --- a/pipe/pipe.go +++ b/pipe/pipe.go @@ -4,7 +4,7 @@ import ( "sync" "time" - "github.com/minus5/go-uof-sdk" + "github.com/pvotal-tech/go-uof-sdk" ) // Number of concurent api calls of one type. For example: no more than x diff --git a/pipe/player.go b/pipe/player.go index 1342a97..f657dcd 100644 --- a/pipe/player.go +++ b/pipe/player.go @@ -4,7 +4,7 @@ import ( "sync" "time" - "github.com/minus5/go-uof-sdk" + "github.com/pvotal-tech/go-uof-sdk" ) type playerAPI interface { diff --git a/pipe/player_test.go b/pipe/player_test.go index 59765b9..18e8032 100644 --- a/pipe/player_test.go +++ b/pipe/player_test.go @@ -5,7 +5,7 @@ import ( "sync" "testing" - "github.com/minus5/go-uof-sdk" + "github.com/pvotal-tech/go-uof-sdk" "github.com/stretchr/testify/assert" ) diff --git a/pipe/recovery.go b/pipe/recovery.go index 46f8344..2f9867a 100644 --- a/pipe/recovery.go +++ b/pipe/recovery.go @@ -6,7 +6,7 @@ import ( "sync" "time" - "github.com/minus5/go-uof-sdk" + "github.com/pvotal-tech/go-uof-sdk" ) // on start recover all after timestamp or full diff --git a/pipe/recovery_test.go b/pipe/recovery_test.go index 9f93bfe..96b4b11 100644 --- a/pipe/recovery_test.go +++ b/pipe/recovery_test.go @@ -3,7 +3,7 @@ package pipe import ( "testing" - "github.com/minus5/go-uof-sdk" + "github.com/pvotal-tech/go-uof-sdk" "github.com/stretchr/testify/assert" ) diff --git a/pipe/store.go b/pipe/store.go index 7b4d7b1..4b312bd 100644 --- a/pipe/store.go +++ b/pipe/store.go @@ -8,7 +8,7 @@ import ( "os" "sync" - "github.com/minus5/go-uof-sdk" + "github.com/pvotal-tech/go-uof-sdk" ) func InnerFileStore(root string) InnerStage { diff --git a/queue/queue.go b/queue/queue.go index 22076a1..a3aeffb 100644 --- a/queue/queue.go +++ b/queue/queue.go @@ -10,7 +10,7 @@ import ( "crypto/tls" "fmt" - "github.com/minus5/go-uof-sdk" + "github.com/pvotal-tech/go-uof-sdk" "github.com/streadway/amqp" ) diff --git a/queue/reconnect.go b/queue/reconnect.go index a57a28f..3be779d 100644 --- a/queue/reconnect.go +++ b/queue/reconnect.go @@ -5,7 +5,7 @@ import ( "time" "github.com/cenkalti/backoff/v3" - "github.com/minus5/go-uof-sdk" + "github.com/pvotal-tech/go-uof-sdk" "github.com/pkg/errors" ) diff --git a/sdk/sdk.go b/sdk/sdk.go index b7193ed..e707a8a 100644 --- a/sdk/sdk.go +++ b/sdk/sdk.go @@ -4,10 +4,10 @@ import ( "context" "time" - "github.com/minus5/go-uof-sdk" - "github.com/minus5/go-uof-sdk/api" - "github.com/minus5/go-uof-sdk/pipe" - "github.com/minus5/go-uof-sdk/queue" + "github.com/pvotal-tech/go-uof-sdk" + "github.com/pvotal-tech/go-uof-sdk/api" + "github.com/pvotal-tech/go-uof-sdk/pipe" + "github.com/pvotal-tech/go-uof-sdk/queue" ) var defaultLanguages = uof.Languages("en,de") From be7952cc6debfa07746eb9beaac1f7b0da0aa4ff Mon Sep 17 00:00:00 2001 From: Christopher Ganga Date: Mon, 7 Aug 2023 16:06:22 +0200 Subject: [PATCH 05/26] feat(PVO-311): add specifier parsing --- go.mod | 1 + go.sum | 2 + specifier.go | 119 +++++++++++++++++++++++++++++++++++++++++ speficier_test.go | 132 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 254 insertions(+) create mode 100644 specifier.go create mode 100644 speficier_test.go diff --git a/go.mod b/go.mod index f727354..68b698a 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( require ( github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index bc4c14b..65c16c3 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTx github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= diff --git a/specifier.go b/specifier.go new file mode 100644 index 0000000..3fa5bdc --- /dev/null +++ b/specifier.go @@ -0,0 +1,119 @@ +package uof + +import ( + "fmt" + "strconv" + "strings" + + "github.com/dustin/go-humanize" +) + +func ParseSpecifier(name string, specifiers map[string]string, players map[int]Player, fixture Fixture) (string, error) { + for key, val := range specifiers { + switch { + case strings.Contains(name, "{"+key+"}"): + name = strings.ReplaceAll(name, "{"+key+"}", val) + case strings.Contains(name, "{!"+key+"}"): + intVal, err := strconv.Atoi(val) + if err != nil { + return "", fmt.Errorf("invalid number in specifier with ordinal operator: %s", val) + } + name = strings.ReplaceAll(name, "{!"+key+"}", humanize.Ordinal(intVal)) + case strings.Contains(name, "{"+key+"-"): + i := strings.Index(name, "{"+key+"-") + j := strings.Index(name[i:], "}") + i + nStr := name[i+len(key)+2 : j] + n, err := strconv.Atoi(nStr) + if err != nil { + return "", fmt.Errorf("invalid number in name with sub(-) specifier: %s", name) + } + intVal, err := strconv.Atoi(val) + if err != nil { + return "", fmt.Errorf("invalid number in specifier with sub(-) operator: %s", val) + } + result := intVal - n + name = name[:i] + strconv.Itoa(result) + name[j+1:] + case strings.Contains(name, "{"+key+"+"): + i := strings.Index(name, "{"+key+"+") + j := strings.Index(name[i:], "}") + i + nStr := name[i+len(key)+2 : j] + n, err := strconv.Atoi(nStr) + if err != nil { + return "", fmt.Errorf("invalid number in name with sum(+) specifier: %s", name) + } + intVal, err := strconv.Atoi(val) + if err != nil { + return "", fmt.Errorf("invalid number in specifier with sum(+) operator: %s", val) + } + result := intVal + n + name = name[:i] + strconv.Itoa(result) + name[j+1:] + case strings.Contains(name, "{!"+key+"-"): + i := strings.Index(name, "{!"+key+"-") + j := strings.Index(name[i:], "}") + i + nStr := name[i+len(key)+3 : j] + n, err := strconv.Atoi(nStr) + if err != nil { + return "", fmt.Errorf("invalid number in name with sub(-) ordinal specifier: %s", name) + } + intVal, err := strconv.Atoi(val) + if err != nil { + return "", fmt.Errorf("invalid number in specifier with sub(-) ordinal operator: %s", val) + } + result := intVal - n + name = name[:i] + humanize.Ordinal(result) + name[j+1:] + case strings.Contains(name, "{!"+key+"+"): + i := strings.Index(name, "{!"+key+"+") + j := strings.Index(name[i:], "}") + i + nStr := name[i+len(key)+3 : j] + n, err := strconv.Atoi(nStr) + if err != nil { + return "", fmt.Errorf("invalid number in name with sum(+) ordinal specifier: %s", name) + } + intVal, err := strconv.Atoi(val) + if err != nil { + return "", fmt.Errorf("invalid number in specifier with sum(+) ordinal operator: %s", val) + } + result := intVal + n + name = name[:i] + humanize.Ordinal(result) + name[j+1:] + case strings.Contains(name, "{+"+key+"}"): + i := strings.Index(name, "{") + j := strings.Index(name[i:], "}") + i + intVal, err := strconv.Atoi(val) + if err != nil { + return "", fmt.Errorf("invalid number in specifier with signed operator: %s", val) + } + name = name[:i] + "+" + strconv.Itoa(intVal) + name[j+1:] + case strings.Contains(name, "{-"+key+"}"): + i := strings.Index(name, "{") + j := strings.Index(name[i:], "}") + i + intVal, err := strconv.Atoi(val) + if err != nil { + return "", fmt.Errorf("invalid number in specifier with signed operator: %s", val) + } + name = name[:i] + "-" + strconv.Itoa(intVal) + name[j+1:] + case strings.Contains(name, "{%player}"): + playerID := URN(val).ID() + player, ok := players[playerID] + if !ok { + return "", fmt.Errorf("player with id %d not found", playerID) + } + name = strings.ReplaceAll(name, "{%player}", player.FullName) + case strings.Contains(name, "{$event}"): + name = strings.ReplaceAll(name, "{$event}", fixture.Name) + case strings.Contains(name, "{$competitor"): + i := strings.Index(name, "{$competitor") + j := strings.Index(name[i:], "}") + i + index := name[i+len("{$competitor") : j] + indexInt, err := strconv.Atoi(index) + if err != nil { + return "", fmt.Errorf("invalid number in specifier with competitor operator: %s", index) + } + if indexInt > len(fixture.Competitors) { + return "", fmt.Errorf("invalid number in specifier with competitor operator: %s", index) + } + competitor := fixture.Competitors[indexInt-1] + name = name[:i] + competitor.Name + name[j+1:] + } + } + return name, nil +} diff --git a/speficier_test.go b/speficier_test.go new file mode 100644 index 0000000..1c75497 --- /dev/null +++ b/speficier_test.go @@ -0,0 +1,132 @@ +package uof + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestParseNameWithSpecifier(t *testing.T) { + players := map[int]Player{ + 1234: Player{ + FullName: "John Rodriquez", + }, + } + fixture := Fixture{ + Name: "Euro2016", + Competitors: []Competitor{ + { + Name: "France", + }, + { + Name: "Germany", + }, + }, + } + + testCases := []struct { + description string + name string + specifiers map[string]string + expected string + }{ + { + description: "Replace {X} with value of specifier", + name: "Race to {pointnr} points", + specifiers: map[string]string{"pointnr": "3"}, + expected: "Race to 3 points", + }, + { + description: "Replace {!X} with the ordinal value of specifier X", + name: "{!periodnr} period - total", + specifiers: map[string]string{"periodnr": "2"}, + expected: "2nd period - total", + }, + { + description: "(-) Replace {X+/-c} with the value of the specifier X + or - the number c", + name: "Score difference {pointnr-3}", + specifiers: map[string]string{"pointnr": "10"}, + expected: "Score difference 7", + }, + { + description: "(+) Replace {X+/-c} with the value of the specifier X + or - the number c", + name: "Score difference {pointnr+3}", + specifiers: map[string]string{"pointnr": "10"}, + expected: "Score difference 13", + }, + { + description: "(-) Replace {!X+c} with the ordinal value of specifier X + c", + name: "{!inningnr-1} inning", + specifiers: map[string]string{"inningnr": "2"}, + expected: "1st inning", + }, + { + description: "Replace {!X+c} with the ordinal value of specifier X + c", + name: "{!inningnr+1} inning", + specifiers: map[string]string{"inningnr": "2"}, + expected: "3rd inning", + }, + { + description: "Replace {+X} with the value of specifier X with a +/- sign in front", + name: "Goal Diff {+goals} goals", + specifiers: map[string]string{"goals": "2"}, + expected: "Goal Diff +2 goals", + }, + { + description: "Replace {-X} with the negated value of the specifier with a +/- sign in front", + name: "Goal Diff {-goals} goals", + specifiers: map[string]string{"goals": "2"}, + expected: "Goal Diff -2 goals", + }, + { + description: "Name with 2 normal specifiers", + name: "Holes {from} to {to} - head2head (1x2) groups", + specifiers: map[string]string{"from": "1", "to": "18"}, // {"from":"1", "to":"18"}, + expected: "Holes 1 to 18 - head2head (1x2) groups", + }, + { + description: "Name with 1 normal, 1 ordinal specifier", + name: "{!periodnr} period - {pointnr+3} points", + specifiers: map[string]string{"periodnr": "2", "pointnr": "10"}, + expected: "2nd period - 13 points", + }, + { + description: "Name with 1 ordinal, 1 +/- specifier", + name: "{!half} half, {+goals} goals", + specifiers: map[string]string{"half": "1", "goals": "2"}, + expected: "1st half, +2 goals", + }, + { + description: "Replace {%player} with name of specifier", + name: "{%player} total dismissals", + specifiers: map[string]string{"player": "sr:player:1234"}, + expected: "John Rodriquez total dismissals", + }, + { + description: "Player with 1 normal, 1 ordinal specifier", + name: "{!half} half - {%player} {goals} goals", + specifiers: map[string]string{"half": "1", "player": "sr:player:1234", "goals": "2"}, + expected: "1st half - John Rodriquez 2 goals", + }, + { + description: "Replace {$event} with the name of the event", + name: "Winner of {$event}", + specifiers: map[string]string{"event": "sr:tournament:1"}, + expected: "Winner of Euro2016", + }, + { + description: "Replace {$competitorN} with the Nth competitor in the event", + name: "Winner is {$competitor2}", + specifiers: map[string]string{"competitor1": "sr:competitor:2"}, + expected: "Winner is Germany", + }, + } + + for _, tc := range testCases { + t.Run(tc.description, func(t *testing.T) { + actual, err := ParseSpecifier(tc.name, tc.specifiers, players, fixture) + assert.NoError(t, err) + assert.Equal(t, tc.expected, actual) + }) + } +} From 124b8ec1c1f965520313f0af942cf5979e2542b5 Mon Sep 17 00:00:00 2001 From: Christopher Ganga Date: Mon, 7 Aug 2023 16:09:56 +0200 Subject: [PATCH 06/26] chore: rename files --- specifier.go => specifiers.go | 2 +- speficier_test.go => speficiers_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename specifier.go => specifiers.go (97%) rename speficier_test.go => speficiers_test.go (96%) diff --git a/specifier.go b/specifiers.go similarity index 97% rename from specifier.go rename to specifiers.go index 3fa5bdc..848d331 100644 --- a/specifier.go +++ b/specifiers.go @@ -8,7 +8,7 @@ import ( "github.com/dustin/go-humanize" ) -func ParseSpecifier(name string, specifiers map[string]string, players map[int]Player, fixture Fixture) (string, error) { +func ParseSpecifiers(name string, specifiers map[string]string, players map[int]Player, fixture Fixture) (string, error) { for key, val := range specifiers { switch { case strings.Contains(name, "{"+key+"}"): diff --git a/speficier_test.go b/speficiers_test.go similarity index 96% rename from speficier_test.go rename to speficiers_test.go index 1c75497..a7f3b79 100644 --- a/speficier_test.go +++ b/speficiers_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/assert" ) -func TestParseNameWithSpecifier(t *testing.T) { +func TestParseNameWithSpecifiers(t *testing.T) { players := map[int]Player{ 1234: Player{ FullName: "John Rodriquez", @@ -124,7 +124,7 @@ func TestParseNameWithSpecifier(t *testing.T) { for _, tc := range testCases { t.Run(tc.description, func(t *testing.T) { - actual, err := ParseSpecifier(tc.name, tc.specifiers, players, fixture) + actual, err := ParseSpecifiers(tc.name, tc.specifiers, players, fixture) assert.NoError(t, err) assert.Equal(t, tc.expected, actual) }) From f95f32fe135c4892bb1257ee07c7f7bb14115abe Mon Sep 17 00:00:00 2001 From: Christopher Ganga Date: Mon, 7 Aug 2023 16:18:26 +0200 Subject: [PATCH 07/26] chore: remove comment --- speficiers_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/speficiers_test.go b/speficiers_test.go index a7f3b79..a471491 100644 --- a/speficiers_test.go +++ b/speficiers_test.go @@ -81,7 +81,7 @@ func TestParseNameWithSpecifiers(t *testing.T) { { description: "Name with 2 normal specifiers", name: "Holes {from} to {to} - head2head (1x2) groups", - specifiers: map[string]string{"from": "1", "to": "18"}, // {"from":"1", "to":"18"}, + specifiers: map[string]string{"from": "1", "to": "18"}, expected: "Holes 1 to 18 - head2head (1x2) groups", }, { From 34478774f81fd914caba800c03c2b5d61cbf3681 Mon Sep 17 00:00:00 2001 From: Christopher Ganga Date: Mon, 7 Aug 2023 18:23:22 +0200 Subject: [PATCH 08/26] fix(PVO-311): handle floats in specifiers --- specifiers.go | 20 ++++++++++---------- speficiers_test.go | 6 ++++++ 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/specifiers.go b/specifiers.go index 848d331..2764350 100644 --- a/specifiers.go +++ b/specifiers.go @@ -23,30 +23,30 @@ func ParseSpecifiers(name string, specifiers map[string]string, players map[int] i := strings.Index(name, "{"+key+"-") j := strings.Index(name[i:], "}") + i nStr := name[i+len(key)+2 : j] - n, err := strconv.Atoi(nStr) + n, err := strconv.ParseFloat(nStr, 32) if err != nil { return "", fmt.Errorf("invalid number in name with sub(-) specifier: %s", name) } - intVal, err := strconv.Atoi(val) + intVal, err := strconv.ParseFloat(val, 32) if err != nil { return "", fmt.Errorf("invalid number in specifier with sub(-) operator: %s", val) } result := intVal - n - name = name[:i] + strconv.Itoa(result) + name[j+1:] + name = name[:i] + fmt.Sprint(result) + name[j+1:] case strings.Contains(name, "{"+key+"+"): i := strings.Index(name, "{"+key+"+") j := strings.Index(name[i:], "}") + i nStr := name[i+len(key)+2 : j] - n, err := strconv.Atoi(nStr) + n, err := strconv.ParseFloat(nStr, 32) if err != nil { return "", fmt.Errorf("invalid number in name with sum(+) specifier: %s", name) } - intVal, err := strconv.Atoi(val) + intVal, err := strconv.ParseFloat(val, 32) if err != nil { return "", fmt.Errorf("invalid number in specifier with sum(+) operator: %s", val) } result := intVal + n - name = name[:i] + strconv.Itoa(result) + name[j+1:] + name = name[:i] + fmt.Sprint(result) + name[j+1:] case strings.Contains(name, "{!"+key+"-"): i := strings.Index(name, "{!"+key+"-") j := strings.Index(name[i:], "}") + i @@ -78,19 +78,19 @@ func ParseSpecifiers(name string, specifiers map[string]string, players map[int] case strings.Contains(name, "{+"+key+"}"): i := strings.Index(name, "{") j := strings.Index(name[i:], "}") + i - intVal, err := strconv.Atoi(val) + value, err := strconv.ParseFloat(val, 32) if err != nil { return "", fmt.Errorf("invalid number in specifier with signed operator: %s", val) } - name = name[:i] + "+" + strconv.Itoa(intVal) + name[j+1:] + name = name[:i] + "+" + fmt.Sprint(value) + name[j+1:] case strings.Contains(name, "{-"+key+"}"): i := strings.Index(name, "{") j := strings.Index(name[i:], "}") + i - intVal, err := strconv.Atoi(val) + value, err := strconv.ParseFloat(val, 32) if err != nil { return "", fmt.Errorf("invalid number in specifier with signed operator: %s", val) } - name = name[:i] + "-" + strconv.Itoa(intVal) + name[j+1:] + name = name[:i] + "-" + fmt.Sprint(value) + name[j+1:] case strings.Contains(name, "{%player}"): playerID := URN(val).ID() player, ok := players[playerID] diff --git a/speficiers_test.go b/speficiers_test.go index a471491..68edf20 100644 --- a/speficiers_test.go +++ b/speficiers_test.go @@ -120,6 +120,12 @@ func TestParseNameWithSpecifiers(t *testing.T) { specifiers: map[string]string{"competitor1": "sr:competitor:2"}, expected: "Winner is Germany", }, + { + description: "Replace {X} with value of specifier for decimals", + name: "{!periodnr} period - total {pointnr} points", + specifiers: map[string]string{"periodnr": "3", "pointnr": "3.5"}, + expected: "3rd period - total 3.5 points", + }, } for _, tc := range testCases { From 1768883339b6d0e28575b64ccef1461d688a2dfe Mon Sep 17 00:00:00 2001 From: Christopher Ganga Date: Tue, 8 Aug 2023 10:01:59 +0200 Subject: [PATCH 09/26] feat(PVO-311): fix competitor parsing --- specifiers.go | 39 ++++++++++++++++++++++++--------------- speficiers_test.go | 12 +++++++++--- 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/specifiers.go b/specifiers.go index 2764350..260aeb8 100644 --- a/specifiers.go +++ b/specifiers.go @@ -8,7 +8,31 @@ import ( "github.com/dustin/go-humanize" ) +func parseCompetitor(name string, fixture Fixture) (string, error) { + if !strings.Contains(name, "{$competitor") { + return name, nil + } + i := strings.Index(name, "{$competitor") + j := strings.Index(name[i:], "}") + i + index := name[i+len("{$competitor") : j] + indexInt, err := strconv.Atoi(index) + if err != nil { + return "", fmt.Errorf("invalid number in specifier with competitor operator: %s", index) + } + if indexInt > len(fixture.Competitors) { + return "", fmt.Errorf("invalid number in specifier with competitor operator: %s", index) + } + competitor := fixture.Competitors[indexInt-1] + name = name[:i] + competitor.Name + name[j+1:] + return parseCompetitor(name, fixture) +} + func ParseSpecifiers(name string, specifiers map[string]string, players map[int]Player, fixture Fixture) (string, error) { + name = strings.ReplaceAll(name, "{$event}", fixture.Name) + name, err := parseCompetitor(name, fixture) + if err != nil { + return "", err + } for key, val := range specifiers { switch { case strings.Contains(name, "{"+key+"}"): @@ -98,21 +122,6 @@ func ParseSpecifiers(name string, specifiers map[string]string, players map[int] return "", fmt.Errorf("player with id %d not found", playerID) } name = strings.ReplaceAll(name, "{%player}", player.FullName) - case strings.Contains(name, "{$event}"): - name = strings.ReplaceAll(name, "{$event}", fixture.Name) - case strings.Contains(name, "{$competitor"): - i := strings.Index(name, "{$competitor") - j := strings.Index(name[i:], "}") + i - index := name[i+len("{$competitor") : j] - indexInt, err := strconv.Atoi(index) - if err != nil { - return "", fmt.Errorf("invalid number in specifier with competitor operator: %s", index) - } - if indexInt > len(fixture.Competitors) { - return "", fmt.Errorf("invalid number in specifier with competitor operator: %s", index) - } - competitor := fixture.Competitors[indexInt-1] - name = name[:i] + competitor.Name + name[j+1:] } } return name, nil diff --git a/speficiers_test.go b/speficiers_test.go index 68edf20..2d6a7a2 100644 --- a/speficiers_test.go +++ b/speficiers_test.go @@ -111,13 +111,13 @@ func TestParseNameWithSpecifiers(t *testing.T) { { description: "Replace {$event} with the name of the event", name: "Winner of {$event}", - specifiers: map[string]string{"event": "sr:tournament:1"}, + specifiers: nil, expected: "Winner of Euro2016", }, { - description: "Replace {$competitorN} with the Nth competitor in the event", + description: "Replace {$competitorN} with the Nth competitor in the event (empty map)", name: "Winner is {$competitor2}", - specifiers: map[string]string{"competitor1": "sr:competitor:2"}, + specifiers: nil, expected: "Winner is Germany", }, { @@ -126,6 +126,12 @@ func TestParseNameWithSpecifiers(t *testing.T) { specifiers: map[string]string{"periodnr": "3", "pointnr": "3.5"}, expected: "3rd period - total 3.5 points", }, + { + description: "2 Competitor with goals", + name: "{$competitor1}, {$competitor2} exact corners {cornernr}", + specifiers: map[string]string{"cornernr": "2"}, + expected: "France, Germany exact corners 2", + }, } for _, tc := range testCases { From 087e3e1c2eca8507d7fa1ffc5c43fe245c5060d7 Mon Sep 17 00:00:00 2001 From: Christopher Ganga Date: Tue, 8 Aug 2023 10:04:03 +0200 Subject: [PATCH 10/26] chore: fix typo --- speficiers_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/speficiers_test.go b/speficiers_test.go index 2d6a7a2..d9ddd7c 100644 --- a/speficiers_test.go +++ b/speficiers_test.go @@ -127,7 +127,7 @@ func TestParseNameWithSpecifiers(t *testing.T) { expected: "3rd period - total 3.5 points", }, { - description: "2 Competitor with goals", + description: "2 Competitor with corners", name: "{$competitor1}, {$competitor2} exact corners {cornernr}", specifiers: map[string]string{"cornernr": "2"}, expected: "France, Germany exact corners 2", From 248c333542c837258ea6cb21641fe91c9722ae52 Mon Sep 17 00:00:00 2001 From: Guillermo Mugnaini Date: Tue, 8 Aug 2023 13:38:21 -0300 Subject: [PATCH 11/26] feat(pvo-344): market player pipes sync --- pipe/market.go | 4 ++-- pipe/player.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pipe/market.go b/pipe/market.go index f84359e..7f02209 100644 --- a/pipe/market.go +++ b/pipe/market.go @@ -56,7 +56,7 @@ func (s *markets) getAll() { requestedAt := uof.CurrentTimestamp() for _, lang := range s.languages { - go func(lang uof.Lang) { + func(lang uof.Lang) { defer s.subProcs.Done() ms, err := s.api.Markets(lang) @@ -77,7 +77,7 @@ func (s *markets) variantMarket(marketID int, variant string, requestedAt int) { s.subProcs.Add(len(s.languages)) for _, lang := range s.languages { - go func(lang uof.Lang) { + func(lang uof.Lang) { defer s.subProcs.Done() s.rateLimit <- struct{}{} defer func() { <-s.rateLimit }() diff --git a/pipe/player.go b/pipe/player.go index f657dcd..61b20d8 100644 --- a/pipe/player.go +++ b/pipe/player.go @@ -49,7 +49,7 @@ func (p *player) loop(in <-chan *uof.Message, out chan<- *uof.Message, errc chan func (p *player) get(playerID, requestedAt int) { p.subProcs.Add(len(p.languages)) for _, lang := range p.languages { - go func(lang uof.Lang) { + func(lang uof.Lang) { defer p.subProcs.Done() p.rateLimit <- struct{}{} defer func() { <-p.rateLimit }() From f0d474f28ede1c1d3ebcca0c9ad2153c3d5eadea Mon Sep 17 00:00:00 2001 From: Guillermo Mugnaini Date: Tue, 8 Aug 2023 17:58:40 -0300 Subject: [PATCH 12/26] fix: remove prefix player urn specifier --- specifiers.go | 7 +++++-- speficiers_test.go | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/specifiers.go b/specifiers.go index 260aeb8..07a2258 100644 --- a/specifiers.go +++ b/specifiers.go @@ -116,8 +116,11 @@ func ParseSpecifiers(name string, specifiers map[string]string, players map[int] } name = name[:i] + "-" + fmt.Sprint(value) + name[j+1:] case strings.Contains(name, "{%player}"): - playerID := URN(val).ID() - player, ok := players[playerID] + playerID, err := strconv.ParseInt(val, 10, 0) + if err != nil { + return "", fmt.Errorf("error while parsing player id \"%s\"", val) + } + player, ok := players[int(playerID)] if !ok { return "", fmt.Errorf("player with id %d not found", playerID) } diff --git a/speficiers_test.go b/speficiers_test.go index d9ddd7c..f314dce 100644 --- a/speficiers_test.go +++ b/speficiers_test.go @@ -99,13 +99,13 @@ func TestParseNameWithSpecifiers(t *testing.T) { { description: "Replace {%player} with name of specifier", name: "{%player} total dismissals", - specifiers: map[string]string{"player": "sr:player:1234"}, + specifiers: map[string]string{"player": "1234"}, expected: "John Rodriquez total dismissals", }, { description: "Player with 1 normal, 1 ordinal specifier", name: "{!half} half - {%player} {goals} goals", - specifiers: map[string]string{"half": "1", "player": "sr:player:1234", "goals": "2"}, + specifiers: map[string]string{"half": "1", "player": "1234", "goals": "2"}, expected: "1st half - John Rodriquez 2 goals", }, { From bedebb196849b2d66fcd65a08b67066d768fb6c7 Mon Sep 17 00:00:00 2001 From: Guillermo Mugnaini Date: Tue, 8 Aug 2023 19:54:47 -0300 Subject: [PATCH 13/26] fix: add market 368 case --- specifiers.go | 2 +- speficiers_test.go | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/specifiers.go b/specifiers.go index 07a2258..6a03c22 100644 --- a/specifiers.go +++ b/specifiers.go @@ -115,7 +115,7 @@ func ParseSpecifiers(name string, specifiers map[string]string, players map[int] return "", fmt.Errorf("invalid number in specifier with signed operator: %s", val) } name = name[:i] + "-" + fmt.Sprint(value) + name[j+1:] - case strings.Contains(name, "{%player}"): + case strings.Contains(name, "{%player}") && key == "player": playerID, err := strconv.ParseInt(val, 10, 0) if err != nil { return "", fmt.Errorf("error while parsing player id \"%s\"", val) diff --git a/speficiers_test.go b/speficiers_test.go index f314dce..86c36d9 100644 --- a/speficiers_test.go +++ b/speficiers_test.go @@ -108,6 +108,12 @@ func TestParseNameWithSpecifiers(t *testing.T) { specifiers: map[string]string{"half": "1", "player": "1234", "goals": "2"}, expected: "1st half - John Rodriquez 2 goals", }, + { + description: "Market ID 368", + name: "{!inningnr} innings - {%player} total", + specifiers: map[string]string{"inningnr": "1", "maxovers": "20", "player": "1234", "playernr": "2", "total": "27.5"}, + expected: "1st innings - John Rodriquez total", + }, { description: "Replace {$event} with the name of the event", name: "Winner of {$event}", From 21be3862caaf3f5153fd00fb3fcd87887d707926 Mon Sep 17 00:00:00 2001 From: Guillermo Mugnaini Date: Wed, 9 Aug 2023 13:13:34 -0300 Subject: [PATCH 14/26] feat: custom server config --- api/api.go | 11 ++++++++++ queue/queue.go | 8 ++++++- sdk/sdk.go | 57 +++++++++++++++++++++++++++++++++++--------------- 3 files changed, 58 insertions(+), 18 deletions(-) diff --git a/api/api.go b/api/api.go index 8de48f0..740702f 100644 --- a/api/api.go +++ b/api/api.go @@ -78,6 +78,17 @@ func ProductionGlobal(exitSig context.Context, token string) (*API, error) { return a, a.Ping() } +// DialCustom connects to a custom system +func DialCustom(exitSig context.Context, customServer, token string) (*API, error) { + a := &API{ + server: customServer, + token: token, + exitSig: exitSig, + client: client(), + } + return a, a.Ping() +} + func client() *retryablehttp.Client { c := retryablehttp.NewClient() c.Logger = nil diff --git a/queue/queue.go b/queue/queue.go index a3aeffb..26e6855 100644 --- a/queue/queue.go +++ b/queue/queue.go @@ -9,6 +9,7 @@ import ( "context" "crypto/tls" "fmt" + "strings" "github.com/pvotal-tech/go-uof-sdk" "github.com/streadway/amqp" @@ -59,6 +60,11 @@ func DialReplay(ctx context.Context, bookmakerID, token string, nodeID int) (*Co return dial(ctx, replayServer, bookmakerID, token, nodeID) } +// DialCustom connects to a custom server +func DialCustom(ctx context.Context, server, bookmakerID, token string, nodeID int) (*Connection, error) { + return dial(ctx, server, bookmakerID, token, nodeID) +} + type Connection struct { msgs <-chan amqp.Delivery errs <-chan *amqp.Error @@ -120,7 +126,7 @@ func dial(ctx context.Context, server, bookmakerID, token string, nodeID int) (* } conn, err := amqp.DialTLS(addr, tls) if err != nil { - fmt.Println(addr) + fmt.Println(strings.ReplaceAll(addr, token, "")) return nil, uof.Notice("conn.Dial", err) } diff --git a/sdk/sdk.go b/sdk/sdk.go index e707a8a..c8cbc6e 100644 --- a/sdk/sdk.go +++ b/sdk/sdk.go @@ -17,16 +17,18 @@ type ErrorListenerFunc func(err error) // Config is active SDK configuration type Config struct { - BookmakerID string - Token string - NodeID int - Fixtures time.Time - Recovery []uof.ProducerChange - Stages []pipe.InnerStage - Replay func(*api.ReplayAPI) error - Env uof.Environment - Languages []uof.Lang - ErrorListener ErrorListenerFunc + CustomAMQPServer string + CustomAPIServer string + BookmakerID string + Token string + NodeID int + Fixtures time.Time + Recovery []uof.ProducerChange + Stages []pipe.InnerStage + Replay func(*api.ReplayAPI) error + Env uof.Environment + Languages []uof.Lang + ErrorListener ErrorListenerFunc } // Option sets attributes on the Config. @@ -98,15 +100,28 @@ func config(options ...Option) Config { // connect to the queue and api func connect(ctx context.Context, c Config) (*queue.Connection, *api.API, error) { - conn, err := queue.Dial(ctx, c.Env, c.BookmakerID, c.Token, c.NodeID) - if err != nil { - return nil, nil, err + var conn *queue.Connection + var amqpErr error + if c.CustomAMQPServer != "" { + conn, amqpErr = queue.DialCustom(ctx, c.CustomAMQPServer, c.BookmakerID, c.Token, c.NodeID) + } else { + conn, amqpErr = queue.Dial(ctx, c.Env, c.BookmakerID, c.Token, c.NodeID) } - stg, err := api.Dial(ctx, c.Env, c.Token) - if err != nil { - return nil, nil, err + if amqpErr != nil { + return nil, nil, amqpErr + } + + var apiConn *api.API + var apiErr error + if c.CustomAPIServer != "" { + apiConn, apiErr = api.DialCustom(ctx, c.CustomAPIServer, c.Token) + } else { + apiConn, apiErr = api.Dial(ctx, c.Env, c.Token) + } + if apiErr != nil { + return nil, nil, apiErr } - return conn, stg, nil + return conn, apiConn, nil } // Credentials for establishing connection to the uof queue and api. @@ -118,6 +133,14 @@ func Credentials(bookmakerID, token string, nodeID int) Option { } } +// CustomServers for establishing custom servers +func CustomServers(customAMQPServer, customAPIServer string) Option { + return func(c *Config) { + c.CustomAMQPServer = customAMQPServer + c.CustomAPIServer = customAPIServer + } +} + // Languages for api calls. // // Statefull messages (markets, players, fixtures) will be served in all this From 793763c0a236d1ded393573623a1b028faaaed04 Mon Sep 17 00:00:00 2001 From: Guillermo Mugnaini Date: Wed, 9 Aug 2023 20:06:10 -0300 Subject: [PATCH 15/26] feat(pvo-399): tls select amqp --- queue/queue.go | 54 ++++++++++++++++++++++++++++++++------------------ sdk/sdk.go | 12 +++++++++-- 2 files changed, 45 insertions(+), 21 deletions(-) diff --git a/queue/queue.go b/queue/queue.go index 26e6855..33541fe 100644 --- a/queue/queue.go +++ b/queue/queue.go @@ -9,7 +9,9 @@ import ( "context" "crypto/tls" "fmt" + "net" "strings" + "time" "github.com/pvotal-tech/go-uof-sdk" "github.com/streadway/amqp" @@ -22,47 +24,49 @@ const ( productionServerGlobal = "global.mq.betradar.com:5671" queueExchange = "unifiedfeed" bindingKeyAll = "#" + amqpDefaultHeartbeat = 10 * time.Second + amqpDefaultLocale = "en_US" ) // Dial connects to the queue chosen by environment -func Dial(ctx context.Context, env uof.Environment, bookmakerID, token string, nodeID int) (*Connection, error) { +func Dial(ctx context.Context, env uof.Environment, bookmakerID, token string, nodeID int, isTLS bool) (*Connection, error) { switch env { case uof.Replay: - return DialReplay(ctx, bookmakerID, token, nodeID) + return DialReplay(ctx, bookmakerID, token, nodeID, isTLS) case uof.Staging: - return DialStaging(ctx, bookmakerID, token, nodeID) + return DialStaging(ctx, bookmakerID, token, nodeID, isTLS) case uof.Production: - return DialProduction(ctx, bookmakerID, token, nodeID) + return DialProduction(ctx, bookmakerID, token, nodeID, isTLS) case uof.ProductionGlobal: - return DialProductionGlobal(ctx, bookmakerID, token, nodeID) + return DialProductionGlobal(ctx, bookmakerID, token, nodeID, isTLS) default: return nil, uof.Notice("queue dial", fmt.Errorf("unknown environment %d", env)) } } // Dial connects to the production queue -func DialProduction(ctx context.Context, bookmakerID, token string, nodeID int) (*Connection, error) { - return dial(ctx, productionServer, bookmakerID, token, nodeID) +func DialProduction(ctx context.Context, bookmakerID, token string, nodeID int, isTLS bool) (*Connection, error) { + return dial(ctx, productionServer, bookmakerID, token, nodeID, isTLS) } // Dial connects to the production queue -func DialProductionGlobal(ctx context.Context, bookmakerID, token string, nodeID int) (*Connection, error) { - return dial(ctx, productionServerGlobal, bookmakerID, token, nodeID) +func DialProductionGlobal(ctx context.Context, bookmakerID, token string, nodeID int, isTLS bool) (*Connection, error) { + return dial(ctx, productionServerGlobal, bookmakerID, token, nodeID, isTLS) } // DialStaging connects to the staging queue -func DialStaging(ctx context.Context, bookmakerID, token string, nodeID int) (*Connection, error) { - return dial(ctx, stagingServer, bookmakerID, token, nodeID) +func DialStaging(ctx context.Context, bookmakerID, token string, nodeID int, isTLS bool) (*Connection, error) { + return dial(ctx, stagingServer, bookmakerID, token, nodeID, isTLS) } // DialReplay connects to the replay server -func DialReplay(ctx context.Context, bookmakerID, token string, nodeID int) (*Connection, error) { - return dial(ctx, replayServer, bookmakerID, token, nodeID) +func DialReplay(ctx context.Context, bookmakerID, token string, nodeID int, isTLS bool) (*Connection, error) { + return dial(ctx, replayServer, bookmakerID, token, nodeID, isTLS) } // DialCustom connects to a custom server -func DialCustom(ctx context.Context, server, bookmakerID, token string, nodeID int) (*Connection, error) { - return dial(ctx, server, bookmakerID, token, nodeID) +func DialCustom(ctx context.Context, server, bookmakerID, token string, nodeID int, isTLS bool) (*Connection, error) { + return dial(ctx, server, bookmakerID, token, nodeID, isTLS) } type Connection struct { @@ -117,14 +121,26 @@ func (c *Connection) drain(out chan<- *uof.Message, errc chan<- error) { <-errsDone } -func dial(ctx context.Context, server, bookmakerID, token string, nodeID int) (*Connection, error) { +func dial(ctx context.Context, server, bookmakerID, token string, nodeID int, isTLS bool) (*Connection, error) { addr := fmt.Sprintf("amqps://%s:@%s//unifiedfeed/%s", token, server, bookmakerID) - tls := &tls.Config{ + tlsConfig := &tls.Config{ ServerName: server, InsecureSkipVerify: true, } - conn, err := amqp.DialTLS(addr, tls) + var dialer func(network string, addr string) (net.Conn, error) + if isTLS { + dialer = func(network string, addr string) (net.Conn, error) { + return tls.Dial(network, addr, tlsConfig) + } + } + config := amqp.Config{ + Heartbeat: amqpDefaultHeartbeat, + TLSClientConfig: tlsConfig, + Locale: amqpDefaultLocale, + Dial: dialer, + } + conn, err := amqp.DialConfig(addr, config) if err != nil { fmt.Println(strings.ReplaceAll(addr, token, "")) return nil, uof.Notice("conn.Dial", err) @@ -179,7 +195,7 @@ func dial(ctx context.Context, server, bookmakerID, token string, nodeID int) (* msgs: msgs, errs: errs, reDial: func() (*Connection, error) { - return dial(ctx, server, bookmakerID, token, nodeID) + return dial(ctx, server, bookmakerID, token, nodeID, isTLS) }, info: ConnectionInfo{ server: server, diff --git a/sdk/sdk.go b/sdk/sdk.go index c8cbc6e..729f587 100644 --- a/sdk/sdk.go +++ b/sdk/sdk.go @@ -22,6 +22,7 @@ type Config struct { BookmakerID string Token string NodeID int + IsAMQPTLS bool Fixtures time.Time Recovery []uof.ProducerChange Stages []pipe.InnerStage @@ -103,9 +104,9 @@ func connect(ctx context.Context, c Config) (*queue.Connection, *api.API, error) var conn *queue.Connection var amqpErr error if c.CustomAMQPServer != "" { - conn, amqpErr = queue.DialCustom(ctx, c.CustomAMQPServer, c.BookmakerID, c.Token, c.NodeID) + conn, amqpErr = queue.DialCustom(ctx, c.CustomAMQPServer, c.BookmakerID, c.Token, c.NodeID, c.IsAMQPTLS) } else { - conn, amqpErr = queue.Dial(ctx, c.Env, c.BookmakerID, c.Token, c.NodeID) + conn, amqpErr = queue.Dial(ctx, c.Env, c.BookmakerID, c.Token, c.NodeID, c.IsAMQPTLS) } if amqpErr != nil { return nil, nil, amqpErr @@ -141,6 +142,13 @@ func CustomServers(customAMQPServer, customAPIServer string) Option { } } +// ConfigTLS for setting tls flag +func ConfigTLS(isAMQPTLS bool) Option { + return func(c *Config) { + c.IsAMQPTLS = isAMQPTLS + } +} + // Languages for api calls. // // Statefull messages (markets, players, fixtures) will be served in all this From a65b6f62c26f9a0ef9c2671497a6df802124a6b0 Mon Sep 17 00:00:00 2001 From: Mickael Guesnon Date: Fri, 11 Aug 2023 16:05:57 -0400 Subject: [PATCH 16/26] fix(PVO-66): Skip TLS verify for betradar http client --- api/api.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/api/api.go b/api/api.go index 740702f..21327a8 100644 --- a/api/api.go +++ b/api/api.go @@ -4,9 +4,11 @@ package api import ( "bytes" "context" + "crypto/tls" "encoding/xml" "fmt" "io/ioutil" + "net/http" "text/template" "time" @@ -90,7 +92,11 @@ func DialCustom(exitSig context.Context, customServer, token string) (*API, erro } func client() *retryablehttp.Client { + tr := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } c := retryablehttp.NewClient() + c.HTTPClient.Transport = tr c.Logger = nil c.RetryWaitMin = 1 * time.Second c.RetryWaitMax = 16 * time.Second From 44ead68dbfa7cd7de171693524892ea68db56492 Mon Sep 17 00:00:00 2001 From: Guillermo Mugnaini Date: Thu, 17 Aug 2023 11:00:36 -0300 Subject: [PATCH 17/26] feat(pvo-66): upgrade amqp lib --- go.mod | 4 ++-- go.sum | 20 +++++++++++++++++--- queue/queue.go | 2 +- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 68b698a..ac930e1 100644 --- a/go.mod +++ b/go.mod @@ -4,15 +4,15 @@ go 1.20 require ( github.com/cenkalti/backoff/v3 v3.2.2 + github.com/dustin/go-humanize v1.0.1 github.com/hashicorp/go-retryablehttp v0.7.4 github.com/pkg/errors v0.9.1 - github.com/streadway/amqp v1.1.0 + github.com/rabbitmq/amqp091-go v1.8.1 github.com/stretchr/testify v1.8.4 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect - github.com/dustin/go-humanize v1.0.1 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 65c16c3..c42ed58 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,6 @@ github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= @@ -10,16 +11,29 @@ github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxC github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA= github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/streadway/amqp v1.1.0 h1:py12iX8XSyI7aN/3dUT8DFIDJazNJsVJdxNVEpnQTZM= -github.com/streadway/amqp v1.1.0/go.mod h1:WYSrTEYHOXHd0nwFeUXAe2G2hRnQT+deZJJf88uS9Bg= +github.com/rabbitmq/amqp091-go v1.8.1 h1:RejT1SBUim5doqcL6s7iN6SBmsQqyTgXb1xMlH0h1hA= +github.com/rabbitmq/amqp091-go v1.8.1/go.mod h1:+jPrT9iY2eLjRaMSRHUhc3z14E/l85kv/f+6luSD3pc= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/queue/queue.go b/queue/queue.go index 33541fe..cb5d6f4 100644 --- a/queue/queue.go +++ b/queue/queue.go @@ -14,7 +14,7 @@ import ( "time" "github.com/pvotal-tech/go-uof-sdk" - "github.com/streadway/amqp" + amqp "github.com/rabbitmq/amqp091-go" ) const ( From 7536134489fdc8d832016f4187cacc4fb9679158 Mon Sep 17 00:00:00 2001 From: Guillermo Mugnaini Date: Wed, 13 Sep 2023 22:08:32 -0300 Subject: [PATCH 18/26] feat(pvo-604): add event recovery endpoints --- api/api.go | 27 +++++++++++++-------------- cmd/client/main.go | 13 ++++++++++++- enum.go | 13 +++++++++---- 3 files changed, 34 insertions(+), 19 deletions(-) diff --git a/api/api.go b/api/api.go index 21327a8..8d12012 100644 --- a/api/api.go +++ b/api/api.go @@ -105,9 +105,11 @@ func client() *retryablehttp.Client { } const ( - recovery = "/v1/{{.Producer}}/recovery/initiate_request?after={{.Timestamp}}&request_id={{.RequestID}}&node_id={{.NodeID}}" - fullRecovery = "/v1/{{.Producer}}/recovery/initiate_request?request_id={{.RequestID}}&node_id={{.NodeID}}" - ping = "/v1/users/whoami.xml" + recovery = "/v1/{{.Producer}}/recovery/initiate_request?after={{.Timestamp}}&request_id={{.RequestID}}&node_id={{.NodeID}}" + fullRecovery = "/v1/{{.Producer}}/recovery/initiate_request?request_id={{.RequestID}}&node_id={{.NodeID}}" + sportEventRecovery = "/v1/{.Producer}/odds/events/{{.EventURN}}/initiate_request?request_id={{.RequestID}}&node_id={{.NodeID}}" + sportEventStatefulRecovery = "/v1//{.Producer}/stateful_messages/events/{{.EventURN}}/initiate_request?request_id={{.RequestID}}&node_id={{.NodeID}}" + ping = "/v1/users/whoami.xml" ) func (a *API) RequestRecovery(producer uof.Producer, timestamp, requestID, nodeID int) error { @@ -129,18 +131,15 @@ func (a *API) RequestFullOddsRecovery(producer uof.Producer, requestID, nodeID i return a.post(fullRecovery, ¶ms{Producer: producer, RequestID: requestID, NodeID: nodeID}) } -// // RecoverSportEvent requests to resend all odds for all markets for a sport -// // event. -// func (a *Api) RecoverSportEvent(product, eventID string) error { -// return a.post(fmt.Sprintf("/v1/%s/events/%s/initiate_request", product, eventID)) -// } +// RecoverSportEvent requests to resend all odds for all markets for a sport event. +func (a *API) RecoverSportEvent(producer uof.Producer, eventURN uof.URN, requestID, nodeID int) error { + return a.post(sportEventRecovery, ¶ms{Producer: producer, EventURN: eventURN, RequestID: requestID, NodeID: nodeID}) +} -// // RecoverStatefulForSportEvent requests to resend all stateful-messages -// // (BetSettlement, RollbackBetSettlement, BetCancel, UndoBetCancel) for a sport -// // event. -// func (a *Api) RecoverStatefulForSportEvent(product, eventID string) error { -// return a.post(fmt.Sprintf("/v1/%s/stateful_messages/events/%s/initiate_request", product, eventID)) -// } +// RecoverStatefulForSportEvent requests to resend all stateful-messages (BetSettlement, RollbackBetSettlement, BetCancel, UndoBetCancel) for a sport event. +func (a *API) RecoverStatefulForSportEvent(producer uof.Producer, eventURN uof.URN, requestID, nodeID int) error { + return a.post(sportEventStatefulRecovery, ¶ms{Producer: producer, EventURN: eventURN, RequestID: requestID, NodeID: nodeID}) +} func (a *API) Ping() error { _, err := a.get(ping, nil) diff --git a/cmd/client/main.go b/cmd/client/main.go index c5561dc..cafa76b 100644 --- a/cmd/client/main.go +++ b/cmd/client/main.go @@ -105,8 +105,19 @@ func logMessage(m *uof.Message) { if m.Alive.Subscribed != 0 { fmt.Printf("%-25s producer: %s, timestamp: %d\n", m.Type, m.Alive.Producer, m.Alive.Timestamp) } + case uof.MessageTypeBetSettlement: + for _, v := range m.BetSettlement.Markets { + fmt.Printf("BET SETTLEMENT producer=%v eventID=%d marketID=%v status=%v\n", m.Producer, m.BetSettlement.EventURN.ID(), v.ID, v.Result) + } + case uof.MessageTypeBetStop: + for _, v := range m.BetStop.MarketIDs { + fmt.Printf("BET STOP producer=%v eventID=%d marketID=%v status=%v\n", m.Producer, m.BetStop.EventURN.ID(), v, m.BetStop.Status) + } case uof.MessageTypeOddsChange: - fmt.Printf("%-25s event: %s, markets: %d\n", m.Type, m.EventURN, len(m.OddsChange.Markets)) + fmt.Printf("ODDS CHANGE producer=%v eventID=%d eventStatus=%v\n", m.Producer, m.OddsChange.EventURN.ID(), m.OddsChange.EventStatus) + for _, v := range m.OddsChange.Markets { + fmt.Printf("ODDS CHANGE producer=%v eventID=%d marketID=%v status=%v\n", m.Producer, m.OddsChange.EventURN.ID(), v.ID, v.Status) + } default: var b []byte if false && m.Raw != nil { diff --git a/enum.go b/enum.go index b386f45..257c337 100644 --- a/enum.go +++ b/enum.go @@ -10,9 +10,11 @@ import ( type Producer int8 const ( - ProducerUnknown Producer = 0 - ProducerLiveOdds Producer = 1 - ProducerPrematch Producer = 3 + ProducerUnknown Producer = 0 + ProducerLiveOdds Producer = 1 + ProducerPrematch Producer = 3 + ProducerBetPal Producer = 4 + ProducerPremiumCricket Producer = 5 ) var producers = []struct { @@ -172,9 +174,12 @@ const NoURN = URN("") // those with prefix sr:match for them we reserve positive id-s. All others got // range in negative ids. // Reference: https://docs.betradar.com/display/BD/MG+-+Entities -// http://sdk.sportradar.com/content/unifiedfeedsdk/net/doc/html/e1f73019-73cd-c9f8-0d58-7fe25800abf2.htm +// +// http://sdk.sportradar.com/content/unifiedfeedsdk/net/doc/html/e1f73019-73cd-c9f8-0d58-7fe25800abf2.htm +// // List of currently existing event types is taken from the combo box in the // integration control page. From method "Fixture for a specified sport event". +// //nolint:gocyclo //accepting complexity of 23 func (u URN) EventID() int { id, prefix := u.split() From 095e305fb25bb42c96e6df7f244e932c1ba717b0 Mon Sep 17 00:00:00 2001 From: Guillermo Mugnaini Date: Thu, 14 Sep 2023 19:47:47 -0300 Subject: [PATCH 19/26] feat(pvo-604): improved concurrency --- api/api.go | 4 ++-- pipe/fixture.go | 10 ++++++---- pipe/market.go | 14 ++++++++------ pipe/player.go | 14 ++++++++------ 4 files changed, 24 insertions(+), 18 deletions(-) diff --git a/api/api.go b/api/api.go index 8d12012..182806b 100644 --- a/api/api.go +++ b/api/api.go @@ -107,8 +107,8 @@ func client() *retryablehttp.Client { const ( recovery = "/v1/{{.Producer}}/recovery/initiate_request?after={{.Timestamp}}&request_id={{.RequestID}}&node_id={{.NodeID}}" fullRecovery = "/v1/{{.Producer}}/recovery/initiate_request?request_id={{.RequestID}}&node_id={{.NodeID}}" - sportEventRecovery = "/v1/{.Producer}/odds/events/{{.EventURN}}/initiate_request?request_id={{.RequestID}}&node_id={{.NodeID}}" - sportEventStatefulRecovery = "/v1//{.Producer}/stateful_messages/events/{{.EventURN}}/initiate_request?request_id={{.RequestID}}&node_id={{.NodeID}}" + sportEventRecovery = "/v1/{{.Producer}}/odds/events/{{.EventURN}}/initiate_request?request_id={{.RequestID}}&node_id={{.NodeID}}" + sportEventStatefulRecovery = "/v1/{{.Producer}}/stateful_messages/events/{{.EventURN}}/initiate_request?request_id={{.RequestID}}&node_id={{.NodeID}}" ping = "/v1/users/whoami.xml" ) diff --git a/pipe/fixture.go b/pipe/fixture.go index 56f8987..59694ab 100644 --- a/pipe/fixture.go +++ b/pipe/fixture.go @@ -51,10 +51,12 @@ func (f *fixture) loop(in <-chan *uof.Message, out chan<- *uof.Message, errc cha f.getFixture(u, uof.CurrentTimestamp(), true) } for m := range in { - if u := f.eventURN(m); u != uof.NoURN { - f.getFixture(u, m.ReceivedAt, false) - } - out <- m + go func(m *uof.Message) { + if u := f.eventURN(m); u != uof.NoURN { + f.getFixture(u, m.ReceivedAt, false) + } + out <- m + }(m) } return f.subProcs diff --git a/pipe/market.go b/pipe/market.go index 7f02209..9a7c8ba 100644 --- a/pipe/market.go +++ b/pipe/market.go @@ -41,12 +41,14 @@ func (s *markets) loop(in <-chan *uof.Message, out chan<- *uof.Message, errc cha s.getAll() for m := range in { - if m.Is(uof.MessageTypeOddsChange) { - m.OddsChange.EachVariantMarket(func(marketID int, variant string) { - s.variantMarket(marketID, variant, m.ReceivedAt) - }) - } - out <- m + go func(m *uof.Message) { + if m.Is(uof.MessageTypeOddsChange) { + m.OddsChange.EachVariantMarket(func(marketID int, variant string) { + s.variantMarket(marketID, variant, m.ReceivedAt) + }) + } + out <- m + }(m) } return s.subProcs } diff --git a/pipe/player.go b/pipe/player.go index 61b20d8..db62ea6 100644 --- a/pipe/player.go +++ b/pipe/player.go @@ -36,12 +36,14 @@ func (p *player) loop(in <-chan *uof.Message, out chan<- *uof.Message, errc chan p.errc, p.out = errc, out for m := range in { - if m.Is(uof.MessageTypeOddsChange) { - m.OddsChange.EachPlayer(func(playerID int) { - p.get(playerID, m.ReceivedAt) - }) - } - out <- m + go func(m *uof.Message) { + if m.Is(uof.MessageTypeOddsChange) { + m.OddsChange.EachPlayer(func(playerID int) { + p.get(playerID, m.ReceivedAt) + }) + } + out <- m + }(m) } return p.subProcs } From 460a68e561c6a5d63ada79c9d634a76e7ac1a770 Mon Sep 17 00:00:00 2001 From: Guillermo Mugnaini Date: Tue, 19 Sep 2023 10:13:29 -0300 Subject: [PATCH 20/26] feat(pvo-604): improved concurrency --- bet_settlement.go | 14 +++--- cmd/client/main.go | 50 +++++++++++++----- mapcache.go | 67 ++++++++++++++++++++++++ message.go | 27 +++++----- odds_change.go | 10 ++-- pipe/fixture.go | 10 ++-- pipe/market.go | 20 +++++--- pipe/player.go | 20 +++++--- queue/queue.go | 123 ++++++++++++++++++++++++++++++++------------- sdk/sdk.go | 13 +++-- specifiers.go | 4 +- 11 files changed, 260 insertions(+), 98 deletions(-) create mode 100644 mapcache.go diff --git a/bet_settlement.go b/bet_settlement.go index 2066aa1..1b7be5c 100644 --- a/bet_settlement.go +++ b/bet_settlement.go @@ -108,12 +108,14 @@ func (t *BetSettlementOutcome) UnmarshalXML(d *xml.Decoder, start xml.StartEleme return nil } -//The following list includes all possible combinations of outcome (result) and void_factor: -// result="0" and no void_factor: Lose entire bet -// result="1" and no void_factor: Win entire bet -// result="0" and void_factor="1": Refund entire bet -// result="1" and void_factor="0.5": Refund half bet and win other half -// result="0" and void_factor="0.5": Refund half bet and lose other half. +// The following list includes all possible combinations of outcome (result) and void_factor: +// +// result="0" and no void_factor: Lose entire bet +// result="1" and no void_factor: Win entire bet +// result="0" and void_factor="1": Refund entire bet +// result="1" and void_factor="0.5": Refund half bet and win other half +// result="0" and void_factor="0.5": Refund half bet and lose other half. +// // If the bet on an outcome should be refunded completely void-factor is set to // 1.0. If half of the bet on an outcome should be refunded void_factor is set // to 0.5. diff --git a/cmd/client/main.go b/cmd/client/main.go index cafa76b..2c0891c 100644 --- a/cmd/client/main.go +++ b/cmd/client/main.go @@ -6,6 +6,8 @@ import ( "encoding/json" "errors" "fmt" + "github.com/pvotal-tech/go-uof-sdk" + "github.com/pvotal-tech/go-uof-sdk/sdk" "log" "net/http" _ "net/http/pprof" @@ -13,10 +15,6 @@ import ( "os/signal" "syscall" "time" - - "github.com/pvotal-tech/go-uof-sdk" - "github.com/pvotal-tech/go-uof-sdk/pipe" - "github.com/pvotal-tech/go-uof-sdk/sdk" ) const ( @@ -61,24 +59,30 @@ func exitSignal() context.Context { } func main() { + go func() { + _ = http.ListenAndServe(fmt.Sprintf(":%d", 6060), nil) + }() go debugHTTP() - preloadTo := time.Now().Add(24 * time.Hour) + //preloadTo := time.Now().Add(24 * time.Hour) - timestamp := uof.CurrentTimestamp() - 5*60*1000 // -5 minutes + timestamp := uof.CurrentTimestamp() - 12*60*60*1000 // -5 minutes var pc uof.ProducersChange pc.Add(uof.ProducerPrematch, timestamp) pc.Add(uof.ProducerLiveOdds, timestamp) + pc.Add(uof.ProducerBetPal, timestamp) + pc.Add(uof.ProducerPremiumCricket, timestamp) err := sdk.Run(exitSignal(), - sdk.Credentials(bookmakerID, token, 123), + sdk.Credentials("38616", "j8l0CpSoytxhp7xb7r", 123), sdk.Staging(), sdk.Recovery(pc), - sdk.Fixtures(preloadTo), - sdk.Languages(uof.Languages("en,de,hr")), - sdk.BufferedConsumer(pipe.FileStore("./tmp"), 1024), + sdk.ConfigThrottle(true), + //sdk.Fixtures(preloadTo), + sdk.Languages(uof.Languages("en")), + //sdk.BufferedConsumer(pipe.FileStore("./tmp"), 1024), sdk.Consumer(logMessages), - sdk.ListenErrors(listenSDKErrors), + //sdk.ListenErrors(listenSDKErrors), ) if err != nil { log.Fatal(err) @@ -88,12 +92,32 @@ func main() { // consumer of incoming messages func logMessages(in <-chan *uof.Message) error { for m := range in { - logMessage(m) + processMessage(m) } return nil } -func logMessage(m *uof.Message) { +func processMessage(m *uof.Message) { + var pendingCount, p, requestID, sport string + if m.External { + pendingCount = fmt.Sprintf("pending=%d", m.PendingMsgCount) + p = fmt.Sprintf("producer=%s", m.Producer.Code()) + if m.Type == uof.MessageTypeBetSettlement { + if m.BetSettlement.RequestID != nil { + requestID = fmt.Sprintf("requestID=%d", *m.BetSettlement.RequestID) + } + sport = fmt.Sprintf("sportID=%d", m.SportID) + } + if m.Type == uof.MessageTypeOddsChange { + if m.OddsChange.RequestID != nil { + requestID = fmt.Sprintf("requestID=%d", *m.OddsChange.RequestID) + } + sport = fmt.Sprintf("sportID=%d", m.SportID) + } + } + fmt.Printf("%-60s %-20s %-20s %-20s %-20s %-20s\n", time.Now().String(), m.Type, pendingCount, p, requestID, sport) + time.Sleep(time.Millisecond * 200) + return switch m.Type { case uof.MessageTypeConnection: fmt.Printf("%-25s status: %s, server: %s, local: %s, network: %s, tls: %s\n", m.Type, m.Connection.Status, m.Connection.ServerName, m.Connection.LocalAddr, m.Connection.Network, m.Connection.TLSVersionToString()) diff --git a/mapcache.go b/mapcache.go new file mode 100644 index 0000000..a058174 --- /dev/null +++ b/mapcache.go @@ -0,0 +1,67 @@ +package uof + +import ( + "context" + "sync" + "time" +) + +type MapCache[K string | int, V any] struct { + sync.RWMutex + ctx context.Context + data map[K]*V + expiration map[K]time.Time + timeToLive time.Duration + cacheCleanInterval time.Duration +} + +func NewMapCache[K string | int, V any](ctx context.Context, timeToLive time.Duration, cacheCleanInterval time.Duration) *MapCache[K, V] { + cache := &MapCache[K, V]{ + ctx: ctx, + data: make(map[K]*V), + expiration: make(map[K]time.Time), + timeToLive: timeToLive, + cacheCleanInterval: cacheCleanInterval, + } + + go cache.cleanUpExpiredEntries() + + return cache +} + +func (m *MapCache[K, V]) Set(key K, value V) { + m.Lock() + defer m.Unlock() + m.data[key] = &value + m.expiration[key] = time.Now().Add(m.timeToLive) +} + +func (m *MapCache[K, V]) Get(key K) (*V, bool) { + m.RLock() + defer m.RUnlock() + val, ok := m.data[key] + return val, ok +} + +func (m *MapCache[K, V]) Size() int { + return len(m.data) +} + +func (m *MapCache[K, V]) cleanUpExpiredEntries() { + for { + select { + case <-m.ctx.Done(): + return + case <-time.After(m.cacheCleanInterval): + m.Lock() + currentTime := time.Now() + for key, expirationTime := range m.expiration { + if currentTime.After(expirationTime) { + delete(m.data, key) + delete(m.expiration, key) + } + } + m.Unlock() + } + } +} diff --git a/message.go b/message.go index fa3151c..4c57ebc 100644 --- a/message.go +++ b/message.go @@ -12,18 +12,20 @@ import ( ) type Header struct { - Type MessageType `json:"type,omitempty"` - Scope MessageScope `json:"scope,omitempty"` - Priority MessagePriority `json:"priority,omitempty"` - Lang Lang `json:"lang,omitempty"` - SportID int `json:"sportID,omitempty"` - EventID int `json:"eventID,omitempty"` - EventURN URN `json:"eventURN,omitempty"` - ReceivedAt int `json:"receivedAt,omitempty"` - RequestedAt int `json:"requestedAt,omitempty"` - Producer Producer `json:"producer,omitempty"` - Timestamp int `json:"timestamp,omitempty"` - NodeID int `json:"nodeID,omitempty"` + Type MessageType `json:"type,omitempty"` + Scope MessageScope `json:"scope,omitempty"` + Priority MessagePriority `json:"priority,omitempty"` + Lang Lang `json:"lang,omitempty"` + SportID int `json:"sportID,omitempty"` + EventID int `json:"eventID,omitempty"` + EventURN URN `json:"eventURN,omitempty"` + ReceivedAt int `json:"receivedAt,omitempty"` + RequestedAt int `json:"requestedAt,omitempty"` + Producer Producer `json:"producer,omitempty"` + Timestamp int `json:"timestamp,omitempty"` + NodeID int `json:"nodeID,omitempty"` + PendingMsgCount int `json:"pendingMsgCount,omitempty"` + External bool `json:"external,omitempty"` } type Body struct { @@ -115,6 +117,7 @@ func (m *Message) parseRoutingKey(routingKey string) error { m.NodeID, _ = strconv.Atoi(nodeID) } + m.External = true m.Priority.Parse(priority) m.Type.Parse(messageType) m.Scope.Parse(prematchInterest, liveInterest) diff --git a/odds_change.go b/odds_change.go index 0994c7b..4140e2b 100644 --- a/odds_change.go +++ b/odds_change.go @@ -101,11 +101,11 @@ func (o *OddsChange) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error } // Custom unmarshaling reasons: -// * To cover the case that: 'The default value is active if status is not present.' -// * To convert Specifiers and ExtendedSpecifiers fileds which are -// lists of key value attributes encoded in string to the map. -// * To calculate LineID; market line is uniquely identified by both -// market id and line id +// - To cover the case that: 'The default value is active if status is not present.' +// - To convert Specifiers and ExtendedSpecifiers fileds which are +// lists of key value attributes encoded in string to the map. +// - To calculate LineID; market line is uniquely identified by both +// market id and line id func (m *Market) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { type T Market var overlay struct { diff --git a/pipe/fixture.go b/pipe/fixture.go index 59694ab..56f8987 100644 --- a/pipe/fixture.go +++ b/pipe/fixture.go @@ -51,12 +51,10 @@ func (f *fixture) loop(in <-chan *uof.Message, out chan<- *uof.Message, errc cha f.getFixture(u, uof.CurrentTimestamp(), true) } for m := range in { - go func(m *uof.Message) { - if u := f.eventURN(m); u != uof.NoURN { - f.getFixture(u, m.ReceivedAt, false) - } - out <- m - }(m) + if u := f.eventURN(m); u != uof.NoURN { + f.getFixture(u, m.ReceivedAt, false) + } + out <- m } return f.subProcs diff --git a/pipe/market.go b/pipe/market.go index 9a7c8ba..70e7edb 100644 --- a/pipe/market.go +++ b/pipe/market.go @@ -41,14 +41,18 @@ func (s *markets) loop(in <-chan *uof.Message, out chan<- *uof.Message, errc cha s.getAll() for m := range in { - go func(m *uof.Message) { - if m.Is(uof.MessageTypeOddsChange) { - m.OddsChange.EachVariantMarket(func(marketID int, variant string) { - s.variantMarket(marketID, variant, m.ReceivedAt) - }) - } - out <- m - }(m) + if m.Is(uof.MessageTypeOddsChange) { + //var wg sync.WaitGroup + m.OddsChange.EachVariantMarket(func(marketID int, variant string) { + // go func() { + // wg.Add(1) + s.variantMarket(marketID, variant, m.ReceivedAt) + // wg.Done() + // }() + }) + //wg.Wait() + } + out <- m } return s.subProcs } diff --git a/pipe/player.go b/pipe/player.go index db62ea6..47949f6 100644 --- a/pipe/player.go +++ b/pipe/player.go @@ -36,14 +36,18 @@ func (p *player) loop(in <-chan *uof.Message, out chan<- *uof.Message, errc chan p.errc, p.out = errc, out for m := range in { - go func(m *uof.Message) { - if m.Is(uof.MessageTypeOddsChange) { - m.OddsChange.EachPlayer(func(playerID int) { - p.get(playerID, m.ReceivedAt) - }) - } - out <- m - }(m) + if m.Is(uof.MessageTypeOddsChange) { + //var wg sync.WaitGroup + m.OddsChange.EachPlayer(func(playerID int) { + // go func() { + // wg.Add(1) + p.get(playerID, m.ReceivedAt) + // wg.Done() + // }() + }) + //wg.Wait() + } + out <- m } return p.subProcs } diff --git a/queue/queue.go b/queue/queue.go index cb5d6f4..b42c0ba 100644 --- a/queue/queue.go +++ b/queue/queue.go @@ -29,51 +29,54 @@ const ( ) // Dial connects to the queue chosen by environment -func Dial(ctx context.Context, env uof.Environment, bookmakerID, token string, nodeID int, isTLS bool) (*Connection, error) { +func Dial(ctx context.Context, env uof.Environment, bookmakerID, token string, nodeID int, isTLS, isThrottled bool) (*Connection, error) { switch env { case uof.Replay: - return DialReplay(ctx, bookmakerID, token, nodeID, isTLS) + return DialReplay(ctx, bookmakerID, token, nodeID, isTLS, isThrottled) case uof.Staging: - return DialStaging(ctx, bookmakerID, token, nodeID, isTLS) + return DialStaging(ctx, bookmakerID, token, nodeID, isTLS, isThrottled) case uof.Production: - return DialProduction(ctx, bookmakerID, token, nodeID, isTLS) + return DialProduction(ctx, bookmakerID, token, nodeID, isTLS, isThrottled) case uof.ProductionGlobal: - return DialProductionGlobal(ctx, bookmakerID, token, nodeID, isTLS) + return DialProductionGlobal(ctx, bookmakerID, token, nodeID, isTLS, isThrottled) default: return nil, uof.Notice("queue dial", fmt.Errorf("unknown environment %d", env)) } } // Dial connects to the production queue -func DialProduction(ctx context.Context, bookmakerID, token string, nodeID int, isTLS bool) (*Connection, error) { - return dial(ctx, productionServer, bookmakerID, token, nodeID, isTLS) +func DialProduction(ctx context.Context, bookmakerID, token string, nodeID int, isTLS, isThrottled bool) (*Connection, error) { + return dial(ctx, productionServer, bookmakerID, token, nodeID, isTLS, isThrottled) } // Dial connects to the production queue -func DialProductionGlobal(ctx context.Context, bookmakerID, token string, nodeID int, isTLS bool) (*Connection, error) { - return dial(ctx, productionServerGlobal, bookmakerID, token, nodeID, isTLS) +func DialProductionGlobal(ctx context.Context, bookmakerID, token string, nodeID int, isTLS, isThrottled bool) (*Connection, error) { + return dial(ctx, productionServerGlobal, bookmakerID, token, nodeID, isTLS, isThrottled) } // DialStaging connects to the staging queue -func DialStaging(ctx context.Context, bookmakerID, token string, nodeID int, isTLS bool) (*Connection, error) { - return dial(ctx, stagingServer, bookmakerID, token, nodeID, isTLS) +func DialStaging(ctx context.Context, bookmakerID, token string, nodeID int, isTLS, isThrottled bool) (*Connection, error) { + return dial(ctx, stagingServer, bookmakerID, token, nodeID, isTLS, isThrottled) } // DialReplay connects to the replay server -func DialReplay(ctx context.Context, bookmakerID, token string, nodeID int, isTLS bool) (*Connection, error) { - return dial(ctx, replayServer, bookmakerID, token, nodeID, isTLS) +func DialReplay(ctx context.Context, bookmakerID, token string, nodeID int, isTLS, isThrottled bool) (*Connection, error) { + return dial(ctx, replayServer, bookmakerID, token, nodeID, isTLS, isThrottled) } // DialCustom connects to a custom server -func DialCustom(ctx context.Context, server, bookmakerID, token string, nodeID int, isTLS bool) (*Connection, error) { - return dial(ctx, server, bookmakerID, token, nodeID, isTLS) +func DialCustom(ctx context.Context, server, bookmakerID, token string, nodeID int, isTLS, isThrottled bool) (*Connection, error) { + return dial(ctx, server, bookmakerID, token, nodeID, isTLS, isThrottled) } type Connection struct { - msgs <-chan amqp.Delivery - errs <-chan *amqp.Error - reDial func() (*Connection, error) - info ConnectionInfo + isThrottled bool + msgs <-chan amqp.Delivery + errs <-chan *amqp.Error + chnl *amqp.Channel + queueName string + reDial func() (*Connection, error) + info ConnectionInfo } type ConnectionInfo struct { @@ -96,8 +99,16 @@ func (c *Connection) Listen() (<-chan *uof.Message, <-chan error) { } -// drain consumes from connection until msgs chan is closed func (c *Connection) drain(out chan<- *uof.Message, errc chan<- error) { + if c.isThrottled { + c.drainThrottled(out, errc) + } else { + c.drainContinuous(out, errc) + } +} + +// drain consumes from connection until msgs chan is closed. consumes as fast as it can from queue +func (c *Connection) drainContinuous(out chan<- *uof.Message, errc chan<- error) { errsDone := make(chan struct{}) go func() { for err := range c.errs { @@ -121,7 +132,43 @@ func (c *Connection) drain(out chan<- *uof.Message, errc chan<- error) { <-errsDone } -func dial(ctx context.Context, server, bookmakerID, token string, nodeID int, isTLS bool) (*Connection, error) { +// drain gets a single message and blocks on next iteration if out has not been consumed +func (c *Connection) drainThrottled(out chan<- *uof.Message, errc chan<- error) { + errsDone := make(chan struct{}) + go func() { + for err := range c.errs { + errc <- uof.E("conn", err) + } + close(errsDone) + }() + + for { + delivery, hasMsg, err := c.chnl.Get(c.queueName, true) + if err != nil { + errc <- uof.Notice("conn.channelGet", err) + break + } + if !hasMsg { + continue + } + m, err := uof.NewQueueMessage(delivery.RoutingKey, delivery.Body) + if err != nil { + errc <- uof.Notice("conn.DeliveryParse", err) + continue + } + m.PendingMsgCount = int(delivery.MessageCount) + + // ignores messages that are of no interest to the current session + if m.NodeID != 0 && m.NodeID != c.info.nodeID { + return + } + + out <- m + } + <-errsDone +} + +func dial(ctx context.Context, server, bookmakerID, token string, nodeID int, isTLS, isThrottled bool) (*Connection, error) { addr := fmt.Sprintf("amqps://%s:@%s//unifiedfeed/%s", token, server, bookmakerID) tlsConfig := &tls.Config{ @@ -175,27 +222,33 @@ func dial(ctx context.Context, server, bookmakerID, token string, nodeID int, is } consumerTag := "" - msgs, err := chnl.Consume( - qee.Name, // queue - consumerTag, // consumerTag - true, // auto-ack - true, // exclusive - false, // no-local - false, // no-wait - nil, // args - ) - if err != nil { - return nil, uof.Notice("conn.Consume", err) + var msgs <-chan amqp.Delivery + if !isThrottled { + msgs, err = chnl.Consume( + qee.Name, // queue + consumerTag, // consumerTag + true, // auto-ack + false, // exclusive + false, // no-local + false, // no-wait + nil, // args + ) + if err != nil { + return nil, uof.Notice("conn.Consume", err) + } } errs := make(chan *amqp.Error) chnl.NotifyClose(errs) c := &Connection{ - msgs: msgs, - errs: errs, + isThrottled: isThrottled, + msgs: msgs, + errs: errs, + chnl: chnl, + queueName: qee.Name, reDial: func() (*Connection, error) { - return dial(ctx, server, bookmakerID, token, nodeID, isTLS) + return dial(ctx, server, bookmakerID, token, nodeID, isTLS, isThrottled) }, info: ConnectionInfo{ server: server, diff --git a/sdk/sdk.go b/sdk/sdk.go index 729f587..84d649f 100644 --- a/sdk/sdk.go +++ b/sdk/sdk.go @@ -23,6 +23,7 @@ type Config struct { Token string NodeID int IsAMQPTLS bool + IsThrottled bool Fixtures time.Time Recovery []uof.ProducerChange Stages []pipe.InnerStage @@ -55,7 +56,6 @@ func Run(ctx context.Context, options ...Option) error { return err } } - stages := []pipe.InnerStage{ pipe.Markets(apiConn, c.Languages), pipe.Fixture(apiConn, c.Languages, c.Fixtures), @@ -104,9 +104,9 @@ func connect(ctx context.Context, c Config) (*queue.Connection, *api.API, error) var conn *queue.Connection var amqpErr error if c.CustomAMQPServer != "" { - conn, amqpErr = queue.DialCustom(ctx, c.CustomAMQPServer, c.BookmakerID, c.Token, c.NodeID, c.IsAMQPTLS) + conn, amqpErr = queue.DialCustom(ctx, c.CustomAMQPServer, c.BookmakerID, c.Token, c.NodeID, c.IsAMQPTLS, c.IsThrottled) } else { - conn, amqpErr = queue.Dial(ctx, c.Env, c.BookmakerID, c.Token, c.NodeID, c.IsAMQPTLS) + conn, amqpErr = queue.Dial(ctx, c.Env, c.BookmakerID, c.Token, c.NodeID, c.IsAMQPTLS, c.IsThrottled) } if amqpErr != nil { return nil, nil, amqpErr @@ -149,6 +149,13 @@ func ConfigTLS(isAMQPTLS bool) Option { } } +// ConfigTLS for setting tls flag +func ConfigThrottle(isThrottled bool) Option { + return func(c *Config) { + c.IsThrottled = isThrottled + } +} + // Languages for api calls. // // Statefull messages (markets, players, fixtures) will be served in all this diff --git a/specifiers.go b/specifiers.go index 6a03c22..efce5e4 100644 --- a/specifiers.go +++ b/specifiers.go @@ -27,7 +27,7 @@ func parseCompetitor(name string, fixture Fixture) (string, error) { return parseCompetitor(name, fixture) } -func ParseSpecifiers(name string, specifiers map[string]string, players map[int]Player, fixture Fixture) (string, error) { +func ParseSpecifiers(name string, specifiers map[string]string, players *MapCache[int, Player], fixture Fixture) (string, error) { name = strings.ReplaceAll(name, "{$event}", fixture.Name) name, err := parseCompetitor(name, fixture) if err != nil { @@ -120,7 +120,7 @@ func ParseSpecifiers(name string, specifiers map[string]string, players map[int] if err != nil { return "", fmt.Errorf("error while parsing player id \"%s\"", val) } - player, ok := players[int(playerID)] + player, ok := players.Get(int(playerID)) if !ok { return "", fmt.Errorf("player with id %d not found", playerID) } From 9dd984a79f178d6bf0c88fd27a2175509024c8b3 Mon Sep 17 00:00:00 2001 From: Guillermo Mugnaini Date: Tue, 19 Sep 2023 10:18:49 -0300 Subject: [PATCH 21/26] feat(pvo-604): improved concurrency --- cmd/client/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/client/main.go b/cmd/client/main.go index 2c0891c..30c5a22 100644 --- a/cmd/client/main.go +++ b/cmd/client/main.go @@ -74,7 +74,7 @@ func main() { pc.Add(uof.ProducerPremiumCricket, timestamp) err := sdk.Run(exitSignal(), - sdk.Credentials("38616", "j8l0CpSoytxhp7xb7r", 123), + sdk.Credentials(bookmakerID, token, 123), sdk.Staging(), sdk.Recovery(pc), sdk.ConfigThrottle(true), From c7960f033acd34273d64f5cb9457839a8b40cd31 Mon Sep 17 00:00:00 2001 From: Guillermo Mugnaini Date: Tue, 19 Sep 2023 10:21:05 -0300 Subject: [PATCH 22/26] feat(pvo-604): improved concurrency --- pipe/market.go | 6 ------ pipe/player.go | 6 ------ 2 files changed, 12 deletions(-) diff --git a/pipe/market.go b/pipe/market.go index 70e7edb..7f02209 100644 --- a/pipe/market.go +++ b/pipe/market.go @@ -42,15 +42,9 @@ func (s *markets) loop(in <-chan *uof.Message, out chan<- *uof.Message, errc cha s.getAll() for m := range in { if m.Is(uof.MessageTypeOddsChange) { - //var wg sync.WaitGroup m.OddsChange.EachVariantMarket(func(marketID int, variant string) { - // go func() { - // wg.Add(1) s.variantMarket(marketID, variant, m.ReceivedAt) - // wg.Done() - // }() }) - //wg.Wait() } out <- m } diff --git a/pipe/player.go b/pipe/player.go index 47949f6..61b20d8 100644 --- a/pipe/player.go +++ b/pipe/player.go @@ -37,15 +37,9 @@ func (p *player) loop(in <-chan *uof.Message, out chan<- *uof.Message, errc chan for m := range in { if m.Is(uof.MessageTypeOddsChange) { - //var wg sync.WaitGroup m.OddsChange.EachPlayer(func(playerID int) { - // go func() { - // wg.Add(1) p.get(playerID, m.ReceivedAt) - // wg.Done() - // }() }) - //wg.Wait() } out <- m } From 5f013a232b8d35f64e77f0698d4a2209f41233f5 Mon Sep 17 00:00:00 2001 From: Guillermo Mugnaini Date: Wed, 20 Sep 2023 20:52:56 -0300 Subject: [PATCH 23/26] feat(pvo-476): new fields. type changes --- bet_settlement.go | 10 ++++++---- cmd/client/main.go | 12 +----------- cmd/replay/main.go | 10 +--------- market.go | 2 ++ odds_change.go | 26 ++++++++++++++++++++------ odds_change_test.go | 2 +- queue/queue.go | 16 ++++++++-------- sdk/sdk.go | 4 ++-- speficiers_test.go | 11 ++++++----- 9 files changed, 47 insertions(+), 46 deletions(-) diff --git a/bet_settlement.go b/bet_settlement.go index 1b7be5c..1314850 100644 --- a/bet_settlement.go +++ b/bet_settlement.go @@ -16,9 +16,10 @@ type BetSettlement struct { } type BetSettlementMarket struct { - ID int `xml:"id,attr" json:"id"` - LineID int `json:"lineID"` - Specifiers map[string]string `json:"specifiers,omitempty"` + ID int `xml:"id,attr" json:"id"` + LineID int `json:"lineID"` + Specifiers map[string]string `json:"specifiers,omitempty"` + AllSpecifiers string `json:"allSpecifiers,omitempty"` // Describes the reason for voiding certain outcomes for a particular market. // Only set if at least one of the outcomes have a void_factor. A list of void // reasons can be found above this table or by using the API at @@ -81,7 +82,8 @@ func (t *BetSettlementMarket) UnmarshalXML(d *xml.Decoder, start xml.StartElemen if err := d.DecodeElement(&overlay, &start); err != nil { return err } - t.Specifiers = toSpecifiers(overlay.Specifiers, overlay.ExtendedSpecifiers) + t.AllSpecifiers = getAllSpecifiers(overlay.Specifiers, overlay.ExtendedSpecifiers) + t.Specifiers = toSpecifiers(t.AllSpecifiers) t.LineID = toLineID(overlay.Specifiers) return nil } diff --git a/cmd/client/main.go b/cmd/client/main.go index 30c5a22..bc70939 100644 --- a/cmd/client/main.go +++ b/cmd/client/main.go @@ -30,16 +30,6 @@ func env(name string) string { return e } -var ( - bookmakerID string - token string -) - -func init() { - token = env(EnvToken) - bookmakerID = env(EnvBookmakerID) -} - func debugHTTP() { if err := http.ListenAndServe("localhost:8124", nil); err != nil { log.Fatal(err) @@ -74,7 +64,7 @@ func main() { pc.Add(uof.ProducerPremiumCricket, timestamp) err := sdk.Run(exitSignal(), - sdk.Credentials(bookmakerID, token, 123), + sdk.Credentials(123456, "token_goes_here", 123), sdk.Staging(), sdk.Recovery(pc), sdk.ConfigThrottle(true), diff --git a/cmd/replay/main.go b/cmd/replay/main.go index 035cd59..e845662 100644 --- a/cmd/replay/main.go +++ b/cmd/replay/main.go @@ -18,11 +18,6 @@ import ( "github.com/pvotal-tech/go-uof-sdk/sdk" ) -const ( - EnvBookmakerID = "UOF_BOOKMAKER_ID" - EnvToken = "UOF_TOKEN" -) - func env(name string) string { val, ok := os.LookupEnv(name) if !ok { @@ -32,7 +27,7 @@ func env(name string) string { } var ( - bookmakerID string + bookmakerID int token string scenarioID int eventURN uof.URN @@ -56,9 +51,6 @@ func init() { log.Printf("no event or scenario found, will replay sample event %s", event) } eventURN.Parse(event) - - token = env(EnvToken) - bookmakerID = env(EnvBookmakerID) } func debugHTTP() { diff --git a/market.go b/market.go index cdd239e..7618d75 100644 --- a/market.go +++ b/market.go @@ -53,6 +53,7 @@ type MarketDescription struct { type MarketOutcome struct { ID int `json:"id"` + RawID string `json:"rawId"` Name string `xml:"name,attr" json:"name,omitempty"` Description string `xml:"description,attr,omitempty" json:"description,omitempty"` } @@ -113,6 +114,7 @@ func (t *MarketOutcome) UnmarshalXML(d *xml.Decoder, start xml.StartElement) err return err } t.ID = toOutcomeID(overlay.ID) + t.RawID = overlay.ID return nil } diff --git a/odds_change.go b/odds_change.go index 4140e2b..691c6b4 100644 --- a/odds_change.go +++ b/odds_change.go @@ -51,7 +51,8 @@ type OddsGenerationProperties struct { type Market struct { ID int `xml:"id,attr" json:"id"` LineID int `json:"lineID"` - Specifiers map[string]string `json:"sepcifiers,omitempty"` + Specifiers map[string]string `json:"specifiers,omitempty"` + AllSpecifiers string `json:"allSpecifiers,omitempty"` Status MarketStatus `xml:"status,attr,omitempty" json:"status,omitempty"` CashoutStatus *CashoutStatus `xml:"cashout_status,attr,omitempty" json:"cashoutStatus,omitempty"` // If present, this is set to 1, which states that this is the most balanced @@ -125,7 +126,8 @@ func (m *Market) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { if overlay.Status != nil { m.Status = MarketStatus(*overlay.Status) } - m.Specifiers = toSpecifiers(overlay.Specifiers, overlay.ExtendedSpecifiers) + m.AllSpecifiers = getAllSpecifiers(overlay.Specifiers, overlay.ExtendedSpecifiers) + m.Specifiers = toSpecifiers(m.AllSpecifiers) m.LineID = toLineID(overlay.Specifiers) if overlay.MarketMetadata != nil { m.NextBetstop = overlay.MarketMetadata.NextBetstop @@ -157,11 +159,23 @@ func (m Market) VariantSpecifier() string { return "" } -func toSpecifiers(specifiers, extendedSpecifiers string) map[string]string { - allSpecifiers := specifiers - if extendedSpecifiers != "" { - allSpecifiers = allSpecifiers + "|" + extendedSpecifiers +func getAllSpecifiers(specifiers, extendedSpecifiers string) string { + if specifiers == "" && extendedSpecifiers == "" { + return "" } + + if specifiers == "" { + return extendedSpecifiers + } + + if extendedSpecifiers == "" { + return specifiers + } + + return specifiers + "|" + extendedSpecifiers +} + +func toSpecifiers(allSpecifiers string) map[string]string { if len(allSpecifiers) < 2 { return nil } diff --git a/odds_change_test.go b/odds_change_test.go index 14b528b..a20b0dd 100644 --- a/odds_change_test.go +++ b/odds_change_test.go @@ -165,7 +165,7 @@ func TestSpecifiersParsing(t *testing.T) { }, } for i, d := range data { - s := toSpecifiers(d.specifiers, d.extendedSpecifers) + s := toSpecifiers(getAllSpecifiers(d.specifiers, d.extendedSpecifers)) assert.Equal(t, len(d.specifiersMap), len(s)) m := Market{Specifiers: d.specifiersMap} assert.Equal(t, d.variantSpecifier, m.VariantSpecifier()) diff --git a/queue/queue.go b/queue/queue.go index b42c0ba..6aa4a2c 100644 --- a/queue/queue.go +++ b/queue/queue.go @@ -29,7 +29,7 @@ const ( ) // Dial connects to the queue chosen by environment -func Dial(ctx context.Context, env uof.Environment, bookmakerID, token string, nodeID int, isTLS, isThrottled bool) (*Connection, error) { +func Dial(ctx context.Context, env uof.Environment, bookmakerID int, token string, nodeID int, isTLS, isThrottled bool) (*Connection, error) { switch env { case uof.Replay: return DialReplay(ctx, bookmakerID, token, nodeID, isTLS, isThrottled) @@ -45,27 +45,27 @@ func Dial(ctx context.Context, env uof.Environment, bookmakerID, token string, n } // Dial connects to the production queue -func DialProduction(ctx context.Context, bookmakerID, token string, nodeID int, isTLS, isThrottled bool) (*Connection, error) { +func DialProduction(ctx context.Context, bookmakerID int, token string, nodeID int, isTLS, isThrottled bool) (*Connection, error) { return dial(ctx, productionServer, bookmakerID, token, nodeID, isTLS, isThrottled) } // Dial connects to the production queue -func DialProductionGlobal(ctx context.Context, bookmakerID, token string, nodeID int, isTLS, isThrottled bool) (*Connection, error) { +func DialProductionGlobal(ctx context.Context, bookmakerID int, token string, nodeID int, isTLS, isThrottled bool) (*Connection, error) { return dial(ctx, productionServerGlobal, bookmakerID, token, nodeID, isTLS, isThrottled) } // DialStaging connects to the staging queue -func DialStaging(ctx context.Context, bookmakerID, token string, nodeID int, isTLS, isThrottled bool) (*Connection, error) { +func DialStaging(ctx context.Context, bookmakerID int, token string, nodeID int, isTLS, isThrottled bool) (*Connection, error) { return dial(ctx, stagingServer, bookmakerID, token, nodeID, isTLS, isThrottled) } // DialReplay connects to the replay server -func DialReplay(ctx context.Context, bookmakerID, token string, nodeID int, isTLS, isThrottled bool) (*Connection, error) { +func DialReplay(ctx context.Context, bookmakerID int, token string, nodeID int, isTLS, isThrottled bool) (*Connection, error) { return dial(ctx, replayServer, bookmakerID, token, nodeID, isTLS, isThrottled) } // DialCustom connects to a custom server -func DialCustom(ctx context.Context, server, bookmakerID, token string, nodeID int, isTLS, isThrottled bool) (*Connection, error) { +func DialCustom(ctx context.Context, server string, bookmakerID int, token string, nodeID int, isTLS, isThrottled bool) (*Connection, error) { return dial(ctx, server, bookmakerID, token, nodeID, isTLS, isThrottled) } @@ -168,8 +168,8 @@ func (c *Connection) drainThrottled(out chan<- *uof.Message, errc chan<- error) <-errsDone } -func dial(ctx context.Context, server, bookmakerID, token string, nodeID int, isTLS, isThrottled bool) (*Connection, error) { - addr := fmt.Sprintf("amqps://%s:@%s//unifiedfeed/%s", token, server, bookmakerID) +func dial(ctx context.Context, server string, bookmakerID int, token string, nodeID int, isTLS, isThrottled bool) (*Connection, error) { + addr := fmt.Sprintf("amqps://%s:@%s//unifiedfeed/%d", token, server, bookmakerID) tlsConfig := &tls.Config{ ServerName: server, diff --git a/sdk/sdk.go b/sdk/sdk.go index 84d649f..6674fa2 100644 --- a/sdk/sdk.go +++ b/sdk/sdk.go @@ -19,7 +19,7 @@ type ErrorListenerFunc func(err error) type Config struct { CustomAMQPServer string CustomAPIServer string - BookmakerID string + BookmakerID int Token string NodeID int IsAMQPTLS bool @@ -126,7 +126,7 @@ func connect(ctx context.Context, c Config) (*queue.Connection, *api.API, error) } // Credentials for establishing connection to the uof queue and api. -func Credentials(bookmakerID, token string, nodeID int) Option { +func Credentials(bookmakerID int, token string, nodeID int) Option { return func(c *Config) { c.BookmakerID = bookmakerID c.Token = token diff --git a/speficiers_test.go b/speficiers_test.go index 86c36d9..d65758c 100644 --- a/speficiers_test.go +++ b/speficiers_test.go @@ -1,17 +1,17 @@ package uof import ( + "context" "testing" + "time" "github.com/stretchr/testify/assert" ) func TestParseNameWithSpecifiers(t *testing.T) { - players := map[int]Player{ - 1234: Player{ - FullName: "John Rodriquez", - }, - } + ctx, cancel := context.WithCancel(context.Background()) + players := NewMapCache[int, Player](ctx, time.Hour, time.Hour) + players.Set(1234, Player{FullName: "John Rodriquez"}) fixture := Fixture{ Name: "Euro2016", Competitors: []Competitor{ @@ -147,4 +147,5 @@ func TestParseNameWithSpecifiers(t *testing.T) { assert.Equal(t, tc.expected, actual) }) } + cancel() } From 416a5ec6257bdf0522d85547e3911a55bb9a685d Mon Sep 17 00:00:00 2001 From: Guillermo Mugnaini Date: Wed, 27 Sep 2023 20:32:20 -0300 Subject: [PATCH 24/26] feat(pvo-927): player pipe concurrency flag --- pipe/player.go | 40 ++++++++++++++++++++++++++-------------- sdk/sdk.go | 38 +++++++++++++++++++++++--------------- 2 files changed, 49 insertions(+), 29 deletions(-) diff --git a/pipe/player.go b/pipe/player.go index 61b20d8..d18ae5a 100644 --- a/pipe/player.go +++ b/pipe/player.go @@ -12,22 +12,24 @@ type playerAPI interface { } type player struct { - api playerAPI - em *expireMap - languages []uof.Lang // suported languages - errc chan<- error - out chan<- *uof.Message - rateLimit chan struct{} - subProcs *sync.WaitGroup + api playerAPI + em *expireMap + languages []uof.Lang // suported languages + errc chan<- error + out chan<- *uof.Message + rateLimit chan struct{} + subProcs *sync.WaitGroup + concurrentFetch bool } -func Player(api playerAPI, languages []uof.Lang) InnerStage { +func Player(api playerAPI, languages []uof.Lang, concurrentFetch bool) InnerStage { p := &player{ - api: api, - languages: languages, - em: newExpireMap(time.Hour), - subProcs: &sync.WaitGroup{}, - rateLimit: make(chan struct{}, ConcurentAPICallsLimit), + api: api, + languages: languages, + em: newExpireMap(time.Hour), + subProcs: &sync.WaitGroup{}, + rateLimit: make(chan struct{}, ConcurentAPICallsLimit), + concurrentFetch: concurrentFetch, } return StageWithSubProcessesSync(p.loop) } @@ -37,9 +39,19 @@ func (p *player) loop(in <-chan *uof.Message, out chan<- *uof.Message, errc chan for m := range in { if m.Is(uof.MessageTypeOddsChange) { + var wg sync.WaitGroup m.OddsChange.EachPlayer(func(playerID int) { - p.get(playerID, m.ReceivedAt) + if p.concurrentFetch { + wg.Add(1) + go func() { + p.get(playerID, m.ReceivedAt) + wg.Done() + }() + } else { + p.get(playerID, m.ReceivedAt) + } }) + wg.Wait() } out <- m } diff --git a/sdk/sdk.go b/sdk/sdk.go index 6674fa2..5060148 100644 --- a/sdk/sdk.go +++ b/sdk/sdk.go @@ -17,20 +17,21 @@ type ErrorListenerFunc func(err error) // Config is active SDK configuration type Config struct { - CustomAMQPServer string - CustomAPIServer string - BookmakerID int - Token string - NodeID int - IsAMQPTLS bool - IsThrottled bool - Fixtures time.Time - Recovery []uof.ProducerChange - Stages []pipe.InnerStage - Replay func(*api.ReplayAPI) error - Env uof.Environment - Languages []uof.Lang - ErrorListener ErrorListenerFunc + CustomAMQPServer string + CustomAPIServer string + BookmakerID int + Token string + NodeID int + IsAMQPTLS bool + IsThrottled bool + ConcurrentAPIFetch bool + Fixtures time.Time + Recovery []uof.ProducerChange + Stages []pipe.InnerStage + Replay func(*api.ReplayAPI) error + Env uof.Environment + Languages []uof.Lang + ErrorListener ErrorListenerFunc } // Option sets attributes on the Config. @@ -59,7 +60,7 @@ func Run(ctx context.Context, options ...Option) error { stages := []pipe.InnerStage{ pipe.Markets(apiConn, c.Languages), pipe.Fixture(apiConn, c.Languages, c.Fixtures), - pipe.Player(apiConn, c.Languages), + pipe.Player(apiConn, c.Languages, c.ConcurrentAPIFetch), pipe.BetStop(), } if len(c.Recovery) > 0 { @@ -156,6 +157,13 @@ func ConfigThrottle(isThrottled bool) Option { } } +// ConfigTLS for setting tls flag +func ConfigConcurrentAPIFetch(concurrentAPIFetch bool) Option { + return func(c *Config) { + c.ConcurrentAPIFetch = concurrentAPIFetch + } +} + // Languages for api calls. // // Statefull messages (markets, players, fixtures) will be served in all this From 7889eb7477dc29fac3e2ce7d0ee7fac712ba52e9 Mon Sep 17 00:00:00 2001 From: Guillermo Mugnaini Date: Tue, 17 Oct 2023 13:03:06 -0300 Subject: [PATCH 25/26] fix(pvo-1177): reduce liveoods recovery window --- enum.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enum.go b/enum.go index 257c337..27f7230 100644 --- a/enum.go +++ b/enum.go @@ -25,7 +25,7 @@ var producers = []struct { scope string recoveryWindow int // in minutes }{ - {id: 1, name: "LO", description: "Live Odds", code: "liveodds", scope: "live", recoveryWindow: 4320}, + {id: 1, name: "LO", description: "Live Odds", code: "liveodds", scope: "live", recoveryWindow: 600}, {id: 3, name: "Ctrl", description: "Betradar Ctrl", code: "pre", scope: "prematch", recoveryWindow: 4320}, {id: 4, name: "BetPal", description: "BetPal", code: "betpal", scope: "live", recoveryWindow: 4320}, {id: 5, name: "PremiumCricket", description: "Premium Cricket", code: "premium_cricket", scope: "live|prematch", recoveryWindow: 4320}, From 2248f4acfe62ebd455866742a7375c2610141a72 Mon Sep 17 00:00:00 2001 From: Guillermo Mugnaini Date: Fri, 20 Oct 2023 11:11:15 -0300 Subject: [PATCH 26/26] fix(pvo-1225): print full addr on dial error --- queue/queue.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/queue/queue.go b/queue/queue.go index 6aa4a2c..e81ba90 100644 --- a/queue/queue.go +++ b/queue/queue.go @@ -10,7 +10,6 @@ import ( "crypto/tls" "fmt" "net" - "strings" "time" "github.com/pvotal-tech/go-uof-sdk" @@ -189,8 +188,7 @@ func dial(ctx context.Context, server string, bookmakerID int, token string, nod } conn, err := amqp.DialConfig(addr, config) if err != nil { - fmt.Println(strings.ReplaceAll(addr, token, "")) - return nil, uof.Notice("conn.Dial", err) + return nil, uof.Notice("conn.Dial", fmt.Errorf("%w (%s)", err, addr)) } chnl, err := conn.Channel()