-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
#1: Rough implementation of textures queue
- Loading branch information
1 parent
44f3ee7
commit d2d6d07
Showing
3 changed files
with
194 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
} |