From 51cc8f17af487cc53aafccf050ff1b16fec878a9 Mon Sep 17 00:00:00 2001 From: Holger Schemel Date: Tue, 5 Apr 2022 08:36:14 +0200 Subject: [PATCH] added API functions to get score tape from score server --- src/api.c | 228 +++++++++++++++++++++++++++++++++++++++++++ src/api.h | 1 + src/files.c | 1 + src/libgame/system.h | 1 + src/main.h | 1 + 5 files changed, 232 insertions(+) diff --git a/src/api.c b/src/api.c index 6fd07dce..f2679fa1 100644 --- a/src/api.c +++ b/src/api.c @@ -635,6 +635,234 @@ void ApiGetScoreAsThread(int nr) } +// ============================================================================ +// get score tape API functions +// ============================================================================ + +struct ApiGetScoreTapeThreadData +{ + int level_nr; + int score_id; + char *score_tape_filename; +}; + +static void *CreateThreadData_ApiGetScoreTape(int nr, int id, + char *score_tape_basename) +{ + struct ApiGetScoreTapeThreadData *data = + checked_malloc(sizeof(struct ApiGetScoreTapeThreadData)); + char *score_tape_filename = getScoreTapeFilename(score_tape_basename, nr); + + data->level_nr = nr; + data->score_id = id; + data->score_tape_filename = getStringCopy(score_tape_filename); + + return data; +} + +static void FreeThreadData_ApiGetScoreTape(void *data_raw) +{ + struct ApiGetScoreTapeThreadData *data = data_raw; + + checked_free(data->score_tape_filename); + checked_free(data); +} + +static boolean SetRequest_ApiGetScoreTape(struct HttpRequest *request, + void *data_raw) +{ + struct ApiGetScoreTapeThreadData *data = data_raw; + int score_id = data->score_id; + + request->hostname = setup.api_server_hostname; + request->port = API_SERVER_PORT; + request->method = API_SERVER_METHOD; + request->uri = API_SERVER_URI_GETTAPE; + + snprintf(request->body, MAX_HTTP_BODY_SIZE, + "{\n" + "%s" + " \"game_version\": \"%s\",\n" + " \"game_platform\": \"%s\",\n" + " \"id\": \"%d\"\n" + "}\n", + getPasswordJSON(setup.api_server_password), + getProgramRealVersionString(), + getProgramPlatformString(), + score_id); + + ConvertHttpRequestBodyToServerEncoding(request); + + return TRUE; +} + +static void HandleResponse_ApiGetScoreTape(struct HttpResponse *response, + void *data_raw) +{ + struct ApiGetScoreTapeThreadData *data = data_raw; + + if (response->body_size == 0) + { + // no score tape available for this level + + return; + } + + // (do not convert HTTP response body, as it contains binary data here) + + int level_nr = data->level_nr; + char *filename = data->score_tape_filename; + FILE *file; + int i; + + // used instead of "leveldir_current->subdir" (for network games) + InitScoreTapeDirectory(levelset.identifier, level_nr); + + if (!(file = fopen(filename, MODE_WRITE))) + { + Warn("cannot save score tape file '%s'", filename); + + return; + } + + for (i = 0; i < response->body_size; i++) + fputc(response->body[i], file); + + fclose(file); + + SetFilePermissions(filename, PERMS_PRIVATE); + + server_scores.tape_downloaded = TRUE; +} + +#if defined(PLATFORM_EMSCRIPTEN) +static void Emscripten_ApiGetScoreTape_Loaded(unsigned handle, void *data_raw, + void *buffer, unsigned int size) +{ + struct HttpResponse *response = GetHttpResponseFromBuffer(buffer, size); + + if (response != NULL) + { + HandleResponse_ApiGetScoreTape(response, data_raw); + + checked_free(response); + } + else + { + Error("server response too large to handle (%d bytes)", size); + } + + FreeThreadData_ApiGetScoreTape(data_raw); +} + +static void Emscripten_ApiGetScoreTape_Failed(unsigned handle, void *data_raw, + int code, const char *status) +{ + Error("server failed to handle request: %d %s", code, status); + + FreeThreadData_ApiGetScoreTape(data_raw); +} + +static void Emscripten_ApiGetScoreTape_Progress(unsigned handle, void *data_raw, + int bytes, int size) +{ + // nothing to do here +} + +static void Emscripten_ApiGetScoreTape_HttpRequest(struct HttpRequest *request, + void *data_raw) +{ + if (!SetRequest_ApiGetScoreTape(request, data_raw)) + { + FreeThreadData_ApiGetScoreTape(data_raw); + + return; + } + + emscripten_async_wget2_data(request->uri, + request->method, + request->body, + data_raw, + TRUE, + Emscripten_ApiGetScoreTape_Loaded, + Emscripten_ApiGetScoreTape_Failed, + Emscripten_ApiGetScoreTape_Progress); +} + +#else + +static void ApiGetScoreTape_HttpRequestExt(struct HttpRequest *request, + struct HttpResponse *response, + void *data_raw) +{ + if (!SetRequest_ApiGetScoreTape(request, data_raw)) + return; + + if (!DoHttpRequest(request, response)) + { + Error("HTTP request failed: %s", GetHttpError()); + + return; + } + + if (!HTTP_SUCCESS(response->status_code)) + { + // do not show error message if no scores found for this level set + if (response->status_code == 404) + return; + + Error("server failed to handle request: %d %s", + response->status_code, + response->status_text); + + return; + } + + HandleResponse_ApiGetScoreTape(response, data_raw); +} + +static void ApiGetScoreTape_HttpRequest(struct HttpRequest *request, + struct HttpResponse *response, + void *data_raw) +{ + ApiGetScoreTape_HttpRequestExt(request, response, data_raw); + + FreeThreadData_ApiGetScoreTape(data_raw); +} +#endif + +static int ApiGetScoreTapeThread(void *data_raw) +{ + struct HttpRequest *request = checked_calloc(sizeof(struct HttpRequest)); + struct HttpResponse *response = checked_calloc(sizeof(struct HttpResponse)); + + program.api_thread_count++; + +#if defined(PLATFORM_EMSCRIPTEN) + Emscripten_ApiGetScoreTape_HttpRequest(request, data_raw); +#else + ApiGetScoreTape_HttpRequest(request, response, data_raw); +#endif + + program.api_thread_count--; + + checked_free(request); + checked_free(response); + + return 0; +} + +void ApiGetScoreTapeAsThread(int nr, int id, char *score_tape_basename) +{ + struct ApiGetScoreTapeThreadData *data = + CreateThreadData_ApiGetScoreTape(nr, id, score_tape_basename); + + ExecuteAsThread(ApiGetScoreTapeThread, + "ApiGetScoreTape", data, + "download score tape from server"); +} + + // ============================================================================ // rename player API functions // ============================================================================ diff --git a/src/api.h b/src/api.h index 7090b69c..4f897421 100644 --- a/src/api.h +++ b/src/api.h @@ -14,6 +14,7 @@ void ApiAddScoreAsThread(int, boolean, char *); void ApiGetScoreAsThread(int); +void ApiGetScoreTapeAsThread(int, int, char *); void ApiRenamePlayerAsThread(void); void ApiResetUUIDAsThread(char *); diff --git a/src/files.c b/src/files.c index 2216c671..e3835b7d 100644 --- a/src/files.c +++ b/src/files.c @@ -8666,6 +8666,7 @@ static void setScoreInfoToDefaultsExt(struct ScoreInfo *scores) scores->updated = FALSE; scores->uploaded = FALSE; + scores->tape_downloaded = FALSE; scores->force_last_added = FALSE; } diff --git a/src/libgame/system.h b/src/libgame/system.h index 7a80e91f..24d0d722 100644 --- a/src/libgame/system.h +++ b/src/libgame/system.h @@ -111,6 +111,7 @@ #define API_SERVER_METHOD "POST" #define API_SERVER_URI_ADD "/api/scores/add" #define API_SERVER_URI_GET "/api/scores/get" +#define API_SERVER_URI_GETTAPE "/api/scores/gettape" #define API_SERVER_URI_RENAME "/api/players/rename" #define API_SERVER_URI_RESETUUID "/api/players/resetuuid" diff --git a/src/main.h b/src/main.h index b931e707..00ce3cd2 100644 --- a/src/main.h +++ b/src/main.h @@ -3125,6 +3125,7 @@ struct ScoreInfo boolean updated; boolean uploaded; + boolean tape_downloaded; boolean force_last_added; struct ScoreEntry entry[MAX_SCORE_ENTRIES]; -- 2.34.1