mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-01 14:46:36 +08:00
ci(arch): forbid pkg packages from depending on project core packages
This commit is contained in:
@@ -1,16 +1,29 @@
|
||||
// Copyright 2026 Arctel.net
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package limiter provides in-memory rate limiting utilities.
|
||||
// Package limiter provides in-memory rate limiting utilities without external project dependencies.
|
||||
package limiter
|
||||
|
||||
import (
|
||||
"Wavelet/core/contracts"
|
||||
"context"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Rate specifies a rate limit of Limit events permitted within a Period.
|
||||
type Rate struct {
|
||||
Limit int
|
||||
Period time.Duration
|
||||
}
|
||||
|
||||
// Result holds the outcome of an Allow check.
|
||||
type Result struct {
|
||||
Allowed bool
|
||||
Remaining int
|
||||
ResetAfter time.Duration
|
||||
RetryAfter time.Duration
|
||||
}
|
||||
|
||||
type memoryEntry struct {
|
||||
timestamps []time.Time
|
||||
lastSeen time.Time
|
||||
@@ -29,10 +42,10 @@ func (e *memoryEntry) prune(cutoff time.Time) {
|
||||
}
|
||||
}
|
||||
|
||||
func (e *memoryEntry) calcBlockedResult(limit int, period time.Duration, now time.Time) *contracts.RateLimitResult {
|
||||
func (e *memoryEntry) calcBlockedResult(limit int, period time.Duration, now time.Time) *Result {
|
||||
currentCount := len(e.timestamps)
|
||||
if currentCount == 0 {
|
||||
return &contracts.RateLimitResult{
|
||||
return &Result{
|
||||
Allowed: false,
|
||||
Remaining: limit,
|
||||
ResetAfter: period,
|
||||
@@ -46,7 +59,7 @@ func (e *memoryEntry) calcBlockedResult(limit int, period time.Duration, now tim
|
||||
newest := e.timestamps[currentCount-1]
|
||||
resetAfter := max(0, newest.Add(period).Sub(now))
|
||||
|
||||
return &contracts.RateLimitResult{
|
||||
return &Result{
|
||||
Allowed: false,
|
||||
Remaining: limit - currentCount,
|
||||
ResetAfter: resetAfter,
|
||||
@@ -54,7 +67,7 @@ func (e *memoryEntry) calcBlockedResult(limit int, period time.Duration, now tim
|
||||
}
|
||||
}
|
||||
|
||||
// MemoryLimiter implements contracts.LimiterService using an in-memory sliding window algorithm.
|
||||
// MemoryLimiter implements an in-memory sliding window rate limiter.
|
||||
type MemoryLimiter struct {
|
||||
mu sync.Mutex
|
||||
entries map[string]*memoryEntry
|
||||
@@ -68,14 +81,14 @@ func NewMemoryLimiter() *MemoryLimiter {
|
||||
}
|
||||
|
||||
// Allow checks whether 1 event for key is permitted under rate.
|
||||
func (m *MemoryLimiter) Allow(ctx context.Context, key string, rate contracts.Rate) (*contracts.RateLimitResult, error) {
|
||||
func (m *MemoryLimiter) Allow(ctx context.Context, key string, rate Rate) (*Result, error) {
|
||||
return m.AllowN(ctx, key, rate, 1)
|
||||
}
|
||||
|
||||
// AllowN checks whether n events for key are permitted under rate.
|
||||
func (m *MemoryLimiter) AllowN(_ context.Context, key string, rate contracts.Rate, n int) (*contracts.RateLimitResult, error) {
|
||||
func (m *MemoryLimiter) AllowN(_ context.Context, key string, rate Rate, n int) (*Result, error) {
|
||||
if rate.Limit <= 0 || rate.Period <= 0 || n <= 0 {
|
||||
return &contracts.RateLimitResult{Allowed: true}, nil
|
||||
return &Result{Allowed: true}, nil
|
||||
}
|
||||
|
||||
m.mu.Lock()
|
||||
@@ -102,7 +115,7 @@ func (m *MemoryLimiter) AllowN(_ context.Context, key string, rate contracts.Rat
|
||||
|
||||
remaining := max(0, rate.Limit-len(entry.timestamps))
|
||||
|
||||
return &contracts.RateLimitResult{
|
||||
return &Result{
|
||||
Allowed: true,
|
||||
Remaining: remaining,
|
||||
ResetAfter: rate.Period,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
// Copyright 2026 Arctel.net
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package limiter
|
||||
package limiter_test
|
||||
|
||||
import (
|
||||
"Wavelet/core/contracts"
|
||||
"Wavelet/pkg/limiter"
|
||||
"context"
|
||||
"sync"
|
||||
"testing"
|
||||
@@ -16,9 +16,9 @@ import (
|
||||
|
||||
func TestMemoryLimiter_Basic(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
lim := NewMemoryLimiter()
|
||||
lim := limiter.NewMemoryLimiter()
|
||||
|
||||
rate := contracts.Rate{
|
||||
rate := limiter.Rate{
|
||||
Limit: 3,
|
||||
Period: 100 * time.Millisecond,
|
||||
}
|
||||
@@ -61,9 +61,9 @@ func TestMemoryLimiter_Basic(t *testing.T) {
|
||||
|
||||
func TestMemoryLimiter_WindowSlide(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
lim := NewMemoryLimiter()
|
||||
lim := limiter.NewMemoryLimiter()
|
||||
|
||||
rate := contracts.Rate{
|
||||
rate := limiter.Rate{
|
||||
Limit: 2,
|
||||
Period: 50 * time.Millisecond,
|
||||
}
|
||||
@@ -90,9 +90,9 @@ func TestMemoryLimiter_WindowSlide(t *testing.T) {
|
||||
|
||||
func TestMemoryLimiter_Concurrency(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
lim := NewMemoryLimiter()
|
||||
lim := limiter.NewMemoryLimiter()
|
||||
|
||||
rate := contracts.Rate{
|
||||
rate := limiter.Rate{
|
||||
Limit: 100,
|
||||
Period: time.Second,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user