From 133685ea37c33a2037af918eced17d2473d1757f Mon Sep 17 00:00:00 2001 From: Dominic Masters Date: Wed, 15 Apr 2026 15:11:44 -0500 Subject: [PATCH] Linux HTTP implementation --- cmake/targets/linux.cmake | 5 +- src/dusk/CMakeLists.txt | 6 +- src/dusk/engine/engine.c | 30 +++ src/dusk/network/CMakeLists.txt | 10 + src/dusk/network/networkhttprequest.c | 32 +++ src/dusk/network/networkhttprequest.h | 62 ++++++ src/dusk/network/networkmanager.c | 28 +++ src/dusk/network/networkmanager.h | 37 ++++ src/dusklinux/CMakeLists.txt | 3 +- src/dusklinux/network/CMakeLists.txt | 9 + src/dusklinux/network/networklinux.c | 272 ++++++++++++++++++++++++ src/dusklinux/network/networklinux.h | 98 +++++++++ src/dusklinux/network/networkplatform.h | 14 ++ 13 files changed, 600 insertions(+), 6 deletions(-) create mode 100644 src/dusk/network/CMakeLists.txt create mode 100644 src/dusk/network/networkhttprequest.c create mode 100644 src/dusk/network/networkhttprequest.h create mode 100644 src/dusk/network/networkmanager.c create mode 100644 src/dusk/network/networkmanager.h create mode 100644 src/dusklinux/network/CMakeLists.txt create mode 100644 src/dusklinux/network/networklinux.c create mode 100644 src/dusklinux/network/networklinux.h create mode 100644 src/dusklinux/network/networkplatform.h diff --git a/cmake/targets/linux.cmake b/cmake/targets/linux.cmake index 40723585..6b7ee984 100644 --- a/cmake/targets/linux.cmake +++ b/cmake/targets/linux.cmake @@ -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) @@ -16,12 +17,13 @@ else() endif() # Link required libraries. -target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PUBLIC +target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PUBLIC SDL2 pthread 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 ) \ No newline at end of file diff --git a/src/dusk/CMakeLists.txt b/src/dusk/CMakeLists.txt index bffbe485..2deab40f 100644 --- a/src/dusk/CMakeLists.txt +++ b/src/dusk/CMakeLists.txt @@ -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() \ No newline at end of file +add_subdirectory(thread) \ No newline at end of file diff --git a/src/dusk/engine/engine.c b/src/dusk/engine/engine.c index 181939ed..1b05b03a 100644 --- a/src/dusk/engine/engine.c +++ b/src/dusk/engine/engine.c @@ -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(); diff --git a/src/dusk/network/CMakeLists.txt b/src/dusk/network/CMakeLists.txt new file mode 100644 index 00000000..a5823f7a --- /dev/null +++ b/src/dusk/network/CMakeLists.txt @@ -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 +) diff --git a/src/dusk/network/networkhttprequest.c b/src/dusk/network/networkhttprequest.c new file mode 100644 index 00000000..c4017f52 --- /dev/null +++ b/src/dusk/network/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 + ); +} diff --git a/src/dusk/network/networkhttprequest.h b/src/dusk/network/networkhttprequest.h new file mode 100644 index 00000000..953a81f7 --- /dev/null +++ b/src/dusk/network/networkhttprequest.h @@ -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 +); \ No newline at end of file diff --git a/src/dusk/network/networkmanager.c b/src/dusk/network/networkmanager.c new file mode 100644 index 00000000..3dad0bb0 --- /dev/null +++ b/src/dusk/network/networkmanager.c @@ -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(); +} diff --git a/src/dusk/network/networkmanager.h b/src/dusk/network/networkmanager.h new file mode 100644 index 00000000..419950c1 --- /dev/null +++ b/src/dusk/network/networkmanager.h @@ -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(); \ No newline at end of file diff --git a/src/dusklinux/CMakeLists.txt b/src/dusklinux/CMakeLists.txt index 4d728f25..cac82149 100644 --- a/src/dusklinux/CMakeLists.txt +++ b/src/dusklinux/CMakeLists.txt @@ -12,4 +12,5 @@ target_include_directories(${DUSK_LIBRARY_TARGET_NAME} # Subdirs add_subdirectory(asset) add_subdirectory(log) -add_subdirectory(input) \ No newline at end of file +add_subdirectory(input) +add_subdirectory(network) \ No newline at end of file diff --git a/src/dusklinux/network/CMakeLists.txt b/src/dusklinux/network/CMakeLists.txt new file mode 100644 index 00000000..c1322dc3 --- /dev/null +++ b/src/dusklinux/network/CMakeLists.txt @@ -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 +) diff --git a/src/dusklinux/network/networklinux.c b/src/dusklinux/network/networklinux.c new file mode 100644 index 00000000..21c17edb --- /dev/null +++ b/src/dusklinux/network/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 + +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); +} diff --git a/src/dusklinux/network/networklinux.h b/src/dusklinux/network/networklinux.h new file mode 100644 index 00000000..cea4fe9e --- /dev/null +++ b/src/dusklinux/network/networklinux.h @@ -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 +); diff --git a/src/dusklinux/network/networkplatform.h b/src/dusklinux/network/networkplatform.h new file mode 100644 index 00000000..15645b10 --- /dev/null +++ b/src/dusklinux/network/networkplatform.h @@ -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 \ No newline at end of file