SAKE: Support file download requests for champion ghosts from Mario Kart Wii

Helps address issue #43.
This commit is contained in:
MikeIsAStar 2024-09-08 12:50:00 -04:00
parent 46f269d470
commit a55800eb2f
6 changed files with 152 additions and 17 deletions

View File

@ -21,6 +21,18 @@ const (
"AND courseid = $2 " +
"ORDER BY score ASC " +
"LIMIT 10"
getStoredGhostDataQuery = "" +
"SELECT pid, id " +
"FROM mario_kart_wii_sake " +
"WHERE ($1 = 0 OR regionid = $1) " +
"AND courseid = $2 " +
"ORDER BY score ASC " +
"LIMIT 1"
getFileQuery = "" +
"SELECT ghost " +
"FROM mario_kart_wii_sake " +
"WHERE id = $1 " +
"LIMIT 1"
getGhostFileQuery = "" +
"SELECT ghost " +
"FROM mario_kart_wii_sake " +
@ -54,21 +66,43 @@ func GetMarioKartWiiTopTenRankings(pool *pgxpool.Pool, ctx context.Context, regi
topTenRankings = append(topTenRankings, topTenRanking)
}
err = rows.Err()
if err != nil {
if err = rows.Err(); err != nil {
return nil, err
}
return topTenRankings, nil
}
func GetMarioKartWiiStoredGhostData(pool *pgxpool.Pool, ctx context.Context, regionId common.MarioKartWiiLeaderboardRegionId,
courseId common.MarioKartWiiCourseId) (int, int, error) {
row := pool.QueryRow(ctx, getStoredGhostDataQuery, regionId, courseId)
var pid int
var fileId int
if err := row.Scan(&pid, &fileId); err != nil {
return 0, 0, err
}
return pid, fileId, nil
}
func GetMarioKartWiiFile(pool *pgxpool.Pool, ctx context.Context, fileId int) ([]byte, error) {
row := pool.QueryRow(ctx, getFileQuery, fileId)
var file []byte
if err := row.Scan(&file); err != nil {
return nil, err
}
return file, nil
}
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 {
if err := row.Scan(&ghost); err != nil {
return nil, err
}

View File

@ -9,23 +9,24 @@ import (
func UpdateTables(pool *pgxpool.Pool, ctx context.Context) {
pool.Exec(ctx, `
ALTER TABLE ONLY public.users
ADD IF NOT EXISTS last_ip_address character varying DEFAULT ''::character varying,
ADD IF NOT EXISTS last_ingamesn character varying DEFAULT ''::character varying,
ADD IF NOT EXISTS has_ban boolean DEFAULT false,
ADD IF NOT EXISTS ban_issued timestamp without time zone,
ADD IF NOT EXISTS ban_expires timestamp without time zone,
ADD IF NOT EXISTS ban_reason character varying,
ADD IF NOT EXISTS ban_reason_hidden character varying,
ADD IF NOT EXISTS ban_moderator character varying,
ADD IF NOT EXISTS ban_tos boolean,
ADD IF NOT EXISTS open_host boolean DEFAULT false;
ALTER TABLE ONLY public.users
ADD IF NOT EXISTS last_ip_address character varying DEFAULT ''::character varying,
ADD IF NOT EXISTS last_ingamesn character varying DEFAULT ''::character varying,
ADD IF NOT EXISTS has_ban boolean DEFAULT false,
ADD IF NOT EXISTS ban_issued timestamp without time zone,
ADD IF NOT EXISTS ban_expires timestamp without time zone,
ADD IF NOT EXISTS ban_reason character varying,
ADD IF NOT EXISTS ban_reason_hidden character varying,
ADD IF NOT EXISTS ban_moderator character varying,
ADD IF NOT EXISTS ban_tos boolean,
ADD IF NOT EXISTS open_host boolean DEFAULT false;
`)
pool.Exec(ctx, `
ALTER TABLE ONLY public.mario_kart_wii_sake
ADD IF NOT EXISTS id serial PRIMARY KEY,
ADD IF NOT EXISTS upload_time timestamp without time zone;
`)

View File

@ -72,7 +72,7 @@ const (
xmlNamespace = "http://gamespy.net/RaceService/"
)
var MarioKartWiiGameID = common.GetGameIDOrPanic("mariokartwii") // 1687
var marioKartWiiGameID = common.GetGameIDOrPanic("mariokartwii") // 1687
func handleNintendoRacingServiceRequest(moduleName string, responseWriter http.ResponseWriter, request *http.Request) {
soapActionHeader := request.Header.Get("SOAPAction")
@ -123,7 +123,7 @@ func handleGetTopTenRankingsRequest(moduleName string, responseWriter http.Respo
requestData := requestXML.Body.Data
gameId := requestData.GameId
if gameId != MarioKartWiiGameID {
if gameId != marioKartWiiGameID {
logging.Error(moduleName, "Wrong GameSpy game ID:", aurora.Cyan(gameId))
writeErrorResponse(raceServiceResultInvalidParameters, responseWriter)
return

View File

@ -37,6 +37,36 @@ func handleMarioKartWiiFileDownloadRequest(moduleName string, responseWriter htt
handleMarioKartWiiGhostDownloadRequest(moduleName, responseWriter, request)
return
}
query := request.URL.Query()
fileIdString := query.Get("fileid")
pidString := query.Get("pid")
fileId, err := strconv.Atoi(fileIdString)
if err != nil || fileId <= 0 {
logging.Error(moduleName, "Invalid file ID:", aurora.Cyan(fileIdString))
responseWriter.Header().Set(SakeFileResultHeader, strconv.Itoa(SakeFileResultMissingParameter))
return
}
pid, err := strconv.Atoi(pidString)
if err != nil || pid <= 0 {
logging.Error(moduleName, "Invalid profile ID:", aurora.Cyan(pidString))
responseWriter.Header().Set(SakeFileResultHeader, strconv.Itoa(SakeFileResultMissingParameter))
return
}
file, err := database.GetMarioKartWiiFile(pool, ctx, fileId)
if err != nil {
logging.Error(moduleName, "Failed to get the file from the database:", err)
responseWriter.Header().Set(SakeFileResultHeader, strconv.Itoa(SakeFileResultServerError))
return
}
responseWriter.Header().Set(SakeFileResultHeader, strconv.Itoa(SakeFileResultSuccess))
responseWriter.Header().Set("Content-Length", strconv.Itoa(len(file)))
responseWriter.Write(file)
}
func handleMarioKartWiiGhostDownloadRequest(moduleName string, responseWriter http.ResponseWriter, request *http.Request) {

View File

@ -382,6 +382,71 @@ func searchForRecords(moduleName string, gameInfo common.GameInfo, request Stora
"info": binaryDataValueBase64(database.GetMKWFriendInfo(pool, ctx, uint32(ownerId))),
},
}
case "mariokartwii/StoredGhostData":
if request.Sort != "time" {
logging.Error(moduleName, "Invalid sort string:", aurora.Cyan(request.Sort))
return &errorResponse
}
if request.Offset != 0 {
logging.Error(moduleName, "Invalid offset value:", aurora.Cyan(request.Offset))
return &errorResponse
}
if request.Max != 1 {
logging.Error(moduleName, "Invalid number of records to return:", aurora.Cyan(request.Max))
return &errorResponse
}
if request.Surrounding != 0 {
logging.Error(moduleName, "Invalid number of surrounding records to return:", aurora.Cyan(request.Surrounding))
return &errorResponse
}
if request.OwnerIDs != "" {
logging.Error(moduleName, "Invalid owner id array:", aurora.Cyan(request.OwnerIDs))
return &errorResponse
}
if request.CacheFlag != 0 {
logging.Error(moduleName, "Invalid cache value:", aurora.Cyan(request.CacheFlag))
return &errorResponse
}
match := regexp.MustCompile(`^course = ([1-9]\d?|0) and gameid = 1687(?: and region = ([1-7]))?$`).FindStringSubmatch(request.Filter)
if match == nil {
logging.Error(moduleName, "Invalid filter string:", aurora.Cyan(request.Filter))
return &errorResponse
}
courseIdInt, _ := strconv.Atoi(match[1])
courseId := common.MarioKartWiiCourseId(courseIdInt)
if !courseId.IsValid() {
logging.Error(moduleName, "Invalid course ID:", aurora.Cyan(courseIdInt))
return &errorResponse
}
var regionId common.MarioKartWiiLeaderboardRegionId
if regionIdExists := match[2] != ""; regionIdExists {
regionIdInt, _ := strconv.Atoi(match[2])
regionId = common.MarioKartWiiLeaderboardRegionId(regionIdInt)
} else {
regionId = common.Worldwide
}
pid, fileId, err := database.GetMarioKartWiiStoredGhostData(pool, ctx, regionId, courseId)
if err != nil {
logging.Error(moduleName, "Failed to get the stored ghost data from the database:", err)
return &errorResponse
}
values = []map[string]StorageValue{
{
"profile": intValue(int32(pid)),
"fileid": intValue(int32(fileId)),
},
}
}
// Sort the values now

View File

@ -68,6 +68,11 @@ CREATE TABLE IF NOT EXISTS public.mario_kart_wii_sake (
);
ALTER TABLE ONLY public.mario_kart_wii_sake
ADD IF NOT EXISTS id serial PRIMARY KEY,
ADD IF NOT EXISTS upload_time timestamp without time zone;
ALTER TABLE public.mario_kart_wii_sake OWNER TO wiilink;
--