ripple-api/app/websockets/scores.go
2017-02-19 18:19:59 +01:00

122 lines
2.3 KiB
Go

package websockets
import (
"encoding/json"
"fmt"
"sync"
"zxq.co/ripple/rippleapi/app/v1"
)
type subscribeScoresUser struct {
User int `json:"user"`
Modes []int `json:"modes"`
}
// SubscribeScores subscribes a connection to score updates.
func SubscribeScores(c *conn, message incomingMessage) {
var ssu []subscribeScoresUser
err := json.Unmarshal(message.Data, &ssu)
if err != nil {
c.WriteJSON(TypeInvalidMessage, err.Error())
return
}
scoreSubscriptionsMtx.Lock()
var found bool
for idx, el := range scoreSubscriptions {
// already exists, change the users
if el.Conn.ID == c.ID {
found = true
scoreSubscriptions[idx].Users = ssu
}
}
// if it was not found, we need to add it
if !found {
scoreSubscriptions = append(scoreSubscriptions, scoreSubscription{c, ssu})
}
scoreSubscriptionsMtx.Unlock()
c.WriteJSON(TypeSubscribed, message)
}
type scoreSubscription struct {
Conn *conn
Users []subscribeScoresUser
}
var scoreSubscriptions []scoreSubscription
var scoreSubscriptionsMtx = new(sync.RWMutex)
func scoreRetriever() {
ps, err := red.Subscribe("api:score_submission")
if err != nil {
fmt.Println(err)
}
for {
msg, err := ps.ReceiveMessage()
if err != nil {
fmt.Println(err.Error())
return
}
go handleNewScore(msg.Payload)
}
}
type score struct {
v1.Score
UserID int `json:"user_id"`
}
func handleNewScore(id string) {
var s score
err := db.Get(&s, `
SELECT
id, beatmap_md5, score, max_combo, full_combo, mods,
300_count, 100_count, 50_count, gekis_count, katus_count, misses_count,
time, play_mode, accuracy, pp, completed, userid AS user_id
FROM scores WHERE id = ?`, id)
if err != nil {
fmt.Println(err)
return
}
scoreSubscriptionsMtx.RLock()
cp := make([]scoreSubscription, len(scoreSubscriptions))
copy(cp, scoreSubscriptions)
scoreSubscriptionsMtx.RUnlock()
for _, el := range cp {
if len(el.Users) > 0 && !scoreUserValid(el.Users, s) {
continue
}
el.Conn.WriteJSON(TypeNewScore, s)
}
}
func scoreUserValid(users []subscribeScoresUser, s score) bool {
for _, u := range users {
if u.User == s.UserID {
if len(u.Modes) > 0 {
if !inModes(u.Modes, s.PlayMode) {
return false
}
}
return true
}
}
return false
}
func inModes(modes []int, i int) bool {
for _, m := range modes {
if m == i {
return true
}
}
return false
}