mirror of
https://github.com/WiiLink24/wfc-server.git
synced 2026-04-25 16:23:38 -05:00
SAKE: Support file download requests from Mario Kart Wii
Helps address issue #43.
This commit is contained in:
parent
3a40000040
commit
51122570b7
|
|
@ -21,7 +21,15 @@ const (
|
|||
"AND courseid = $2 " +
|
||||
"ORDER BY score ASC " +
|
||||
"LIMIT 10"
|
||||
uploadGhostFileStatement = "" +
|
||||
getGhostFileQuery = "" +
|
||||
"SELECT ghost " +
|
||||
"FROM mario_kart_wii_sake " +
|
||||
"WHERE courseid = $1 " +
|
||||
"AND score < $2 " +
|
||||
"AND pid <> $3 " +
|
||||
"ORDER BY score DESC " +
|
||||
"LIMIT 1"
|
||||
insertGhostFileStatement = "" +
|
||||
"INSERT INTO mario_kart_wii_sake (regionid, courseid, score, pid, playerinfo, ghost) " +
|
||||
"VALUES ($1, $2, $3, $4, $5, $6) " +
|
||||
"ON CONFLICT (courseid, pid) DO UPDATE " +
|
||||
|
|
@ -54,9 +62,22 @@ func GetMarioKartWiiTopTenRankings(pool *pgxpool.Pool, ctx context.Context, regi
|
|||
return topTenRankings, nil
|
||||
}
|
||||
|
||||
func UploadMarioKartWiiGhostFile(pool *pgxpool.Pool, ctx context.Context, regionId common.MarioKartWiiLeaderboardRegionId,
|
||||
func GetMarioKartWiiGhostFile(pool *pgxpool.Pool, ctx context.Context, courseId common.MarioKartWiiCourseId,
|
||||
time int, pid int) ([]byte, error) {
|
||||
row := pool.QueryRow(ctx, getGhostFileQuery, courseId, time, pid)
|
||||
|
||||
var ghost []byte
|
||||
err := row.Scan(&ghost)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ghost, nil
|
||||
}
|
||||
|
||||
func InsertMarioKartWiiGhostFile(pool *pgxpool.Pool, ctx context.Context, regionId common.MarioKartWiiLeaderboardRegionId,
|
||||
courseId common.MarioKartWiiCourseId, score int, pid int, playerInfo string, ghost []byte) error {
|
||||
_, err := pool.Exec(ctx, uploadGhostFileStatement, regionId, courseId, score, pid, playerInfo, ghost)
|
||||
_, err := pool.Exec(ctx, insertGhostFileStatement, regionId, courseId, score, pid, playerInfo, ghost)
|
||||
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path"
|
||||
"strings"
|
||||
"wwfc/common"
|
||||
"wwfc/logging"
|
||||
|
||||
|
|
@ -42,8 +42,8 @@ func Shutdown() {
|
|||
func HandleRequest(responseWriter http.ResponseWriter, request *http.Request) {
|
||||
logging.Info("RACE", aurora.Yellow(request.Method), aurora.Cyan(request.URL), "via", aurora.Cyan(request.Host), "from", aurora.BrightCyan(request.RemoteAddr))
|
||||
|
||||
switch path.Base(request.URL.Path) {
|
||||
case "NintendoRacingService.asmx":
|
||||
switch {
|
||||
case strings.HasSuffix(request.URL.Path, "NintendoRacingService.asmx"):
|
||||
moduleName := "RACE:RacingService:" + request.RemoteAddr
|
||||
handleNintendoRacingServiceRequest(moduleName, responseWriter, request)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,7 +101,6 @@ func handleNintendoRacingServiceRequest(moduleName string, responseWriter http.R
|
|||
soapAction := soapActionHeader[slashIndex+1 : slashIndex+1+quotationMarkIndex]
|
||||
switch soapAction {
|
||||
case "GetTopTenRankings":
|
||||
logging.Info(moduleName, "Received a Top 10 rankings request")
|
||||
handleGetTopTenRankingsRequest(moduleName, responseWriter, requestBody)
|
||||
default:
|
||||
logging.Info(moduleName, "Unhandled SOAPAction:", aurora.Cyan(soapAction))
|
||||
|
|
|
|||
|
|
@ -47,8 +47,11 @@ func HandleRequest(w http.ResponseWriter, r *http.Request) {
|
|||
case urlPath == "/SakeStorageServer/StorageServer.asmx":
|
||||
moduleName := "SAKE:Storage:" + r.RemoteAddr
|
||||
handleStorageRequest(moduleName, w, r)
|
||||
case strings.Contains(urlPath, "upload.aspx"):
|
||||
case strings.HasSuffix(urlPath, "download.aspx"):
|
||||
moduleName := "SAKE:File:" + r.RemoteAddr
|
||||
handleFileUploadRequest(moduleName, w, r)
|
||||
handleFileRequest(moduleName, w, r, FileRequestDownload)
|
||||
case strings.HasSuffix(urlPath, "upload.aspx"):
|
||||
moduleName := "SAKE:File:" + r.RemoteAddr
|
||||
handleFileRequest(moduleName, w, r, FileRequestUpload)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,82 @@ const (
|
|||
rkgdFileName = "ghost.bin"
|
||||
)
|
||||
|
||||
func handleMarioKartWiiFileDownloadRequest(moduleName string, responseWriter http.ResponseWriter, request *http.Request) {
|
||||
if strings.HasSuffix(request.URL.Path, "ghostdownload.aspx") {
|
||||
handleMarioKartWiiGhostDownloadRequest(moduleName, responseWriter, request)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func handleMarioKartWiiGhostDownloadRequest(moduleName string, responseWriter http.ResponseWriter, request *http.Request) {
|
||||
query := request.URL.Query()
|
||||
|
||||
regionIdString := query.Get("region")
|
||||
pidString := query.Get("p0")
|
||||
courseIdString := query.Get("c0")
|
||||
timeString := query.Get("t0")
|
||||
|
||||
regionIdInt, err := strconv.Atoi(regionIdString)
|
||||
if err != nil {
|
||||
logging.Error(moduleName, "Invalid region id")
|
||||
responseWriter.Header().Set(common.SakeFileResultHeader, strconv.Itoa(common.SakeFileResultMissingParameter))
|
||||
return
|
||||
}
|
||||
if common.MarioKartWiiLeaderboardRegionId(regionIdInt) != common.Worldwide {
|
||||
logging.Error(moduleName, "Invalid region id")
|
||||
responseWriter.Header().Set(common.SakeFileResultHeader, strconv.Itoa(common.SakeFileResultMissingParameter))
|
||||
return
|
||||
}
|
||||
|
||||
courseIdInt, err := strconv.Atoi(courseIdString)
|
||||
if err != nil {
|
||||
logging.Error(moduleName, "Invalid course id")
|
||||
responseWriter.Header().Set(common.SakeFileResultHeader, strconv.Itoa(common.SakeFileResultMissingParameter))
|
||||
return
|
||||
}
|
||||
courseId := common.MarioKartWiiCourseId(courseIdInt)
|
||||
if !courseId.IsValid() {
|
||||
logging.Error(moduleName, "Invalid course id")
|
||||
responseWriter.Header().Set(common.SakeFileResultHeader, strconv.Itoa(common.SakeFileResultMissingParameter))
|
||||
return
|
||||
}
|
||||
|
||||
pid, err := strconv.Atoi(pidString)
|
||||
if err != nil || pid <= 0 {
|
||||
logging.Error(moduleName, "Invalid pid")
|
||||
responseWriter.Header().Set(common.SakeFileResultHeader, strconv.Itoa(common.SakeFileResultMissingParameter))
|
||||
return
|
||||
}
|
||||
|
||||
time, err := strconv.Atoi(timeString)
|
||||
if err != nil || time <= 0 {
|
||||
logging.Error(moduleName, "Invalid time")
|
||||
responseWriter.Header().Set(common.SakeFileResultHeader, strconv.Itoa(common.SakeFileResultMissingParameter))
|
||||
return
|
||||
}
|
||||
|
||||
ghost, err := database.GetMarioKartWiiGhostFile(pool, ctx, courseId, time, pid)
|
||||
if err != nil {
|
||||
logging.Error(moduleName, "Failed to get a ghost file from the database")
|
||||
responseWriter.Header().Set(common.SakeFileResultHeader, strconv.Itoa(common.SakeFileResultServerError))
|
||||
return
|
||||
}
|
||||
|
||||
responseBody := append(downloadedGhostFileHeader(), ghost...)
|
||||
|
||||
responseWriter.Header().Set(common.SakeFileResultHeader, strconv.Itoa(common.SakeFileResultSuccess))
|
||||
responseWriter.Header().Set("Content-Length", strconv.Itoa(len(responseBody)))
|
||||
responseWriter.Write(responseBody)
|
||||
}
|
||||
|
||||
func handleMarioKartWiiFileUploadRequest(moduleName string, responseWriter http.ResponseWriter, request *http.Request) {
|
||||
if strings.HasSuffix(request.URL.Path, "ghostupload.aspx") {
|
||||
handleMarioKartWiiGhostUploadRequest(moduleName, responseWriter, request)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func handleMarioKartWiiGhostUploadRequest(moduleName string, responseWriter http.ResponseWriter, request *http.Request) {
|
||||
query := request.URL.Query()
|
||||
|
||||
regionIdString := query.Get("regionid")
|
||||
|
|
@ -137,7 +212,7 @@ func handleMarioKartWiiFileUploadRequest(moduleName string, responseWriter http.
|
|||
ghostFile = nil
|
||||
}
|
||||
|
||||
err = database.UploadMarioKartWiiGhostFile(pool, ctx, regionId, courseId, score, pid, playerInfo, ghostFile)
|
||||
err = database.InsertMarioKartWiiGhostFile(pool, ctx, regionId, courseId, score, pid, playerInfo, ghostFile)
|
||||
if err != nil {
|
||||
logging.Error(moduleName, "Failed to insert the ghost file into the database")
|
||||
responseWriter.Header().Set(common.SakeFileResultHeader, strconv.Itoa(common.SakeFileResultServerError))
|
||||
|
|
@ -147,6 +222,14 @@ func handleMarioKartWiiFileUploadRequest(moduleName string, responseWriter http.
|
|||
responseWriter.Header().Set(common.SakeFileResultHeader, strconv.Itoa(common.SakeFileResultSuccess))
|
||||
}
|
||||
|
||||
func downloadedGhostFileHeader() []byte {
|
||||
var downloadedGhostFileHeader [0x200]byte
|
||||
|
||||
binary.BigEndian.PutUint32(downloadedGhostFileHeader[0x40:0x44], uint32(len(downloadedGhostFileHeader)))
|
||||
|
||||
return downloadedGhostFileHeader[:]
|
||||
}
|
||||
|
||||
func isPlayerInfoValid(playerInfoString string) bool {
|
||||
playerInfoByteArray, err := common.DecodeGameSpyBase64(playerInfoString, common.GameSpyBase64EncodingURLSafe)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -15,11 +15,18 @@ import (
|
|||
"github.com/logrusorgru/aurora/v3"
|
||||
)
|
||||
|
||||
const (
|
||||
FileRequestDownload = iota
|
||||
FileRequestUpload
|
||||
)
|
||||
|
||||
const (
|
||||
SOAPEnvNamespace = "http://schemas.xmlsoap.org/soap/envelope/"
|
||||
SakeNamespace = "http://gamespy.net/sake"
|
||||
)
|
||||
|
||||
type FileRequest int
|
||||
|
||||
type StorageRequestEnvelope struct {
|
||||
XMLName xml.Name
|
||||
Body StorageRequestBody
|
||||
|
|
@ -112,6 +119,10 @@ type StorageSearchForRecordsResponse struct {
|
|||
Values StorageResponseValues `xml:"values"` // ???
|
||||
}
|
||||
|
||||
var fileDownloadHandlers = map[int]func(string, http.ResponseWriter, *http.Request){
|
||||
common.GameSpyGameIdMarioKartWii: handleMarioKartWiiFileDownloadRequest,
|
||||
}
|
||||
|
||||
var fileUploadHandlers = map[int]func(string, http.ResponseWriter, *http.Request){
|
||||
common.GameSpyGameIdMarioKartWii: handleMarioKartWiiFileUploadRequest,
|
||||
}
|
||||
|
|
@ -178,19 +189,30 @@ func handleStorageRequest(moduleName string, w http.ResponseWriter, r *http.Requ
|
|||
w.Write(payload)
|
||||
}
|
||||
|
||||
func handleFileUploadRequest(moduleName string, responseWriter http.ResponseWriter, request *http.Request) {
|
||||
query := request.URL.Query()
|
||||
func handleFileRequest(moduleName string, responseWriter http.ResponseWriter, request *http.Request,
|
||||
fileRequest FileRequest) {
|
||||
|
||||
gameIdString := query.Get("gameid")
|
||||
gameIdString := request.URL.Query().Get("gameid")
|
||||
gameId, err := strconv.Atoi(gameIdString)
|
||||
if err != nil {
|
||||
logging.Error(moduleName, "Invalid GameSpy game id")
|
||||
return
|
||||
}
|
||||
|
||||
handler, handlerExists := fileUploadHandlers[gameId]
|
||||
var handler func(string, http.ResponseWriter, *http.Request)
|
||||
var handlerExists bool
|
||||
switch fileRequest {
|
||||
case FileRequestDownload:
|
||||
handler, handlerExists = fileDownloadHandlers[gameId]
|
||||
case FileRequestUpload:
|
||||
handler, handlerExists = fileUploadHandlers[gameId]
|
||||
default:
|
||||
logging.Error(moduleName, "Invalid file request")
|
||||
return
|
||||
}
|
||||
|
||||
if !handlerExists {
|
||||
logging.Warn(moduleName, "Unhandled file upload request for game id:", aurora.Cyan(gameId))
|
||||
logging.Warn(moduleName, "Unhandled file request for GameSpy game id:", aurora.Cyan(gameId))
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user