1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2025-12-23 15:52:55 +01:00

Merge branch 'master-server-improvements' into develop

This commit is contained in:
IntelOrca
2015-11-08 23:50:59 +00:00
5 changed files with 133 additions and 25 deletions

View File

@@ -16,6 +16,14 @@ void http_dispose() { }
#define WIN32_LEAN_AND_MEAN
#include <curl/curl.h>
#define MIME_TYPE_APPLICATION_JSON "application/json"
typedef struct {
char *ptr;
int length;
int position;
} read_buffer;
typedef struct {
char *ptr;
int length;
@@ -32,6 +40,22 @@ void http_dispose()
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;
size_t remainingBytes = readBuffer->length - readBuffer->position;
size_t readBytes = size * nmemb;
if (readBytes > remainingBytes) {
readBytes = remainingBytes;
}
memcpy(ptr, readBuffer->ptr + readBuffer->position, 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;
@@ -54,33 +78,55 @@ static size_t http_request_write_func(void *ptr, size_t size, size_t nmemb, void
return newBytesLength;
}
http_json_response *http_request_json(const char *url)
http_json_response *http_request_json(const http_json_request *request)
{
CURL *curl;
CURLcode curlResult;
http_json_response *response;
read_buffer readBuffer;
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;
}
writeBuffer.ptr = NULL;
writeBuffer.length = 0;
writeBuffer.capacity = 0;
curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Accept: application/json");
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);
char contentLengthHeaderValue[64];
snprintf(contentLengthHeaderValue, sizeof(contentLengthHeaderValue), "Content-Length: %d", 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_CAINFO, "curl-ca-bundle.crt");
curl_easy_setopt(curl, CURLOPT_URL, url);
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->body != NULL) {
free(readBuffer.ptr);
}
if (curlResult != CURLE_OK) {
log_error("HTTP request failed: %s.", curl_easy_strerror(curlResult));
if (writeBuffer.ptr != NULL)
@@ -115,24 +161,27 @@ http_json_response *http_request_json(const char *url)
return response;
}
void http_request_json_async(const char *url, void (*callback)(http_json_response*))
void http_request_json_async(const http_json_request *request, void (*callback)(http_json_response*))
{
struct TempThreadArgs {
char *url;
http_json_request request;
void (*callback)(http_json_response*);
};
TempThreadArgs *args = (TempThreadArgs*)malloc(sizeof(TempThreadArgs));
args->url = _strdup(url);
args->request.url = _strdup(request->url);
args->request.method = request->method;
args->request.body = json_deep_copy(request->body);
args->callback = callback;
SDL_Thread *thread = SDL_CreateThread([](void *ptr) -> int {
TempThreadArgs *args = (TempThreadArgs*)ptr;
http_json_response *response = http_request_json(args->url);
http_json_response *response = http_request_json(&args->request);
args->callback(response);
free(args->url);
free((char*)args->request.url);
json_decref((json_t*)args->request.body);
free(args);
return 0;
}, NULL, args);

View File

@@ -5,13 +5,24 @@
#include <jansson.h>
#include "../common.h"
typedef struct {
const char *method;
const char *url;
const json_t *body;
} http_json_request;
typedef struct {
int status_code;
json_t *root;
} http_json_response;
http_json_response *http_request_json(const char *url);
void http_request_json_async(const char *url, void (*callback)(http_json_response*));
#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);
#endif // DISABLE_HTTP

View File

@@ -19,6 +19,7 @@
*****************************************************************************/
extern "C" {
#include "../openrct2.h"
#include "../platform/platform.h"
}
@@ -854,10 +855,16 @@ void Network::AdvertiseRegister()
last_advertise_time = SDL_GetTicks();
// Send the registration request
std::string url = GetMasterServerUrl()
+ std::string("?command=register&port=") + std::to_string(listening_port)
+ std::string("&key=") + advertise_key;
http_request_json_async(url.c_str(), [](http_json_response *response) -> void {
http_json_request request;
request.url = GetMasterServerUrl();
request.method = HTTP_METHOD_POST;
json_t *body = json_object();
json_object_set(body, "key", json_string(advertise_key.c_str()));
json_object_set(body, "port", json_integer(listening_port));
request.body = body;
http_request_json_async(&request, [](http_json_response *response) -> void {
if (response == NULL) {
log_warning("Unable to connect to master server");
return;
@@ -883,6 +890,8 @@ void Network::AdvertiseRegister()
}
http_request_json_dispose(response);
});
json_decref(body);
#endif
}
@@ -890,14 +899,31 @@ void Network::AdvertiseHeartbeat()
{
#ifndef DISABLE_HTTP
// Send the heartbeat request
std::string url = GetMasterServerUrl()
+ std::string("?command=heartbeat&token=") + advertise_token
+ std::string("&players=") + std::to_string(network_get_num_players());
http_json_request request;
request.url = GetMasterServerUrl();
request.method = HTTP_METHOD_PUT;
// TODO send status data (e.g. players) via JSON body
json_t *body = json_object();
json_object_set(body, "token", json_string(advertise_token.c_str()));
json_object_set(body, "dedicated", json_boolean(gOpenRCT2Headless));
json_object_set(body, "players", json_integer(network_get_num_players()));
json_t *gameInfo = json_object();
json_object_set(gameInfo, "mapSize", json_integer(RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE, uint8) - 2));
json_object_set(gameInfo, "day", json_integer(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_TICKS, uint16)));
json_object_set(gameInfo, "month", json_integer(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, uint16)));
json_object_set(gameInfo, "guests", json_integer(RCT2_GLOBAL(RCT2_ADDRESS_GUESTS_IN_PARK, uint16)));
json_object_set(gameInfo, "parkValue", json_integer(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PARK_VALUE, money32)));
if (!(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY)) {
money32 cash = DECRYPT_MONEY(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONEY_ENCRYPTED, money32));
json_object_set(gameInfo, "cash", json_integer(cash));
}
json_object_set(body, "gameInfo", gameInfo);
request.body = body;
gNetwork.last_heartbeat_time = SDL_GetTicks();
http_request_json_async(url.c_str(), [](http_json_response *response) -> void {
http_request_json_async(&request, [](http_json_response *response) -> void {
if (response == NULL) {
log_warning("Unable to connect to master server");
return;
@@ -915,6 +941,8 @@ void Network::AdvertiseHeartbeat()
}
http_request_json_dispose(response);
});
json_decref(body);
#endif
}
@@ -1064,7 +1092,7 @@ void Network::Server_Send_GAMEINFO(NetworkConnection& connection)
json_object_set(obj, "maxPlayers", json_integer(gConfigNetwork.maxplayers));
json_object_set(obj, "description", json_string(gConfigNetwork.server_description));
packet->WriteString(json_dumps(obj, 0));
json_object_clear(obj);
json_decref(obj);
#endif
connection.QueuePacket(std::move(packet));
}

