Skip to content

Commit

Permalink
Add support for rate-limiting using Redis (#4)
Browse files Browse the repository at this point in the history
* feat: add cache support using redis storage

* feat: add rate-limiting support for APIs
  • Loading branch information
Praveen Yadav committed Feb 13, 2024
1 parent 31ce151 commit 08dcbfd
Show file tree
Hide file tree
Showing 25 changed files with 586 additions and 30 deletions.
2 changes: 2 additions & 0 deletions common/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require (
github.com/mitchellh/mapstructure v1.5.0
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.18.2
github.com/zeebo/assert v1.3.1
google.golang.org/grpc v1.61.0
gopkg.in/yaml.v2 v2.4.0
)
Expand All @@ -33,6 +34,7 @@ require (
golang.org/x/text v0.14.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0 // indirect
google.golang.org/protobuf v1.32.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
4 changes: 2 additions & 2 deletions common/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ github.com/mcuadros/go-defaults v1.2.0 h1:FODb8WSf0uGaY8elWJAkoLL0Ri6AlZ1bFlenk5
github.com/mcuadros/go-defaults v1.2.0/go.mod h1:WEZtHEVIGYVDqkKSWBdWKUVdRyKlMfulPaGDWIVeCWY=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
Expand Down Expand Up @@ -63,6 +62,7 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/zeebo/assert v1.3.1 h1:vukIABvugfNMZMQO1ABsyQDJDTVQbn+LWSMy1ol1h6A=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
Expand All @@ -82,8 +82,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
Expand Down
15 changes: 14 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,17 @@ services:
- GATEWAY_HOST=0.0.0.0
- GATEWAY_PORT=8080
ports:
- 8080:8080
- 8080:8080

redis:
image: redis:7.2-alpine
restart: always
ports:
- 6379:6379
command: redis-server --save 20 1 --loglevel warning --requirepass eYVX7EwVmmxKPCDmwMtyKVge8oLd2t81
volumes:
- redis:/data

volumes:
redis:
driver: local
23 changes: 10 additions & 13 deletions gateway/cmd/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,17 @@ import (
)

const Description = `
▄▄▄ ██▓ ▄████ ▄▄▄ ▄▄▄█████▓▓█████ █ █░ ▄▄▄ ▓██ ██▓
▒████▄ ▓██▒ ██▒ ▀█▒▒████▄ ▓ ██▒ ▓▒▓█ ▀ ▓█░ █ ░█░▒████▄ ▒██ ██▒
▒██ ▀█▄ ▒██▒ ▒██░▄▄▄░▒██ ▀█▄ ▒ ▓██░ ▒░▒███ ▒█░ █ ░█ ▒██ ▀█▄ ▒██ ██░
░██▄▄▄▄██ ░██░ ░▓█ ██▓░██▄▄▄▄██░ ▓██▓ ░ ▒▓█ ▄ ░█░ █ ░█ ░██▄▄▄▄██ ░ ▐██▓░
▓█ ▓██▒░██░ ░▒▓███▀▒ ▓█ ▓██▒ ▒██▒ ░ ░▒████▒░░██▒██▓ ▓█ ▓██▒ ░ ██▒▓░
▒▒ ▓▒█░░▓ ░▒ ▒ ▒▒ ▓▒█░ ▒ ░░ ░░ ▒░ ░░ ▓░▒ ▒ ▒▒ ▓▒█░ ██▒▒▒
▒ ▒▒ ░ ▒ ░ ░ ░ ▒ ▒▒ ░ ░ ░ ░ ░ ▒ ░ ░ ▒ ▒▒ ░▓██ ░▒░
░ ▒ ▒ ░ ░ ░ ░ ░ ▒ ░ ░ ░ ░ ░ ▒ ▒ ▒ ░░
░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░░ ░
░ ░
███▄ ▄███▓ ▒█████ ▄▄▄▄ ██▓ █ ██ ██████
▓██▒▀█▀ ██▒▒██▒ ██▒▓█████▄ ▓██▒ ██ ▓██▒▒██ ▒
▓██ ▓██░▒██░ ██▒▒██▒ ▄██▒██▒▓██ ▒██░░ ▓██▄
▒██ ▒██ ▒██ ██░▒██░█▀ ░██░▓▓█ ░██░ ▒ ██▒
▒██▒ ░██▒░ ████▓▒░░▓█ ▀█▓░██░▒▒█████▓ ▒██████▒▒
░ ▒░ ░ ░░ ▒░▒░▒░ ░▒▓███▀▒░▓ ░▒▓▒ ▒ ▒ ▒ ▒▓▒ ▒ ░
░ ░ ░ ░ ▒ ▒░ ▒░▒ ░ ▒ ░░░▒░ ░ ░ ░ ░▒ ░ ░
░ ░ ░ ░ ░ ▒ ░ ░ ▒ ░ ░░░ ░ ░ ░ ░ ░
░ ░ ░ ░ ░ ░ ░
🌈 AI gateway is an open-source, lightweight and high-performance gateway
`

Expand Down
19 changes: 15 additions & 4 deletions gateway/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,25 @@ import (
"path/filepath"

"github.com/missingstudio/studio/backend/internal/ingester"
"github.com/missingstudio/studio/backend/internal/ratelimiter"
"github.com/missingstudio/studio/common/config"
)

type Config struct {
Host string `yaml:"host" json:"host,omitempty" mapstructure:"host" default:"0.0.0.0"`
Port int `yaml:"port" json:"port,omitempty" mapstructure:"port" default:"8080"`
LogFormatJson bool `yaml:"log_format_json" json:"log_format_json,omitempty" mapstructure:"log_format_json" default:"false"`
Ingester ingester.Config `yaml:"ingester" json:"ingester,omitempty" mapstructure:"ingester"`
Host string `yaml:"host" json:"host,omitempty" mapstructure:"host" default:"0.0.0.0"`
Port int `yaml:"port" json:"port,omitempty" mapstructure:"port" default:"8080"`
LogFormatJson bool `yaml:"log_format_json" json:"log_format_json,omitempty" mapstructure:"log_format_json" default:"false"`
Ingester ingester.Config `yaml:"ingester" json:"ingester,omitempty" mapstructure:"ingester"`
Redis RedisConfig `yaml:"redis" mapstructure:"redis" json:"redis,omitempty"`
Ratelimiter ratelimiter.Config `yaml:"ratelimiter" mapstructure:"ratelimiter" json:"ratelimiter,omitempty"`
}

type RedisConfig struct {
Host string `yaml:"host" json:"host,omitempty" mapstructure:"host" default:"localhost"`
Port int `yaml:"port" json:"port,omitempty" mapstructure:"port" default:"6379"`
Username string `yaml:"username" mapstructure:"username" json:"username,omitempty"`
Password string `yaml:"password" mapstructure:"password" json:"password,omitempty"`
Database string `yaml:"database" mapstructure:"database" json:"database,omitempty"`
}

func Load(serverConfigFileFromFlag string) (*Config, error) {
Expand Down
6 changes: 6 additions & 0 deletions gateway/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ require (
gopkg.in/yaml.v2 v2.4.0
)

require (
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
)

require (
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.31.0-20230824200731-b9b8148056b9.1 // indirect
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9 // indirect
Expand Down Expand Up @@ -64,6 +69,7 @@ require (
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/pierrec/lz4/v4 v4.1.17 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/redis/go-redis/v9 v9.4.0
github.com/rivo/uniseg v0.2.0 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
Expand Down
10 changes: 10 additions & 0 deletions gateway/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,22 @@ github.com/apache/arrow/go/v13 v13.0.0 h1:kELrvDQuKZo8csdWYqBQfyi431x6Zs/YJTEgUu
github.com/apache/arrow/go/v13 v13.0.0/go.mod h1:W69eByFNO0ZR30q1/7Sr9d83zcVZmF2MiP3fFYAWJOc=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/bufbuild/protovalidate-go v0.3.0 h1:t9zKgM//9VtPnP0TvyFqWubLQtSbwLwEUVOxgtX9/os=
github.com/bufbuild/protovalidate-go v0.3.0/go.mod h1:4mZkDYMGJlnHHQ9rPOhVEZ4bA13iOJBRLzywxy8f/lo=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA=
github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE=
github.com/frankban/quicktest v1.11.0/go.mod h1:K+q6oSqb0W0Ininfk863uOk1lMy69l/P6txr3mVT54s=
Expand Down Expand Up @@ -117,6 +125,8 @@ github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFu
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/redis/go-redis/v9 v9.4.0 h1:Yzoz33UZw9I/mFhx4MNrB6Fk+XHO1VukNcCa1+lwyKk=
github.com/redis/go-redis/v9 v9.4.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
Expand Down
13 changes: 9 additions & 4 deletions gateway/internal/api/v1/deps.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
package v1

import "github.com/missingstudio/studio/backend/internal/ingester"
import (
"github.com/missingstudio/studio/backend/internal/ingester"
"github.com/missingstudio/studio/backend/internal/ratelimiter"
)

type Deps struct {
ingester ingester.Ingester
ingester ingester.Ingester
ratelimiter *ratelimiter.RateLimiter
}

func NewDeps(ingester ingester.Ingester) *Deps {
func NewDeps(ingester ingester.Ingester, ratelimiter *ratelimiter.RateLimiter) *Deps {
return &Deps{
ingester: ingester,
ingester: ingester,
ratelimiter: ratelimiter,
}
}
1 change: 1 addition & 0 deletions gateway/internal/api/v1/v1.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ func Register(d *Deps) (http.Handler, error) {
stdInterceptors := []connect.Interceptor{
validateInterceptor,
otelconnectInterceptor,
interceptor.RateLimiterInterceptor(d.ratelimiter),
interceptor.ProviderInterceptor(),
interceptor.RetryInterceptor(),
}
Expand Down
34 changes: 34 additions & 0 deletions gateway/internal/cache/cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package cache

import (
"time"

"github.com/missingstudio/studio/backend/internal/encoding"
)

type store interface {
Get(key string) ([]byte, error)
Set(key string, value any, ttl time.Duration) error
}

type Cache struct {
store store
}

func NewCache(s store) *Cache {
return &Cache{
store: s,
}
}

func (c *Cache) ComputeHashKey(value string) string {
return encoding.Encode(value)
}

func (c *Cache) SetValue(key string, value []byte, ttl time.Duration) error {
return c.store.Set(c.ComputeHashKey(key), value, ttl)
}

func (c *Cache) GetValue(key string) ([]byte, error) {
return c.store.Get(c.ComputeHashKey(key))
}
39 changes: 39 additions & 0 deletions gateway/internal/cache/cache_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package cache_test

import (
"testing"
"time"

"github.com/missingstudio/studio/backend/internal/cache"
"github.com/missingstudio/studio/backend/internal/mock"
)

func TestCache_SetValue(t *testing.T) {
// Create a new instance of the MockStore
mockStore := mock.NewMockStore()

// Create a new Cache with the MockStore
cache := cache.NewCache(mockStore)

key := "key"
value := []byte("value")
ttl := 5 * time.Second

// Set the value in the cache
err := cache.SetValue(key, value, ttl)
if err != nil {
t.Errorf("Error setting value in cache: %v", err)
}

// Verify that the value is correctly stored in the MockStore
storedValue, err := mockStore.Get(cache.ComputeHashKey(key))
if err != nil {
t.Errorf("Error getting value from store: %v", err)
}

if storedValue == nil {
t.Error("Expected value in store, but got nil")
} else if string(storedValue) != string(value) {
t.Errorf("Expected value '%s' in store, but got '%s'", value, storedValue)
}
}
13 changes: 13 additions & 0 deletions gateway/internal/encoding/encoding.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package encoding

import (
"crypto/sha256"
"encoding/hex"
)

func Encode(secret string) string {
h := sha256.New()
h.Write([]byte(secret))

return hex.EncodeToString(h.Sum(nil))
}
8 changes: 4 additions & 4 deletions gateway/internal/ingester/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ type Config struct {
}

type InfluxConfig struct {
Host string `yaml:"host" mapstructure:"host" default:"none" json:"host,omitempty"`
Token string `yaml:"token" mapstructure:"token" default:"json" json:"token,omitempty"`
Organization string `yaml:"organization" mapstructure:"organization" default:"json" json:"organization,omitempty"`
Database string `yaml:"database" mapstructure:"database" default:"json" json:"database,omitempty"`
Host string `yaml:"host" mapstructure:"host" default:"http://localhost:1234" json:"host,omitempty"`
Token string `yaml:"token" mapstructure:"token" json:"token,omitempty"`
Organization string `yaml:"organization" mapstructure:"organization" json:"organization,omitempty"`
Database string `yaml:"database" mapstructure:"database" json:"database,omitempty"`
}
23 changes: 22 additions & 1 deletion gateway/internal/interceptor/interceptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@ import (

"connectrpc.com/connect"
"github.com/missingstudio/studio/backend/config"
"github.com/missingstudio/studio/backend/internal/ratelimiter"
"github.com/missingstudio/studio/backend/internal/schema"
"github.com/missingstudio/studio/backend/pkg/utils"
"github.com/missingstudio/studio/common/errors"
"github.com/missingstudio/studio/common/resilience/retry"
)

var ErrProviderHeaderNotExit = errors.New(fmt.Errorf("x-ms-provider provider header not available"))
var (
ErrProviderHeaderNotExit = errors.New(fmt.Errorf("x-ms-provider provider header not available"))
ErrRateLimitExceeded = errors.NewForbidden("rate limit exceeded")
)

func NewLogInterceptor() connect.UnaryInterceptorFunc {
interceptor := func(next connect.UnaryFunc) connect.UnaryFunc {
Expand All @@ -26,6 +30,23 @@ func NewLogInterceptor() connect.UnaryInterceptorFunc {
return connect.UnaryInterceptorFunc(interceptor)
}

func RateLimiterInterceptor(rl *ratelimiter.RateLimiter) connect.UnaryInterceptorFunc {
interceptor := func(next connect.UnaryFunc) connect.UnaryFunc {
return connect.UnaryFunc(func(
ctx context.Context,
req connect.AnyRequest,
) (connect.AnyResponse, error) {
key := "req_count"
if !rl.Limiter.Validate(key) {
return nil, ErrRateLimitExceeded
}

return next(ctx, req)
})
}
return connect.UnaryInterceptorFunc(interceptor)
}

func ProviderInterceptor() connect.UnaryInterceptorFunc {
interceptor := func(next connect.UnaryFunc) connect.UnaryFunc {
return connect.UnaryFunc(func(
Expand Down
26 changes: 26 additions & 0 deletions gateway/internal/mock/mock_cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package mock

import "time"

type MockStore struct {
data map[string][]byte
}

func NewMockStore() *MockStore {
return &MockStore{
data: make(map[string][]byte),
}
}

func (m *MockStore) Get(key string) ([]byte, error) {
value, exists := m.data[key]
if !exists {
return nil, nil
}
return value, nil
}

func (m *MockStore) Set(key string, value any, ttl time.Duration) error {
m.data[key] = value.([]byte)
return nil
}
7 changes: 7 additions & 0 deletions gateway/internal/ratelimiter/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package ratelimiter

type Config struct {
Type string `yaml:"type" json:"type,omitempty" mapstructure:"type" default:"sliding_window"`
DurationInSecond int `yaml:"duration_in_seconds" json:"duration_in_seconds,omitempty" mapstructure:"duration_in_seconds" default:"1"`
NumberOfRequests int `yaml:"number_of_requests" json:"number_of_requests,omitempty" mapstructure:"number_of_requests" default:"20"`
}
5 changes: 5 additions & 0 deletions gateway/internal/ratelimiter/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package ratelimiter

type RateLimiterProvider interface {
Validate(key string) bool
}
Loading

0 comments on commit 08dcbfd

Please sign in to comment.