mirror of
https://github.com/elyby/chrly.git
synced 2024-12-23 21:50:03 +05:30
#1: Rough implementation of textures queue
This commit is contained in:
parent
44f3ee7413
commit
d2d6d07fa6
96
api/mojang/queue/cycle.go
Normal file
96
api/mojang/queue/cycle.go
Normal file
@ -0,0 +1,96 @@
|
||||
package queue
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/elyby/chrly/api/mojang"
|
||||
)
|
||||
|
||||
var once sync.Once
|
||||
var jobsQueue = JobsQueue{}
|
||||
|
||||
func ScheduleTexturesForUsername(username string) chan *mojang.SignedTexturesResponse {
|
||||
once.Do(func() {
|
||||
jobsQueue.New()
|
||||
startQueue()
|
||||
})
|
||||
|
||||
// TODO: prevent of adding the same username more than once
|
||||
resultChan := make(chan *mojang.SignedTexturesResponse)
|
||||
jobsQueue.Enqueue(&Job{username, resultChan})
|
||||
|
||||
return resultChan
|
||||
}
|
||||
|
||||
func startQueue() {
|
||||
go func() {
|
||||
for {
|
||||
start := time.Now()
|
||||
queueRound()
|
||||
time.Sleep(time.Second - time.Since(start))
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func queueRound() {
|
||||
if jobsQueue.IsEmpty() {
|
||||
return
|
||||
}
|
||||
|
||||
jobs := jobsQueue.Dequeue(100)
|
||||
var usernames []string
|
||||
for _, job := range jobs {
|
||||
usernames = append(usernames, job.Username)
|
||||
}
|
||||
|
||||
profiles, err := mojang.UsernamesToUuids(usernames)
|
||||
switch err.(type) {
|
||||
case *mojang.TooManyRequestsError:
|
||||
for _, job := range jobs {
|
||||
job.RespondTo <- nil
|
||||
}
|
||||
|
||||
return
|
||||
case error:
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for _, job := range jobs {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
var result *mojang.SignedTexturesResponse
|
||||
shouldCache := true
|
||||
var uuid string
|
||||
for _, profile := range profiles {
|
||||
if strings.EqualFold(job.Username, profile.Name) {
|
||||
uuid = profile.Id
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if uuid != "" {
|
||||
result, err = mojang.UuidToTextures(uuid, true)
|
||||
if err != nil {
|
||||
if _, ok := err.(*mojang.TooManyRequestsError); !ok {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
shouldCache = false
|
||||
}
|
||||
}
|
||||
|
||||
wg.Done()
|
||||
|
||||
job.RespondTo <- result
|
||||
|
||||
if shouldCache {
|
||||
// TODO: store result to cache
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
}
|
51
api/mojang/queue/queue.go
Normal file
51
api/mojang/queue/queue.go
Normal file
@ -0,0 +1,51 @@
|
||||
// Based on the implementation from https://flaviocopes.com/golang-data-structure-queue/
|
||||
|
||||
package queue
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/elyby/chrly/api/mojang"
|
||||
)
|
||||
|
||||
type Job struct {
|
||||
Username string
|
||||
RespondTo chan *mojang.SignedTexturesResponse
|
||||
}
|
||||
|
||||
type JobsQueue struct {
|
||||
items []*Job
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
func (s *JobsQueue) New() *JobsQueue {
|
||||
s.items = []*Job{}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *JobsQueue) Enqueue(t *Job) {
|
||||
s.lock.Lock()
|
||||
s.items = append(s.items, t)
|
||||
s.lock.Unlock()
|
||||
}
|
||||
|
||||
func (s *JobsQueue) Dequeue(n int) []*Job {
|
||||
s.lock.Lock()
|
||||
if n > s.Size() {
|
||||
n = s.Size()
|
||||
}
|
||||
|
||||
items := s.items[0:n]
|
||||
s.items = s.items[n:len(s.items)]
|
||||
s.lock.Unlock()
|
||||
|
||||
return items
|
||||
}
|
||||
|
||||
func (s *JobsQueue) IsEmpty() bool {
|
||||
return len(s.items) == 0
|
||||
}
|
||||
|
||||
func (s *JobsQueue) Size() int {
|
||||
return len(s.items)
|
||||
}
|
47
api/mojang/queue/queue_test.go
Normal file
47
api/mojang/queue/queue_test.go
Normal file
@ -0,0 +1,47 @@
|
||||
package queue
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
testify "github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestEnqueue(t *testing.T) {
|
||||
assert := testify.New(t)
|
||||
|
||||
s := createQueue()
|
||||
s.Enqueue(&Job{Username: "username1"})
|
||||
s.Enqueue(&Job{Username: "username2"})
|
||||
s.Enqueue(&Job{Username: "username3"})
|
||||
|
||||
assert.Equal(3, s.Size())
|
||||
}
|
||||
|
||||
func TestDequeueN(t *testing.T) {
|
||||
assert := testify.New(t)
|
||||
|
||||
s := createQueue()
|
||||
s.Enqueue(&Job{Username: "username1"})
|
||||
s.Enqueue(&Job{Username: "username2"})
|
||||
s.Enqueue(&Job{Username: "username3"})
|
||||
s.Enqueue(&Job{Username: "username4"})
|
||||
|
||||
items := s.Dequeue(2)
|
||||
assert.Len(items, 2)
|
||||
assert.Equal("username1", items[0].Username)
|
||||
assert.Equal("username2", items[1].Username)
|
||||
assert.Equal(2, s.Size())
|
||||
|
||||
items = s.Dequeue(40)
|
||||
assert.Len(items, 2)
|
||||
assert.Equal("username3", items[0].Username)
|
||||
assert.Equal("username4", items[1].Username)
|
||||
assert.True(s.IsEmpty())
|
||||
}
|
||||
|
||||
func createQueue() JobsQueue {
|
||||
s := JobsQueue{}
|
||||
s.New()
|
||||
|
||||
return s
|
||||
}
|
Loading…
Reference in New Issue
Block a user