View File

@@ -130,7 +130,12 @@ static void twitch_join()
_twitchState = TWITCH_STATE_JOINING;
_twitchIdle = false;
http_request_json_async(url, [](http_json_response *jsonResponse) -> void {
http_json_request request;
request.url = url;
request.method = HTTP_METHOD_GET;
request.body = NULL;
http_request_json_async(&request, [](http_json_response *jsonResponse) -> void {
if (jsonResponse == NULL) {
_twitchState = TWITCH_STATE_LEFT;
console_writeline("Unable to connect to twitch channel.");
@@ -191,7 +196,12 @@ static void twitch_get_followers()
_twitchState = TWITCH_STATE_WAITING;
_twitchIdle = false;
http_request_json_async(url, [](http_json_response *jsonResponse) -> void {
http_json_request request;
request.url = url;
request.method = HTTP_METHOD_GET;
request.body = NULL;
http_request_json_async(&request, [](http_json_response *jsonResponse) -> void {
if (jsonResponse == NULL) {
_twitchState = TWITCH_STATE_JOINED;
} else {
@@ -212,7 +222,12 @@ static void twitch_get_messages()
_twitchState = TWITCH_STATE_WAITING;
_twitchIdle = false;
http_request_json_async(url, [](http_json_response *jsonResponse) -> void {
http_json_request request;
request.url = url;
request.method = HTTP_METHOD_GET;
request.body = NULL;
http_request_json_async(&request, [](http_json_response *jsonResponse) -> void {
if (jsonResponse == NULL) {
_twitchState = TWITCH_STATE_JOINED;
} else {

View File

@@ -651,7 +651,12 @@ static void fetch_servers()
}
}
SDL_UnlockMutex(_mutex);
http_request_json_async(masterServerUrl, fetch_servers_callback);
http_json_request request;
request.url = masterServerUrl;
request.method = HTTP_METHOD_GET;
request.body = NULL;
http_request_json_async(&request, fetch_servers_callback);
#endif
}
@@ -721,7 +726,7 @@ static void fetch_servers_callback(http_json_response* response)
}
http_request_json_dispose(response);
rct_window* window = window_bring_to_front_by_class(WC_SERVER_LIST);
rct_window *window = window_find_by_class(WC_SERVER_LIST);
if (window != NULL) {
window_invalidate(window);
}