Linux HTTP implementation
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
# Find link platform-specific libraries
|
||||
find_package(SDL2 REQUIRED)
|
||||
find_package(OpenGL REQUIRED)
|
||||
find_package(CURL REQUIRED)
|
||||
|
||||
# Setup endianess at compile time to optimize.
|
||||
include(TestBigEndian)
|
||||
@@ -22,6 +23,7 @@ target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||
OpenGL::GL
|
||||
GL
|
||||
m
|
||||
CURL::libcurl
|
||||
)
|
||||
|
||||
# Define platform-specific macros.
|
||||
@@ -38,4 +40,5 @@ target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||
DUSK_INPUT_POINTER
|
||||
DUSK_INPUT_GAMEPAD
|
||||
DUSK_TIME_DYNAMIC
|
||||
THREAD_PTHREAD=1
|
||||
)
|
||||
@@ -74,8 +74,6 @@ add_subdirectory(scene)
|
||||
add_subdirectory(script)
|
||||
add_subdirectory(time)
|
||||
add_subdirectory(ui)
|
||||
add_subdirectory(network)
|
||||
add_subdirectory(util)
|
||||
|
||||
# if(DUSK_TARGET_SYSTEM STREQUAL "linux" OR DUSK_TARGET_SYSTEM STREQUAL "psp")
|
||||
# add_subdirectory(thread)
|
||||
# endif()
|
||||
add_subdirectory(thread)
|
||||
@@ -20,6 +20,9 @@
|
||||
#include "entity/component/physics/entityphysics.h"
|
||||
#include "game/game.h"
|
||||
#include "physics/physicsmanager.h"
|
||||
#include "network/networkmanager.h"
|
||||
#include "network/networkhttprequest.h"
|
||||
|
||||
#include "display/mesh/cube.h"
|
||||
#include "display/mesh/plane.h"
|
||||
|
||||
@@ -29,6 +32,22 @@ engine_t ENGINE;
|
||||
static entityid_t phBoxEnt;
|
||||
static componentid_t phBoxPhys;
|
||||
|
||||
/* ---- test network callbacks ---- */
|
||||
|
||||
static void onTestResponse(
|
||||
const uint16_t status,
|
||||
const char_t *body,
|
||||
const networkhttpheader_t *responseHeaders,
|
||||
const uint32_t responseHeaderCount,
|
||||
void *user
|
||||
) {
|
||||
printf("HTTP %d: %s\n", status, body);
|
||||
}
|
||||
|
||||
static void onTestError(errorret_t error, void *user) {
|
||||
printf("HTTP error: %s\n", error.state->message);
|
||||
}
|
||||
|
||||
errorret_t engineInit(const int32_t argc, const char_t **argv) {
|
||||
memoryZero(&ENGINE, sizeof(engine_t));
|
||||
ENGINE.running = true;
|
||||
@@ -46,8 +65,17 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) {
|
||||
errorChain(sceneInit());
|
||||
entityManagerInit();
|
||||
physicsManagerInit();
|
||||
errorChain(networkManagerInit());
|
||||
errorChain(gameInit());
|
||||
|
||||
networkHTTPRequest(
|
||||
"http://localhost:3000/test",
|
||||
NETWORK_HTTP_REQUEST_METHOD_GET,
|
||||
NULL, NULL, 0, NULL,
|
||||
onTestResponse,
|
||||
onTestError
|
||||
);
|
||||
|
||||
/* ---- Camera ---- */
|
||||
entityid_t cam = entityManagerAdd();
|
||||
componentid_t camPos = entityAddComponent(cam, COMPONENT_TYPE_POSITION);
|
||||
@@ -107,6 +135,7 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) {
|
||||
errorret_t engineUpdate(void) {
|
||||
timeUpdate();
|
||||
inputUpdate();
|
||||
errorChain(networkManagerUpdate());
|
||||
|
||||
uiUpdate();
|
||||
errorChain(sceneUpdate());
|
||||
@@ -134,6 +163,7 @@ void engineExit(void) {
|
||||
}
|
||||
|
||||
errorret_t engineDispose(void) {
|
||||
errorChain(networkManagerDispose());
|
||||
sceneDispose();
|
||||
errorChain(gameDispose());
|
||||
entityManagerDispose();
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
networkmanager.c
|
||||
networkhttprequest.c
|
||||
)
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "networkhttprequest.h"
|
||||
#include "assert/assert.h"
|
||||
#include "network/networkplatform.h"
|
||||
|
||||
void networkHTTPRequest(
|
||||
const char_t *url,
|
||||
const networkhttprequestmethod_t method,
|
||||
const char_t *bodyOrNull,
|
||||
const networkhttpheader_t *headers,
|
||||
const uint32_t headerCount,
|
||||
void *user,
|
||||
networkhttpcallback_t callback,
|
||||
networkhttperrorcallback_t errorCallback
|
||||
) {
|
||||
assertStrLenMin(url, 1, "URL must be non-empty");
|
||||
assertNotNull(callback, "Callback must be non-NULL");
|
||||
assertNotNull(errorCallback, "Error callback must be non-NULL");
|
||||
assertTrue(headerCount == 0 || headers != NULL, "Headers must not be NULL when headerCount > 0");
|
||||
|
||||
uint32_t count = (headers == NULL) ? 0 : headerCount;
|
||||
|
||||
networkPlatformHTTPRequest(
|
||||
url, method, bodyOrNull, headers, count, user, callback, errorCallback
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "error/error.h"
|
||||
|
||||
typedef enum {
|
||||
NETWORK_HTTP_REQUEST_METHOD_GET,
|
||||
NETWORK_HTTP_REQUEST_METHOD_POST,
|
||||
NETWORK_HTTP_REQUEST_METHOD_PUT,
|
||||
NETWORK_HTTP_REQUEST_METHOD_DELETE,
|
||||
NETWORK_HTTP_REQUEST_METHOD_HEAD,
|
||||
NETWORK_HTTP_REQUEST_METHOD_OPTIONS,
|
||||
} networkhttprequestmethod_t;
|
||||
|
||||
typedef struct {
|
||||
const char_t *key;
|
||||
const char_t *value;
|
||||
} networkhttpheader_t;
|
||||
|
||||
typedef void (*networkhttpcallback_t)(
|
||||
const uint16_t status,
|
||||
const char_t *body,
|
||||
const networkhttpheader_t *responseHeaders,
|
||||
const uint32_t responseHeaderCount,
|
||||
void *user
|
||||
);
|
||||
|
||||
typedef void (*networkhttperrorcallback_t)(
|
||||
errorret_t error,
|
||||
void *user
|
||||
);
|
||||
|
||||
/**
|
||||
* Makes a HTTP Request. The request itself is asynchronous but the callback
|
||||
* will be invoked on the main thread when next available.
|
||||
*
|
||||
* @param url URL to request.
|
||||
* @param method Method to use for the request.
|
||||
* @param bodyOrNull If POST or PUT, custom body string, can be NULL.
|
||||
* @param headers Array of key-value headers.
|
||||
* @param headerCount Count of headers, can be anything if headers is NULL.
|
||||
* @param user Callback pointer received to the callback.
|
||||
* @param callback The callback to invoke when the request completes.
|
||||
* @param errorCallback The callback to invoke if the request fails.
|
||||
* Note, this doesn't count Non-200 status codes, just
|
||||
* network errors.
|
||||
*/
|
||||
void networkHTTPRequest(
|
||||
const char_t *url,
|
||||
const networkhttprequestmethod_t method,
|
||||
const char_t *bodyOrNull,
|
||||
const networkhttpheader_t *headers,
|
||||
const uint32_t headerCount,
|
||||
void *user,
|
||||
networkhttpcallback_t callback,
|
||||
networkhttperrorcallback_t errorCallback
|
||||
);
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "networkmanager.h"
|
||||
#include "util/memory.h"
|
||||
#include "network/networkplatform.h"
|
||||
|
||||
networkmanager_t NETWORK_MANAGER;
|
||||
|
||||
errorret_t networkManagerInit() {
|
||||
memoryZero(&NETWORK_MANAGER, sizeof(networkmanager_t));
|
||||
errorChain(networkPlatformInit());
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t networkManagerUpdate() {
|
||||
errorChain(networkPlatformUpdate());
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t networkManagerDispose() {
|
||||
errorChain(networkPlatformDispose());
|
||||
errorOk();
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "error/error.h"
|
||||
|
||||
typedef struct {
|
||||
void *nothing;
|
||||
} networkmanager_t;
|
||||
|
||||
extern networkmanager_t NETWORK_MANAGER;
|
||||
|
||||
/**
|
||||
* Initializes the network manager. This will NOT connect to the network.
|
||||
*
|
||||
* @return An error code indicating success or failure.
|
||||
*/
|
||||
errorret_t networkManagerInit();
|
||||
|
||||
/**
|
||||
* Updates the network manager, dispatching any completed async request
|
||||
* callbacks on the main thread.
|
||||
*
|
||||
* @return An error code indicating success or failure.
|
||||
*/
|
||||
errorret_t networkManagerUpdate();
|
||||
|
||||
/**
|
||||
* Disposes of the network manager. This will NOT disconnect from the network.
|
||||
*
|
||||
* @return An error code indicating success or failure.
|
||||
*/
|
||||
errorret_t networkManagerDispose();
|
||||
@@ -13,3 +13,4 @@ target_include_directories(${DUSK_LIBRARY_TARGET_NAME}
|
||||
add_subdirectory(asset)
|
||||
add_subdirectory(log)
|
||||
add_subdirectory(input)
|
||||
add_subdirectory(network)
|
||||
@@ -0,0 +1,9 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
networklinux.c
|
||||
)
|
||||
@@ -0,0 +1,272 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "networklinux.h"
|
||||
#include "util/memory.h"
|
||||
#include "util/string.h"
|
||||
#include "assert/assert.h"
|
||||
#include <curl/curl.h>
|
||||
|
||||
static networklinux_t NETWORK_LINUX;
|
||||
|
||||
static size_t networkLinuxCurlWrite(
|
||||
char *ptr,
|
||||
size_t size,
|
||||
size_t nmemb,
|
||||
void *userdata
|
||||
) {
|
||||
assertNotNull(ptr, "curl write ptr must not be NULL");
|
||||
assertNotNull(userdata, "curl write userdata must not be NULL");
|
||||
networkhttppendingitem_t *item = (networkhttppendingitem_t *)userdata;
|
||||
size_t incoming = size * nmemb;
|
||||
size_t written = strlen(item->responseBody);
|
||||
size_t space = NETWORK_HTTP_RESPONSE_MAX - 1 - written;
|
||||
|
||||
if(incoming > space) incoming = space;
|
||||
if(incoming > 0) {
|
||||
memcpy(item->responseBody + written, ptr, incoming);
|
||||
item->responseBody[written + incoming] = '\0';
|
||||
}
|
||||
|
||||
/* Return the original byte count — curl treats anything else as an error. */
|
||||
return size * nmemb;
|
||||
}
|
||||
|
||||
static void networkLinuxHTTPThread(thread_t *thread) {
|
||||
assertNotNull(thread, "Thread must not be NULL");
|
||||
assertNotNull(thread->data, "Thread data must not be NULL");
|
||||
networkhttppendingitem_t *item = (networkhttppendingitem_t *)thread->data;
|
||||
|
||||
CURL *curl = curl_easy_init();
|
||||
if(!curl) {
|
||||
stringCopy(
|
||||
item->errorMessage, "curl_easy_init failed", NETWORK_ERROR_MESSAGE_MAX - 1
|
||||
);
|
||||
item->isError = true;
|
||||
goto done;
|
||||
}
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_URL, item->url);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, networkLinuxCurlWrite);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, item);
|
||||
|
||||
switch(item->method) {
|
||||
case NETWORK_HTTP_REQUEST_METHOD_POST:
|
||||
curl_easy_setopt(curl, CURLOPT_POST, 1L);
|
||||
curl_easy_setopt(
|
||||
curl, CURLOPT_POSTFIELDS, item->hasBody ? item->body : ""
|
||||
);
|
||||
curl_easy_setopt(
|
||||
curl, CURLOPT_POSTFIELDSIZE,
|
||||
(long)(item->hasBody ? strlen(item->body) : 0)
|
||||
);
|
||||
break;
|
||||
|
||||
case NETWORK_HTTP_REQUEST_METHOD_PUT:
|
||||
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
|
||||
if(item->hasBody) {
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, item->body);
|
||||
curl_easy_setopt(
|
||||
curl, CURLOPT_POSTFIELDSIZE, (long)strlen(item->body)
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case NETWORK_HTTP_REQUEST_METHOD_DELETE:
|
||||
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
|
||||
break;
|
||||
|
||||
case NETWORK_HTTP_REQUEST_METHOD_HEAD:
|
||||
curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
|
||||
break;
|
||||
|
||||
case NETWORK_HTTP_REQUEST_METHOD_OPTIONS:
|
||||
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "OPTIONS");
|
||||
break;
|
||||
|
||||
case NETWORK_HTTP_REQUEST_METHOD_GET:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Build header list */
|
||||
struct curl_slist *curlHeaders = NULL;
|
||||
if(item->headerCount > 0) {
|
||||
char_t line[NETWORK_HTTP_HEADER_KEY_MAX + NETWORK_HTTP_HEADER_VAL_MAX + 3];
|
||||
for(uint32_t i = 0; i < item->headerCount; i++) {
|
||||
snprintf(
|
||||
line, sizeof(line), "%s: %s", item->headerKeys[i], item->headerVals[i]
|
||||
);
|
||||
curlHeaders = curl_slist_append(curlHeaders, line);
|
||||
}
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, curlHeaders);
|
||||
}
|
||||
|
||||
CURLcode res = curl_easy_perform(curl);
|
||||
|
||||
if(res != CURLE_OK) {
|
||||
stringCopy(
|
||||
item->errorMessage, curl_easy_strerror(res), NETWORK_ERROR_MESSAGE_MAX - 1
|
||||
);
|
||||
item->isError = true;
|
||||
} else {
|
||||
long code = 0;
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code);
|
||||
item->status = (uint16_t)code;
|
||||
item->isError = false;
|
||||
}
|
||||
|
||||
if(curlHeaders) curl_slist_free_all(curlHeaders);
|
||||
curl_easy_cleanup(curl);
|
||||
|
||||
done:
|
||||
threadMutexLock(&NETWORK_LINUX.resultsMutex);
|
||||
item->resultReady = true;
|
||||
threadMutexUnlock(&NETWORK_LINUX.resultsMutex);
|
||||
}
|
||||
|
||||
errorret_t networkLinuxInit() {
|
||||
memoryZero(&NETWORK_LINUX, sizeof(networklinux_t));
|
||||
threadMutexInit(&NETWORK_LINUX.resultsMutex);
|
||||
|
||||
CURLcode res = curl_global_init(CURL_GLOBAL_ALL);
|
||||
if(res != CURLE_OK) {
|
||||
errorThrow("curl_global_init failed: %s", curl_easy_strerror(res));
|
||||
}
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t networkLinuxUpdate() {
|
||||
for(int32_t i = 0; i < NETWORK_HTTP_PENDING_MAX; i++) {
|
||||
/* Check under lock whether this slot has a result waiting. */
|
||||
threadMutexLock(&NETWORK_LINUX.resultsMutex);
|
||||
|
||||
networkhttppendingitem_t *item = &NETWORK_LINUX.requests[i];
|
||||
if(!item->used || !item->resultReady) {
|
||||
threadMutexUnlock(&NETWORK_LINUX.resultsMutex);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Snapshot the small values we need after we drop the lock. */
|
||||
bool_t isError = item->isError;
|
||||
uint16_t status = item->status;
|
||||
networkhttpcallback_t cb = item->callback;
|
||||
networkhttperrorcallback_t errCb = item->errorCallback;
|
||||
void *user = item->user;
|
||||
|
||||
/*
|
||||
* Keep pointers into item's string buffers — valid because item->used is
|
||||
* still true here and only this (main) thread clears it.
|
||||
*/
|
||||
const char_t *responseBody = item->responseBody;
|
||||
const char_t *errorMessage = item->errorMessage;
|
||||
|
||||
threadMutexUnlock(&NETWORK_LINUX.resultsMutex);
|
||||
|
||||
/* Fire the callback without holding the lock. */
|
||||
if(isError) {
|
||||
errorstate_t errState;
|
||||
errState.code = ERROR_NOT_OK;
|
||||
errState.message = (char_t *)errorMessage;
|
||||
errState.lines = (char_t *)"";
|
||||
errorret_t err;
|
||||
err.code = ERROR_NOT_OK;
|
||||
err.state = &errState;
|
||||
errCb(err, user);
|
||||
} else {
|
||||
cb(status, responseBody, NULL, 0, user);
|
||||
}
|
||||
|
||||
/* Release the slot now that the callback has consumed it. */
|
||||
threadMutexLock(&NETWORK_LINUX.resultsMutex);
|
||||
item->used = false;
|
||||
item->resultReady = false;
|
||||
threadMutexUnlock(&NETWORK_LINUX.resultsMutex);
|
||||
}
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t networkLinuxDispose() {
|
||||
curl_global_cleanup();
|
||||
threadMutexDispose(&NETWORK_LINUX.resultsMutex);
|
||||
errorOk();
|
||||
}
|
||||
|
||||
void networkLinuxHTTPRequest(
|
||||
const char_t *url,
|
||||
const networkhttprequestmethod_t method,
|
||||
const char_t *bodyOrNull,
|
||||
const networkhttpheader_t *headers,
|
||||
const uint32_t headerCount,
|
||||
void *user,
|
||||
networkhttpcallback_t callback,
|
||||
networkhttperrorcallback_t errorCallback
|
||||
) {
|
||||
assertStrLenMin(url, 1, "URL must be non-empty");
|
||||
assertStrLenMax(url, NETWORK_HTTP_URL_MAX, "URL exceeds maximum length");
|
||||
assertNotNull(callback, "Callback must be non-NULL");
|
||||
assertNotNull(errorCallback, "Error callback must be non-NULL");
|
||||
assertTrue(headerCount == 0 || headers != NULL, "Headers must not be NULL when headerCount > 0");
|
||||
|
||||
/* Allocate a slot. */
|
||||
threadMutexLock(&NETWORK_LINUX.resultsMutex);
|
||||
|
||||
networkhttppendingitem_t *item = NULL;
|
||||
for(int32_t i = 0; i < NETWORK_HTTP_PENDING_MAX; i++) {
|
||||
if(!NETWORK_LINUX.requests[i].used) {
|
||||
item = &NETWORK_LINUX.requests[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!item) {
|
||||
threadMutexUnlock(&NETWORK_LINUX.resultsMutex);
|
||||
errorstate_t errState;
|
||||
errState.code = ERROR_NOT_OK;
|
||||
errState.message = (char_t *)"No free HTTP request slots";
|
||||
errState.lines = (char_t *)"";
|
||||
errorret_t err;
|
||||
err.code = ERROR_NOT_OK;
|
||||
err.state = &errState;
|
||||
errorCallback(err, user);
|
||||
return;
|
||||
}
|
||||
|
||||
memoryZero(item, sizeof(networkhttppendingitem_t));
|
||||
item->used = true;
|
||||
|
||||
threadMutexUnlock(&NETWORK_LINUX.resultsMutex);
|
||||
|
||||
/* Fill the slot (safe: only we have access while used=true, resultReady=false). */
|
||||
stringCopy(item->url, url, NETWORK_HTTP_URL_MAX - 1);
|
||||
item->method = method;
|
||||
|
||||
if(bodyOrNull != NULL) {
|
||||
assertStrLenMax(bodyOrNull, NETWORK_HTTP_BODY_MAX, "Body exceeds maximum length");
|
||||
stringCopy(item->body, bodyOrNull, NETWORK_HTTP_BODY_MAX - 1);
|
||||
item->hasBody = true;
|
||||
}
|
||||
|
||||
uint32_t hdrCount = headerCount;
|
||||
if(hdrCount > NETWORK_HTTP_HEADER_MAX) hdrCount = NETWORK_HTTP_HEADER_MAX;
|
||||
item->headerCount = hdrCount;
|
||||
for(uint32_t i = 0; i < hdrCount; i++) {
|
||||
assertStrLenMax(headers[i].key, NETWORK_HTTP_HEADER_KEY_MAX, "Header key exceeds maximum length");
|
||||
assertStrLenMax(headers[i].value, NETWORK_HTTP_HEADER_VAL_MAX, "Header value exceeds maximum length");
|
||||
stringCopy(item->headerKeys[i], headers[i].key, NETWORK_HTTP_HEADER_KEY_MAX - 1);
|
||||
stringCopy(item->headerVals[i], headers[i].value, NETWORK_HTTP_HEADER_VAL_MAX - 1);
|
||||
}
|
||||
|
||||
item->callback = callback;
|
||||
item->errorCallback = errorCallback;
|
||||
item->user = user;
|
||||
|
||||
/* Kick off the background thread. */
|
||||
threadInit(&item->thread, networkLinuxHTTPThread);
|
||||
item->thread.data = item;
|
||||
threadStartRequest(&item->thread);
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
#include "network/networkhttprequest.h"
|
||||
#include "thread/thread.h"
|
||||
|
||||
#define NETWORK_HTTP_PENDING_MAX 16
|
||||
#define NETWORK_HTTP_URL_MAX 512
|
||||
#define NETWORK_HTTP_BODY_MAX 8192
|
||||
#define NETWORK_HTTP_RESPONSE_MAX 65536
|
||||
#define NETWORK_HTTP_HEADER_MAX 16
|
||||
#define NETWORK_HTTP_HEADER_KEY_MAX 64
|
||||
#define NETWORK_HTTP_HEADER_VAL_MAX 256
|
||||
#define NETWORK_ERROR_MESSAGE_MAX 256
|
||||
|
||||
typedef struct {
|
||||
bool_t used;
|
||||
volatile bool_t resultReady;
|
||||
bool_t isError;
|
||||
|
||||
char_t url[NETWORK_HTTP_URL_MAX];
|
||||
networkhttprequestmethod_t method;
|
||||
char_t body[NETWORK_HTTP_BODY_MAX];
|
||||
bool_t hasBody;
|
||||
char_t headerKeys[NETWORK_HTTP_HEADER_MAX][NETWORK_HTTP_HEADER_KEY_MAX];
|
||||
char_t headerVals[NETWORK_HTTP_HEADER_MAX][NETWORK_HTTP_HEADER_VAL_MAX];
|
||||
uint32_t headerCount;
|
||||
|
||||
networkhttpcallback_t callback;
|
||||
networkhttperrorcallback_t errorCallback;
|
||||
void *user;
|
||||
|
||||
uint16_t status;
|
||||
char_t responseBody[NETWORK_HTTP_RESPONSE_MAX];
|
||||
char_t errorMessage[NETWORK_ERROR_MESSAGE_MAX];
|
||||
|
||||
thread_t thread;
|
||||
} networkhttppendingitem_t;
|
||||
|
||||
typedef struct {
|
||||
networkhttppendingitem_t requests[NETWORK_HTTP_PENDING_MAX];
|
||||
threadmutex_t resultsMutex;
|
||||
} networklinux_t;
|
||||
|
||||
/**
|
||||
* Initializes the network manager. Must be called before any other network
|
||||
* functions.
|
||||
*
|
||||
* @return Any error that occurs.
|
||||
*/
|
||||
errorret_t networkLinuxInit();
|
||||
|
||||
/**
|
||||
* Updates the network manager, called once per frame to handle completed
|
||||
* HTTP requests.
|
||||
*
|
||||
* @return Any error that occurs.
|
||||
*/
|
||||
errorret_t networkLinuxUpdate();
|
||||
|
||||
/**
|
||||
* Disposes the network manager.
|
||||
*
|
||||
* @return Any error that occurs.
|
||||
*/
|
||||
errorret_t networkLinuxDispose();
|
||||
|
||||
/**
|
||||
* Submits an asynchronous HTTP request. The callback will be invoked on the
|
||||
* main thread when next available.
|
||||
*
|
||||
* @param url URL to request.
|
||||
* @param method Method to use for the request.
|
||||
* @param bodyOrNull If POST or PUT, custom body string, can be NULL.
|
||||
* @param headers Array of key-value headers.
|
||||
* @param headerCount Count of headers, can be anything if headers is NULL.
|
||||
* @param user Callback pointer received to the callback.
|
||||
* @param callback The callback to invoke when the request completes.
|
||||
* @param errorCallback The callback to invoke if the request fails.
|
||||
* Note, this doesn't count Non-200 status codes, just
|
||||
* network errors.
|
||||
*/
|
||||
void networkLinuxHTTPRequest(
|
||||
const char_t *url,
|
||||
const networkhttprequestmethod_t method,
|
||||
const char_t *bodyOrNull,
|
||||
const networkhttpheader_t *headers,
|
||||
const uint32_t headerCount,
|
||||
void *user,
|
||||
networkhttpcallback_t callback,
|
||||
networkhttperrorcallback_t errorCallback
|
||||
);
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "networklinux.h"
|
||||
|
||||
#define networkPlatformInit networkLinuxInit
|
||||
#define networkPlatformUpdate networkLinuxUpdate
|
||||
#define networkPlatformDispose networkLinuxDispose
|
||||
#define networkPlatformHTTPRequest networkLinuxHTTPRequest
|
||||
Reference in New Issue
Block a user