mirror of
https://github.com/WiiLink24/wfc-server.git
synced 2026-03-21 17:44:58 -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) {
|
||||
// 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"]
|
||||
|
|
|
|||
|
|
@ -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])
|
||||
|
|
|
|||
96
qr2/group.go
96
qr2/group.go
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user