-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathrate_limiter.go
More file actions
64 lines (53 loc) · 1.59 KB
/
Copy pathrate_limiter.go
File metadata and controls
64 lines (53 loc) · 1.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package api
import (
"context"
"fmt"
"github.com/rs/zerolog"
"github.com/sethvargo/go-limiter"
"github.com/ethereum/go-ethereum/rpc"
"github.com/onflow/flow-evm-gateway/metrics"
errs "github.com/onflow/flow-evm-gateway/models/errors"
)
type RateLimiter interface {
Apply(ctx context.Context, method string) error
}
type DefaultRateLimiter struct {
limiter limiter.Store
collector metrics.Collector
logger zerolog.Logger
}
func NewRateLimiter(
limiter limiter.Store,
collector metrics.Collector,
logger zerolog.Logger,
) RateLimiter {
return DefaultRateLimiter{
limiter: limiter,
collector: collector,
logger: logger,
}
}
// Apply will limit requests with the configured limiter.
// In case the limit is reached, an ErrRateLimit error
// will be returned.
func (rl DefaultRateLimiter) Apply(ctx context.Context, method string) error {
// Future improvement: implement a leaky bucket with wait times instead of errors.
// Investigate middleware application for all methods, including websockets.
// Current go-ethereum server doesn't expose ws connection for inspection
// don't change this to naive middleware handler, because it won't limit
// websocket requests.
remote := rpc.PeerInfoFromContext(ctx).RemoteAddr
if remote == "" {
return nil // if no client identifier disable limit
}
_, _, _, ok, err := rl.limiter.Take(ctx, remote)
if err != nil {
return fmt.Errorf("failed to check rate limit: %w", err)
}
if !ok {
rl.collector.RequestRateLimited(method)
rl.logger.Debug().Str("origin", remote).Msg("rate limit reached")
return errs.ErrRateLimit
}
return nil
}