From 7a8e465114815815796c2ebbe5f2e018a9265a3f Mon Sep 17 00:00:00 2001 From: Holger Schemel Date: Thu, 11 Nov 2021 18:10:57 +0100 Subject: [PATCH] improved handling of failed tape uploads to score server When initially mass-uploading personal tapes, a single failed upload caused the whole process to be restarted from scratch, ignoring all tapes that were already uploaded. This improvement marks completely uploaded tape directories to be able to skip them after failures and repeated upload attempts. (In addition, non-existing tape directories are skipped right away, without checking for each single tape file.) Another improvement remembers if tapes were not uploaded (either because the score server was disabled, or because uploading the tape failed). If this happens, the game adds an entry to upload tapes to the setup menu, and asks for uploading missing tapes on next start. --- src/files.c | 48 +++++++++++++++++++++++++++++++++++++++++++- src/init.c | 3 +++ src/libgame/misc.c | 16 +++++++++++++++ src/libgame/misc.h | 1 + src/libgame/setup.c | 33 ++++++++++++++++++++++++++++++ src/libgame/setup.h | 4 ++++ src/libgame/system.h | 3 +++ src/screens.c | 37 +++++++++++++++++++++++++++++----- src/tape.c | 40 +++++++++++++++++++++++++++++++++++- 9 files changed, 178 insertions(+), 7 deletions(-) diff --git a/src/files.c b/src/files.c index 28a19e67..fa5b9e45 100644 --- a/src/files.c +++ b/src/files.c @@ -9445,10 +9445,25 @@ static char *get_file_base64(char *filename) return buffer_encoded; } +static void PrepareScoreTapesForUpload(char *leveldir_subdir) +{ + MarkTapeDirectoryUploadsAsIncomplete(leveldir_subdir); + + // if score tape not uploaded, ask for uploading missing tapes later + if (!setup.has_remaining_tapes) + setup.ask_for_remaining_tapes = TRUE; + + setup.provide_uploading_tapes = TRUE; + setup.has_remaining_tapes = TRUE; + + SaveSetup_ServerSetup(); +} + struct ApiAddScoreThreadData { int level_nr; boolean tape_saved; + char *leveldir_subdir; char *score_tape_filename; struct ScoreEntry score_entry; }; @@ -9465,8 +9480,9 @@ static void *CreateThreadData_ApiAddScore(int nr, boolean tape_saved, data->level_nr = nr; data->tape_saved = tape_saved; - data->score_entry = *score_entry; + data->leveldir_subdir = getStringCopy(leveldir_current->subdir); data->score_tape_filename = getStringCopy(score_tape_filename); + data->score_entry = *score_entry; return data; } @@ -9475,6 +9491,7 @@ static void FreeThreadData_ApiAddScore(void *data_raw) { struct ApiAddScoreThreadData *data = data_raw; + checked_free(data->leveldir_subdir); checked_free(data->score_tape_filename); checked_free(data); } @@ -9586,6 +9603,13 @@ static void HandleResponse_ApiAddScore(struct HttpResponse *response, server_scores.uploaded = TRUE; } +static void HandleFailure_ApiAddScore(void *data_raw) +{ + struct ApiAddScoreThreadData *data = data_raw; + + PrepareScoreTapesForUpload(data->leveldir_subdir); +} + #if defined(PLATFORM_EMSCRIPTEN) static void Emscripten_ApiAddScore_Loaded(unsigned handle, void *data_raw, void *buffer, unsigned int size) @@ -9601,6 +9625,8 @@ static void Emscripten_ApiAddScore_Loaded(unsigned handle, void *data_raw, else { Error("server response too large to handle (%d bytes)", size); + + HandleFailure_ApiAddScore(data_raw); } FreeThreadData_ApiAddScore(data_raw); @@ -9611,6 +9637,8 @@ static void Emscripten_ApiAddScore_Failed(unsigned handle, void *data_raw, { Error("server failed to handle request: %d %s", code, status); + HandleFailure_ApiAddScore(data_raw); + FreeThreadData_ApiAddScore(data_raw); } @@ -9653,6 +9681,8 @@ static void ApiAddScore_HttpRequestExt(struct HttpRequest *request, { Error("HTTP request failed: %s", GetHttpError()); + HandleFailure_ApiAddScore(data_raw); + return; } @@ -9662,6 +9692,8 @@ static void ApiAddScore_HttpRequestExt(struct HttpRequest *request, response->status_code, response->status_text); + HandleFailure_ApiAddScore(data_raw); + return; } @@ -9713,7 +9745,11 @@ static void ApiAddScoreAsThread(int nr, boolean tape_saved, void SaveServerScore(int nr, boolean tape_saved) { if (!runtime.use_api_server) + { + PrepareScoreTapesForUpload(leveldir_current->subdir); + return; + } ApiAddScoreAsThread(nr, tape_saved, NULL); } @@ -10065,6 +10101,10 @@ static struct TokenInfo server_setup_tokens[] = TYPE_SWITCH, &setup.ask_for_uploading_tapes, TEST_PREFIX "ask_for_uploading_tapes" }, + { + TYPE_SWITCH, + &setup.ask_for_remaining_tapes, TEST_PREFIX "ask_for_remaining_tapes" + }, { TYPE_SWITCH, &setup.provide_uploading_tapes, TEST_PREFIX "provide_uploading_tapes" @@ -10073,6 +10113,10 @@ static struct TokenInfo server_setup_tokens[] = TYPE_SWITCH, &setup.ask_for_using_api_server,TEST_PREFIX "ask_for_using_api_server" }, + { + TYPE_SWITCH, + &setup.has_remaining_tapes, TEST_PREFIX "has_remaining_tapes" + }, }; static struct TokenInfo editor_setup_tokens[] = @@ -10874,8 +10918,10 @@ static void setSetupInfoToDefaults_ServerSetup(struct SetupInfo *si) si->api_server_hostname = getStringCopy(API_SERVER_HOSTNAME); si->api_server_password = getStringCopy(UNDEFINED_PASSWORD); si->ask_for_uploading_tapes = TRUE; + si->ask_for_remaining_tapes = FALSE; si->provide_uploading_tapes = TRUE; si->ask_for_using_api_server = TRUE; + si->has_remaining_tapes = FALSE; } static void setSetupInfoToDefaults_EditorCascade(struct SetupInfo *si) diff --git a/src/init.c b/src/init.c index 8c6c7e12..2d6b750d 100644 --- a/src/init.c +++ b/src/init.c @@ -6330,6 +6330,9 @@ void OpenAll(void) print_timestamp_done("OpenAll"); + if (setup.ask_for_remaining_tapes) + setup.ask_for_uploading_tapes = TRUE; + DrawMainMenu(); #if 0 diff --git a/src/libgame/misc.c b/src/libgame/misc.c index 8bc45721..faf6c011 100644 --- a/src/libgame/misc.c +++ b/src/libgame/misc.c @@ -2786,6 +2786,22 @@ int copyFile(char *filename_from, char *filename_to) return 0; } +boolean touchFile(char *filename) +{ + FILE *file; + + if (!(file = fopen(filename, MODE_WRITE))) + { + Warn("cannot touch file '%s'", filename); + + return FALSE; + } + + fclose(file); + + return TRUE; +} + // ---------------------------------------------------------------------------- // functions for directory handling diff --git a/src/libgame/misc.h b/src/libgame/misc.h index 83b77730..27ae0f3d 100644 --- a/src/libgame/misc.h +++ b/src/libgame/misc.h @@ -258,6 +258,7 @@ int seekFile(File *, long, int); int getByteFromFile(File *); char *getStringFromFile(File *, char *, int); int copyFile(char *, char *); +boolean touchFile(char *); Directory *openDirectory(char *); int closeDirectory(Directory *); diff --git a/src/libgame/setup.c b/src/libgame/setup.c index 0a406540..9ea17549 100644 --- a/src/libgame/setup.c +++ b/src/libgame/setup.c @@ -1155,11 +1155,44 @@ char *getCustomMusicDirectory(void) return NULL; // cannot find specified artwork file anywhere } +void MarkTapeDirectoryUploadsAsComplete(char *level_subdir) +{ + char *filename = getPath2(getTapeDir(level_subdir), UPLOADED_FILENAME); + + touchFile(filename); + + checked_free(filename); +} + +void MarkTapeDirectoryUploadsAsIncomplete(char *level_subdir) +{ + char *filename = getPath2(getTapeDir(level_subdir), UPLOADED_FILENAME); + + unlink(filename); + + checked_free(filename); +} + +boolean CheckTapeDirectoryUploadsComplete(char *level_subdir) +{ + char *filename = getPath2(getTapeDir(level_subdir), UPLOADED_FILENAME); + boolean success = fileExists(filename); + + checked_free(filename); + + return success; +} + void InitTapeDirectory(char *level_subdir) { + boolean new_tape_dir = !directoryExists(getTapeDir(level_subdir)); + createDirectory(getUserGameDataDir(), "user data", PERMS_PRIVATE); createDirectory(getTapeDir(NULL), "main tape", PERMS_PRIVATE); createDirectory(getTapeDir(level_subdir), "level tape", PERMS_PRIVATE); + + if (new_tape_dir) + MarkTapeDirectoryUploadsAsComplete(level_subdir); } void InitScoreDirectory(char *level_subdir) diff --git a/src/libgame/setup.h b/src/libgame/setup.h index 68f67a78..ab52a7a8 100644 --- a/src/libgame/setup.h +++ b/src/libgame/setup.h @@ -288,6 +288,10 @@ char *getCustomArtworkConfigFilename(int); char *getCustomArtworkLevelConfigFilename(int); char *getCustomMusicDirectory(void); +void MarkTapeDirectoryUploadsAsComplete(char *); +void MarkTapeDirectoryUploadsAsIncomplete(char *); +boolean CheckTapeDirectoryUploadsComplete(char *); + void InitTapeDirectory(char *); void InitScoreDirectory(char *); void InitScoreCacheDirectory(char *); diff --git a/src/libgame/system.h b/src/libgame/system.h index d9b42321..8ad5c08f 100644 --- a/src/libgame/system.h +++ b/src/libgame/system.h @@ -685,6 +685,7 @@ #define MUSICINFO_FILENAME "musicinfo.conf" #define ARTWORKINFO_CACHE_FILE "artworkinfo.cache" #define LEVELTEMPLATE_FILENAME "template.level" +#define UPLOADED_FILENAME ".uploaded" #define LEVELFILE_EXTENSION "level" #define TAPEFILE_EXTENSION "tape" #define SCOREFILE_EXTENSION "score" @@ -1514,8 +1515,10 @@ struct SetupInfo char *api_server_hostname; char *api_server_password; boolean ask_for_uploading_tapes; + boolean ask_for_remaining_tapes; boolean provide_uploading_tapes; boolean ask_for_using_api_server; + boolean has_remaining_tapes; struct SetupAutoSetupInfo auto_setup; struct SetupLevelSetupInfo level_setup; diff --git a/src/screens.c b/src/screens.c index cf8077f8..e34a9df5 100644 --- a/src/screens.c +++ b/src/screens.c @@ -7076,7 +7076,7 @@ static struct TokenInfo setup_info_game[] = { TYPE_SWITCH, &setup.use_api_server, "Use Highscore Server:" }, { TYPE_ENTER_LIST, execSetupChooseScoresType,"Scores in Highscore List:" }, { TYPE_STRING, &scores_type_text, "" }, - { TYPE_ENTER_LIST, execOfferUploadTapes, "Upload All Tapes to Server" }, + { TYPE_ENTER_LIST, execOfferUploadTapes, "Upload Tapes to Server" }, { TYPE_SWITCH, &setup.multiple_users, "Multiple Users/Teams:" }, { TYPE_YES_NO, &setup.input_on_focus, "Only Move Focussed Player:" }, { TYPE_SWITCH, &setup.time_limit, "Time Limit:" }, @@ -10072,7 +10072,9 @@ static int UploadTapes(void) static boolean OfferUploadTapes(void) { - if (!Request("Upload all your tapes to the high score server now?", REQ_ASK)) + if (!Request(setup.has_remaining_tapes ? + "Upload missing tapes to the high score server now?" : + "Upload all your tapes to the high score server now?", REQ_ASK)) return FALSE; int num_tapes_uploaded = UploadTapes(); @@ -10080,7 +10082,23 @@ static boolean OfferUploadTapes(void) if (num_tapes_uploaded < 0) { - Request("Cannot upload tapes to score server!", REQ_CONFIRM); + num_tapes_uploaded = -num_tapes_uploaded - 1; + + if (num_tapes_uploaded == 0) + sprintf(message, "Upload failed! No tapes uploaded!"); + else if (num_tapes_uploaded == 1) + sprintf(message, "Upload failed! Only 1 tape uploaded!"); + else + sprintf(message, "Upload failed! Only %d tapes uploaded!", + num_tapes_uploaded); + + Request(message, REQ_CONFIRM); + + // if uploading tapes failed, add tape upload entry to setup menu + setup.provide_uploading_tapes = TRUE; + setup.has_remaining_tapes = TRUE; + + SaveSetup_ServerSetup(); return FALSE; } @@ -10094,8 +10112,12 @@ static boolean OfferUploadTapes(void) Request(message, REQ_CONFIRM); + if (num_tapes_uploaded > 0) + Request("New scores will be visible after a few minutes!", REQ_CONFIRM); + // after all tapes have been uploaded, remove entry from setup menu setup.provide_uploading_tapes = FALSE; + setup.has_remaining_tapes = FALSE; SaveSetup_ServerSetup(); @@ -10107,16 +10129,21 @@ void CheckUploadTapes(void) if (!setup.ask_for_uploading_tapes) return; - // after asking for uploading all tapes once, do not ask again + // after asking for uploading tapes, do not ask again setup.ask_for_uploading_tapes = FALSE; + setup.ask_for_remaining_tapes = FALSE; if (directoryExists(getTapeDir(NULL))) { boolean tapes_uploaded = OfferUploadTapes(); if (!tapes_uploaded) - Request("You can upload your tapes from the setup menu later!", + { + Request(setup.has_remaining_tapes ? + "You can upload missing tapes from the setup menu later!" : + "You can upload your tapes from the setup menu later!", REQ_CONFIRM); + } } else { diff --git a/src/tape.c b/src/tape.c index 03ecf689..2a1a3ec3 100644 --- a/src/tape.c +++ b/src/tape.c @@ -1668,6 +1668,41 @@ static int AutoPlayTapesExt(boolean initialize) init_level_set = FALSE; } + if (autoplay.all_levelsets && global.autoplay_mode == AUTOPLAY_MODE_UPLOAD) + { + boolean skip_levelset = FALSE; + + if (!directoryExists(getTapeDir(autoplay.leveldir->subdir))) + { + Print("No tape directory for this level set found -- skipping.\n"); + + skip_levelset = TRUE; + } + + if (CheckTapeDirectoryUploadsComplete(autoplay.leveldir->subdir)) + { + Print("All tapes for this level set already uploaded -- skipping.\n"); + + skip_levelset = TRUE; + } + + if (skip_levelset) + { + PrintTapeReplaySummary(&autoplay); + + // continue with next level set + autoplay.leveldir = getNextValidAutoPlayEntry(autoplay.leveldir); + + // all level sets processed + if (autoplay.leveldir == NULL) + break; + + init_level_set = TRUE; + + continue; + } + } + if (global.autoplay_mode != AUTOPLAY_MODE_FIX || patch_nr == 0) level_nr = autoplay.level_nr++; @@ -1681,6 +1716,9 @@ static int AutoPlayTapesExt(boolean initialize) if (!autoplay.all_levelsets) break; + if (global.autoplay_mode == AUTOPLAY_MODE_UPLOAD) + MarkTapeDirectoryUploadsAsComplete(autoplay.leveldir->subdir); + // continue with next level set autoplay.leveldir = getNextValidAutoPlayEntry(autoplay.leveldir); @@ -1841,7 +1879,7 @@ static int AutoPlayTapesExt(boolean initialize) if (!success) { - num_tapes = -1; + num_tapes = -num_tapes; break; } -- 2.34.1