Add /api/groups endpoint

This commit is contained in:
mkwcat 2023-12-11 14:14:36 -05:00
parent 22045c4f49
commit 53cec11f17
No known key found for this signature in database
GPG Key ID: 7A505679CE9E7AA9
6 changed files with 140 additions and 26 deletions

48
api/groups.go Normal file
View File

@ -0,0 +1,48 @@
package api
import (
"encoding/json"
"net/http"
"net/url"
"strconv"
"wwfc/qr2"
)
func HandleGroups(w http.ResponseWriter, r *http.Request) {
u, err := url.Parse(r.URL.String())
if err != nil {
panic(err)
}
query, err := url.ParseQuery(u.RawQuery)
if err != nil {
panic(err)
}
groups := qr2.GetGroups(append(query["gamename"], "")[0])
for _, group := range groups {
for i, player := range group.Players {
filtered := map[string]string{}
filtered["dwc_pid"] = player["dwc_pid"]
filtered["ingamename"] = player["ingamename"]
if player["gamename"] == "mariokartwii" {
filtered["ev"] = player["ev"]
filtered["eb"] = player["eb"]
}
group.Players[i] = filtered
}
}
jsonData, err := json.Marshal(groups)
if err != nil {
panic(err)
}
w.Header().Set("Content-Type", "text/json")
w.Header().Set("Content-Length", strconv.Itoa(len(jsonData)))
w.Write(jsonData)
}

View File

@ -109,6 +109,8 @@ func (g *GameSpySession) authAddFriend(command common.GameSpyCommand) {
}
func (g *GameSpySession) setStatus(command common.GameSpyCommand) {
// TODO: Some games don't make it obvious to QR2 when they leave a group, so try checking via a status update
status := command.CommandValue
statstring, ok := command.OtherValues["statstring"]

View File

@ -9,6 +9,7 @@ import (
"regexp"
"strconv"
"strings"
"wwfc/api"
"wwfc/common"
"wwfc/logging"
"wwfc/nhttp"
@ -75,6 +76,12 @@ func handleRequest(w http.ResponseWriter, r *http.Request) {
return
}
// Check for /api/groups
if r.URL.Path == "/api/groups" {
api.HandleGroups(w, r)
return
}
// Stage 1
if match := regexStage1URL.FindStringSubmatch(r.URL.String()); match != nil {
val, err := strconv.Atoi(match[1])

View File

@ -10,28 +10,44 @@ import (
type Group struct {
GroupID uint32
ServerAID uint8
Players map[uint8]*Session
GroupName string
GameName string
Server *Session
Players map[*Session]bool
}
var groups = map[*Group]bool{}
var groups = map[string]*Group{}
func processResvOK(moduleName string, cmd common.MatchCommandDataResvOK, sender, destination *Session) bool {
group := sender.GroupPointer
if group == nil {
logging.Notice(moduleName, "Creating new group", aurora.Cyan(cmd.GroupID), "/", aurora.Cyan(cmd.ProfileID))
group = &Group{
GroupID: cmd.GroupID,
ServerAID: uint8(cmd.SenderAID),
Players: map[uint8]*Session{uint8(cmd.SenderAID): sender},
}
sender.GroupPointer = group
groups[group] = true
if len(groups) >= 100000 {
logging.Error(moduleName, "Hit arbitrary global maximum group count (somehow)")
return false
}
if uint8(cmd.SenderAID) != sender.GroupAID {
logging.Error(moduleName, "ResvOK: Invalid sender AID")
return false
group := sender.GroupPointer
if group == nil {
group = &Group{
GroupID: cmd.GroupID,
GroupName: "",
GameName: sender.Data["gamename"],
Server: sender,
Players: map[*Session]bool{sender: true},
}
for {
groupName := common.RandomString(6)
if groups[groupName] != nil {
continue
}
group.GroupName = groupName
break
}
sender.GroupPointer = group
groups[group.GroupName] = group
logging.Notice(moduleName, "Created new group", aurora.Cyan(group.GroupName))
}
// TODO: Check if the sender is the actual server (host) once host migration works
@ -39,10 +55,9 @@ func processResvOK(moduleName string, cmd common.MatchCommandDataResvOK, sender,
// Keep group ID updated
sender.GroupPointer.GroupID = cmd.GroupID
logging.Info(moduleName, "New AID", aurora.Cyan(uint8(cmd.ReceiverNewAID)), "in group", aurora.Cyan(group.GroupID))
group.Players[uint8(cmd.ReceiverNewAID)] = destination
logging.Info(moduleName, "New player", aurora.BrightCyan(destination.Data["dwc_pid"]), "in group", aurora.Cyan(group.GroupName))
group.Players[destination] = true
destination.GroupPointer = group
destination.GroupAID = uint8(cmd.ReceiverNewAID)
return true
}
@ -79,3 +94,46 @@ func ProcessGPResvOK(cmd common.MatchCommandDataResvOK, senderIP uint64, senderP
return processResvOK(moduleName, cmd, from, to)
}
type GroupInfo struct {
GroupName string `json:"id"`
GameName string `json:"gamename"`
ServerPID string `json:"host"`
Players []map[string]string `json:"players"`
}
// GetGroups returns an unsorted copy of all online rooms
func GetGroups(gameName string) []GroupInfo {
var groupsCopy []GroupInfo
mutex.Lock()
for _, group := range groups {
if gameName != "" && gameName != group.GameName {
continue
}
groupInfo := GroupInfo{
GroupName: group.GroupName,
GameName: group.GameName,
ServerPID: "",
Players: []map[string]string{},
}
if group.Server != nil {
groupInfo.ServerPID = group.Server.Data["dwc_pid"]
}
for session, _ := range group.Players {
mapData := map[string]string{}
for k, v := range session.Data {
mapData[k] = v
}
groupInfo.Players = append(groupInfo.Players, mapData)
}
groupsCopy = append(groupsCopy, groupInfo)
}
mutex.Unlock()
return groupsCopy
}

View File

@ -72,7 +72,6 @@ func SendClientMessage(senderIP string, destSearchID uint64, message []byte) {
logging.Error(moduleName, "Received invalid match version")
return
}
logging.Info(moduleName, "Version:", version)
senderProfileID := binary.LittleEndian.Uint32(message[0x10:0x14])
moduleName = "QR2/MSG:p" + strconv.FormatUint(uint64(senderProfileID), 10)

View File

@ -30,7 +30,6 @@ type Session struct {
PacketCount uint32
ReservationID uint64
GroupPointer *Group
GroupAID uint8
}
var (
@ -52,13 +51,14 @@ func removeSession(sessionId uint32) {
}
if session.GroupPointer != nil {
delete(session.GroupPointer.Players, session.GroupAID)
delete(session.GroupPointer.Players, session)
if len(session.GroupPointer.Players) == 0 {
logging.Notice("QR2", "Deleting group", aurora.Cyan(session.GroupPointer.GroupID))
delete(groups, session.GroupPointer)
} else if session.GroupPointer.ServerAID == session.GroupAID {
logging.Notice("QR2", "Server down in group", aurora.Cyan(session.GroupPointer.GroupID))
logging.Notice("QR2", "Deleting group", aurora.Cyan(session.GroupPointer.GroupName))
delete(groups, session.GroupPointer.GroupName)
} else if session.GroupPointer.Server == session {
logging.Notice("QR2", "Server down in group", aurora.Cyan(session.GroupPointer.GroupName))
session.GroupPointer.Server = nil
// TODO: Search for new host via dwc_hoststate
}
}