mirror of
https://github.com/elyby/chrly.git
synced 2024-08-25 14:20:00 +05:30
116 lines
2.3 KiB
Go
116 lines
2.3 KiB
Go
package mojangtextures
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/elyby/chrly/api/mojang"
|
|
|
|
"github.com/tevino/abool"
|
|
)
|
|
|
|
var now = time.Now
|
|
|
|
type inMemoryItem struct {
|
|
textures *mojang.SignedTexturesResponse
|
|
timestamp int64
|
|
}
|
|
|
|
type InMemoryTexturesStorage struct {
|
|
GCPeriod time.Duration
|
|
Duration time.Duration
|
|
|
|
lock sync.Mutex
|
|
data map[string]*inMemoryItem
|
|
working *abool.AtomicBool
|
|
}
|
|
|
|
func NewInMemoryTexturesStorage() *InMemoryTexturesStorage {
|
|
storage := &InMemoryTexturesStorage{
|
|
GCPeriod: 10 * time.Second,
|
|
Duration: time.Minute + 10*time.Second,
|
|
data: make(map[string]*inMemoryItem),
|
|
}
|
|
|
|
return storage
|
|
}
|
|
|
|
func (s *InMemoryTexturesStorage) Start() {
|
|
if s.working == nil {
|
|
s.working = abool.New()
|
|
}
|
|
|
|
if !s.working.IsSet() {
|
|
go func() {
|
|
time.Sleep(s.GCPeriod)
|
|
// TODO: this can be reimplemented in future with channels, but right now I have no idea how to make it right
|
|
for s.working.IsSet() {
|
|
start := time.Now()
|
|
s.gc()
|
|
time.Sleep(s.GCPeriod - time.Since(start))
|
|
}
|
|
}()
|
|
}
|
|
|
|
s.working.Set()
|
|
}
|
|
|
|
func (s *InMemoryTexturesStorage) Stop() {
|
|
s.working.UnSet()
|
|
}
|
|
|
|
func (s *InMemoryTexturesStorage) GetTextures(uuid string) (*mojang.SignedTexturesResponse, error) {
|
|
s.lock.Lock()
|
|
defer s.lock.Unlock()
|
|
|
|
item, exists := s.data[uuid]
|
|
validRange := s.getMinimalNotExpiredTimestamp()
|
|
if !exists || validRange > item.timestamp {
|
|
return nil, &ValueNotFound{}
|
|
}
|
|
|
|
return item.textures, nil
|
|
}
|
|
|
|
func (s *InMemoryTexturesStorage) StoreTextures(uuid string, textures *mojang.SignedTexturesResponse) {
|
|
var timestamp int64
|
|
if textures != nil {
|
|
decoded := textures.DecodeTextures()
|
|
if decoded == nil {
|
|
panic("unable to decode textures")
|
|
}
|
|
|
|
timestamp = decoded.Timestamp
|
|
} else {
|
|
timestamp = unixNanoToUnixMicro(now().UnixNano())
|
|
}
|
|
|
|
s.lock.Lock()
|
|
defer s.lock.Unlock()
|
|
|
|
s.data[uuid] = &inMemoryItem{
|
|
textures: textures,
|
|
timestamp: timestamp,
|
|
}
|
|
}
|
|
|
|
func (s *InMemoryTexturesStorage) gc() {
|
|
s.lock.Lock()
|
|
defer s.lock.Unlock()
|
|
|
|
maxTime := s.getMinimalNotExpiredTimestamp()
|
|
for uuid, value := range s.data {
|
|
if maxTime > value.timestamp {
|
|
delete(s.data, uuid)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *InMemoryTexturesStorage) getMinimalNotExpiredTimestamp() int64 {
|
|
return unixNanoToUnixMicro(now().Add(s.Duration * time.Duration(-1)).UnixNano())
|
|
}
|
|
|
|
func unixNanoToUnixMicro(unixNano int64) int64 {
|
|
return unixNano / 10e5
|
|
}
|