improved handling of failed tape uploads to score server
[rocksndiamonds.git] / src / files.c
index 442a0b674b915681014f63d50075ac4cf2928c50..fa5b9e45de312059aed05884faf00b2da6e12c91 100644 (file)
@@ -8401,7 +8401,7 @@ void SaveScoreTape(int nr)
   char *filename = getScoreTapeFilename(tape.score_tape_basename, nr);
 
   // used instead of "leveldir_current->subdir" (for network games)
-  InitScoreDirectory(levelset.identifier);
+  InitScoreTapeDirectory(levelset.identifier, nr);
 
   SaveTapeExt(filename);
 }
@@ -9280,12 +9280,16 @@ static int ApiGetScoreThread(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_ApiGetScore_HttpRequest(request, data_raw);
 #else
   ApiGetScore_HttpRequest(request, response, data_raw);
 #endif
 
+  program.api_thread_count--;
+
   checked_free(request);
   checked_free(response);
 
@@ -9441,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;
 };
@@ -9461,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;
 }
@@ -9471,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);
 }
@@ -9529,6 +9550,7 @@ static boolean SetRequest_ApiAddScore(struct HttpRequest *request,
           "  \"level_nr\":             \"%d\",\n"
           "  \"level_name\":           \"%s\",\n"
           "  \"level_author\":         \"%s\",\n"
+          "  \"use_step_counter\":     \"%d\",\n"
           "  \"rate_time_over_score\": \"%d\",\n"
           "  \"player_name\":          \"%s\",\n"
           "  \"player_uuid\":          \"%s\",\n"
@@ -9550,6 +9572,7 @@ static boolean SetRequest_ApiAddScore(struct HttpRequest *request,
           level_nr,
           level_name,
           level_author,
+          level.use_step_counter,
           level.rate_time_over_score,
           player_name,
           player_uuid,
@@ -9580,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)
@@ -9595,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);
@@ -9605,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);
 }
 
@@ -9647,6 +9681,8 @@ static void ApiAddScore_HttpRequestExt(struct HttpRequest *request,
   {
     Error("HTTP request failed: %s", GetHttpError());
 
+    HandleFailure_ApiAddScore(data_raw);
+
     return;
   }
 
@@ -9656,6 +9692,8 @@ static void ApiAddScore_HttpRequestExt(struct HttpRequest *request,
          response->status_code,
          response->status_text);
 
+    HandleFailure_ApiAddScore(data_raw);
+
     return;
   }
 
@@ -9677,12 +9715,16 @@ static int ApiAddScoreThread(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_ApiAddScore_HttpRequest(request, data_raw);
 #else
   ApiAddScore_HttpRequest(request, response, data_raw);
 #endif
 
+  program.api_thread_count--;
+
   checked_free(request);
   checked_free(response);
 
@@ -9703,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);
 }
@@ -10055,10 +10101,22 @@ 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"
   },
+  {
+    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[] =
@@ -10860,7 +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)