add delay retries to leaderboard submits
This commit is contained in:
parent
ca6b07cc47
commit
db5358f70f
|
@ -133,7 +133,8 @@ typedef struct
|
||||||
enum rcheevos_async_io_type
|
enum rcheevos_async_io_type
|
||||||
{
|
{
|
||||||
CHEEVOS_ASYNC_RICHPRESENCE,
|
CHEEVOS_ASYNC_RICHPRESENCE,
|
||||||
CHEEVOS_ASYNC_AWARD_ACHIEVEMENT
|
CHEEVOS_ASYNC_AWARD_ACHIEVEMENT,
|
||||||
|
CHEEVOS_ASYNC_SUBMIT_LBOARD
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct rcheevos_async_io_request
|
typedef struct rcheevos_async_io_request
|
||||||
|
@ -143,6 +144,8 @@ typedef struct rcheevos_async_io_request
|
||||||
int attempt_count;
|
int attempt_count;
|
||||||
char type;
|
char type;
|
||||||
char hardcore;
|
char hardcore;
|
||||||
|
char* success_message;
|
||||||
|
char* failure_message;
|
||||||
char user_agent[256];
|
char user_agent[256];
|
||||||
} rcheevos_async_io_request;
|
} 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 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_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)
|
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);
|
rcheevos_async_award_achievement(request);
|
||||||
task_set_finished(task, 1);
|
task_set_finished(task, 1);
|
||||||
break;
|
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);
|
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)
|
static const char* rcheevos_rc_error(int ret)
|
||||||
{
|
{
|
||||||
switch (ret)
|
switch (ret)
|
||||||
|
@ -686,28 +717,6 @@ error:
|
||||||
Test all the achievements (call once per frame).
|
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)
|
static void rcheevos_async_award_achievement(rcheevos_async_io_request* request)
|
||||||
{
|
{
|
||||||
char buffer[256];
|
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);
|
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)
|
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->type = CHEEVOS_ASYNC_AWARD_ACHIEVEMENT;
|
||||||
request->id = cheevo->info->id;
|
request->id = cheevo->info->id;
|
||||||
request->hardcore = ((mode & RCHEEVOS_ACTIVE_HARDCORE) != 0) ? 1 : 0;
|
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_get_user_agent(request->user_agent);
|
||||||
rcheevos_async_award_achievement(request);
|
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,
|
static void rcheevos_async_submit_lboard(rcheevos_async_io_request* request)
|
||||||
const char* error)
|
|
||||||
{
|
{
|
||||||
int ret;
|
|
||||||
MD5_CTX ctx;
|
|
||||||
uint8_t hash[16];
|
|
||||||
char signature[64];
|
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
char user_agent[256];
|
settings_t *settings = config_get_ptr();
|
||||||
const rcheevos_lboard_t* lboard = (const rcheevos_lboard_t*)user_data;
|
int ret = rc_url_submit_lboard(buffer, sizeof(buffer), settings->arrays.cheevos_username,
|
||||||
settings_t *settings = config_get_ptr();
|
rcheevos_locals.token, request->id, request->value, rcheevos_locals.hash);
|
||||||
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);
|
|
||||||
|
|
||||||
if (ret != 0)
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
rcheevos_get_user_agent(user_agent);
|
|
||||||
|
|
||||||
rcheevos_log_url(RCHEEVOS_TAG "rc_url_submit_lboard: %s\n", buffer);
|
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)
|
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);
|
runloop_msg_queue_push(buffer, 0, 2 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
||||||
|
|
||||||
/* Start the submit task. */
|
/* 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)
|
static void rcheevos_test_leaderboards(void)
|
||||||
|
|
|
@ -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_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]);
|
int rc_url_get_gameid(char* buffer, size_t size, unsigned char hash[16]);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,18 @@
|
||||||
#include "rurl.h"
|
#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 <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
static int rc_url_encode(char* encoded, size_t len, const char* str) {
|
static int rc_url_encode(char* encoded, size_t len, const char* str) {
|
||||||
for (;;) {
|
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;
|
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_user_name[64];
|
||||||
char urle_login_token[64];
|
char urle_login_token[64];
|
||||||
|
char signature[64];
|
||||||
|
unsigned char hash[16];
|
||||||
|
md5_state_t state;
|
||||||
int written;
|
int written;
|
||||||
|
|
||||||
if (rc_url_encode(urle_user_name, sizeof(urle_user_name), user_name) != 0) {
|
if (rc_url_encode(urle_user_name, sizeof(urle_user_name), user_name) != 0) {
|
||||||
|
@ -82,6 +97,12 @@ int rc_url_submit_lboard(char* buffer, size_t size, const char* user_name, const
|
||||||
return -1;
|
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(
|
written = snprintf(
|
||||||
buffer,
|
buffer,
|
||||||
size,
|
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]
|
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;
|
return (size_t)written >= size ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue