ripple-api/app/websockets/scores.go

143 lines
2.7 KiB
Go
Raw Permalink Normal View History

2017-02-19 17:19:59 +00:00
package websockets
import (
"encoding/json"
"fmt"
"strings"
2017-02-19 17:19:59 +00:00
"sync"
"gopkg.in/thehowl/go-osuapi.v1"
2017-02-19 17:19:59 +00:00
"zxq.co/ripple/rippleapi/app/v1"
"zxq.co/x/getrank"
2017-02-19 17:19:59 +00:00
)
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(TypeSubscribedToScores, ssu)
2017-02-19 17:19:59 +00:00
}
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) {
defer catchPanic()
2017-02-19 17:19:59 +00:00
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
}
s.Rank = strings.ToUpper(getrank.GetRank(
osuapi.Mode(s.PlayMode),
osuapi.Mods(s.Mods),
s.Accuracy,
s.Count300,
s.Count100,
s.Count50,
s.CountMiss,
))
2017-02-19 17:19:59 +00:00
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
}
func catchPanic() {
r := recover()
if r != nil {
fmt.Println(r)
// TODO: sentry
}
}