diff --git a/go.mod b/go.mod index 273e0a2c..b3f8ebef 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.14 require ( github.com/aws/aws-sdk-go v1.35.19 // indirect github.com/go-redis/redis/v8 v8.3.3 + github.com/gofiber/fiber/v2 v2.1.2 github.com/gofiber/utils v0.0.10 github.com/golang/snappy v0.0.2 // indirect github.com/gomodule/redigo v1.8.2 diff --git a/go.sum b/go.sum index 8444e476..b84445e6 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,5 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= github.com/aws/aws-sdk-go v1.34.28 h1:sscPpn/Ns3i0F4HPEWAVcwdIRaZZCuL7llJ2/60yPIk= github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48= github.com/aws/aws-sdk-go v1.35.19 h1:vdIqQnOIqTNtvnOdt9r3Bf/FiCJ7KV/7O2BIj4TPx2w= @@ -43,6 +44,9 @@ github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWe github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= +github.com/gofiber/fiber v1.14.6 h1:QRUPvPmr8ijQuGo1MgupHBn8E+wW0IKqiOvIZPtV70o= +github.com/gofiber/fiber/v2 v2.1.2 h1:b4rpt9xtj7LxT1Vp3yR76LOfs6ZzPJybbNMjjpn+fos= +github.com/gofiber/fiber/v2 v2.1.2/go.mod h1:jMNH7iuOJ1AGdoJrx1OwaZIX7SOrQUtJi9R35QWhi4s= github.com/gofiber/utils v0.0.10 h1:3Mr7X7JdCUo7CWf/i5sajSaDmArEDtti8bM1JUVso2U= github.com/gofiber/utils v0.0.10/go.mod h1:9J5aHFUIjq0XfknT4+hdSMG6/jzfaAgCu4HEbWDeBlo= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -75,6 +79,7 @@ github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaR github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= github.com/klauspost/compress v1.9.5 h1:U+CaK85mrNNb4k8BNOfgJtJ/gr6kswUCFj6miSzVC6M= github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.2 h1:MiK62aErc3gIiVEtyzKfeOHgW7atJb5g/KNX5m3c2nQ= github.com/klauspost/compress v1.11.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -122,6 +127,9 @@ github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.16.0/go.mod h1:YOKImeEosDdBPnxc0gy7INqi3m1zK6A+xl6TwOBhHCA= +github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV0YCnDjqSL7/q/JyPhhJSPk= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc h1:n+nNi93yXLkJvKwXNP9d55HC7lGK4H/SRcwB5IaUZLo= @@ -143,6 +151,7 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0 h1:wBouT66WTYFXdxfVdz9sVWARVd/2vfGcmI45D2gj45M= golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -166,8 +175,10 @@ golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201026173827-119d4633e4d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= diff --git a/memory/README.md b/memory/README.md index cd9a658d..b2f3514f 100644 --- a/memory/README.md +++ b/memory/README.md @@ -5,5 +5,5 @@ An in-memory storage driver. ### Creation ```go -store := memoryStore.New() +store := memory.New() ``` diff --git a/memory/config.go b/memory/config.go new file mode 100644 index 00000000..aefaa2c5 --- /dev/null +++ b/memory/config.go @@ -0,0 +1,21 @@ +package memory + +import "time" + +// Config defines the config for memory storage. +type Config struct { + GCInterval time.Duration +} + +// ConfigDefault is the default config +var ConfigDefault = Config{ + GCInterval: 10 * time.Second, +} + +// Helper function to set default values +func configDefault(cfg Config) Config { + if int(cfg.GCInterval) == 0 { + cfg.GCInterval = ConfigDefault.GCInterval + } + return cfg +} diff --git a/memory/go.mod b/memory/go.mod deleted file mode 100644 index 343f9b50..00000000 --- a/memory/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module github.com/gofiber/storage/memory - -go 1.15 - -require github.com/gofiber/utils v0.0.10 diff --git a/memory/go.sum b/memory/go.sum deleted file mode 100644 index 68aa6d7c..00000000 --- a/memory/go.sum +++ /dev/null @@ -1,2 +0,0 @@ -github.com/gofiber/utils v0.0.10 h1:3Mr7X7JdCUo7CWf/i5sajSaDmArEDtti8bM1JUVso2U= -github.com/gofiber/utils v0.0.10/go.mod h1:9J5aHFUIjq0XfknT4+hdSMG6/jzfaAgCu4HEbWDeBlo= diff --git a/memory/memory.go b/memory/memory.go index a06f9488..13a1dbd6 100644 --- a/memory/memory.go +++ b/memory/memory.go @@ -1,88 +1,103 @@ -package memoryStore +package memory import ( "sync" "time" ) -func New() *MemoryStore { - ms := &MemoryStore{ - data: make(map[string]dataPoint), - gcInterval: time.Second * 10, - } - go ms.gc() - return ms -} - -type MemoryStore struct { +// Storage interface that is implemented by storage providers +type Storage struct { mux sync.RWMutex - data map[string]dataPoint + db map[string]entry gcInterval time.Duration } -type dataPoint struct { +type entry struct { data []byte expiry int64 } -func (ms *MemoryStore) Get(id string) ([]byte, error) { - ms.mux.RLock() - v, ok := ms.data[id] - ms.mux.RUnlock() +// New creates a new memory storage +func New(config ...Config) *Storage { + // Set default config + cfg := ConfigDefault + + // Override config if provided + if len(config) > 0 { + cfg = configDefault(config[0]) + } + + // Create storage + store := &Storage{ + db: make(map[string]entry), + gcInterval: cfg.GCInterval, + } + + // start garbage collector + go store.gc() + + return store +} + +// Get value by key +func (s *Storage) Get(key string) ([]byte, error) { + s.mux.RLock() + v, ok := s.db[key] + s.mux.RUnlock() if !ok { - return []byte{}, nil + return nil, nil } if v.expiry < time.Now().Unix() && v.expiry != 0 { - ms.Delete(id) - return []byte{}, nil + s.Delete(key) + return nil, nil } return v.data, nil } -func (ms *MemoryStore) Set(id string, val []byte, expiration time.Duration) error { - - var expirationTime int64 - if expiration != 0 { - expirationTime = time.Now().Add(expiration).Unix() +// Set key with value +func (s *Storage) Set(key string, val []byte, exp time.Duration) error { + var expire int64 + if exp != 0 { + expire = time.Now().Add(exp).Unix() } - ms.mux.Lock() - ms.data[id] = dataPoint{val, expirationTime} - ms.mux.Unlock() + s.mux.Lock() + s.db[key] = entry{val, expire} + s.mux.Unlock() return nil } -func (ms *MemoryStore) Delete(id string) error { - ms.mux.Lock() - delete(ms.data, id) - ms.mux.Unlock() +// Delete key by key +func (s *Storage) Delete(key string) error { + s.mux.Lock() + delete(s.db, key) + s.mux.Unlock() return nil } -func (ms *MemoryStore) Clear() error { - ms.mux.Lock() - ms.data = make(map[string]dataPoint) - ms.mux.Unlock() +// Clear all keys +func (s *Storage) Clear() error { + s.mux.Lock() + s.db = make(map[string]entry) + s.mux.Unlock() return nil } -func (ms *MemoryStore) gc() { - tick := time.NewTicker(ms.gcInterval) +func (s *Storage) gc() { + tick := time.NewTicker(s.gcInterval) for { <-tick.C - ms.mux.Lock() + s.mux.Lock() now := time.Now().Unix() - for id, v := range ms.data { + for id, v := range s.db { if v.expiry < now && v.expiry != 0 { - delete(ms.data, id) + delete(s.db, id) } } - - ms.mux.Unlock() - + s.mux.Unlock() } } diff --git a/memory/memory_test.go b/memory/memory_test.go index ecbd7387..6e9f2f7e 100644 --- a/memory/memory_test.go +++ b/memory/memory_test.go @@ -1,10 +1,10 @@ -package memoryStore +package memory import ( "testing" "time" - "github.com/gofiber/utils" + "github.com/gofiber/fiber/v2/utils" ) func Test_Set(t *testing.T) { @@ -16,7 +16,7 @@ func Test_Set(t *testing.T) { store.Set(id, value, 0) - utils.AssertEqual(t, dataPoint{value, 0}, store.data[id]) + utils.AssertEqual(t, entry{value, 0}, store.db[id]) } @@ -31,7 +31,7 @@ func Test_SetExpiry(t *testing.T) { store.Set(id, value, expiry) now := time.Now().Unix() - fromStore, found := store.data[id] + fromStore, found := store.db[id] utils.AssertEqual(t, true, found) delta := fromStore.expiry - now @@ -47,8 +47,8 @@ func Test_SetExpiry(t *testing.T) { func Test_GC(t *testing.T) { // New() isn't being used here so the gcInterval can be set low - store := &MemoryStore{ - data: make(map[string]dataPoint), + store := &Storage{ + db: make(map[string]entry), gcInterval: time.Second * 1, } go store.gc() @@ -58,11 +58,11 @@ func Test_GC(t *testing.T) { expireAt := time.Now().Add(time.Second * 2).Unix() - store.data[id] = dataPoint{value, expireAt} + store.db[id] = entry{value, expireAt} time.Sleep(time.Second * 4) // The purpose of the long delay is to ensure the GC has time to run and delete the value - _, found := store.data[id] + _, found := store.db[id] utils.AssertEqual(t, false, found) } @@ -74,7 +74,7 @@ func Test_Get(t *testing.T) { id := "hello" value := []byte("Hi there!") - store.data[id] = dataPoint{value, 0} + store.db[id] = entry{value, 0} returnedValue, err := store.Get(id) utils.AssertEqual(t, nil, err) @@ -89,12 +89,12 @@ func Test_Delete(t *testing.T) { id := "hello" value := []byte("Hi there!") - store.data[id] = dataPoint{value, 0} + store.db[id] = entry{value, 0} err := store.Delete(id) utils.AssertEqual(t, nil, err) - _, found := store.data[id] + _, found := store.db[id] utils.AssertEqual(t, false, found) } @@ -106,11 +106,11 @@ func Test_Clear(t *testing.T) { id := "hello" value := []byte("Hi there!") - store.data[id] = dataPoint{value, 0} + store.db[id] = entry{value, 0} err := store.Clear() utils.AssertEqual(t, nil, err) - utils.AssertEqual(t, make(map[string]dataPoint), store.data) + utils.AssertEqual(t, make(map[string]entry), store.db) } @@ -137,7 +137,7 @@ func Benchmark_Get(b *testing.B) { id := "hello" value := []byte("Hi there!") - store.data[id] = dataPoint{value, 0} + store.db[id] = entry{value, 0} b.ResetTimer()