Merge branch 'Overv-download-saved-park' into develop

This commit is contained in:
Ted John 2016-12-28 19:17:18 +00:00
commit 2892a7ad3f
7 changed files with 420 additions and 198 deletions

View File

@ -18,6 +18,7 @@
#include "core/Console.hpp"
#include "core/Guard.hpp"
#include "core/String.hpp"
#include "FileClassifier.h"
#include "network/network.h"
#include "object/ObjectRepository.h"
#include "OpenRCT2.h"
@ -41,6 +42,7 @@ extern "C"
#include "network/http.h"
#include "object_list.h"
#include "platform/platform.h"
#include "rct1.h"
#include "rct2/interop.h"
#include "version.h"
}
@ -88,6 +90,8 @@ namespace OpenRCT2
static void RunGameLoop();
static void RunFixedFrame();
static void RunVariableFrame();
static bool OpenParkAutoDetectFormat(const utf8 * path);
}
extern "C"
@ -216,9 +220,32 @@ extern "C"
title_load();
break;
case STARTUP_ACTION_OPEN:
if (!rct2_open_file(gOpenRCT2StartupActionPath))
{
bool parkLoaded = false;
// A path that includes "://" is illegal with all common filesystems, so it is almost certainly a URL
// This way all cURL supported protocols, like http, ftp, scp and smb are automatically handled
if (strstr(gOpenRCT2StartupActionPath, "://") != nullptr)
{
fprintf(stderr, "Failed to load '%s'", gOpenRCT2StartupActionPath);
#ifndef DISABLE_HTTP
// Download park and open it using its temporary filename
char tmpPath[MAX_PATH];
if (!http_download_park(gOpenRCT2StartupActionPath, tmpPath))
{
title_load();
break;
}
parkLoaded = OpenRCT2::OpenParkAutoDetectFormat(tmpPath);
#endif
}
else
{
parkLoaded = rct2_open_file(gOpenRCT2StartupActionPath);
}
if (!parkLoaded)
{
Console::Error::WriteLine("Failed to load '%s'", gOpenRCT2StartupActionPath);
title_load();
break;
}
@ -245,6 +272,7 @@ extern "C"
}
#endif // DISABLE_NETWORK
break;
}
case STARTUP_ACTION_EDIT:
if (String::SizeOf(gOpenRCT2StartupActionPath) == 0)
{
@ -478,4 +506,62 @@ namespace OpenRCT2
sprite_position_tween_restore();
}
static bool OpenParkAutoDetectFormat(const utf8 * path)
{
ClassifiedFile info;
if (TryClassifyFile(path, &info))
{
if (info.Type == FILE_TYPE::SAVED_GAME)
{
if (info.Version <= 2)
{
if (rct1_load_saved_game(path))
{
game_load_init();
return true;
}
}
else
{
if (game_load_save(path))
{
gFirstTimeSave = 0;
return true;
}
}
Console::Error::WriteLine("Error loading saved game.");
}
else if (info.Type == FILE_TYPE::SCENARIO)
{
if (info.Version <= 2)
{
if (rct1_load_scenario(path))
{
scenario_begin();
return true;
}
}
else
{
if (scenario_load_and_play_from_path(path))
{
return true;
}
}
Console::Error::WriteLine("Error loading scenario.");
}
else
{
Console::Error::WriteLine("Invalid file type.");
Console::Error::WriteLine("Invalid file type.");
}
}
else
{
Console::Error::WriteLine("Unable to detect file type.");
}
return false;
}
}

View File

