From b61c24ae4f526670af7a66e82e12f88cc1d7ced0 Mon Sep 17 00:00:00 2001 From: Wittano Bonarotti Date: Sun, 2 Jun 2024 19:53:31 +0200 Subject: [PATCH] fix(joke): added mutex for set activation flag for external APIs --- bot/joke/humorapi.go | 8 ++++++-- bot/joke/jokedev.go | 8 ++++++-- bot/joke/types.go | 24 +++++++++++++++--------- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/bot/joke/humorapi.go b/bot/joke/humorapi.go index 2b8547a..59b229d 100644 --- a/bot/joke/humorapi.go +++ b/bot/joke/humorapi.go @@ -11,6 +11,7 @@ import ( "log/slog" "net/http" "os" + "sync" "time" ) @@ -30,10 +31,11 @@ var HumorAPILimitExceededErr = errors.New("humorAPI: daily limit of jokes was ex type HumorAPIService struct { client http.Client active bool + m sync.Mutex globalCtx context.Context } -func (h HumorAPIService) Active(ctx context.Context) (active bool) { +func (h *HumorAPIService) Active(ctx context.Context) (active bool) { select { case <-ctx.Done(): active = false @@ -77,10 +79,12 @@ func (h *HumorAPIService) RandomJoke(ctx context.Context, search joke.SearchPara limitExceeded := len(res.Header[xAPIQuotaLeftHeaderName]) > 0 && res.Header[xAPIQuotaLeftHeaderName][0] == "0" if res.StatusCode == http.StatusTooManyRequests || res.StatusCode == http.StatusPaymentRequired || limitExceeded { + h.m.Lock() h.active = false resetTime := time.Now().Add(time.Hour * 24) - go unlockService(h.globalCtx, &h.active, resetTime) + go unlockService(h.globalCtx, &h.m, &h.active, resetTime) + h.m.Unlock() return joke.Joke{}, HumorAPILimitExceededErr } else if res.StatusCode != http.StatusOK { diff --git a/bot/joke/jokedev.go b/bot/joke/jokedev.go index b258cd1..b8c2fd8 100644 --- a/bot/joke/jokedev.go +++ b/bot/joke/jokedev.go @@ -8,6 +8,7 @@ import ( "github.com/wittano/komputer/db/joke" "io" "net/http" + "sync" "time" ) @@ -74,10 +75,11 @@ var DevServiceLimitExceededErr = errors.New("jokedev: current limit exceeded") type DevService struct { client http.Client active bool + m sync.Mutex globalCtx context.Context } -func (d DevService) Active(ctx context.Context) (active bool) { +func (d *DevService) Active(ctx context.Context) (active bool) { select { case <-ctx.Done(): active = false @@ -121,10 +123,12 @@ func (d *DevService) RandomJoke(ctx context.Context, params joke.SearchParams) ( if res.StatusCode == http.StatusTooManyRequests || isLimitExceeded { const rateLimitReset = "RateLimit-Reset" + d.m.Lock() resetTime := resetTime(res.Header[rateLimitReset]) d.active = false - go unlockService(d.globalCtx, &d.active, resetTime) + go unlockService(d.globalCtx, &d.m, &d.active, resetTime) + d.m.Unlock() return joke.Joke{}, DevServiceLimitExceededErr } diff --git a/bot/joke/types.go b/bot/joke/types.go index 2d681e2..bbf794c 100644 --- a/bot/joke/types.go +++ b/bot/joke/types.go @@ -6,29 +6,33 @@ import ( "github.com/wittano/komputer/db/joke" "net/http" "os" + "sync" "time" ) func NewJokeDevService(globalCtx context.Context) joke.SearchService { - client := http.Client{Timeout: time.Second * 1} - - return &DevService{client, true, globalCtx} + return &DevService{ + client: http.Client{Timeout: time.Second}, + active: true, + globalCtx: globalCtx, + } } func NewHumorAPIService(globalCtx context.Context) joke.SearchService { - client := http.Client{Timeout: time.Second * 1} - env, ok := os.LookupEnv(humorAPIKey) - active := ok || env != "" - return &HumorAPIService{client, active, globalCtx} + return &HumorAPIService{ + client: http.Client{Timeout: time.Second}, + active: ok || env != "", + globalCtx: globalCtx, + } } -func NewDatabaseJokeService(database db.MongodbService) joke.Database { +func NewJokeDatabase(database db.MongodbService) joke.Database { return joke.Database{Mongodb: database} } -func unlockService(ctx context.Context, activeFlag *bool, resetTime time.Time) { +func unlockService(ctx context.Context, m *sync.Mutex, activeFlag *bool, resetTime time.Time) { deadlineCtx, cancel := context.WithDeadline(ctx, resetTime) defer cancel() @@ -39,7 +43,9 @@ func unlockService(ctx context.Context, activeFlag *bool, resetTime time.Time) { select { case <-deadlineCtx.Done(): + m.Lock() *activeFlag = true + m.Unlock() return default: }