add delay retries to leaderboard submits

This commit is contained in:
Jamiras 2020-02-29 08:42:17 -07:00
parent ca6b07cc47
commit db5358f70f
3 changed files with 80 additions and 64 deletions

View File

@ -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)

View File

@ -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]);

View File

@ -1,6 +1,18 @@
#include "rurl.h"
#ifdef RARCH_INTERNAL
#include <rhash.h> /* 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 <stdio.h>
#include <string.h>
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;
}