summaryrefslogtreecommitdiffstats
path: root/internal/ratelimit/config.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/ratelimit/config.go')
-rw-r--r--internal/ratelimit/config.go153
1 files changed, 153 insertions, 0 deletions
diff --git a/internal/ratelimit/config.go b/internal/ratelimit/config.go
new file mode 100644
index 0000000..132c96b
--- /dev/null
+++ b/internal/ratelimit/config.go
@@ -0,0 +1,153 @@
1package ratelimit
2
3import "time"
4
5// Config configures the rate limiter behavior.
6type Config struct {
7 // RequestsPerSecond is the default rate limit in requests per second.
8 // This applies to authenticated users (identified by pubkey).
9 // Default: 10
10 RequestsPerSecond float64
11
12 // BurstSize is the maximum burst size (token bucket capacity).
13 // Allows users to make burst requests up to this limit.
14 // Default: 20
15 BurstSize int
16
17 // IPRequestsPerSecond is the rate limit for unauthenticated users.
18 // These are identified by IP address.
19 // Typically set lower than authenticated user limits.
20 // Default: 5
21 IPRequestsPerSecond float64
22
23 // IPBurstSize is the burst size for IP-based rate limiting.
24 // Default: 10
25 IPBurstSize int
26
27 // MethodLimits provides per-method rate limit overrides.
28 // Key is the full gRPC method name (e.g., "/nostr.v1.NostrRelay/PublishEvent")
29 // If not specified, uses the default RequestsPerSecond and BurstSize.
30 MethodLimits map[string]MethodLimit
31
32 // UserLimits provides per-user custom rate limits.
33 // Key is the pubkey. Useful for VIP/premium users or admins.
34 // If not specified, uses the default limits.
35 UserLimits map[string]UserLimit
36
37 // SkipMethods is a list of gRPC methods that bypass rate limiting.
38 // Useful for health checks or public endpoints.
39 // Example: []string{"/grpc.health.v1.Health/Check"}
40 SkipMethods []string
41
42 // SkipUsers is a list of pubkeys that bypass rate limiting.
43 // Useful for admins or monitoring services.
44 SkipUsers []string
45
46 // CleanupInterval is how often to remove idle rate limiters from memory.
47 // Limiters that haven't been used recently are removed to save memory.
48 // Default: 5 minutes
49 CleanupInterval time.Duration
50
51 // MaxIdleTime is how long a limiter can be idle before being cleaned up.
52 // Default: 10 minutes
53 MaxIdleTime time.Duration
54}
55
56// MethodLimit defines rate limits for a specific gRPC method.
57type MethodLimit struct {
58 RequestsPerSecond float64
59 BurstSize int
60}
61
62// UserLimit defines custom rate limits for a specific user (pubkey).
63type UserLimit struct {
64 // RequestsPerSecond is the default rate for this user.
65 RequestsPerSecond float64
66
67 // BurstSize is the burst size for this user.
68 BurstSize int
69
70 // MethodLimits provides per-method overrides for this user.
71 // Allows fine-grained control like "VIP user gets 100 req/s for queries
72 // but still only 5 req/s for publishes"
73 MethodLimits map[string]MethodLimit
74}
75
76// DefaultConfig returns the default rate limit configuration.
77func DefaultConfig() *Config {
78 return &Config{
79 RequestsPerSecond: 10,
80 BurstSize: 20,
81 IPRequestsPerSecond: 5,
82 IPBurstSize: 10,
83 CleanupInterval: 5 * time.Minute,
84 MaxIdleTime: 10 * time.Minute,
85 }
86}
87
88// Validate checks if the configuration is valid.
89func (c *Config) Validate() error {
90 if c.RequestsPerSecond <= 0 {
91 c.RequestsPerSecond = 10
92 }
93 if c.BurstSize <= 0 {
94 c.BurstSize = 20
95 }
96 if c.IPRequestsPerSecond <= 0 {
97 c.IPRequestsPerSecond = 5
98 }
99 if c.IPBurstSize <= 0 {
100 c.IPBurstSize = 10
101 }
102 if c.CleanupInterval <= 0 {
103 c.CleanupInterval = 5 * time.Minute
104 }
105 if c.MaxIdleTime <= 0 {
106 c.MaxIdleTime = 10 * time.Minute
107 }
108 return nil
109}
110
111// GetLimitForMethod returns the rate limit for a specific method and user.
112// Precedence: UserLimit.MethodLimit > MethodLimit > UserLimit > Default
113func (c *Config) GetLimitForMethod(pubkey, method string) (requestsPerSecond float64, burstSize int) {
114 // Check user-specific method limit first (highest precedence)
115 if userLimit, ok := c.UserLimits[pubkey]; ok {
116 if methodLimit, ok := userLimit.MethodLimits[method]; ok {
117 return methodLimit.RequestsPerSecond, methodLimit.BurstSize
118 }
119 }
120
121 // Check global method limit
122 if methodLimit, ok := c.MethodLimits[method]; ok {
123 return methodLimit.RequestsPerSecond, methodLimit.BurstSize
124 }
125
126 // Check user-specific default limit
127 if userLimit, ok := c.UserLimits[pubkey]; ok {
128 return userLimit.RequestsPerSecond, userLimit.BurstSize
129 }
130
131 // Fall back to global default
132 return c.RequestsPerSecond, c.BurstSize
133}
134
135// ShouldSkipMethod returns true if the method should bypass rate limiting.
136func (c *Config) ShouldSkipMethod(method string) bool {
137 for _, skip := range c.SkipMethods {
138 if skip == method {
139 return true
140 }
141 }
142 return false
143}
144
145// ShouldSkipUser returns true if the user should bypass rate limiting.
146func (c *Config) ShouldSkipUser(pubkey string) bool {
147 for _, skip := range c.SkipUsers {
148 if skip == pubkey {
149 return true
150 }
151 }
152 return false
153}