mirror of
https://github.com/WiiLink24/wfc-server.git
synced 2026-04-26 10:18:29 -05:00
Add /api/groups endpoint
This commit is contained in:
parent
22045c4f49
commit
53cec11f17
48
api/groups.go
Normal file
48
api/groups.go
Normal 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)
|
||||||
|
}
|
||||||
|
|
@ -109,6 +109,8 @@ func (g *GameSpySession) authAddFriend(command common.GameSpyCommand) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GameSpySession) setStatus(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
|
status := command.CommandValue
|
||||||
|
|
||||||
statstring, ok := command.OtherValues["statstring"]
|
statstring, ok := command.OtherValues["statstring"]
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"wwfc/api"
|
||||||
"wwfc/common"
|
"wwfc/common"
|
||||||
"wwfc/logging"
|
"wwfc/logging"
|
||||||
"wwfc/nhttp"
|
"wwfc/nhttp"
|
||||||
|
|
@ -75,6 +76,12 @@ func handleRequest(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for /api/groups
|
||||||
|
if r.URL.Path == "/api/groups" {
|
||||||
|
api.HandleGroups(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Stage 1
|
// Stage 1
|
||||||
if match := regexStage1URL.FindStringSubmatch(r.URL.String()); match != nil {
|
if match := regexStage1URL.FindStringSubmatch(r.URL.String()); match != nil {
|
||||||
val, err := strconv.Atoi(match[1])
|
val, err := strconv.Atoi(match[1])
|
||||||
|
|
|
||||||
96
qr2/group.go
96
qr2/group.go
|
|
@ -10,28 +10,44 @@ import (
|
||||||
|
|
||||||
type Group struct {
|
type Group struct {
|
||||||
GroupID uint32
|
GroupID uint32
|
||||||
ServerAID uint8
|
GroupName string
|
||||||
Players map[uint8]*Session
|
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 {
|
func processResvOK(moduleName string, cmd common.MatchCommandDataResvOK, sender, destination *Session) bool {
|
||||||
group := sender.GroupPointer
|
if len(groups) >= 100000 {
|
||||||
if group == nil {
|
logging.Error(moduleName, "Hit arbitrary global maximum group count (somehow)")
|
||||||
logging.Notice(moduleName, "Creating new group", aurora.Cyan(cmd.GroupID), "/", aurora.Cyan(cmd.ProfileID))
|
return false
|
||||||
group = &Group{
|
|
||||||
GroupID: cmd.GroupID,
|
|
||||||
ServerAID: uint8(cmd.SenderAID),
|
|
||||||
Players: map[uint8]*Session{uint8(cmd.SenderAID): sender},
|
|
||||||
}
|
|
||||||
sender.GroupPointer = group
|
|
||||||
groups[group] = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if uint8(cmd.SenderAID) != sender.GroupAID {
|
group := sender.GroupPointer
|
||||||
logging.Error(moduleName, "ResvOK: Invalid sender AID")
|
if group == nil {
|
||||||
return false
|
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
|
// 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
|
// Keep group ID updated
|
||||||
sender.GroupPointer.GroupID = cmd.GroupID
|
sender.GroupPointer.GroupID = cmd.GroupID
|
||||||
|
|
||||||
logging.Info(moduleName, "New AID", aurora.Cyan(uint8(cmd.ReceiverNewAID)), "in group", aurora.Cyan(group.GroupID))
|
logging.Info(moduleName, "New player", aurora.BrightCyan(destination.Data["dwc_pid"]), "in group", aurora.Cyan(group.GroupName))
|
||||||
group.Players[uint8(cmd.ReceiverNewAID)] = destination
|
group.Players[destination] = true
|
||||||
destination.GroupPointer = group
|
destination.GroupPointer = group
|
||||||
destination.GroupAID = uint8(cmd.ReceiverNewAID)
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
@ -79,3 +94,46 @@ func ProcessGPResvOK(cmd common.MatchCommandDataResvOK, senderIP uint64, senderP
|
||||||
|
|
||||||
return processResvOK(moduleName, cmd, from, to)
|
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
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,6 @@ func SendClientMessage(senderIP string, destSearchID uint64, message []byte) {
|
||||||
logging.Error(moduleName, "Received invalid match version")
|
logging.Error(moduleName, "Received invalid match version")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logging.Info(moduleName, "Version:", version)
|
|
||||||
|
|
||||||
senderProfileID := binary.LittleEndian.Uint32(message[0x10:0x14])
|
senderProfileID := binary.LittleEndian.Uint32(message[0x10:0x14])
|
||||||
moduleName = "QR2/MSG:p" + strconv.FormatUint(uint64(senderProfileID), 10)
|
moduleName = "QR2/MSG:p" + strconv.FormatUint(uint64(senderProfileID), 10)
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,6 @@ type Session struct {
|
||||||
PacketCount uint32
|
PacketCount uint32
|
||||||
ReservationID uint64
|
ReservationID uint64
|
||||||
GroupPointer *Group
|
GroupPointer *Group
|
||||||
GroupAID uint8
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -52,13 +51,14 @@ func removeSession(sessionId uint32) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if session.GroupPointer != nil {
|
if session.GroupPointer != nil {
|
||||||
delete(session.GroupPointer.Players, session.GroupAID)
|
delete(session.GroupPointer.Players, session)
|
||||||
|
|
||||||
if len(session.GroupPointer.Players) == 0 {
|
if len(session.GroupPointer.Players) == 0 {
|
||||||
logging.Notice("QR2", "Deleting group", aurora.Cyan(session.GroupPointer.GroupID))
|
logging.Notice("QR2", "Deleting group", aurora.Cyan(session.GroupPointer.GroupName))
|
||||||
delete(groups, session.GroupPointer)
|
delete(groups, session.GroupPointer.GroupName)
|
||||||
} else if session.GroupPointer.ServerAID == session.GroupAID {
|
} else if session.GroupPointer.Server == session {
|
||||||
logging.Notice("QR2", "Server down in group", aurora.Cyan(session.GroupPointer.GroupID))
|
logging.Notice("QR2", "Server down in group", aurora.Cyan(session.GroupPointer.GroupName))
|
||||||
|
session.GroupPointer.Server = nil
|
||||||
// TODO: Search for new host via dwc_hoststate
|
// TODO: Search for new host via dwc_hoststate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user