@ -121,8 +121,13 @@ static void PrintLaunchInformation();
const CommandLineCommand CommandLine::RootCommands[]
{
// Main commands
#ifndef DISABLE_HTTP
DefineCommand("", "<uri>", StandardOptions, HandleNoCommand ),
DefineCommand("edit", "<uri>", StandardOptions, HandleCommandEdit ),
#else
DefineCommand("", "<path>", StandardOptions, HandleNoCommand ),
DefineCommand("edit", "<path>", StandardOptions, HandleCommandEdit ),
#endif
DefineCommand("intro", "", StandardOptions, HandleCommandIntro ),
#ifndef DISABLE_NETWORK
DefineCommand("host", "<uri>", StandardOptions, HandleCommandHost ),
@ -148,7 +153,9 @@ const CommandLineExample CommandLine::RootExamples[]
{ "./my_park.sv6", "open a saved park" },
{ "./SnowyPark.sc6", "install and open a scenario" },
{ "./ShuttleLoop.td6", "install a track" },
#ifndef DISABLE_HTTP
{ "https://openrct2.website/files/SnowyPark.sv6", "download and open a saved park" },
#endif
#ifndef DISABLE_NETWORK
{ "host ./my_park.sv6 --port 11753 --headless", "run a headless server for a saved park" },
#endif

View File

@ -100,7 +100,7 @@ private:
_lastAdvertiseTime = SDL_GetTicks();
// Send the registration request
http_json_request request;
http_request_t request;
request.tag = this;
request.url = GetMasterServerUrl();
request.method = HTTP_METHOD_POST;
@ -108,9 +108,10 @@ private:
json_t *body = json_object();
json_object_set_new(body, "key", json_string(_key.c_str()));
json_object_set_new(body, "port", json_integer(_port));
request.body = body;
request.root = body;
request.type = HTTP_DATA_JSON;
http_request_json_async(&request, [](http_json_response * response) -> void
http_request_async(&request, [](http_response_t * response) -> void
{
if (response == nullptr)
{
@ -120,7 +121,7 @@ private:
{
auto advertiser = static_cast<NetworkServerAdvertiser*>(response->tag);
advertiser->OnRegistrationResponse(response->root);
http_request_json_dispose(response);
http_request_dispose(response);
}
});
@ -129,16 +130,17 @@ private:
void SendHeartbeat()
{
http_json_request request;
http_request_t request;
request.tag = this;
request.url = GetMasterServerUrl();
request.method = HTTP_METHOD_PUT;
json_t * jsonBody = GetHeartbeatJson();
request.body = jsonBody;
request.root = jsonBody;
request.type = HTTP_DATA_JSON;
_lastHeartbeatTime = SDL_GetTicks();
http_request_json_async(&request, [](http_json_response *response) -> void
http_request_async(&request, [](http_response_t *response) -> void
{
if (response == nullptr)
{
@ -148,7 +150,7 @@ private:
{
auto advertiser = static_cast<NetworkServerAdvertiser*>(response->tag);
advertiser->OnHeartbeatResponse(response->root);
http_request_json_dispose(response);
http_request_dispose(response);
}
});

View File

@ -15,8 +15,8 @@
#pragma endregion
extern "C" {
#include "http.h"
#include "../platform/platform.h"
#include "http.h"
#include "../platform/platform.h"
}
#ifdef DISABLE_HTTP
@ -29,10 +29,11 @@ void http_dispose() { }
#include "../core/Math.hpp"
#include "../core/Path.hpp"
#include "../core/String.hpp"
#include "../core/Console.hpp"
#ifdef __WINDOWS__
// cURL includes windows.h, but we don't need all of it.
#define WIN32_LEAN_AND_MEAN
// cURL includes windows.h, but we don't need all of it.
#define WIN32_LEAN_AND_MEAN
#endif
#include <curl/curl.h>
@ -40,189 +41,290 @@ void http_dispose() { }
#define OPENRCT2_USER_AGENT "OpenRCT2/" OPENRCT2_VERSION
typedef struct read_buffer {
char *ptr;
size_t length;
size_t position;
char *ptr;
size_t length;
size_t position;
} read_buffer;
typedef struct write_buffer {
char *ptr;
size_t length;
size_t capacity;
char *ptr;
size_t length;
size_t capacity;
} write_buffer;
void http_init()
{
curl_global_init(CURL_GLOBAL_DEFAULT);
curl_global_init(CURL_GLOBAL_DEFAULT);
}
void http_dispose()
{
curl_global_cleanup();
curl_global_cleanup();
}
static size_t http_request_read_func(void *ptr, size_t size, size_t nmemb, void *userdata)
{
read_buffer *readBuffer = (read_buffer*)userdata;
read_buffer *readBuffer = (read_buffer*)userdata;
size_t remainingBytes = readBuffer->length - readBuffer->position;
size_t readBytes = size * nmemb;
if (readBytes > remainingBytes) {
readBytes = remainingBytes;
}
size_t remainingBytes = readBuffer->length - readBuffer->position;
size_t readBytes = size * nmemb;
if (readBytes > remainingBytes) {
readBytes = remainingBytes;
}
memcpy(ptr, readBuffer->ptr + readBuffer->position, readBytes);
memcpy(ptr, readBuffer->ptr + readBuffer->position, readBytes);
readBuffer->position += readBytes;
return readBytes;
readBuffer->position += readBytes;
return readBytes;
}
static size_t http_request_write_func(void *ptr, size_t size, size_t nmemb, void *userdata)
{
write_buffer *writeBuffer = (write_buffer*)userdata;
write_buffer *writeBuffer = (write_buffer*)userdata;
size_t newBytesLength = size * nmemb;
if (newBytesLength > 0) {
size_t newCapacity = writeBuffer->capacity;
size_t newLength = writeBuffer->length + newBytesLength;
while (newLength > newCapacity) {
newCapacity = Math::Max<size_t>(4096, newCapacity * 2);
size_t newBytesLength = size * nmemb;
if (newBytesLength > 0) {
size_t newCapacity = writeBuffer->capacity;
size_t newLength = writeBuffer->length + newBytesLength;
while (newLength > newCapacity) {
newCapacity = Math::Max<size_t>(4096, newCapacity * 2);
}
if (newCapacity != writeBuffer->capacity) {
writeBuffer->ptr = (char*)realloc(writeBuffer->ptr, newCapacity);
writeBuffer->capacity = newCapacity;
}
memcpy(writeBuffer->ptr + writeBuffer->length, ptr, newBytesLength);
writeBuffer->length = newLength;
}
return newBytesLength;
}
http_response_t *http_request(const http_request_t *request)
{
CURL *curl;
CURLcode curlResult;
http_response_t *response;
read_buffer readBuffer = { 0 };
write_buffer writeBuffer;
curl = curl_easy_init();
if (curl == NULL)
return NULL;
if (request->type == HTTP_DATA_JSON && request->root != NULL) {
readBuffer.ptr = json_dumps(request->root, JSON_COMPACT);
readBuffer.length = strlen(readBuffer.ptr);
readBuffer.position = 0;
} else if (request->type == HTTP_DATA_RAW && request->body != NULL) {
readBuffer.ptr = request->body;
readBuffer.length = request->size;
readBuffer.position = 0;
}
writeBuffer.ptr = NULL;
writeBuffer.length = 0;
writeBuffer.capacity = 0;
curl_slist *headers = NULL;
if (request->type == HTTP_DATA_JSON) {
headers = curl_slist_append(headers, "Accept: " MIME_TYPE_APPLICATION_JSON);
if (request->root != NULL) {
headers = curl_slist_append(headers, "Content-Type: " MIME_TYPE_APPLICATION_JSON);
}
}
if (readBuffer.ptr != NULL) {
char contentLengthHeaderValue[64];
snprintf(contentLengthHeaderValue, sizeof(contentLengthHeaderValue), "Content-Length: %zu", readBuffer.length);
headers = curl_slist_append(headers, contentLengthHeaderValue);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, readBuffer.ptr);
}
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, request->method);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, true);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);
curl_easy_setopt(curl, CURLOPT_USERAGENT, OPENRCT2_USER_AGENT);
curl_easy_setopt(curl, CURLOPT_URL, request->url);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &writeBuffer);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_request_write_func);
curlResult = curl_easy_perform(curl);
if (request->type == HTTP_DATA_JSON && request->root != NULL) {
free(readBuffer.ptr);
}
if (curlResult != CURLE_OK) {
log_error("HTTP request failed: %s.", curl_easy_strerror(curlResult));
if (writeBuffer.ptr != NULL)
free(writeBuffer.ptr);
return NULL;
}
long httpStatusCode;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpStatusCode);
char* contentType;
curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &contentType);
// Null terminate the response buffer
writeBuffer.length++;
writeBuffer.ptr = (char*)realloc(writeBuffer.ptr, writeBuffer.length);
writeBuffer.capacity = writeBuffer.length;
writeBuffer.ptr[writeBuffer.length - 1] = 0;
response = NULL;
// Parse as JSON if response is JSON
if (contentType != NULL && strstr(contentType, "json") != NULL) {
json_t *root;
json_error_t error;
root = json_loads(writeBuffer.ptr, 0, &error);
if (root != NULL) {
response = (http_response_t*) malloc(sizeof(http_response_t));
response->tag = request->tag;
response->status_code = (int) httpStatusCode;
response->root = root;
response->type = HTTP_DATA_JSON;
response->size = writeBuffer.length;
}
free(writeBuffer.ptr);
} else {
response = (http_response_t*) malloc(sizeof(http_response_t));
response->tag = request->tag;
response->status_code = (int) httpStatusCode;
response->body = writeBuffer.ptr;
response->type = HTTP_DATA_RAW;
response->size = writeBuffer.length;
}
curl_easy_cleanup(curl);
return response;
}
void http_request_async(const http_request_t *request, void (*callback)(http_response_t*))
{
struct TempThreadArgs {
http_request_t request;
void (*callback)(http_response_t*);
};
TempThreadArgs *args = (TempThreadArgs*)malloc(sizeof(TempThreadArgs));
args->request.url = _strdup(request->url);
args->request.method = request->method;
if (request->type == HTTP_DATA_JSON) {
args->request.root = json_deep_copy(request->root);
} else {
char* bodyCopy = (char*) malloc(request->size);
memcpy(bodyCopy, request->body, request->size);
args->request.body = bodyCopy;
}
args->request.type = request->type;
args->request.size = request->size;
args->request.tag = request->tag;
args->callback = callback;
SDL_Thread *thread = SDL_CreateThread([](void *ptr) -> int {
TempThreadArgs *args = (TempThreadArgs*)ptr;
http_response_t *response = http_request(&args->request);
args->callback(response);
free((char*)args->request.url);
if (args->request.type == HTTP_DATA_JSON) {
json_decref((json_t*) args->request.root);
} else {
free(args->request.body);
}
free(args);
return 0;
}, NULL, args);
if (thread == NULL) {
log_error("Unable to create thread!");
callback(NULL);
} else {
SDL_DetachThread(thread);
}
}
void http_request_dispose(http_response_t *response)
{
if (response->type == HTTP_DATA_JSON && response->root != NULL)
json_decref(response->root);
else if (response->type == HTTP_DATA_RAW && response->body != NULL)
free(response->body);
free(response);
}
const char *http_get_extension_from_url(const char *url, const char *fallback)
{
const char *extension = strrchr(url, '.');
// Assume a save file by default if no valid extension can be determined
if (extension == NULL || strchr(extension, '/') != NULL) {
return fallback;
} else {
return extension;
}
}
bool http_download_park(const char *url, char tmpPath[L_tmpnam + 10])
{
// Download park to buffer in memory
http_request_t request;
request.url = url;
request.method = "GET";
request.type = HTTP_DATA_NONE;
http_response_t *response = http_request(&request);
if (response == NULL || response->status_code != 200) {
Console::Error::WriteLine("Failed to download '%s'", request.url);
if (response != NULL) {
http_request_dispose(response);
}
if (newCapacity != writeBuffer->capacity) {
writeBuffer->ptr = (char*)realloc(writeBuffer->ptr, newCapacity);
writeBuffer->capacity = newCapacity;
}
memcpy(writeBuffer->ptr + writeBuffer->length, ptr, newBytesLength);
writeBuffer->length = newLength;
}
return newBytesLength;
}
http_json_response *http_request_json(const http_json_request *request)
{
CURL *curl;
CURLcode curlResult;
http_json_response *response;
read_buffer readBuffer = { 0 };
write_buffer writeBuffer;
curl = curl_easy_init();
if (curl == NULL)
return NULL;
if (request->body != NULL) {
readBuffer.ptr = json_dumps(request->body, JSON_COMPACT);
readBuffer.length = strlen(readBuffer.ptr);
readBuffer.position = 0;
return false;
}
writeBuffer.ptr = NULL;
writeBuffer.length = 0;
writeBuffer.capacity = 0;
// Generate temporary filename that includes the original extension
if (tmpnam(tmpPath) == NULL) {
Console::Error::WriteLine("Failed to generate temporary filename for downloaded park '%s'", request.url);
http_request_dispose(response);
return false;
}
size_t remainingBytes = L_tmpnam + 10 - strlen(tmpPath);
curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Accept: " MIME_TYPE_APPLICATION_JSON);
if (request->body != NULL) {
headers = curl_slist_append(headers, "Content-Type: " MIME_TYPE_APPLICATION_JSON);
const char *ext = http_get_extension_from_url(request.url, ".sv6");
strncat(tmpPath, ext, remainingBytes);
char contentLengthHeaderValue[64];
snprintf(contentLengthHeaderValue, sizeof(contentLengthHeaderValue), "Content-Length: %zu", readBuffer.length);
headers = curl_slist_append(headers, contentLengthHeaderValue);
// Store park in temporary file and load it (discard ending NUL in response body)
FILE* tmpFile = fopen(tmpPath, "wb");
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, readBuffer.ptr);
if (tmpFile == NULL) {
Console::Error::WriteLine("Failed to write downloaded park '%s' to temporary file", request.url);
http_request_dispose(response);
return false;
}
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, request->method);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, true);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);
curl_easy_setopt(curl, CURLOPT_USERAGENT, OPENRCT2_USER_AGENT);
curl_easy_setopt(curl, CURLOPT_URL, request->url);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &writeBuffer);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_request_write_func);
fwrite(response->body, 1, response->size - 1, tmpFile);
fclose(tmpFile);
curlResult = curl_easy_perform(curl);
http_request_dispose(response);
if (request->body != NULL) {
free(readBuffer.ptr);
}
if (curlResult != CURLE_OK) {
log_error("HTTP request failed: %s.", curl_easy_strerror(curlResult));
if (writeBuffer.ptr != NULL)
free(writeBuffer.ptr);
return NULL;
}
long httpStatusCode;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpStatusCode);
curl_easy_cleanup(curl);
// Null terminate the response buffer
writeBuffer.length++;
writeBuffer.ptr = (char*)realloc(writeBuffer.ptr, writeBuffer.length);
writeBuffer.capacity = writeBuffer.length;
writeBuffer.ptr[writeBuffer.length - 1] = 0;
response = NULL;
// Parse as JSON
json_t *root;
json_error_t error;
root = json_loads(writeBuffer.ptr, 0, &error);
if (root != NULL) {
response = (http_json_response*)malloc(sizeof(http_json_response));
response->tag = request->tag;
response->status_code = (int)httpStatusCode;
response->root = root;
}
free(writeBuffer.ptr);
return response;
}
void http_request_json_async(const http_json_request *request, void (*callback)(http_json_response*))
{
struct TempThreadArgs {
http_json_request request;
void (*callback)(http_json_response*);
};
TempThreadArgs *args = (TempThreadArgs*)malloc(sizeof(TempThreadArgs));
args->request.url = _strdup(request->url);
args->request.method = request->method;
args->request.body = json_deep_copy(request->body);
args->request.tag = request->tag;
args->callback = callback;
SDL_Thread *thread = SDL_CreateThread([](void *ptr) -> int {
TempThreadArgs *args = (TempThreadArgs*)ptr;
http_json_response *response = http_request_json(&args->request);
args->callback(response);
free((char*)args->request.url);
json_decref((json_t*)args->request.body);
free(args);
return 0;
}, NULL, args);
if (thread == NULL) {
log_error("Unable to create thread!");
callback(NULL);
} else {
SDL_DetachThread(thread);
}
}
void http_request_json_dispose(http_json_response *response)
{
if (response->root != NULL)
json_decref(response->root);
free(response);
return true;
}
#endif

