Simplify, simplify, simplify. Kill code that was unloved and unused
This commit is contained in:
+108
-180
@@ -883,27 +883,122 @@ DN_API DN_OSThreadLane DN_OS_TCThreadLaneEquip(DN_OSThreadLane lane)
|
||||
return result;
|
||||
}
|
||||
|
||||
// NOTE: DN_OSHttp
|
||||
DN_API void DN_OS_HttpRequestWait(DN_OSHttpResponse *response)
|
||||
static DN_I32 DN_OS_AsyncThreadEntryPoint_(DN_OSThread *thread)
|
||||
{
|
||||
if (response && response->on_complete_semaphore.handle != 0)
|
||||
DN_OS_SemaphoreWait(&response->on_complete_semaphore, DN_OS_SEMAPHORE_INFINITE_TIMEOUT);
|
||||
DN_OS_ThreadSetNameFmt("%.*s", DN_Str8PrintFmt(thread->name));
|
||||
DN_OSAsyncCore *async = DN_Cast(DN_OSAsyncCore *) thread->user_context;
|
||||
DN_Ring *ring = &async->ring;
|
||||
for (;;) {
|
||||
DN_OS_SemaphoreWait(&async->worker_sem, UINT32_MAX);
|
||||
if (async->join_threads)
|
||||
break;
|
||||
|
||||
DN_OSAsyncTask task = {};
|
||||
for (DN_OS_MutexScope(&async->ring_mutex)) {
|
||||
if (DN_RingHasData(ring, sizeof(task)))
|
||||
DN_RingRead(ring, &task, sizeof(task));
|
||||
}
|
||||
|
||||
if (task.work.func) {
|
||||
DN_OS_ConditionVariableBroadcast(&async->ring_write_cv); // Resume any blocked ring write(s)
|
||||
|
||||
DN_OSAsyncWorkArgs args = {};
|
||||
args.input = task.work.input;
|
||||
args.thread = thread;
|
||||
|
||||
DN_AtomicAddU32(&async->busy_threads, 1);
|
||||
task.work.func(args);
|
||||
DN_AtomicSubU32(&async->busy_threads, 1);
|
||||
|
||||
if (task.completion_sem.handle != 0)
|
||||
DN_OS_SemaphoreIncrement(&task.completion_sem, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DN_API DN_OSHttpResponse DN_OS_HttpRequest(DN_Arena *arena, DN_Str8 host, DN_Str8 path, DN_OSHttpRequestSecure secure, DN_Str8 method, DN_Str8 body, DN_Str8 headers)
|
||||
DN_API void DN_OS_AsyncInit(DN_OSAsyncCore *async, char *base, DN_USize base_size, DN_OSThread *threads, DN_U32 threads_size)
|
||||
{
|
||||
// TODO(doyle): Revise the memory allocation and its lifetime
|
||||
DN_OSHttpResponse result = {};
|
||||
DN_TCScratch scratch = DN_TCScratchBeginArena(&arena, 1);
|
||||
result.scratch_arena = scratch.arena;
|
||||
DN_Assert(async);
|
||||
async->ring.size = base_size;
|
||||
async->ring.base = base;
|
||||
async->ring_mutex = DN_OS_MutexInit();
|
||||
async->ring_write_cv = DN_OS_ConditionVariableInit();
|
||||
async->worker_sem = DN_OS_SemaphoreInit(0);
|
||||
async->thread_count = threads_size;
|
||||
async->threads = threads;
|
||||
for (DN_ForIndexU(index, async->thread_count)) {
|
||||
DN_OSThread *thread = async->threads + index;
|
||||
DN_OS_ThreadInit(thread, DN_OS_AsyncThreadEntryPoint_, /*lane=*/ nullptr, DN_TCInitArgsDefault(), async);
|
||||
}
|
||||
}
|
||||
|
||||
DN_API void DN_OS_AsyncDeinit(DN_OSAsyncCore *async)
|
||||
{
|
||||
DN_Assert(async);
|
||||
DN_AtomicSetValue32(&async->join_threads, true);
|
||||
DN_OS_SemaphoreIncrement(&async->worker_sem, async->thread_count);
|
||||
for (DN_ForItSize(it, DN_OSThread, async->threads, async->thread_count))
|
||||
DN_OS_ThreadJoin(it.data, DN_TCDeinitArenas_Yes);
|
||||
}
|
||||
|
||||
static bool DN_OS_AsyncQueueTask_(DN_OSAsyncCore *async, DN_OSAsyncTask const *task, DN_U64 wait_time_ms) {
|
||||
DN_U64 end_time_ms = DN_OS_DateUnixTimeMs() + wait_time_ms;
|
||||
bool result = false;
|
||||
for (DN_OS_MutexScope(&async->ring_mutex)) {
|
||||
for (;;) {
|
||||
if (DN_RingHasSpace(&async->ring, sizeof(*task))) {
|
||||
DN_RingWriteStruct(&async->ring, task);
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
DN_OS_ConditionVariableWaitUntil(&async->ring_write_cv, &async->ring_mutex, end_time_ms);
|
||||
if (DN_OS_DateUnixTimeMs() >= end_time_ms)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result)
|
||||
DN_OS_SemaphoreIncrement(&async->worker_sem, 1); // Flag that a job is available
|
||||
|
||||
DN_OS_HttpRequestAsync(&result, arena, host, path, secure, method, body, headers);
|
||||
DN_OS_HttpRequestWait(&result);
|
||||
DN_TCScratchEnd(&scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
// NOTE: DN_OSPrint
|
||||
DN_API bool DN_OS_AsyncQueueWork(DN_OSAsyncCore *async, DN_OSAsyncWorkFunc *func, void *input, DN_U64 wait_time_ms)
|
||||
{
|
||||
DN_OSAsyncTask task = {};
|
||||
task.work.func = func;
|
||||
task.work.input = input;
|
||||
bool result = DN_OS_AsyncQueueTask_(async, &task, wait_time_ms);
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_API DN_OSAsyncTask DN_OS_AsyncQueueTask(DN_OSAsyncCore *async, DN_OSAsyncWorkFunc *func, void *input, DN_U64 wait_time_ms)
|
||||
{
|
||||
DN_OSAsyncTask result = {};
|
||||
result.work.func = func;
|
||||
result.work.input = input;
|
||||
result.completion_sem = DN_OS_SemaphoreInit(0);
|
||||
result.queued = DN_OS_AsyncQueueTask_(async, &result, wait_time_ms);
|
||||
if (!result.queued)
|
||||
DN_OS_SemaphoreDeinit(&result.completion_sem);
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_API bool DN_OS_AsyncWaitTask(DN_OSAsyncTask *task, DN_U32 timeout_ms)
|
||||
{
|
||||
bool result = true;
|
||||
if (!task->queued)
|
||||
return result;
|
||||
|
||||
DN_OSSemaphoreWaitResult wait = DN_OS_SemaphoreWait(&task->completion_sem, timeout_ms);
|
||||
result = wait == DN_OSSemaphoreWaitResult_Success;
|
||||
if (result)
|
||||
DN_OS_SemaphoreDeinit(&task->completion_sem);
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_API DN_LogStyle DN_OS_PrintStyleColour(uint8_t r, uint8_t g, uint8_t b, DN_LogBold bold)
|
||||
{
|
||||
DN_LogStyle result = {};
|
||||
@@ -1077,173 +1172,6 @@ DN_API void DN_OS_PrintLnFVStyle(DN_OSPrintDest dest, DN_LogStyle style, DN_FMT_
|
||||
DN_OS_Print(dest, DN_Str8Lit("\n"));
|
||||
}
|
||||
|
||||
// NOTE: DN_VArray
|
||||
template <typename T>
|
||||
DN_VArray<T> DN_OS_VArrayInitByteSize(DN_USize byte_size)
|
||||
{
|
||||
DN_VArray<T> result = {};
|
||||
result.data = DN_Cast(T *) DN_OS_MemReserve(byte_size, DN_MemCommit_No, DN_MemPage_ReadWrite);
|
||||
if (result.data)
|
||||
result.max = byte_size / sizeof(T);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
DN_VArray<T> DN_OS_VArrayInit(DN_USize max)
|
||||
{
|
||||
DN_VArray<T> result = DN_OS_VArrayInitByteSize<T>(max * sizeof(T));
|
||||
DN_Assert(result.max >= max);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, DN_USize N>
|
||||
DN_VArray<T> DN_OS_VArrayInitCArray(T const (&items)[N], DN_USize max)
|
||||
{
|
||||
DN_USize real_max = DN_Max(N, max);
|
||||
DN_VArray<T> result = DN_OS_VArrayInit<T>(real_max);
|
||||
if (DN_OS_VArrayIsValid(&result))
|
||||
DN_OS_VArrayAddArray(&result, items, N);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void DN_OS_VArrayDeinit(DN_VArray<T> *array)
|
||||
{
|
||||
DN_OS_MemRelease(array->data, array->max * sizeof(T));
|
||||
*array = {};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool DN_OS_VArrayIsValid(DN_VArray<T> const *array)
|
||||
{
|
||||
bool result = array->data && array->size <= array->max;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T *DN_OS_VArrayAddArray(DN_VArray<T> *array, T const *items, DN_USize count)
|
||||
{
|
||||
T *result = DN_OS_VArrayMakeArray(array, count, DN_ZMem_No);
|
||||
if (result)
|
||||
DN_Memcpy(result, items, count * sizeof(T));
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, DN_USize N>
|
||||
T *DN_OS_VArrayAddCArray(DN_VArray<T> *array, T const (&items)[N])
|
||||
{
|
||||
T *result = DN_OS_VArrayAddArray(array, items, N);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T *DN_OS_VArrayAdd(DN_VArray<T> *array, T const &item)
|
||||
{
|
||||
T *result = DN_OS_VArrayAddArray(array, &item, 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T *DN_OS_VArrayMakeArray(DN_VArray<T> *array, DN_USize count, DN_ZMem z_mem)
|
||||
{
|
||||
if (!DN_OS_VArrayIsValid(array))
|
||||
return nullptr;
|
||||
|
||||
if (!DN_CheckF((array->size + count) < array->max, "Array is out of space (user requested +%zu items, array has %zu/%zu items)", count, array->size, array->max))
|
||||
return nullptr;
|
||||
|
||||
if (!DN_OS_VArrayReserve(array, count))
|
||||
return nullptr;
|
||||
|
||||
// TODO: Use placement new
|
||||
T *result = array->data + array->size;
|
||||
array->size += count;
|
||||
if (z_mem == DN_ZMem_Yes)
|
||||
DN_Memset(result, 0, count * sizeof(T));
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T *DN_OS_VArrayMake(DN_VArray<T> *array, DN_ZMem z_mem)
|
||||
{
|
||||
T *result = DN_OS_VArrayMakeArray(array, 1, z_mem);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T *DN_OS_VArrayInsertArray(DN_VArray<T> *array, DN_USize index, T const *items, DN_USize count)
|
||||
{
|
||||
T *result = nullptr;
|
||||
if (!DN_OS_VArrayIsValid(array))
|
||||
return result;
|
||||
if (DN_OS_VArrayReserve(array, array->size + count))
|
||||
result = DN_ArrayInsertArray(array->data, &array->size, array->max, index, items, count);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, DN_USize N>
|
||||
T *DN_OS_VArrayInsertCArray(DN_VArray<T> *array, DN_USize index, T const (&items)[N])
|
||||
{
|
||||
T *result = DN_OS_VArrayInsertArray(array, index, items, N);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T *DN_OS_VArrayInsert(DN_VArray<T> *array, DN_USize index, T const &item)
|
||||
{
|
||||
T *result = DN_OS_VArrayInsertArray(array, index, &item, 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T *DN_OS_VArrayPopFront(DN_VArray<T> *array, DN_USize count)
|
||||
{
|
||||
T *result = DN_Cast(T *)DN_ArrayPopFront(array->data, &array->size, sizeof(T), count);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T *DN_OS_VArrayPopBack(DN_VArray<T> *array, DN_USize count)
|
||||
{
|
||||
T *result = DN_Cast(T *)DN_ArrayPopBack(array->data, &array->size, sizeof(T), count);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
DN_ArrayEraseResult DN_OS_VArrayEraseRange(DN_VArray<T> *array, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase)
|
||||
{
|
||||
DN_ArrayEraseResult result = {};
|
||||
if (!DN_OS_VArrayIsValid(array))
|
||||
return result;
|
||||
result = DN_ArrayEraseRange(array->data, &array->size, sizeof(T), begin_index, count, erase);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void DN_OS_VArrayClear(DN_VArray<T> *array, DN_ZMem z_mem)
|
||||
{
|
||||
if (array) {
|
||||
if (z_mem == DN_ZMem_Yes)
|
||||
DN_Memset(array->data, 0, array->size * sizeof(T));
|
||||
array->size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool DN_OS_VArrayReserve(DN_VArray<T> *array, DN_USize count)
|
||||
{
|
||||
if (!DN_OS_VArrayIsValid(array) || count == 0)
|
||||
return false;
|
||||
|
||||
DN_USize real_commit = (array->size + count) * sizeof(T);
|
||||
DN_USize aligned_commit = DN_AlignUpPowerOfTwo(real_commit, DN_Get()->os.page_size);
|
||||
if (array->commit >= aligned_commit)
|
||||
return true;
|
||||
bool result = DN_OS_MemCommit(array->data, aligned_commit, DN_MemPage_ReadWrite);
|
||||
array->commit = aligned_commit;
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_API DN_StackTrace DN_StackTraceFromAllocator(DN_Allocator allocator, DN_U16 limit)
|
||||
{
|
||||
DN_StackTrace result = {};
|
||||
|
||||
+46
-86
@@ -31,10 +31,6 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(DN_PLATFORM_EMSCRIPTEN)
|
||||
#include <emscripten/fetch.h> // emscripten_fetch (for DN_OSHttpResponse)
|
||||
#endif
|
||||
|
||||
extern DN_CPUFeatureDecl g_dn_cpu_feature_decl[DN_CPUFeature_Count];
|
||||
|
||||
struct DN_OSTimer /// Record time between two time-points using the OS's performance counter.
|
||||
@@ -229,42 +225,6 @@ struct DN_OSThread
|
||||
DN_TCInitArgs tc_init_args;
|
||||
};
|
||||
|
||||
// NOTE: DN_OSHttp
|
||||
enum DN_OSHttpRequestSecure
|
||||
{
|
||||
DN_OSHttpRequestSecure_No,
|
||||
DN_OSHttpRequestSecure_Yes,
|
||||
};
|
||||
|
||||
struct DN_OSHttpResponse
|
||||
{
|
||||
// NOTE: Response data
|
||||
DN_U32 error_code;
|
||||
DN_Str8 error_msg;
|
||||
DN_U16 http_status;
|
||||
DN_Str8 body;
|
||||
DN_B32 done;
|
||||
|
||||
// NOTE: Book-keeping
|
||||
DN_Arena *arena; // Allocates memory for the response
|
||||
|
||||
// NOTE: Async book-keeping
|
||||
// Synchronous HTTP response uses the TLS scratch arena whereas async
|
||||
// calls use their own dedicated arena.
|
||||
DN_Arena tmp_arena;
|
||||
DN_Arena scratch_arena;
|
||||
DN_Str8Builder builder;
|
||||
DN_OSSemaphore on_complete_semaphore;
|
||||
|
||||
#if defined(DN_PLATFORM_EMSCRIPTEN)
|
||||
emscripten_fetch_t *em_handle;
|
||||
#elif defined(DN_PLATFORM_WIN32)
|
||||
HINTERNET w32_request_session;
|
||||
HINTERNET w32_request_connection;
|
||||
HINTERNET w32_request_handle;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct DN_OSCore
|
||||
{
|
||||
DN_CPUReport cpu_report;
|
||||
@@ -509,10 +469,52 @@ DN_API DN_OSThreadLane* DN_OS_TCThreadLane ()
|
||||
DN_API void DN_OS_TCThreadLaneSync (void **ptr_to_share);
|
||||
DN_API DN_OSThreadLane DN_OS_TCThreadLaneEquip (DN_OSThreadLane lane);
|
||||
|
||||
DN_API void DN_OS_HttpRequestAsync (DN_OSHttpResponse *response, DN_Arena *arena, DN_Str8 host, DN_Str8 path, DN_OSHttpRequestSecure secure, DN_Str8 method, DN_Str8 body, DN_Str8 headers);
|
||||
DN_API void DN_OS_HttpRequestWait (DN_OSHttpResponse *response);
|
||||
DN_API void DN_OS_HttpRequestFree (DN_OSHttpResponse *response);
|
||||
DN_API DN_OSHttpResponse DN_OS_HttpRequest (DN_Arena *arena, DN_Str8 host, DN_Str8 path, DN_OSHttpRequestSecure secure, DN_Str8 method, DN_Str8 body, DN_Str8 headers);
|
||||
enum DN_OSAsyncPriority
|
||||
{
|
||||
DN_OSAsyncPriority_Low,
|
||||
DN_OSAsyncPriority_High,
|
||||
DN_OSAsyncPriority_Count,
|
||||
};
|
||||
|
||||
struct DN_OSAsyncCore
|
||||
{
|
||||
DN_OSMutex ring_mutex;
|
||||
DN_OSConditionVariable ring_write_cv;
|
||||
DN_OSSemaphore worker_sem;
|
||||
DN_Ring ring;
|
||||
DN_OSThread *threads;
|
||||
DN_U32 thread_count;
|
||||
DN_U32 busy_threads;
|
||||
DN_U32 join_threads;
|
||||
};
|
||||
|
||||
struct DN_OSAsyncWorkArgs
|
||||
{
|
||||
DN_OSThread *thread;
|
||||
void *input;
|
||||
};
|
||||
|
||||
typedef void(DN_OSAsyncWorkFunc)(DN_OSAsyncWorkArgs work_args);
|
||||
|
||||
struct DN_OSAsyncWork
|
||||
{
|
||||
DN_OSAsyncWorkFunc *func;
|
||||
void *input;
|
||||
void *output;
|
||||
};
|
||||
|
||||
struct DN_OSAsyncTask
|
||||
{
|
||||
bool queued;
|
||||
DN_OSAsyncWork work;
|
||||
DN_OSSemaphore completion_sem;
|
||||
};
|
||||
|
||||
DN_API void DN_OS_AsyncInit (DN_OSAsyncCore *async, char *base, DN_USize base_size, DN_OSThread *threads, DN_U32 threads_size);
|
||||
DN_API void DN_OS_AsyncDeinit (DN_OSAsyncCore *async);
|
||||
DN_API bool DN_OS_AsyncQueueWork(DN_OSAsyncCore *async, DN_OSAsyncWorkFunc *func, void *input, DN_U64 wait_time_ms);
|
||||
DN_API DN_OSAsyncTask DN_OS_AsyncQueueTask(DN_OSAsyncCore *async, DN_OSAsyncWorkFunc *func, void *input, DN_U64 wait_time_ms);
|
||||
DN_API bool DN_OS_AsyncWaitTask (DN_OSAsyncTask *task, DN_U32 timeout_ms);
|
||||
|
||||
// NOTE: DN_OSPrint
|
||||
enum DN_OSPrintDest
|
||||
@@ -570,46 +572,4 @@ DN_API void DN_OS_PrintLnFV (DN_OSPrintDest dest, DN_FMT_ATTRIB char
|
||||
DN_API void DN_OS_PrintLnStyle (DN_OSPrintDest dest, DN_LogStyle style, DN_Str8 string);
|
||||
DN_API void DN_OS_PrintLnFStyle (DN_OSPrintDest dest, DN_LogStyle style, DN_FMT_ATTRIB char const *fmt, ...);
|
||||
DN_API void DN_OS_PrintLnFVStyle (DN_OSPrintDest dest, DN_LogStyle style, DN_FMT_ATTRIB char const *fmt, va_list args);
|
||||
|
||||
// NOTE: DN_VArray
|
||||
// TODO(doyle): Add an API for shrinking the array by decomitting pages back to the OS.
|
||||
template <typename T> struct DN_VArray
|
||||
{
|
||||
T *data; // Pointer to the start of the array items in the block of memory
|
||||
DN_USize size; // Number of items currently in the array
|
||||
DN_USize max; // Maximum number of items this array can store
|
||||
DN_USize commit; // Bytes committed
|
||||
|
||||
T *begin() { return data; }
|
||||
T *end () { return data + size; }
|
||||
T const *begin() const { return data; }
|
||||
T const *end () const { return data + size; }
|
||||
};
|
||||
|
||||
template <typename T> DN_VArray<T> DN_OS_VArrayInitByteSize (DN_USize byte_size);
|
||||
template <typename T> DN_VArray<T> DN_OS_VArrayInit (DN_USize max);
|
||||
template <typename T, DN_USize N> DN_VArray<T> DN_OS_VArrayInitCArray (T const (&items)[N], DN_USize max);
|
||||
template <typename T> void DN_OS_VArrayDeinit (DN_VArray<T> *array);
|
||||
template <typename T> bool DN_OS_VArrayIsValid (DN_VArray<T> const *array);
|
||||
template <typename T> bool DN_OS_VArrayReserve (DN_VArray<T> *array, DN_USize count);
|
||||
template <typename T> T * DN_OS_VArrayAddArray (DN_VArray<T> *array, T const *items, DN_USize count);
|
||||
template <typename T, DN_USize N> T * DN_OS_VArrayAddCArray (DN_VArray<T> *array, T const (&items)[N]);
|
||||
template <typename T> T * DN_OS_VArrayAdd (DN_VArray<T> *array, T const &item);
|
||||
#define DN_OS_VArrayAddArrayAssert(...) DN_HardAssert(DN_OS_VArrayAddArray(__VA_ARGS__))
|
||||
#define DN_OS_VArrayAddCArrayAssert(...) DN_HardAssert(DN_OS_VArrayAddCArray(__VA_ARGS__))
|
||||
#define DN_OS_VArrayAddAssert(...) DN_HardAssert(DN_OS_VArrayAdd(__VA_ARGS__))
|
||||
template <typename T> T * DN_OS_VArrayMakeArray (DN_VArray<T> *array, DN_USize count, DN_ZMem z_mem);
|
||||
template <typename T> T * DN_OS_VArrayMake (DN_VArray<T> *array, DN_ZMem z_mem);
|
||||
#define DN_OS_VArrayMakeArrayAssert(...) DN_HardAssert(DN_OS_VArrayMakeArray(__VA_ARGS__))
|
||||
#define DN_OS_VArrayMakeAssert(...) DN_HardAssert(DN_OS_VArrayMake(__VA_ARGS__))
|
||||
template <typename T> T * DN_OS_VArrayInsertArray (DN_VArray<T> *array, DN_USize index, T const *items, DN_USize count);
|
||||
template <typename T, DN_USize N> T * DN_OS_VArrayInsertCArray (DN_VArray<T> *array, DN_USize index, T const (&items)[N]);
|
||||
template <typename T> T * DN_OS_VArrayInsert (DN_VArray<T> *array, DN_USize index, T const &item);
|
||||
#define DN_OS_VArrayInsertArrayAssert(...) DN_HardAssert(DN_OS_VArrayInsertArray(__VA_ARGS__))
|
||||
#define DN_OS_VArrayInsertCArrayAssert(...) DN_HardAssert(DN_OS_VArrayInsertCArray(__VA_ARGS__))
|
||||
#define DN_OS_VArrayInsertAssert(...) DN_HardAssert(DN_OS_VArrayInsert(__VA_ARGS__))
|
||||
template <typename T> T DN_OS_VArrayPopFront (DN_VArray<T> *array, DN_USize count);
|
||||
template <typename T> T DN_OS_VArrayPopBack (DN_VArray<T> *array, DN_USize count);
|
||||
template <typename T> DN_ArrayEraseResult DN_OS_VArrayEraseRange (DN_VArray<T> *array, DN_USize begin_index, DN_ISize count, DN_ArrayErase erase);
|
||||
template <typename T> void DN_OS_VArrayClear (DN_VArray<T> *array, DN_ZMem z_mem);
|
||||
#endif // !defined(DN_OS_H)
|
||||
|
||||
@@ -1444,154 +1444,3 @@ DN_API DN_OSPosixProcSelfStatus DN_OS_PosixProcSelfStatus()
|
||||
DN_OS_FileClose(&file);
|
||||
return result;
|
||||
}
|
||||
|
||||
// NOTE: DN_OSHttp /////////////////////////////////////////////////////////////////////////////////
|
||||
#if 0 // TODO(doyle): Implement websockets for Windows and Emscripten
|
||||
static EM_BOOL EMWebSocketOnOpenCallback(int type, const EmscriptenWebSocketOpenEvent *event, void *user_context)
|
||||
{
|
||||
(void)user_context;
|
||||
(void)type;
|
||||
(void)event;
|
||||
// EMSCRIPTEN_RESULT result = emscripten_websocket_send_utf8_text(event->socket, R"({"jsonrpc":"2.0","id":1,"method": "eth_subscribe","params":["newHeads"]})");
|
||||
// if (result)
|
||||
// DN_LogInfoF("Failed to emscripten_websocket_send_utf8_text(): %d\n", result);
|
||||
return EM_TRUE;
|
||||
}
|
||||
|
||||
static EM_BOOL EMWebSocketOnMsgCallback(int type, const EmscriptenWebSocketMessageEvent *event __attribute__((nonnull)), void *user_context)
|
||||
{
|
||||
(void)type;
|
||||
(void)user_context;
|
||||
(void)event;
|
||||
if (event->isText) {
|
||||
DN_LogInfoF("Received: %.*s", event->numBytes, event->data);
|
||||
} else {
|
||||
DN_LogInfoF("Received: %d bytes", event->numBytes);
|
||||
}
|
||||
return EM_TRUE;
|
||||
}
|
||||
|
||||
static EM_BOOL EMWebSocketOnErrorCallback(int type, const EmscriptenWebSocketErrorEvent *event, void *user_context)
|
||||
{
|
||||
(void)user_context;
|
||||
(void)type;
|
||||
(void)event;
|
||||
return EM_TRUE;
|
||||
}
|
||||
|
||||
static EM_BOOL EMWebSocketOnCloseCallback(int type, const EmscriptenWebSocketCloseEvent *event, void *user_context)
|
||||
{
|
||||
(void)user_context;
|
||||
(void)type;
|
||||
(void)event;
|
||||
return EM_TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(DN_PLATFORM_EMSCRIPTEN)
|
||||
static void DN_OS_HttpRequestEMFetchOnSuccessCallback(emscripten_fetch_t *fetch)
|
||||
{
|
||||
DN_OSHttpResponse *response = DN_Cast(DN_OSHttpResponse *) fetch->userData;
|
||||
if (!DN_Check(response))
|
||||
return;
|
||||
|
||||
response->http_status = DN_Cast(DN_U32) fetch->status;
|
||||
response->body = DN_Str8AllocArena(fetch->numBytes, DN_ZMem_No, response->arena);
|
||||
if (response->body.data)
|
||||
DN_Memcpy(response->body.data, fetch->data, fetch->numBytes);
|
||||
|
||||
DN_OS_SemaphoreIncrement(&response->on_complete_semaphore, 1);
|
||||
DN_AtomicAddU32(&response->done, 1);
|
||||
}
|
||||
|
||||
static void DN_OS_HttpRequestEMFetchOnErrorCallback(emscripten_fetch_t *fetch)
|
||||
{
|
||||
DN_OSHttpResponse *response = DN_Cast(DN_OSHttpResponse *) fetch->userData;
|
||||
if (!DN_Check(response))
|
||||
return;
|
||||
|
||||
response->http_status = DN_Cast(DN_U32) fetch->status;
|
||||
response->body = DN_Str8AllocArena(fetch->numBytes, DN_ZMem_No, response->arena);
|
||||
if (response->body.size)
|
||||
DN_Memcpy(response->body.data, fetch->data, fetch->numBytes);
|
||||
|
||||
DN_OS_SemaphoreIncrement(&response->on_complete_semaphore, 1);
|
||||
DN_AtomicAddU32(&response->done, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
DN_API void DN_OS_HttpRequestAsync(DN_OSHttpResponse *response,
|
||||
DN_Arena *arena,
|
||||
DN_Str8 host,
|
||||
DN_Str8 path,
|
||||
DN_OSHttpRequestSecure secure,
|
||||
DN_Str8 method,
|
||||
DN_Str8 body,
|
||||
DN_Str8 headers)
|
||||
{
|
||||
if (!response || !arena)
|
||||
return;
|
||||
|
||||
response->arena = arena;
|
||||
response->builder.arena = response->scratch_arena.mem ? &response->scratch_arena : &response->tmp_arena;
|
||||
|
||||
DN_Arena *scratch = &response->scratch_arena;
|
||||
DN_TCScratch scratch_ = DN_TCScratchBeginArena(&arena, 1);
|
||||
DN_DEFER { DN_TCScratchEnd(&scratch_); };
|
||||
if (!scratch)
|
||||
scratch = &scratch_.arena;
|
||||
|
||||
#if defined(DN_PLATFORM_EMSCRIPTEN)
|
||||
emscripten_fetch_attr_t fetch_attribs = {};
|
||||
emscripten_fetch_attr_init(&fetch_attribs);
|
||||
|
||||
if (method.size >= sizeof(fetch_attribs.requestMethod)) {
|
||||
response->error_msg =
|
||||
DN_Str8FromFmtArena(arena,
|
||||
"Request method in EM has a size limit of 31 characters, method was "
|
||||
"'%.*s' which is %zu characters long",
|
||||
DN_Str8PrintFmt(method),
|
||||
method.size);
|
||||
DN_CheckF(method.size < sizeof(fetch_attribs.requestMethod),
|
||||
"%.*s",
|
||||
DN_Str8PrintFmt(response->error_msg));
|
||||
response->error_code = DN_Cast(DN_U32) - 1;
|
||||
DN_AtomicAddU32(&response->done, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
DN_Memcpy(fetch_attribs.requestMethod, method.data, method.size);
|
||||
|
||||
fetch_attribs.requestData = body.data;
|
||||
fetch_attribs.requestDataSize = body.size;
|
||||
fetch_attribs.attributes = EMSCRIPTEN_FETCH_LOAD_TO_MEMORY;
|
||||
fetch_attribs.onsuccess = DN_OS_HttpRequestEMFetchOnSuccessCallback;
|
||||
fetch_attribs.onerror = DN_OS_HttpRequestEMFetchOnErrorCallback;
|
||||
fetch_attribs.userData = response;
|
||||
|
||||
DN_Str8 url = DN_Str8FromFmtArena(scratch, "%.*s%.*s", DN_Str8PrintFmt(host), DN_Str8PrintFmt(path));
|
||||
DN_LogInfoF("Initiating HTTP '%s' request to '%.*s' with payload '%.*s'",
|
||||
fetch_attribs.requestMethod,
|
||||
DN_Str8PrintFmt(url),
|
||||
DN_Str8PrintFmt(body));
|
||||
response->on_complete_semaphore = DN_OS_SemaphoreInit(0);
|
||||
response->em_handle = emscripten_fetch(&fetch_attribs, url.data);
|
||||
#else // #elif defined(DN_OS_WIN32)
|
||||
DN_InvalidCodePathF("Unimplemented function");
|
||||
#endif
|
||||
}
|
||||
|
||||
DN_API void DN_OS_HttpRequestFree(DN_OSHttpResponse *response)
|
||||
{
|
||||
// NOTE: Cleanup
|
||||
#if defined(DN_PLATFORM_EMSCRIPTEN)
|
||||
if (response->em_handle) {
|
||||
emscripten_fetch_close(response->em_handle);
|
||||
response->em_handle = nullptr;
|
||||
}
|
||||
#endif // #elif defined(DN_OS_WIN32)
|
||||
|
||||
DN_MemListDeinit(response->tmp_arena.mem);
|
||||
DN_OS_SemaphoreDeinit(&response->on_complete_semaphore);
|
||||
*response = {};
|
||||
}
|
||||
|
||||
+12
-212
@@ -395,15 +395,9 @@ DN_API DN_OSFileRead DN_OS_FileRead(DN_OSFile *file, void *buffer, DN_USize size
|
||||
if (!file || !file->handle || file->error || !buffer || size <= 0)
|
||||
return result;
|
||||
|
||||
DN_TCScratch scratch = DN_TCScratchBeginArena(nullptr, 0);
|
||||
if (!DN_Check(size <= (unsigned long)-1)) {
|
||||
DN_Str8x32 buffer_size_str8 = DN_Str8x32FromByteCountU64Auto(size);
|
||||
DN_ErrSinkAppendF(
|
||||
err,
|
||||
1 /*error_code*/,
|
||||
"Current implementation doesn't support reading >4GiB file (requested %.*s), implement Win32 overlapped IO",
|
||||
DN_Str8PrintFmt(buffer_size_str8));
|
||||
DN_TCScratchEnd(&scratch);
|
||||
if (size > ULONG_MAX) {
|
||||
DN_Str8x32 desc = DN_Str8x32FromByteCountU64Auto(size);
|
||||
DN_ErrSinkAppendF(err, 1 /*error_code*/, "Current implementation doesn't support reading >4GiB file (requested %.*s), implement Win32 overlapped IO", DN_Str8PrintFmt(desc));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -414,6 +408,7 @@ DN_API DN_OSFileRead DN_OS_FileRead(DN_OSFile *file, void *buffer, DN_USize size
|
||||
/*LPDWORD lpNumberOfByesRead*/ &bytes_read,
|
||||
/*LPOVERLAPPED lpOverlapped*/ nullptr);
|
||||
if (read_result == 0) {
|
||||
DN_TCScratch scratch = DN_TCScratchBeginArena(nullptr, 0);
|
||||
DN_OSW32Error win_error = DN_OS_W32LastError(&scratch.arena);
|
||||
DN_ErrSinkAppendF(err, win_error.code, "Failed to read data from file: (%u) %.*s", win_error.code, DN_Str8PrintFmt(win_error.msg));
|
||||
DN_TCScratchEnd(&scratch);
|
||||
@@ -421,6 +416,7 @@ DN_API DN_OSFileRead DN_OS_FileRead(DN_OSFile *file, void *buffer, DN_USize size
|
||||
}
|
||||
|
||||
if (bytes_read != size) {
|
||||
DN_TCScratch scratch = DN_TCScratchBeginArena(nullptr, 0);
|
||||
DN_OSW32Error win_error = DN_OS_W32LastError(&scratch.arena);
|
||||
DN_ErrSinkAppendF(
|
||||
err,
|
||||
@@ -436,7 +432,6 @@ DN_API DN_OSFileRead DN_OS_FileRead(DN_OSFile *file, void *buffer, DN_USize size
|
||||
|
||||
result.bytes_read = bytes_read;
|
||||
result.success = true;
|
||||
DN_TCScratchEnd(&scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -732,7 +727,7 @@ DN_API DN_OSExecResult DN_OS_ExecPump(DN_OSExecAsyncHandle handle,
|
||||
DN_ErrSinkAppendF(err, result.os_error_code, "Executed command failed to terminate: %.*s", DN_Str8PrintFmt(win_error.msg));
|
||||
DN_TCScratchEnd(&scratch);
|
||||
return result;
|
||||
} else if (DN_Check(exec_result == WAIT_TIMEOUT || exec_result == WAIT_OBJECT_0)) {
|
||||
} else if (exec_result == WAIT_TIMEOUT || exec_result == WAIT_OBJECT_0) {
|
||||
// NOTE: Read stdout from process
|
||||
// If the pipes are full, the process will block. We periodically
|
||||
// flush the pipes to make sure this doesn't happen
|
||||
@@ -1341,204 +1336,6 @@ DN_API void DN_OS_W32ThreadSetName(DN_Str8 name)
|
||||
DN_TCScratchEnd(&scratch);
|
||||
}
|
||||
|
||||
void DN_OS_HttpRequestWin32Callback(HINTERNET session, DWORD *dwContext, DWORD dwInternetStatus, VOID *lpvStatusInformation, DWORD dwStatusInformationLength)
|
||||
{
|
||||
(void)session;
|
||||
(void)dwStatusInformationLength;
|
||||
|
||||
DN_OSHttpResponse *response = DN_Cast(DN_OSHttpResponse *) dwContext;
|
||||
HINTERNET request = DN_Cast(HINTERNET) response->w32_request_handle;
|
||||
DN_OSW32Error error = {};
|
||||
DWORD const READ_BUFFER_SIZE = DN_Megabytes(1);
|
||||
|
||||
if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_RESOLVING_NAME) {
|
||||
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_NAME_RESOLVED) {
|
||||
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER) {
|
||||
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER) {
|
||||
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_SENDING_REQUEST) {
|
||||
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_REQUEST_SENT) {
|
||||
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE) {
|
||||
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED) {
|
||||
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION) {
|
||||
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED) {
|
||||
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED) {
|
||||
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_HANDLE_CREATED) {
|
||||
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING) {
|
||||
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_DETECTING_PROXY) {
|
||||
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_REDIRECT) {
|
||||
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_INTERMEDIATE_RESPONSE) {
|
||||
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_SECURE_FAILURE) {
|
||||
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE) {
|
||||
DWORD status = 0;
|
||||
DWORD status_size = sizeof(status_size);
|
||||
if (WinHttpQueryHeaders(request,
|
||||
WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
|
||||
WINHTTP_HEADER_NAME_BY_INDEX,
|
||||
&status,
|
||||
&status_size,
|
||||
WINHTTP_NO_HEADER_INDEX)) {
|
||||
response->http_status = DN_Cast(uint16_t) status;
|
||||
|
||||
// NOTE: You can normally call into WinHttpQueryDataAvailable which means the kernel
|
||||
// will buffer the response into a single buffer and return us the full size of the
|
||||
// request.
|
||||
//
|
||||
// or
|
||||
//
|
||||
// You may call WinHttpReadData directly to write the memory into our buffer directly.
|
||||
// This is advantageous to avoid a copy from the kernel buffer into our buffer. If the
|
||||
// end user application knows the typical payload size then they can optimise for this
|
||||
// to prevent unnecessary allocation on the user side.
|
||||
void *buffer = DN_ArenaAlloc(response->builder.arena, READ_BUFFER_SIZE, 1 /*align*/, DN_ZMem_No);
|
||||
if (!WinHttpReadData(request, buffer, READ_BUFFER_SIZE, nullptr))
|
||||
error = DN_OS_W32LastError(&response->tmp_arena);
|
||||
} else {
|
||||
error = DN_OS_W32LastError(&response->tmp_arena);
|
||||
}
|
||||
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE) {
|
||||
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_READ_COMPLETE) {
|
||||
DWORD bytes_read = dwStatusInformationLength;
|
||||
if (bytes_read) {
|
||||
DN_Str8 prev_buffer = DN_Str8FromPtr(DN_Cast(char *) lpvStatusInformation, bytes_read);
|
||||
DN_Str8BuilderAppendRef(&response->builder, prev_buffer);
|
||||
|
||||
void *buffer = DN_ArenaAlloc(response->builder.arena, READ_BUFFER_SIZE, 1 /*align*/, DN_ZMem_No);
|
||||
if (!WinHttpReadData(request, buffer, READ_BUFFER_SIZE, nullptr))
|
||||
error = DN_OS_W32LastError(&response->tmp_arena);
|
||||
}
|
||||
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE) {
|
||||
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_REQUEST_ERROR) {
|
||||
WINHTTP_ASYNC_RESULT *async_result = DN_Cast(WINHTTP_ASYNC_RESULT *) lpvStatusInformation;
|
||||
error = DN_OS_W32ErrorCodeToMsg(&response->tmp_arena, DN_Cast(DN_U32) async_result->dwError);
|
||||
} else if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE) {
|
||||
if (!WinHttpReceiveResponse(request, 0))
|
||||
error = DN_OS_W32LastError(&response->tmp_arena);
|
||||
}
|
||||
|
||||
// NOTE: If the request handle is missing, then, the response has been freed.
|
||||
// MSDN says that this callback can still be called after closing the handle
|
||||
// and trigger the WINHTTP_CALLBACK_STATUS_REQUEST_ERROR.
|
||||
if (request) {
|
||||
bool read_complete = dwInternetStatus == WINHTTP_CALLBACK_STATUS_READ_COMPLETE && dwStatusInformationLength == 0;
|
||||
if (read_complete)
|
||||
response->body = DN_Str8FromStr8BuilderArena(&response->builder, response->arena);
|
||||
|
||||
if (read_complete || dwInternetStatus == WINHTTP_CALLBACK_STATUS_REQUEST_ERROR || error.code) {
|
||||
DN_OS_SemaphoreIncrement(&response->on_complete_semaphore, 1);
|
||||
DN_AtomicAddU32(&response->done, 1);
|
||||
}
|
||||
|
||||
if (error.code) {
|
||||
response->error_code = error.code;
|
||||
response->error_msg = error.msg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DN_API void DN_OS_HttpRequestAsync(DN_OSHttpResponse *response,
|
||||
DN_Arena *arena,
|
||||
DN_Str8 host,
|
||||
DN_Str8 path,
|
||||
DN_OSHttpRequestSecure secure,
|
||||
DN_Str8 method,
|
||||
DN_Str8 body,
|
||||
DN_Str8 headers)
|
||||
{
|
||||
if (!response || !arena)
|
||||
return;
|
||||
|
||||
response->arena = arena;
|
||||
response->builder = DN_Str8BuilderFromArena(response->scratch_arena.mem ? &response->scratch_arena : &response->tmp_arena);
|
||||
|
||||
DN_TCScratch scratch_ = DN_TCScratchBeginArena(&arena, 1);
|
||||
if (!response->scratch_arena.mem)
|
||||
response->scratch_arena = scratch_.arena;
|
||||
|
||||
DN_OSW32Error error = {};
|
||||
DN_DEFER
|
||||
{
|
||||
response->error_msg = error.msg;
|
||||
response->error_code = error.code;
|
||||
if (error.code) {
|
||||
// NOTE: 'Wait' handles failures gracefully, skipping the wait and
|
||||
// cleans up the request
|
||||
DN_OS_HttpRequestWait(response);
|
||||
DN_AtomicAddU32(&response->done, 1);
|
||||
}
|
||||
DN_TCScratchEnd(&scratch_);
|
||||
};
|
||||
|
||||
response->w32_request_session = WinHttpOpen(nullptr /*user agent*/, WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, WINHTTP_FLAG_ASYNC);
|
||||
if (!response->w32_request_session) {
|
||||
error = DN_OS_W32LastError(&response->tmp_arena);
|
||||
return;
|
||||
}
|
||||
|
||||
DWORD callback_flags = WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE |
|
||||
WINHTTP_CALLBACK_STATUS_READ_COMPLETE |
|
||||
WINHTTP_CALLBACK_STATUS_REQUEST_ERROR |
|
||||
WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE;
|
||||
if (WinHttpSetStatusCallback(response->w32_request_session,
|
||||
DN_Cast(WINHTTP_STATUS_CALLBACK) DN_OS_HttpRequestWin32Callback,
|
||||
callback_flags,
|
||||
DN_Cast(DWORD_PTR) nullptr /*dwReserved*/) == WINHTTP_INVALID_STATUS_CALLBACK) {
|
||||
error = DN_OS_W32LastError(&response->tmp_arena);
|
||||
return;
|
||||
}
|
||||
|
||||
DN_Str16 host16 = DN_OS_W32Str8ToStr16(&response->scratch_arena, host);
|
||||
response->w32_request_connection = WinHttpConnect(response->w32_request_session, host16.data, secure ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT, 0 /*reserved*/);
|
||||
if (!response->w32_request_connection) {
|
||||
error = DN_OS_W32LastError(&response->tmp_arena);
|
||||
return;
|
||||
}
|
||||
|
||||
DN_Str16 method16 = DN_OS_W32Str8ToStr16(&response->scratch_arena, method);
|
||||
DN_Str16 path16 = DN_OS_W32Str8ToStr16(&response->scratch_arena, path);
|
||||
response->w32_request_handle = WinHttpOpenRequest(response->w32_request_connection,
|
||||
method16.data,
|
||||
path16.data,
|
||||
nullptr /*version*/,
|
||||
nullptr /*referrer*/,
|
||||
nullptr /*accept types*/,
|
||||
secure ? WINHTTP_FLAG_SECURE : 0);
|
||||
if (!response->w32_request_handle) {
|
||||
error = DN_OS_W32LastError(&response->tmp_arena);
|
||||
return;
|
||||
}
|
||||
|
||||
DN_Str16 headers16 = DN_OS_W32Str8ToStr16(&response->scratch_arena, headers);
|
||||
response->on_complete_semaphore = DN_OS_SemaphoreInit(0);
|
||||
if (!WinHttpSendRequest(response->w32_request_handle,
|
||||
headers16.data,
|
||||
DN_Cast(DWORD) headers16.size,
|
||||
body.data /*optional data*/,
|
||||
DN_Cast(DWORD) body.size /*optional length*/,
|
||||
DN_Cast(DWORD) body.size /*total content length*/,
|
||||
DN_Cast(DWORD_PTR) response)) {
|
||||
error = DN_OS_W32LastError(&response->tmp_arena);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
DN_API void DN_OS_HttpRequestFree(DN_OSHttpResponse *response)
|
||||
{
|
||||
// NOTE: Cleanup
|
||||
// NOTE: These calls are synchronous even when the HTTP request is async.
|
||||
WinHttpCloseHandle(response->w32_request_handle);
|
||||
WinHttpCloseHandle(response->w32_request_connection);
|
||||
WinHttpCloseHandle(response->w32_request_session);
|
||||
|
||||
response->w32_request_session = nullptr;
|
||||
response->w32_request_connection = nullptr;
|
||||
response->w32_request_handle = nullptr;
|
||||
DN_MemListDeinit(response->tmp_arena.mem);
|
||||
DN_OS_SemaphoreDeinit(&response->on_complete_semaphore);
|
||||
|
||||
*response = {};
|
||||
}
|
||||
|
||||
// NOTE: DN_OS_W32
|
||||
DN_API DN_Str16 DN_OS_W32ErrorCodeToMsg16Alloc(DN_U32 error_code)
|
||||
{
|
||||
DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
|
||||
@@ -1638,7 +1435,8 @@ DN_API DN_Str16 DN_OS_W32Str8ToStr16(DN_Arena *arena, DN_Str8 src)
|
||||
return result;
|
||||
|
||||
int chars_written = MultiByteToWideChar(CP_UTF8, 0 /*dwFlags*/, src.data, DN_Cast(int) src.size, buffer, required_size);
|
||||
if (DN_Check(chars_written == required_size)) {
|
||||
DN_Assert(chars_written == required_size);
|
||||
if (chars_written == required_size) {
|
||||
result.data = buffer;
|
||||
result.size = chars_written;
|
||||
result.data[result.size] = 0;
|
||||
@@ -1700,7 +1498,8 @@ DN_API DN_Str8 DN_OS_W32Str16ToStr8(DN_Arena *arena, DN_Str16 src)
|
||||
DN_Str8 buffer = DN_Str8AllocArena(required_size, DN_ZMem_No, &temp);
|
||||
if (buffer.size) {
|
||||
int chars_written = WideCharToMultiByte(CP_UTF8, 0 /*dwFlags*/, src.data, src_size, buffer.data, DN_Cast(int) buffer.size, nullptr, nullptr);
|
||||
if (DN_Check(chars_written == required_size)) {
|
||||
DN_Assert(chars_written == required_size);
|
||||
if (chars_written == required_size) {
|
||||
result = buffer;
|
||||
result.data[result.size] = 0;
|
||||
}
|
||||
@@ -1730,7 +1529,8 @@ DN_API DN_Str8 DN_OS_W32Str16ToStr8FromHeap(DN_Str16 src)
|
||||
return result;
|
||||
|
||||
int chars_written = WideCharToMultiByte(CP_UTF8, 0 /*dwFlags*/, src.data, src_size, buffer.data, DN_Cast(int) buffer.size, nullptr, nullptr);
|
||||
if (DN_Check(chars_written == required_size)) {
|
||||
DN_Assert(chars_written == required_size);
|
||||
if (chars_written == required_size) {
|
||||
result = buffer;
|
||||
result.data[result.size] = 0;
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user