mirror of
https://github.com/elyby/chrly.git
synced 2024-12-25 14:39:55 +05:30
68 lines
1.8 KiB
Go
68 lines
1.8 KiB
Go
|
package mojang
|
||
|
|
||
|
import (
|
||
|
"sync"
|
||
|
"time"
|
||
|
|
||
|
"github.com/jellydator/ttlcache/v3"
|
||
|
)
|
||
|
|
||
|
type MojangApiTexturesProvider struct {
|
||
|
MojangApiTexturesEndpoint func(uuid string, signed bool) (*SignedTexturesResponse, error)
|
||
|
}
|
||
|
|
||
|
func (ctx *MojangApiTexturesProvider) GetTextures(uuid string) (*SignedTexturesResponse, error) {
|
||
|
return ctx.MojangApiTexturesEndpoint(uuid, true)
|
||
|
}
|
||
|
|
||
|
// Perfectly there should be an object with provider and cache implementation,
|
||
|
// but I decided not to introduce a layer and just implement cache in place.
|
||
|
type TexturesProviderWithInMemoryCache struct {
|
||
|
provider TexturesProvider
|
||
|
once sync.Once
|
||
|
cache *ttlcache.Cache[string, *SignedTexturesResponse]
|
||
|
}
|
||
|
|
||
|
func NewTexturesProviderWithInMemoryCache(provider TexturesProvider) *TexturesProviderWithInMemoryCache {
|
||
|
storage := &TexturesProviderWithInMemoryCache{
|
||
|
provider: provider,
|
||
|
cache: ttlcache.New[string, *SignedTexturesResponse](
|
||
|
ttlcache.WithDisableTouchOnHit[string, *SignedTexturesResponse](),
|
||
|
// I'm aware of ttlcache.WithLoader(), but it doesn't allow to return an error
|
||
|
),
|
||
|
}
|
||
|
|
||
|
return storage
|
||
|
}
|
||
|
|
||
|
func (s *TexturesProviderWithInMemoryCache) GetTextures(uuid string) (*SignedTexturesResponse, error) {
|
||
|
item := s.cache.Get(uuid)
|
||
|
// Don't check item.IsExpired() since Get function is already did this check
|
||
|
if item != nil {
|
||
|
return item.Value(), nil
|
||
|
}
|
||
|
|
||
|
result, err := s.provider.GetTextures(uuid)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
s.cache.Set(uuid, result, time.Minute)
|
||
|
// Call it only after first set so GC will work more often
|
||
|
s.startGcOnce()
|
||
|
|
||
|
return result, nil
|
||
|
}
|
||
|
|
||
|
func (s *TexturesProviderWithInMemoryCache) StopGC() {
|
||
|
// If you call the Stop() on a non-started GC, the process will hang trying to close the uninitialized channel
|
||
|
s.startGcOnce()
|
||
|
s.cache.Stop()
|
||
|
}
|
||
|
|
||
|
func (s *TexturesProviderWithInMemoryCache) startGcOnce() {
|
||
|
s.once.Do(func() {
|
||
|
go s.cache.Start()
|
||
|
})
|
||
|
}
|