View File

@ -21,27 +21,48 @@
#include <jansson.h>
#include "../common.h"
typedef struct http_json_request {
typedef enum http_data_type_T {
HTTP_DATA_NONE,
HTTP_DATA_RAW,
HTTP_DATA_JSON
} http_data_type;
typedef struct http_request_t {
void *tag;
const char *method;
const char *url;
const json_t *body;
} http_json_request;
http_data_type type;
size_t size;
union {
const json_t *root;
char* body;
};
} http_request_t;
typedef struct http_json_response {
typedef struct http_response_t {
void *tag;
int status_code;
json_t *root;
} http_json_response;
http_data_type type;
size_t size;
union {
json_t *root;
char* body;
};
} http_response_t;
#define HTTP_METHOD_GET "GET"
#define HTTP_METHOD_POST "POST"
#define HTTP_METHOD_PUT "PUT"
#define HTTP_METHOD_DELETE "DELETE"
http_json_response *http_request_json(const http_json_request *request);
void http_request_json_async(const http_json_request *request, void (*callback)(http_json_response*));
void http_request_json_dispose(http_json_response *response);
http_response_t *http_request(const http_request_t *request);
void http_request_async(const http_request_t *request, void (*callback)(http_response_t*));
void http_request_dispose(http_response_t *response);
const char *http_get_extension_from_url(const char *url, const char *fallback);
// Padding for extension that is appended to temporary file name
bool http_download_park(const char *url, char tmpPath[L_tmpnam + 10]);
#endif // DISABLE_HTTP
// These callbacks are defined anyway, but are dummy if HTTP is disabled

View File

@ -106,11 +106,11 @@ namespace Twitch
constexpr uint32 PulseTime = 10 * 1000;
constexpr const char * TwitchExtendedBaseUrl = "http://openrct.ursalabs.co/api/1/";
static int _twitchState = TWITCH_STATE_LEFT;
static bool _twitchIdle = true;
static uint32 _twitchLastPulseTick = 0;
static int _twitchLastPulseOperation = 1;
static http_json_response * _twitchJsonResponse;
static int _twitchState = TWITCH_STATE_LEFT;
static bool _twitchIdle = true;
static uint32 _twitchLastPulseTick = 0;
static int _twitchLastPulseOperation = 1;
static http_response_t * _twitchJsonResponse;
static void Join();
static void Leave();
@ -199,11 +199,12 @@ namespace Twitch
_twitchState = TWITCH_STATE_JOINING;
_twitchIdle = false;
http_json_request request;
http_request_t request;
request.url = url;
request.method = HTTP_METHOD_GET;
request.body = nullptr;
http_request_json_async(&request, [](http_json_response *jsonResponse) -> void
request.type = HTTP_DATA_JSON;
http_request_async(&request, [](http_response_t *jsonResponse) -> void
{
if (jsonResponse == nullptr)
{
@ -222,7 +223,7 @@ namespace Twitch
_twitchState = TWITCH_STATE_LEFT;
}
http_request_json_dispose(jsonResponse);
http_request_dispose(jsonResponse);
_twitchLastPulseTick = 0;
console_writeline("Connected to twitch channel.");
@ -238,7 +239,7 @@ namespace Twitch
{
if (_twitchJsonResponse != nullptr)
{
http_request_json_dispose(_twitchJsonResponse);
http_request_dispose(_twitchJsonResponse);
_twitchJsonResponse = nullptr;
}
@ -275,11 +276,12 @@ namespace Twitch
_twitchState = TWITCH_STATE_WAITING;
_twitchIdle = false;
http_json_request request;
http_request_t request;
request.url = url;
request.method = HTTP_METHOD_GET;
request.body = NULL;
http_request_json_async(&request, [](http_json_response * jsonResponse) -> void
request.type = HTTP_DATA_JSON;
http_request_async(&request, [](http_response_t * jsonResponse) -> void
{
if (jsonResponse == nullptr)
{
@ -305,11 +307,12 @@ namespace Twitch
_twitchState = TWITCH_STATE_WAITING;
_twitchIdle = false;
http_json_request request;
http_request_t request;
request.url = url;
request.method = HTTP_METHOD_GET;
request.body = nullptr;
http_request_json_async(&request, [](http_json_response * jsonResponse) -> void
request.type = HTTP_DATA_JSON;
http_request_async(&request, [](http_response_t * jsonResponse) -> void
{
if (jsonResponse == nullptr)
{
@ -326,7 +329,7 @@ namespace Twitch
static void ParseFollowers()
{
http_json_response *jsonResponse = _twitchJsonResponse;
http_response_t *jsonResponse = _twitchJsonResponse;
if (json_is_array(jsonResponse->root))
{
std::vector<AudienceMember> members;
@ -349,7 +352,7 @@ namespace Twitch
ManageGuestNames(members);
}
http_request_json_dispose(_twitchJsonResponse);
http_request_dispose(_twitchJsonResponse);
_twitchJsonResponse = NULL;
_twitchState = TWITCH_STATE_JOINED;
@ -358,7 +361,7 @@ namespace Twitch
static void ParseMessages()
{
http_json_response * jsonResponse = _twitchJsonResponse;
http_response_t * jsonResponse = _twitchJsonResponse;
if (json_is_array(jsonResponse->root))
{
size_t messageCount = json_array_size(jsonResponse->root);
@ -375,7 +378,7 @@ namespace Twitch
}
}
http_request_json_dispose(_twitchJsonResponse);
http_request_dispose(_twitchJsonResponse);
_twitchJsonResponse = nullptr;
_twitchState = TWITCH_STATE_JOINED;
}

View File

@ -141,7 +141,7 @@ static void sort_servers();
static void join_server(char *address);
static void fetch_servers();
#ifndef DISABLE_HTTP
static void fetch_servers_callback(http_json_response* response);
static void fetch_servers_callback(http_response_t* response);
#endif
void window_server_list_open()
@ -775,16 +775,17 @@ static void fetch_servers()
sort_servers();
SDL_UnlockMutex(_mutex);
http_json_request request;
http_request_t request;
request.url = masterServerUrl;
request.method = HTTP_METHOD_GET;
request.body = NULL;
http_request_json_async(&request, fetch_servers_callback);
request.type = HTTP_DATA_JSON;
http_request_async(&request, fetch_servers_callback);
#endif
}
#ifndef DISABLE_HTTP
static void fetch_servers_callback(http_json_response* response)
static void fetch_servers_callback(http_response_t* response)
{
if (response == NULL) {
log_warning("Unable to connect to master server");
@ -793,21 +794,21 @@ static void fetch_servers_callback(http_json_response* response)
json_t *jsonStatus = json_object_get(response->root, "status");
if (!json_is_number(jsonStatus)) {
http_request_json_dispose(response);
http_request_dispose(response);
log_warning("Invalid response from master server");
return;
}
int status = (int)json_integer_value(jsonStatus);
if (status != 200) {
http_request_json_dispose(response);
http_request_dispose(response);
log_warning("Master server failed to return servers");
return;
}
json_t *jsonServers = json_object_get(response->root, "servers");
if (!json_is_array(jsonServers)) {
http_request_json_dispose(response);
http_request_dispose(response);
log_warning("Invalid response from master server");
return;
}
@ -852,7 +853,7 @@ static void fetch_servers_callback(http_json_response* response)
newserver->maxplayers = (uint8)json_integer_value(maxPlayers);
SDL_UnlockMutex(_mutex);
}
http_request_json_dispose(response);
http_request_dispose(response);
sort_servers();
_numPlayersOnline = get_total_player_count();