mirror of
https://github.com/elyby/chrly.git
synced 2025-01-11 14:22:14 +05:30
#1: Renaming
This commit is contained in:
parent
d2d6d07fa6
commit
879a33344b
@ -1,96 +0,0 @@
|
|||||||
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/jobs_structure.go
Normal file
51
api/mojang/queue/jobs_structure.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 jobItem struct {
|
||||||
|
Username string
|
||||||
|
RespondTo chan *mojang.SignedTexturesResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
type jobsQueue struct {
|
||||||
|
items []*jobItem
|
||||||
|
lock sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *jobsQueue) New() *jobsQueue {
|
||||||
|
s.items = []*jobItem{}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *jobsQueue) Enqueue(t *jobItem) {
|
||||||
|
s.lock.Lock()
|
||||||
|
s.items = append(s.items, t)
|
||||||
|
s.lock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *jobsQueue) Dequeue(n int) []*jobItem {
|
||||||
|
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)
|
||||||
|
}
|
@ -10,9 +10,9 @@ func TestEnqueue(t *testing.T) {
|
|||||||
assert := testify.New(t)
|
assert := testify.New(t)
|
||||||
|
|
||||||
s := createQueue()
|
s := createQueue()
|
||||||
s.Enqueue(&Job{Username: "username1"})
|
s.Enqueue(&jobItem{Username: "username1"})
|
||||||
s.Enqueue(&Job{Username: "username2"})
|
s.Enqueue(&jobItem{Username: "username2"})
|
||||||
s.Enqueue(&Job{Username: "username3"})
|
s.Enqueue(&jobItem{Username: "username3"})
|
||||||
|
|
||||||
assert.Equal(3, s.Size())
|
assert.Equal(3, s.Size())
|
||||||
}
|
}
|
||||||
@ -21,10 +21,10 @@ func TestDequeueN(t *testing.T) {
|
|||||||
assert := testify.New(t)
|
assert := testify.New(t)
|
||||||
|
|
||||||
s := createQueue()
|
s := createQueue()
|
||||||
s.Enqueue(&Job{Username: "username1"})
|
s.Enqueue(&jobItem{Username: "username1"})
|
||||||
s.Enqueue(&Job{Username: "username2"})
|
s.Enqueue(&jobItem{Username: "username2"})
|
||||||
s.Enqueue(&Job{Username: "username3"})
|
s.Enqueue(&jobItem{Username: "username3"})
|
||||||
s.Enqueue(&Job{Username: "username4"})
|
s.Enqueue(&jobItem{Username: "username4"})
|
||||||
|
|
||||||
items := s.Dequeue(2)
|
items := s.Dequeue(2)
|
||||||
assert.Len(items, 2)
|
assert.Len(items, 2)
|
||||||
@ -39,8 +39,8 @@ func TestDequeueN(t *testing.T) {
|
|||||||
assert.True(s.IsEmpty())
|
assert.True(s.IsEmpty())
|
||||||
}
|
}
|
||||||
|
|
||||||
func createQueue() JobsQueue {
|
func createQueue() jobsQueue {
|
||||||
s := JobsQueue{}
|
s := jobsQueue{}
|
||||||
s.New()
|
s.New()
|
||||||
|
|
||||||
return s
|
return s
|
@ -1,51 +1,95 @@
|
|||||||
// Based on the implementation from https://flaviocopes.com/golang-data-structure-queue/
|
|
||||||
|
|
||||||
package queue
|
package queue
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/elyby/chrly/api/mojang"
|
"github.com/elyby/chrly/api/mojang"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Job struct {
|
var onFirstCall sync.Once
|
||||||
Username string
|
var queue = jobsQueue{}
|
||||||
RespondTo chan *mojang.SignedTexturesResponse
|
|
||||||
|
func ScheduleTexturesForUsername(username string) (resultChan chan *mojang.SignedTexturesResponse) {
|
||||||
|
onFirstCall.Do(func() {
|
||||||
|
queue.New()
|
||||||
|
startQueue()
|
||||||
|
})
|
||||||
|
|
||||||
|
// TODO: prevent of adding the same username more than once
|
||||||
|
queue.Enqueue(&jobItem{username, resultChan})
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
type JobsQueue struct {
|
func startQueue() {
|
||||||
items []*Job
|
go func() {
|
||||||
lock sync.RWMutex
|
for {
|
||||||
|
start := time.Now()
|
||||||
|
queueRound()
|
||||||
|
time.Sleep(time.Second - time.Since(start))
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *JobsQueue) New() *JobsQueue {
|
func queueRound() {
|
||||||
s.items = []*Job{}
|
if queue.IsEmpty() {
|
||||||
return s
|
return
|
||||||
}
|
|
||||||
|
|
||||||
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]
|
jobs := queue.Dequeue(100)
|
||||||
s.items = s.items[n:len(s.items)]
|
var usernames []string
|
||||||
s.lock.Unlock()
|
for _, job := range jobs {
|
||||||
|
usernames = append(usernames, job.Username)
|
||||||
|
}
|
||||||
|
|
||||||
return items
|
profiles, err := mojang.UsernamesToUuids(usernames)
|
||||||
}
|
switch err.(type) {
|
||||||
|
case *mojang.TooManyRequestsError:
|
||||||
|
for _, job := range jobs {
|
||||||
|
job.RespondTo <- nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *JobsQueue) IsEmpty() bool {
|
return
|
||||||
return len(s.items) == 0
|
case error:
|
||||||
}
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *JobsQueue) Size() int {
|
var wg sync.WaitGroup
|
||||||
return len(s.items)
|
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()
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user