Skip to content

Commit ebfe8ca

Browse files
authored
switch fetch_games_list API from r=gameslist to r=systemgames (#512)
1 parent 110b679 commit ebfe8ca

5 files changed

Lines changed: 170 additions & 45 deletions

File tree

include/rc_api_info.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,26 @@ rc_api_fetch_games_list_request_t;
164164
typedef struct rc_api_game_list_entry_t {
165165
/* The unique identifier of the game */
166166
uint32_t id;
167+
/* The number of achievements in the game */
168+
uint32_t num_achievements;
169+
/* The number of leaderboards in the game */
170+
uint32_t num_leaderboards;
171+
/* The number of points in the game */
172+
uint32_t points;
167173
/* The name of the game */
168174
const char* name;
175+
/* The image name for the game badge */
176+
const char* image_name;
177+
/* The URL for the game badge image */
178+
const char* image_url;
179+
/* An array of supported hashes */
180+
const char** supported_hashes;
181+
/* An array of unsupported hashes */
182+
const char** unsupported_hashes;
183+
/* The number of items in the supported_hashes array */
184+
uint32_t num_supported_hashes;
185+
/* The number of items in the unsupported_hashes array */
186+
uint32_t num_unsupported_hashes;
169187
}
170188
rc_api_game_list_entry_t;
171189

src/rapi/rc_api_common.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,57 @@ int rc_json_get_required_unum_array(uint32_t** entries, uint32_t* num_entries, r
503503
return RC_OK;
504504
}
505505

506+
static int rc_json_get_string_array(const char*** entries, uint32_t* num_entries, rc_api_response_t* response, const rc_json_field_t* array, const char* field_name) {
507+
if (*num_entries) {
508+
rc_json_iterator_t iterator;
509+
rc_json_field_t value;
510+
const char** entry;
511+
512+
*entries = (const char**)rc_buffer_alloc(&response->buffer, *num_entries * sizeof(const char*));
513+
if (!*entries)
514+
return RC_OUT_OF_MEMORY;
515+
516+
value.name = field_name;
517+
518+
memset(&iterator, 0, sizeof(iterator));
519+
iterator.json = array->value_start;
520+
iterator.end = array->value_end;
521+
522+
entry = *entries;
523+
while (rc_json_get_array_entry_value(&value, &iterator)) {
524+
if (!rc_json_get_string(entry, &response->buffer, &value, field_name))
525+
return RC_MISSING_VALUE;
526+
527+
++entry;
528+
}
529+
}
530+
else {
531+
*entries = NULL;
532+
}
533+
534+
return RC_OK;
535+
}
536+
537+
int rc_json_get_required_string_array(const char*** entries, uint32_t* num_entries, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name) {
538+
rc_json_field_t array;
539+
540+
memset(&array, 0, sizeof(array));
541+
if (!rc_json_get_required_array(num_entries, &array, response, field, field_name))
542+
return RC_MISSING_VALUE;
543+
544+
return rc_json_get_string_array(entries, num_entries, response, &array, field_name);
545+
}
546+
547+
int rc_json_get_optional_string_array(const char*** entries, uint32_t* num_entries, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name) {
548+
rc_json_field_t array;
549+
550+
memset(&array, 0, sizeof(array));
551+
if (!rc_json_get_optional_array(num_entries, &array, field, field_name))
552+
*num_entries = 0;
553+
554+
return rc_json_get_string_array(entries, num_entries, response, &array, field_name);
555+
}
556+
506557
int rc_json_get_required_array(uint32_t* num_entries, rc_json_field_t* array_field, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name) {
507558
#ifndef NDEBUG
508559
if (strcmp(field->name, field_name) != 0)

src/rapi/rc_api_common.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ int rc_json_get_required_bool(int* out, rc_api_response_t* response, const rc_js
6464
int rc_json_get_required_datetime(time_t* out, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name);
6565
int rc_json_get_required_object(rc_json_field_t* fields, size_t field_count, rc_api_response_t* response, rc_json_field_t* field, const char* field_name);
6666
int rc_json_get_required_unum_array(uint32_t** entries, uint32_t* num_entries, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name);
67+
int rc_json_get_required_string_array(const char*** entries, uint32_t* num_entries, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name);
68+
int rc_json_get_optional_string_array(const char*** entries, uint32_t* num_entries, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name);
6769
int rc_json_get_required_array(uint32_t* num_entries, rc_json_field_t* array_field, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name);
6870
int rc_json_get_array_entry_object(rc_json_field_t* fields, size_t field_count, rc_json_iterator_t* iterator);
6971
int rc_json_get_next_object_field(rc_json_iterator_t* iterator, rc_json_field_t* field);

src/rapi/rc_api_info.c

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -325,8 +325,8 @@ int rc_api_init_fetch_games_list_request_hosted(rc_api_request_t* request,
325325
return RC_INVALID_STATE;
326326

327327
rc_url_builder_init(&builder, &request->buffer, 48);
328-
rc_url_builder_append_str_param(&builder, "r", "gameslist");
329-
rc_url_builder_append_unum_param(&builder, "c", api_params->console_id);
328+
rc_url_builder_append_str_param(&builder, "r", "systemgames");
329+
rc_url_builder_append_unum_param(&builder, "s", api_params->console_id);
330330

331331
request->post_data = rc_url_builder_finalize(&builder);
332332
request->content_type = RC_CONTENT_TYPE_URLENCODED;
@@ -347,49 +347,78 @@ int rc_api_process_fetch_games_list_response(rc_api_fetch_games_list_response_t*
347347
int rc_api_process_fetch_games_list_server_response(rc_api_fetch_games_list_response_t* response, const rc_api_server_response_t* server_response) {
348348
rc_api_game_list_entry_t* entry;
349349
rc_json_iterator_t iterator;
350-
rc_json_field_t field;
350+
rc_json_field_t array_field;
351351
int result;
352-
char* end;
353352

354353
rc_json_field_t fields[] = {
355354
RC_JSON_NEW_FIELD("Success"),
356355
RC_JSON_NEW_FIELD("Error"),
357356
RC_JSON_NEW_FIELD("Response")
358357
};
359358

359+
rc_json_field_t game_fields[] = {
360+
RC_JSON_NEW_FIELD("ID"),
361+
RC_JSON_NEW_FIELD("Title"),
362+
RC_JSON_NEW_FIELD("ImageIcon"),
363+
RC_JSON_NEW_FIELD("ImageUrl"),
364+
RC_JSON_NEW_FIELD("NumAchievements"),
365+
RC_JSON_NEW_FIELD("NumLeaderboards"),
366+
RC_JSON_NEW_FIELD("Points"),
367+
RC_JSON_NEW_FIELD("SupportedHashes"), /* array */
368+
RC_JSON_NEW_FIELD("UnsupportedHashes"), /* array */
369+
};
370+
360371
memset(response, 0, sizeof(*response));
361372
rc_buffer_init(&response->response.buffer);
362373

363374
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
364375
if (result != RC_OK)
365376
return result;
366377

367-
if (!fields[2].value_start) {
368-
/* call rc_json_get_required_object to generate the error message */
369-
rc_json_get_required_object(NULL, 0, &response->response, &fields[2], "Response");
378+
if (!rc_json_get_required_array(&response->num_entries, &array_field, &response->response, &fields[2], "Response"))
370379
return RC_MISSING_VALUE;
371-
}
372380

373-
response->num_entries = fields[2].array_size;
374-
rc_buffer_reserve(&response->response.buffer, response->num_entries * (32 + sizeof(rc_api_game_list_entry_t)));
381+
if (response->num_entries) {
382+
/* 8=image_name, 32=title, 64=image_url, 32=one hash */
383+
rc_buffer_reserve(&response->response.buffer, response->num_entries * (8 + 32 + 64 + 32 + sizeof(rc_api_game_list_entry_t)));
375384

376-
response->entries = (rc_api_game_list_entry_t*)rc_buffer_alloc(&response->response.buffer, response->num_entries * sizeof(rc_api_game_list_entry_t));
377-
if (!response->entries)
378-
return RC_OUT_OF_MEMORY;
385+
response->entries = (rc_api_game_list_entry_t*)rc_buffer_alloc(&response->response.buffer, response->num_entries * sizeof(rc_api_game_list_entry_t));
386+
if (!response->entries)
387+
return RC_OUT_OF_MEMORY;
379388

380-
memset(&iterator, 0, sizeof(iterator));
381-
iterator.json = fields[2].value_start;
382-
iterator.end = fields[2].value_end;
389+
memset(&iterator, 0, sizeof(iterator));
390+
iterator.json = array_field.value_start;
391+
iterator.end = array_field.value_end;
383392

384-
entry = response->entries;
385-
while (rc_json_get_next_object_field(&iterator, &field)) {
386-
entry->id = strtol(field.name, &end, 10);
393+
entry = response->entries;
394+
while (rc_json_get_array_entry_object(game_fields, sizeof(game_fields) / sizeof(game_fields[0]), &iterator)) {
395+
if (!rc_json_get_required_unum(&entry->id, &response->response, &game_fields[0], "ID"))
396+
return RC_MISSING_VALUE;
397+
if (!rc_json_get_required_string(&entry->name, &response->response, &game_fields[1], "Title"))
398+
return RC_MISSING_VALUE;
399+
if (!rc_json_get_required_unum(&entry->num_achievements, &response->response, &game_fields[4], "NumAchievements"))
400+
return RC_MISSING_VALUE;
401+
if (!rc_json_get_required_unum(&entry->num_leaderboards, &response->response, &game_fields[5], "NumLeaderboards"))
402+
return RC_MISSING_VALUE;
403+
if (!rc_json_get_required_unum(&entry->points, &response->response, &game_fields[6], "Points"))
404+
return RC_MISSING_VALUE;
387405

388-
field.name = "";
389-
if (!rc_json_get_string(&entry->name, &response->response.buffer, &field, ""))
390-
return RC_MISSING_VALUE;
406+
/* ImageIcon will be '/Images/0123456.png' - only return the '0123456' */
407+
rc_json_extract_filename(&game_fields[2]);
408+
if (!rc_json_get_required_string(&entry->image_name, &response->response, &game_fields[2], "ImageIcon"))
409+
return RC_MISSING_VALUE;
410+
if (!rc_json_get_required_string(&entry->image_url, &response->response, &game_fields[3], "ImageUrl"))
411+
return RC_MISSING_VALUE;
391412

392-
++entry;
413+
result = rc_json_get_required_string_array(&entry->supported_hashes, &entry->num_supported_hashes, &response->response, &game_fields[7], "SupportedHashes");
414+
if (result != RC_OK)
415+
return result;
416+
result = rc_json_get_optional_string_array(&entry->unsupported_hashes, &entry->num_unsupported_hashes, &response->response, &game_fields[8], "UnsupportedHashes");
417+
if (result != RC_OK)
418+
return result;
419+
420+
++entry;
421+
}
393422
}
394423

395424
return RC_OK;

test/rapi/test_rc_api_info.c

Lines changed: 47 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ static void test_init_fetch_games_list_request() {
324324

325325
ASSERT_NUM_EQUALS(rc_api_init_fetch_games_list_request(&request, &fetch_games_list_request), RC_OK);
326326
ASSERT_STR_EQUALS(request.url, DOREQUEST_URL);
327-
ASSERT_STR_EQUALS(request.post_data, "r=gameslist&c=12");
327+
ASSERT_STR_EQUALS(request.post_data, "r=systemgames&s=12");
328328
ASSERT_STR_EQUALS(request.content_type, RC_CONTENT_TYPE_URLENCODED);
329329

330330
rc_api_destroy_request(&request);
@@ -333,40 +333,65 @@ static void test_init_fetch_games_list_request() {
333333
static void test_process_fetch_games_list_response() {
334334
rc_api_fetch_games_list_response_t fetch_games_list_response;
335335
rc_api_game_list_entry_t* entry;
336-
const char* server_response = "{\"Success\":true,\"Response\":{"
337-
"\"1234\":\"Game Name 1\","
338-
"\"17\":\"Game Name 2\","
339-
"\"9923\":\"Game Name 3\","
340-
"\"12303\":\"Game Name 4\","
341-
"\"4338\":\"Game Name 5\","
342-
"\"5437\":\"Game Name 6\""
343-
"}}";
336+
const char* server_response = "{\"Success\":true,\"Response\":["
337+
"{\"ID\":111,\"Title\":\"Game Name 1\",\"NumAchievements\":6,\"NumLeaderboards\":0,\"Points\":40,"
338+
"\"ImageIcon\":\"/Images/001110.png\",\"ImageUrl\":\"http://host/Images/001110.png\","
339+
"\"SupportedHashes\":[\"0123456789abcdeffedcba9876543210\"]},"
340+
"{\"ID\":222,\"Title\":\"Game Name 2\",\"NumAchievements\":0,\"NumLeaderboards\":0,\"Points\":0,"
341+
"\"ImageIcon\":\"/Images/002220.png\",\"ImageUrl\":\"http://host/Images/002220.png\","
342+
"\"SupportedHashes\":[]},"
343+
"{\"ID\":333,\"Title\":\"Game Name 3\",\"NumAchievements\":14,\"NumLeaderboards\":3,\"Points\":200,"
344+
"\"ImageIcon\":\"/Images/003330.png\",\"ImageUrl\":\"http://host/Images/003330.png\","
345+
"\"SupportedHashes\":[\"deadbeefdeadbeefdeadbeefdeadbeef\",\"00112233445566778899aabbccddeeff\"],"
346+
"\"UnsupportedHashes\":[\"abababababababababababababababab\"]}"
347+
"]}";
344348

345349
memset(&fetch_games_list_response, 0, sizeof(fetch_games_list_response));
346350

347351
ASSERT_NUM_EQUALS(rc_api_process_fetch_games_list_response(&fetch_games_list_response, server_response), RC_OK);
348352
ASSERT_NUM_EQUALS(fetch_games_list_response.response.succeeded, 1);
349353
ASSERT_PTR_NULL(fetch_games_list_response.response.error_message);
350-
ASSERT_NUM_EQUALS(fetch_games_list_response.num_entries, 6);
354+
ASSERT_NUM_EQUALS(fetch_games_list_response.num_entries, 3);
351355

352356
entry = &fetch_games_list_response.entries[0];
353-
ASSERT_NUM_EQUALS(entry->id, 1234);
357+
ASSERT_NUM_EQUALS(entry->id, 111);
354358
ASSERT_STR_EQUALS(entry->name, "Game Name 1");
359+
ASSERT_NUM_EQUALS(entry->num_achievements, 6);
360+
ASSERT_NUM_EQUALS(entry->num_leaderboards, 0);
361+
ASSERT_NUM_EQUALS(entry->points, 40);
362+
ASSERT_STR_EQUALS(entry->image_name, "001110");
363+
ASSERT_STR_EQUALS(entry->image_url, "http://host/Images/001110.png");
364+
ASSERT_NUM_EQUALS(entry->num_supported_hashes, 1);
365+
ASSERT_STR_EQUALS(entry->supported_hashes[0], "0123456789abcdeffedcba9876543210");
366+
ASSERT_NUM_EQUALS(entry->num_unsupported_hashes, 0);
367+
ASSERT_PTR_NULL(entry->unsupported_hashes);
368+
355369
entry = &fetch_games_list_response.entries[1];
356-
ASSERT_NUM_EQUALS(entry->id, 17);
370+
ASSERT_NUM_EQUALS(entry->id, 222);
357371
ASSERT_STR_EQUALS(entry->name, "Game Name 2");
372+
ASSERT_NUM_EQUALS(entry->num_achievements, 0);
373+
ASSERT_NUM_EQUALS(entry->num_leaderboards, 0);
374+
ASSERT_NUM_EQUALS(entry->points, 0);
375+
ASSERT_STR_EQUALS(entry->image_name, "002220");
376+
ASSERT_STR_EQUALS(entry->image_url, "http://host/Images/002220.png");
377+
ASSERT_NUM_EQUALS(entry->num_supported_hashes, 0);
378+
ASSERT_PTR_NULL(entry->supported_hashes);
379+
ASSERT_NUM_EQUALS(entry->num_unsupported_hashes, 0);
380+
ASSERT_PTR_NULL(entry->unsupported_hashes);
381+
358382
entry = &fetch_games_list_response.entries[2];
359-
ASSERT_NUM_EQUALS(entry->id, 9923);
383+
ASSERT_NUM_EQUALS(entry->id, 333);
360384
ASSERT_STR_EQUALS(entry->name, "Game Name 3");
361-
entry = &fetch_games_list_response.entries[3];
362-
ASSERT_NUM_EQUALS(entry->id, 12303);
363-
ASSERT_STR_EQUALS(entry->name, "Game Name 4");
364-
entry = &fetch_games_list_response.entries[4];
365-
ASSERT_NUM_EQUALS(entry->id, 4338);
366-
ASSERT_STR_EQUALS(entry->name, "Game Name 5");
367-
entry = &fetch_games_list_response.entries[5];
368-
ASSERT_NUM_EQUALS(entry->id, 5437);
369-
ASSERT_STR_EQUALS(entry->name, "Game Name 6");
385+
ASSERT_NUM_EQUALS(entry->num_achievements, 14);
386+
ASSERT_NUM_EQUALS(entry->num_leaderboards, 3);
387+
ASSERT_NUM_EQUALS(entry->points, 200);
388+
ASSERT_STR_EQUALS(entry->image_name, "003330");
389+
ASSERT_STR_EQUALS(entry->image_url, "http://host/Images/003330.png");
390+
ASSERT_NUM_EQUALS(entry->num_supported_hashes, 2);
391+
ASSERT_STR_EQUALS(entry->supported_hashes[0], "deadbeefdeadbeefdeadbeefdeadbeef");
392+
ASSERT_STR_EQUALS(entry->supported_hashes[1], "00112233445566778899aabbccddeeff");
393+
ASSERT_NUM_EQUALS(entry->num_unsupported_hashes, 1);
394+
ASSERT_STR_EQUALS(entry->unsupported_hashes[0], "abababababababababababababababab");
370395

371396
rc_api_destroy_fetch_games_list_response(&fetch_games_list_response);
372397
}

0 commit comments

Comments
 (0)