Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions go.work
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ use (
./src/go/libs/loa-api
./src/go/libs/loa-db
./src/go/libs/monitoring
./src/go/libs/ratelimit
./src/go/libs/schedule
)
1 change: 1 addition & 0 deletions go.work.sum
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
Expand Down
11 changes: 8 additions & 3 deletions src/go/apps/auction-item-stat-scraper/scraper/scraper.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,25 @@ import (
"github.com/KubrickCode/loa-work/src/go/libs/loaApi/request"
"github.com/KubrickCode/loa-work/src/go/libs/loadb"
"github.com/KubrickCode/loa-work/src/go/libs/loadb/models"
"golang.org/x/time/rate"
"github.com/KubrickCode/loa-work/src/go/libs/ratelimit"
)

const (
defaultRateLimitInterval = time.Second
defaultRateLimitBurst = 1
)

type Scraper struct {
client request.APIClient
db loadb.DB
rateLimiter *rate.Limiter
rateLimiter ratelimit.Limiter
}

func NewScraper(client request.APIClient, db loadb.DB) *Scraper {
return &Scraper{
client: client,
db: db,
rateLimiter: rate.NewLimiter(rate.Every(time.Second), 1),
rateLimiter: ratelimit.NewLimiterPerDuration(defaultRateLimitInterval, defaultRateLimitBurst),
}
}

Expand Down
22 changes: 18 additions & 4 deletions src/go/apps/market-item-category-scraper/scraper/scraper.go
Original file line number Diff line number Diff line change
@@ -1,26 +1,36 @@
package scraper

import (
"context"
"errors"
"fmt"
"log"
"time"

"github.com/KubrickCode/loa-work/src/go/libs/loaApi/request"
"github.com/KubrickCode/loa-work/src/go/libs/loadb"
"github.com/KubrickCode/loa-work/src/go/libs/loadb/models"
"github.com/KubrickCode/loa-work/src/go/libs/ratelimit"
)

const (
defaultRateLimitInterval = time.Second
defaultRateLimitBurst = 1
)

var ErrNoMarketItemCategories = errors.New("no market item categories found")

type Scraper struct {
client request.APIClient
db loadb.DB
client request.APIClient
db loadb.DB
rateLimiter ratelimit.Limiter
}

func NewScraper(client request.APIClient, db loadb.DB) *Scraper {
return &Scraper{
client: client,
db: db,
client: client,
db: db,
rateLimiter: ratelimit.NewLimiterPerDuration(defaultRateLimitInterval, defaultRateLimitBurst),
}
}

Expand All @@ -41,6 +51,10 @@ func (s *Scraper) Start() error {
}

func (s *Scraper) getCategories() ([]*models.MarketItemCategory, error) {
if err := s.rateLimiter.Wait(context.Background()); err != nil {
return nil, fmt.Errorf("rate limiter error: %w", err)
}

resp, err := s.client.GetCategoryList()
if err != nil {
return nil, err
Expand Down
69 changes: 57 additions & 12 deletions src/go/apps/market-item-category-scraper/scraper/scraper_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
package scraper

import (
"context"
"errors"
"testing"

"github.com/KubrickCode/loa-work/src/go/libs/loaApi"
"github.com/KubrickCode/loa-work/src/go/libs/ratelimit"
)

// noopLimiter implements ratelimit.Limiter with no delay
type noopLimiter struct{}

func (l *noopLimiter) Wait(ctx context.Context) error {
return nil
}

type mockAPIClient struct {
getAuctionItemListFunc func(params *loaApi.GetAuctionItemListParams) (*loaApi.GetAuctionItemListResponse, error)
getCategoryListFunc func() (*loaApi.GetCategoryListResponse, error)
Expand Down Expand Up @@ -65,8 +74,9 @@ func TestGetCategories_Success(t *testing.T) {
}

scraper := &Scraper{
client: mockClient,
db: nil,
client: mockClient,
db: nil,
rateLimiter: &noopLimiter{},
}

categories, err := scraper.getCategories()
Expand Down Expand Up @@ -95,17 +105,14 @@ func TestGetCategories_APIError(t *testing.T) {
}

scraper := &Scraper{
client: mockClient,
db: nil,
client: mockClient,
db: nil,
rateLimiter: &noopLimiter{},
}

_, err := scraper.getCategories()
if err == nil {
t.Fatal("Expected error, got nil")
}

if err != expectedErr {
t.Errorf("Expected error %v, got %v", expectedErr, err)
if !errors.Is(err, expectedErr) {
t.Fatalf("Expected error %v, got %v", expectedErr, err)
}
}

Expand All @@ -119,8 +126,9 @@ func TestGetCategories_EmptyResponse(t *testing.T) {
}

scraper := &Scraper{
client: mockClient,
db: nil,
client: mockClient,
db: nil,
rateLimiter: &noopLimiter{},
}

_, err := scraper.getCategories()
Expand Down Expand Up @@ -195,3 +203,40 @@ func TestGetFlattenCategories_EmptySubCategories(t *testing.T) {
t.Errorf("Expected name 'Category without subs', got %s", flattened[0].Name)
}
}

func TestNewScraper_RateLimiterInitialization(t *testing.T) {
mockClient := &mockAPIClient{}
scraper := NewScraper(mockClient, nil)

if scraper.rateLimiter == nil {
t.Fatal("Expected rateLimiter to be initialized, got nil")
}
}

func TestRateLimiter_InterfaceCompliance(t *testing.T) {
mockClient := &mockAPIClient{
getCategoryListFunc: func() (*loaApi.GetCategoryListResponse, error) {
return &loaApi.GetCategoryListResponse{
Categories: []loaApi.Category{
{Code: 10000, CodeName: "Test"},
},
}, nil
},
}

// Test with real limiter
scraper := &Scraper{
client: mockClient,
db: nil,
rateLimiter: ratelimit.NewLimiterPerDuration(0, 1), // instant for test
}

categories, err := scraper.getCategories()
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}

if len(categories) != 1 {
t.Errorf("Expected 1 category, got %d", len(categories))
}
}
22 changes: 18 additions & 4 deletions src/go/apps/market-item-scraper/scraper/scraper.go
Original file line number Diff line number Diff line change
@@ -1,24 +1,34 @@
package scraper

import (
"context"
"fmt"
"log"
"time"

"github.com/KubrickCode/loa-work/src/go/libs/loaApi"
"github.com/KubrickCode/loa-work/src/go/libs/loaApi/request"
"github.com/KubrickCode/loa-work/src/go/libs/loadb"
"github.com/KubrickCode/loa-work/src/go/libs/loadb/models"
"github.com/KubrickCode/loa-work/src/go/libs/ratelimit"
)

const (
defaultRateLimitInterval = time.Second
defaultRateLimitBurst = 1
)

type Scraper struct {
client request.APIClient
db loadb.DB
client request.APIClient
db loadb.DB
rateLimiter ratelimit.Limiter
}

func NewScraper(client request.APIClient, db loadb.DB) *Scraper {
return &Scraper{
client: client,
db: db,
client: client,
db: db,
rateLimiter: ratelimit.NewLimiterPerDuration(defaultRateLimitInterval, defaultRateLimitBurst),
}
}

Expand Down Expand Up @@ -62,6 +72,10 @@ func (s *Scraper) getItemsToSave(categories []*models.MarketItemCategory) ([]*mo
pageNo := 1

for {
if err := s.rateLimiter.Wait(context.Background()); err != nil {
return nil, fmt.Errorf("rate limiter error: %w", err)
}

resp, err := s.client.GetMarketItemList(&loaApi.GetMarketItemListParams{
CategoryCode: category.Code,
PageNo: pageNo,
Expand Down
Loading
Loading