From db5358f70ffcd5034b49f58ef6737c7eb7548729 Mon Sep 17 00:00:00 2001 From: Jamiras Date: Sat, 29 Feb 2020 08:42:17 -0700 Subject: [PATCH] add delay retries to leaderboard submits --- cheevos-new/cheevos.c | 113 ++++++++++++++++------------------- deps/rcheevos/include/rurl.h | 2 +- deps/rcheevos/src/rurl/url.c | 29 ++++++++- 3 files changed, 80 insertions(+), 64 deletions(-) diff --git a/cheevos-new/cheevos.c b/cheevos-new/cheevos.c index 14147edd59..3a90950bea 100644 --- a/cheevos-new/cheevos.c +++ b/cheevos-new/cheevos.c @@ -133,7 +133,8 @@ typedef struct enum rcheevos_async_io_type { CHEEVOS_ASYNC_RICHPRESENCE, - CHEEVOS_ASYNC_AWARD_ACHIEVEMENT + CHEEVOS_ASYNC_AWARD_ACHIEVEMENT, + CHEEVOS_ASYNC_SUBMIT_LBOARD }; typedef struct rcheevos_async_io_request @@ -143,6 +144,8 @@ typedef struct rcheevos_async_io_request int attempt_count; char type; char hardcore; + char* success_message; + char* failure_message; char user_agent[256]; } rcheevos_async_io_request; @@ -373,6 +376,7 @@ static void rcheevos_log_url(const char* format, const char* url) static retro_time_t rcheevos_async_send_rich_presence(rcheevos_async_io_request* request); static void rcheevos_async_award_achievement(rcheevos_async_io_request* request); +static void rcheevos_async_submit_lboard(rcheevos_async_io_request* request); static void rcheevos_async_task_handler(retro_task_t* task) { @@ -398,6 +402,11 @@ static void rcheevos_async_task_handler(retro_task_t* task) rcheevos_async_award_achievement(request); task_set_finished(task, 1); break; + + case CHEEVOS_ASYNC_SUBMIT_LBOARD: + rcheevos_async_submit_lboard(request); + task_set_finished(task, 1); + break; } } @@ -411,6 +420,28 @@ static void rcheevos_async_schedule(rcheevos_async_io_request* request, retro_ti task_queue_push(task); } +static void rcheevos_async_task_callback(retro_task_t* task, void* task_data, void* user_data, const char* error) +{ + rcheevos_async_io_request* request = (rcheevos_async_io_request*)user_data; + + if (!error) + { + CHEEVOS_LOG(RCHEEVOS_TAG "%s %u\n", request->success_message, request->id); + free(request); + } + else + { + /* double the wait between each attempt until we hit a maximum delay of two minutes + * 250ms -> 500ms -> 1s -> 2s -> 4s -> 8s -> 16s -> 32s -> 64s -> 120s -> 120s... */ + retro_time_t retry_delay = (request->attempt_count > 8) ? (120 * 1000 * 1000) : ((250 * 1000) << request->attempt_count); + + request->attempt_count++; + rcheevos_async_schedule(request, retry_delay); + + CHEEVOS_ERR(RCHEEVOS_TAG "%s %u: %s\n", request->failure_message, request->id, error); + } +} + static const char* rcheevos_rc_error(int ret) { switch (ret) @@ -686,28 +717,6 @@ error: Test all the achievements (call once per frame). *****************************************************************************/ -static void rcheevos_award_task_callback(retro_task_t* task, void* task_data, void* user_data, const char* error) -{ - rcheevos_async_io_request* request = (rcheevos_async_io_request*)user_data; - - if (!error) - { - CHEEVOS_LOG(RCHEEVOS_TAG "Awarded achievement %u\n", request->id); - free(request); - } - else - { - /* double the wait between each attempt until we hit a maximum delay of two minutes - * 250ms -> 500ms -> 1s -> 2s -> 4s -> 8s -> 16s -> 32s -> 64s -> 120s -> 120s... */ - retro_time_t retry_delay = (request->attempt_count > 8) ? (120 * 1000 * 1000) : ((250 * 1000) << request->attempt_count); - - request->attempt_count++; - rcheevos_async_schedule(request, retry_delay); - - CHEEVOS_ERR(RCHEEVOS_TAG "Error awarding achievement %u: %s\n", request->id, error); - } -} - static void rcheevos_async_award_achievement(rcheevos_async_io_request* request) { char buffer[256]; @@ -722,7 +731,7 @@ static void rcheevos_async_award_achievement(rcheevos_async_io_request* request) } rcheevos_log_url(RCHEEVOS_TAG "rc_url_award_cheevo: %s\n", buffer); - task_push_http_transfer_with_user_agent(buffer, true, NULL, request->user_agent, rcheevos_award_task_callback, request); + task_push_http_transfer_with_user_agent(buffer, true, NULL, request->user_agent, rcheevos_async_task_callback, request); } static void rcheevos_award(rcheevos_cheevo_t* cheevo, int mode) @@ -761,6 +770,8 @@ static void rcheevos_award(rcheevos_cheevo_t* cheevo, int mode) request->type = CHEEVOS_ASYNC_AWARD_ACHIEVEMENT; request->id = cheevo->info->id; request->hardcore = ((mode & RCHEEVOS_ACTIVE_HARDCORE) != 0) ? 1 : 0; + request->success_message = "Awarded achievement"; + request->failure_message = "Error awarding achievement"; rcheevos_get_user_agent(request->user_agent); rcheevos_async_award_achievement(request); } @@ -891,51 +902,22 @@ static void rcheevos_test_cheevo_set(bool official) } } -static void rcheevos_lboard_submit_task(retro_task_t *task, void* task_data, void* user_data, - const char* error) +static void rcheevos_async_submit_lboard(rcheevos_async_io_request* request) { - int ret; - MD5_CTX ctx; - uint8_t hash[16]; - char signature[64]; char buffer[256]; - char user_agent[256]; - const rcheevos_lboard_t* lboard = (const rcheevos_lboard_t*)user_data; - settings_t *settings = config_get_ptr(); - const char *cheevos_username = settings->arrays.cheevos_username; - - if (!error) - { - CHEEVOS_LOG(RCHEEVOS_TAG "Submitted leaderboard %u\n", lboard->info->id); - return; - } - - CHEEVOS_ERR(RCHEEVOS_TAG "Error submitting leaderboard %u: %s\n", lboard->info->id, error); - - /* Try again. */ - - /* Evaluate the signature. */ - snprintf(signature, sizeof(signature), "%u%s%u", lboard->info->id, - cheevos_username, lboard->info->id); - - MD5_Init(&ctx); - MD5_Update(&ctx, (void*)signature, strlen(signature)); - MD5_Final(hash, &ctx); - - /* Start the request. */ - ret = rc_url_submit_lboard(buffer, sizeof(buffer), cheevos_username, - rcheevos_locals.token, lboard->info->id, lboard->last_value, hash); + settings_t *settings = config_get_ptr(); + int ret = rc_url_submit_lboard(buffer, sizeof(buffer), settings->arrays.cheevos_username, + rcheevos_locals.token, request->id, request->value, rcheevos_locals.hash); if (ret != 0) { - CHEEVOS_ERR(RCHEEVOS_TAG "Buffer to small to create URL\n"); + CHEEVOS_ERR(RCHEEVOS_TAG "Buffer too small to create URL\n"); + free(request); return; } - rcheevos_get_user_agent(user_agent); - rcheevos_log_url(RCHEEVOS_TAG "rc_url_submit_lboard: %s\n", buffer); - task_push_http_transfer_with_user_agent(buffer, true, NULL, user_agent, rcheevos_lboard_submit_task, user_data); + task_push_http_transfer_with_user_agent(buffer, true, NULL, request->user_agent, rcheevos_async_task_callback, request); } static void rcheevos_lboard_submit(rcheevos_lboard_t* lboard) @@ -962,7 +944,16 @@ static void rcheevos_lboard_submit(rcheevos_lboard_t* lboard) runloop_msg_queue_push(buffer, 0, 2 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); /* Start the submit task. */ - rcheevos_lboard_submit_task(NULL, NULL, lboard, "no error, first try"); + { + rcheevos_async_io_request* request = (rcheevos_async_io_request*)calloc(1, sizeof(rcheevos_async_io_request)); + request->type = CHEEVOS_ASYNC_SUBMIT_LBOARD; + request->id = lboard->info->id; + request->value = lboard->last_value; + request->success_message = "Submitted leaderboard"; + request->failure_message = "Error submitting leaderboard"; + rcheevos_get_user_agent(request->user_agent); + rcheevos_async_submit_lboard(request); + } } static void rcheevos_test_leaderboards(void) diff --git a/deps/rcheevos/include/rurl.h b/deps/rcheevos/include/rurl.h index f21ecf2fe9..1c1a44cd0e 100644 --- a/deps/rcheevos/include/rurl.h +++ b/deps/rcheevos/include/rurl.h @@ -9,7 +9,7 @@ extern "C" { int rc_url_award_cheevo(char* buffer, size_t size, const char* user_name, const char* login_token, unsigned cheevo_id, int hardcore); -int rc_url_submit_lboard(char* buffer, size_t size, const char* user_name, const char* login_token, unsigned lboard_id, int value, unsigned char hash[16]); +int rc_url_submit_lboard(char* buffer, size_t size, const char* user_name, const char* login_token, unsigned lboard_id, int value, const char* game_hash); int rc_url_get_gameid(char* buffer, size_t size, unsigned char hash[16]); diff --git a/deps/rcheevos/src/rurl/url.c b/deps/rcheevos/src/rurl/url.c index e7b7a67aab..5ac67aa361 100644 --- a/deps/rcheevos/src/rurl/url.c +++ b/deps/rcheevos/src/rurl/url.c @@ -1,6 +1,18 @@ #include "rurl.h" +#ifdef RARCH_INTERNAL +#include /* libretro-common/include/rhash.h */ +#define md5_state_t MD5_CTX +#define md5_byte_t unsigned char +#define md5_init(state) MD5_Init(state) +#define md5_append(state, buffer, size) MD5_Update(state, buffer, size) +#define md5_finish(state, hash) MD5_Final(hash, state) +#else +#include "..\rhash\md5.h" +#endif + #include +#include static int rc_url_encode(char* encoded, size_t len, const char* str) { for (;;) { @@ -69,9 +81,12 @@ int rc_url_award_cheevo(char* buffer, size_t size, const char* user_name, const return (size_t)written >= size ? -1 : 0; } -int rc_url_submit_lboard(char* buffer, size_t size, const char* user_name, const char* login_token, unsigned lboard_id, int value, unsigned char hash[16]) { +int rc_url_submit_lboard(char* buffer, size_t size, const char* user_name, const char* login_token, unsigned lboard_id, int value, const char* game_hash) { char urle_user_name[64]; char urle_login_token[64]; + char signature[64]; + unsigned char hash[16]; + md5_state_t state; int written; if (rc_url_encode(urle_user_name, sizeof(urle_user_name), user_name) != 0) { @@ -81,7 +96,13 @@ int rc_url_submit_lboard(char* buffer, size_t size, const char* user_name, const if (rc_url_encode(urle_login_token, sizeof(urle_login_token), login_token) != 0) { return -1; } - + + /* Evaluate the signature. */ + snprintf(signature, sizeof(signature), "%u%s%u", lboard_id, user_name, lboard_id); + md5_init(&state); + md5_append(&state, (unsigned char*)signature, (int)strlen(signature)); + md5_finish(&state, hash); + written = snprintf( buffer, size, @@ -94,6 +115,10 @@ int rc_url_submit_lboard(char* buffer, size_t size, const char* user_name, const hash[ 8], hash[ 9], hash[10], hash[11],hash[12], hash[13], hash[14], hash[15] ); + if (game_hash && strlen(game_hash) == 32 && (size - (size_t)written) >= 35) { + written += snprintf(buffer + written, size - (size_t)written, "&m=%s", game_hash); + } + return (size_t)written >= size ? -1 : 0; }