diff --git a/go.mod b/go.mod index f4fa88a..c596801 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,7 @@ require ( github.com/dustin/go-humanize v1.0.0 github.com/elithrar/simple-scrypt v1.3.0 github.com/gabstv/merger v1.0.1 + github.com/go-mail/mail v2.3.1+incompatible github.com/goccy/go-yaml v1.8.6 github.com/gomarkdown/markdown v0.0.0-20201113031856-722100d81a8e github.com/google/uuid v1.2.0 // indirect diff --git a/go.sum b/go.sum index 7408716..c65da8f 100644 --- a/go.sum +++ b/go.sum @@ -80,6 +80,8 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-mail/mail v2.3.1+incompatible h1:UzNOn0k5lpfVtO31cK3hn6I4VEVGhe3lX8AJBAxXExM= +github.com/go-mail/mail v2.3.1+incompatible/go.mod h1:VPWjmmNyRsWXQZHVHT3g0YbIINUkSmuKOiLIDkWbL6M= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= @@ -261,6 +263,7 @@ github.com/spf13/cobra v0.0.7/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHN github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= @@ -286,6 +289,7 @@ github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyC github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/vcraescu/go-paginator v1.0.0 h1:ilNmRhlgG8N44LuxfGoPI2u8guXMA6gUqaPGA5BmRFs= github.com/vcraescu/go-paginator v1.0.0/go.mod h1:caZCjjt2qcA1O2aDzW7lwAcK4Rxw3LNvdEVF/ONxZWw= +github.com/wblakecaldwell/profiler v0.0.0-20150908040756-6111ef1313a1 h1:Dz/PRieZRmOhDfOlkVpY1LYYIfNoTJjlDirAlagOr0s= github.com/wblakecaldwell/profiler v0.0.0-20150908040756-6111ef1313a1/go.mod h1:3+0F8oLB1rQlbIcRAuqDgGdzNi9X69un/aPz4cUAFV4= github.com/writeas/slug v1.2.0 h1:EMQ+cwLiOcA6EtFwUgyw3Ge18x9uflUnOnR6bp/J+/g= github.com/writeas/slug v1.2.0/go.mod h1:RE8shOqQP3YhsfsQe0L3RnuejfQ4Mk+JjY5YJQFubfQ= diff --git a/internal/ttlcache.go b/internal/ttlcache.go new file mode 100644 index 0000000..776d8ca --- /dev/null +++ b/internal/ttlcache.go @@ -0,0 +1,73 @@ +package internal + +import ( + "sync" + "time" +) + +type CachedItem struct { + Value int + Expiry time.Time +} + +func (item CachedItem) Expired() bool { + return time.Now().After(item.Expiry) +} + +type CachedItems map[string]CachedItem + +type TTLCache struct { + sync.RWMutex + + ttl time.Duration + items map[string]CachedItem +} + +func (cache *TTLCache) Dec(k string) int { + return cache.Set(k, cache.Get(k)-1) +} + +func (cache *TTLCache) Inc(k string) int { + return cache.Set(k, cache.Get(k)+1) +} + +func (cache *TTLCache) Get(k string) int { + cache.RLock() + defer cache.RUnlock() + v, ok := cache.items[k] + if !ok { + return 0 + } + return v.Value +} + +func (cache *TTLCache) Set(k string, v int) int { + cache.Lock() + defer cache.Unlock() + + cache.items[k] = CachedItem{v, time.Now().Add(cache.ttl)} + + return v +} + +func (cache *TTLCache) Reset(k string) int { + return cache.Set(k, 0) +} + +func NewTTLCache(ttl time.Duration) *TTLCache { + cache := &TTLCache{ttl: ttl, items: make(CachedItems)} + + go func() { + for range time.Tick(ttl) { + cache.Lock() + for k, v := range cache.items { + if v.Expired() { + delete(cache.items, k) + } + } + cache.Unlock() + } + }() + + return cache +}