This repository has been archived by the owner on Jan 27, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #36 from owncloud/feature/accounts-uuid-middleware
- Loading branch information
Showing
18 changed files
with
756 additions
and
271 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
issues: | ||
exclude-rules: | ||
- path: pkg/middleware/account_uuid.go | ||
text: "SA4006:" | ||
linters: | ||
- staticcheck | ||
- path: pkg/proxy/proxy_integration_test.go | ||
linters: | ||
- bodyclose | ||
linters: | ||
enable: | ||
- bodyclose | ||
- deadcode | ||
- gosimple | ||
- govet | ||
- staticcheck | ||
- structcheck | ||
- typecheck | ||
- unused | ||
- varcheck | ||
- depguard | ||
- golint | ||
- unconvert | ||
# - scopelint | ||
- maligned | ||
- misspell | ||
- prealloc | ||
#- gosec | ||
|
||
disable: | ||
- errcheck | ||
- ineffassign | ||
- scopelint |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package cache | ||
|
||
import ( | ||
"fmt" | ||
"sync" | ||
) | ||
|
||
// Entry represents an entry on the cache. You can type assert on V. | ||
type Entry struct { | ||
V interface{} | ||
Valid bool | ||
} | ||
|
||
// Cache is a barebones cache implementation. | ||
type Cache struct { | ||
entries map[string]map[string]Entry | ||
size int | ||
m sync.Mutex | ||
} | ||
|
||
// NewCache returns a new instance of Cache. | ||
func NewCache(o ...Option) Cache { | ||
opts := newOptions(o...) | ||
|
||
return Cache{ | ||
size: opts.size, | ||
entries: map[string]map[string]Entry{}, | ||
} | ||
} | ||
|
||
// Get gets an entry on a service `svcKey` by a give `key`. | ||
func (c *Cache) Get(svcKey, key string) (*Entry, error) { | ||
var value Entry | ||
ok := true | ||
|
||
c.m.Lock() | ||
defer c.m.Unlock() | ||
|
||
if value, ok = c.entries[svcKey][key]; !ok { | ||
return nil, fmt.Errorf("invalid service key: `%v`", key) | ||
} | ||
|
||
return &value, nil | ||
} | ||
|
||
// Set sets a key / value. It lets a service add entries on a request basis. | ||
func (c *Cache) Set(svcKey, key string, val interface{}) error { | ||
c.m.Lock() | ||
defer c.m.Unlock() | ||
|
||
if !c.fits() { | ||
return fmt.Errorf("cache is full") | ||
} | ||
|
||
if _, ok := c.entries[svcKey]; !ok { | ||
c.entries[svcKey] = map[string]Entry{} | ||
} | ||
|
||
if _, ok := c.entries[svcKey][key]; ok { | ||
return fmt.Errorf("key `%v` already exists", key) | ||
} | ||
|
||
c.entries[svcKey][key] = Entry{ | ||
V: val, | ||
Valid: true, | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// Invalidate invalidates a cache Entry by key. | ||
func (c *Cache) Invalidate(svcKey, key string) error { | ||
r, err := c.Get(svcKey, key) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
r.Valid = false | ||
c.entries[svcKey][key] = *r | ||
return nil | ||
} | ||
|
||
// Evict frees memory from the cache by removing invalid keys. It is a noop. | ||
func (c *Cache) Evict() { | ||
for _, v := range c.entries { | ||
for k, svcEntry := range v { | ||
if !svcEntry.Valid { | ||
delete(v, k) | ||
} | ||
} | ||
} | ||
} | ||
|
||
// Length returns the amount of entries per service key. | ||
func (c *Cache) Length(k string) int { | ||
return len(c.entries[k]) | ||
} | ||
|
||
func (c *Cache) fits() bool { | ||
return c.size >= len(c.entries) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
package cache | ||
|
||
import ( | ||
"testing" | ||
) | ||
|
||
// Prevents from invalid import cycle. | ||
type AccountsCacheEntry struct { | ||
Email string | ||
UUID string | ||
} | ||
|
||
func TestSet(t *testing.T) { | ||
c := NewCache( | ||
Size(256), | ||
) | ||
|
||
err := c.Set("accounts", "hello@foo.bar", AccountsCacheEntry{ | ||
Email: "hello@foo.bar", | ||
UUID: "9c31b040-59e2-4a2b-926b-334d9e3fbd05", | ||
}) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
if c.Length("accounts") != 1 { | ||
t.Errorf("expected length 1 got `%v`", len(c.entries)) | ||
} | ||
|
||
item, err := c.Get("accounts", "hello@foo.bar") | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
if cachedEntry, ok := item.V.(AccountsCacheEntry); !ok { | ||
t.Errorf("invalid cached value type") | ||
} else { | ||
if cachedEntry.Email != "hello@foo.bar" { | ||
t.Errorf("invalid value. Expected `hello@foo.bar` got: `%v`", cachedEntry.Email) | ||
} | ||
} | ||
} | ||
|
||
func TestEvict(t *testing.T) { | ||
c := NewCache( | ||
Size(256), | ||
) | ||
|
||
if err := c.Set("accounts", "hello@foo.bar", AccountsCacheEntry{ | ||
Email: "hello@foo.bar", | ||
UUID: "9c31b040-59e2-4a2b-926b-334d9e3fbd05", | ||
}); err != nil { | ||
t.Error(err) | ||
} | ||
|
||
if err := c.Invalidate("accounts", "hello@foo.bar"); err != nil { | ||
t.Error(err) | ||
} | ||
|
||
v, err := c.Get("accounts", "hello@foo.bar") | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
if v.Valid { | ||
t.Errorf("cache key unexpected valid state") | ||
} | ||
|
||
c.Evict() | ||
|
||
if c.Length("accounts") != 0 { | ||
t.Errorf("expected length 0 got `%v`", len(c.entries)) | ||
} | ||
} | ||
|
||
func TestGet(t *testing.T) { | ||
svcCache := NewCache( | ||
Size(256), | ||
) | ||
|
||
err := svcCache.Set("accounts", "node", "0.0.0.0:1234") | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
raw, err := svcCache.Get("accounts", "node") | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
v, ok := raw.V.(string) | ||
if !ok { | ||
t.Errorf("invalid type on service node key") | ||
} | ||
|
||
if v != "0.0.0.0:1234" { | ||
t.Errorf("expected `0.0.0.0:1234` got `%v`", v) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package cache | ||
|
||
import "time" | ||
|
||
// Options are all the possible options. | ||
type Options struct { | ||
size int | ||
ttl time.Duration | ||
} | ||
|
||
// Option mutates option | ||
type Option func(*Options) | ||
|
||
// Size configures the size of the cache in items. | ||
func Size(s int) Option { | ||
return func(o *Options) { | ||
o.size = s | ||
} | ||
} | ||
|
||
// TTL rebuilds the cache after the configured duration. | ||
func TTL(ttl time.Duration) Option { | ||
return func(o *Options) { | ||
o.ttl = ttl | ||
} | ||
} | ||
|
||
func newOptions(opts ...Option) Options { | ||
o := Options{} | ||
|
||
for _, v := range opts { | ||
v(&o) | ||
} | ||
|
||
return o | ||
} |
Oops, something went wrong.