added API functions to get score tape from score server
authorHolger Schemel <info@artsoft.org>
Tue, 5 Apr 2022 06:36:14 +0000 (08:36 +0200)
committerHolger Schemel <info@artsoft.org>
Tue, 5 Apr 2022 06:36:14 +0000 (08:36 +0200)
src/api.c
src/api.h
src/files.c
src/libgame/system.h
src/main.h

index 6fd07dce6fa1a9ecf2eeb6d437f0e1092f6cfcfc..f2679fa1ae91cc87f798c127a22d4ea8f1039e15 100644 (file)
--- 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
 // ============================================================================
index 7090b69c212f124f8914bf70b4d57c627da8fb8b..4f897421cc4d6e1b327ab58f20726af394f77c79 100644 (file)
--- 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 *);
 
index 2216c6713db44a1fa8e201f755f5bfd94810cd68..e3835b7d7df84134015808ff28d3bde6b50e4031 100644 (file)
@@ -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;
 }
 
index 7a80e91f0da848da91979a38e772a3ad50fe741d..24d0d722502b70ddb5c083740e812bef192cb861 100644 (file)
 #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"
 
index b931e707317a04470338accad4e3f591b6edffa0..00ce3cd258883d8ec0e909b5417fee53e7ef8692 100644 (file)
@@ -3125,6 +3125,7 @@ struct ScoreInfo
 
   boolean updated;
   boolean uploaded;
+  boolean tape_downloaded;
   boolean force_last_added;
 
   struct ScoreEntry entry[MAX_SCORE_ENTRIES];