Skip to content

Commit

Permalink
Added last seen stats for visitor
Browse files Browse the repository at this point in the history
  • Loading branch information
iambenkay committed Dec 17, 2020
1 parent 02efca7 commit 8d34f11
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 41 deletions.
26 changes: 17 additions & 9 deletions middleware/rate_limiter.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"golang.org/x/time/rate"
"net/http"
"sync"
"time"
)

// RateLimiterStore is the interface to be implemented by custom stores.
Expand Down Expand Up @@ -73,27 +74,34 @@ func RateLimiterWithConfig(config RateLimiterConfig) echo.MiddlewareFunc {
}

// RateLimiterMemoryStore is the built-in store implementation for RateLimiter
type RateLimiterMemoryStore struct {
visitors map[string]*rate.Limiter
mutex sync.Mutex
rate rate.Limit
burst int
}
type (
RateLimiterMemoryStore struct {
visitors map[string]visitor
mutex sync.Mutex
rate rate.Limit
burst int
}
visitor struct {
*rate.Limiter
lastSeen time.Time
}
)

// Allow implements RateLimiterStore.Allow
func (store *RateLimiterMemoryStore) Allow(identifier string) bool {
store.mutex.Lock()

if store.visitors == nil {
store.visitors = make(map[string]*rate.Limiter)
store.visitors = make(map[string]visitor)
}

limiter, exists := store.visitors[identifier]
if !exists {
limiter = rate.NewLimiter(store.rate, store.burst)
limiter.Limiter = rate.NewLimiter(store.rate, store.burst)
limiter.lastSeen = time.Now()
store.visitors[identifier] = limiter
}

limiter.lastSeen = time.Now()
store.mutex.Unlock()
return limiter.Allow()
}
106 changes: 74 additions & 32 deletions middleware/rate_limiter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,46 +119,88 @@ func TestRateLimiter(t *testing.T) {
}

func TestRateLimiterWithConfig(t *testing.T) {
var inMemoryStore = new(RateLimiterMemoryStore)
inMemoryStore.rate = 1
inMemoryStore.burst = 3

e := echo.New()
{
var inMemoryStore = new(RateLimiterMemoryStore)
inMemoryStore.rate = 1
inMemoryStore.burst = 3

handler := func(c echo.Context) error {
return c.String(http.StatusOK, "test")
e := echo.New()

handler := func(c echo.Context) error {
return c.String(http.StatusOK, "test")
}

testCases := []struct {
id string
code int
}{
{"127.0.0.1", 200},
{"127.0.0.1", 200},
{"127.0.0.1", 200},
{"127.0.0.1", 429},
{"127.0.0.1", 429},
{"127.0.0.1", 429},
{"127.0.0.1", 429},
}

for _, tc := range testCases {
req := httptest.NewRequest(http.MethodGet, "/", nil)
req.Header.Add(echo.HeaderXRealIP, tc.id)

rec := httptest.NewRecorder()

c := e.NewContext(req, rec)
mw := RateLimiterWithConfig(RateLimiterConfig{
SourceFunc: func(c echo.Context) string {
return c.RealIP()
},
Store: inMemoryStore,
})

_ = mw(handler)(c)

assert.Equal(t, tc.code, rec.Code)
}
}
{
var inMemoryStore = new(RateLimiterMemoryStore)
inMemoryStore.rate = 1
inMemoryStore.burst = 3

testCases := []struct {
id string
code int
}{
{"127.0.0.1", 200},
{"127.0.0.1", 200},
{"127.0.0.1", 200},
{"127.0.0.1", 429},
{"127.0.0.1", 429},
{"127.0.0.1", 429},
{"127.0.0.1", 429},
}
e := echo.New()

for _, tc := range testCases {
req := httptest.NewRequest(http.MethodGet, "/", nil)
req.Header.Add(echo.HeaderXRealIP, tc.id)
handler := func(c echo.Context) error {
return c.String(http.StatusOK, "test")
}

rec := httptest.NewRecorder()
testCases := []struct {
id string
code int
}{
{"127.0.0.1", 200},
{"127.0.0.1", 200},
{"127.0.0.1", 200},
{"127.0.0.1", 429},
{"127.0.0.1", 429},
{"127.0.0.1", 429},
{"127.0.0.1", 429},
}

c := e.NewContext(req, rec)
mw := RateLimiterWithConfig(RateLimiterConfig{
SourceFunc: func(c echo.Context) string {
return c.RealIP()
},
Store: inMemoryStore,
})
for _, tc := range testCases {
req := httptest.NewRequest(http.MethodGet, "/", nil)
req.Header.Add(echo.HeaderXRealIP, tc.id)

_ = mw(handler)(c)
rec := httptest.NewRecorder()

assert.Equal(t, tc.code, rec.Code)
c := e.NewContext(req, rec)
mw := RateLimiterWithConfig(RateLimiterConfig{
Store: inMemoryStore,
})

_ = mw(handler)(c)

assert.Equal(t, tc.code, rec.Code)
}
}
}

Expand Down

0 comments on commit 8d34f11

Please sign in to comment.