diff --git a/ClassicalSharp/Utils/Camera.cs b/ClassicalSharp/Utils/Camera.cs
index 19f929bb5..22396c58b 100644
--- a/ClassicalSharp/Utils/Camera.cs
+++ b/ClassicalSharp/Utils/Camera.cs
@@ -92,7 +92,7 @@ namespace ClassicalSharp {
float sensitivity = sensiFactor * game.MouseSensitivity;
if (game.SmoothCamera) {
- speedX += delta.X * adjust; game.LocalPlayer.ModelScale.XYZ
+ speedX += delta.X * adjust;
speedX *= slippery;
speedY += delta.Y * adjust;
speedY *= slippery;
diff --git a/src/AsyncDownloader.c b/src/AsyncDownloader.c
deleted file mode 100644
index 77a430cca..000000000
--- a/src/AsyncDownloader.c
+++ /dev/null
@@ -1,335 +0,0 @@
-#include "AsyncDownloader.h"
-#include "Platform.h"
-#include "Funcs.h"
-#include "Logger.h"
-#include "Stream.h"
-#include "GameStructs.h"
-
-void ASyncRequest_Free(struct AsyncRequest* request) {
- Mem_Free(request->Data);
- request->Data = NULL;
- request->Size = 0;
-}
-
-#define ASYNC_DEF_ELEMS 10
-struct AsyncRequestList {
- int MaxElems, Count;
- struct AsyncRequest* Requests;
- struct AsyncRequest DefaultRequests[ASYNC_DEF_ELEMS];
-};
-
-static void AsyncRequestList_EnsureSpace(struct AsyncRequestList* list) {
- if (list->Count < list->MaxElems) return;
- list->Requests = Utils_Resize(list->Requests, &list->MaxElems,
- sizeof(struct AsyncRequest), ASYNC_DEF_ELEMS, 10);
-}
-
-static void AsyncRequestList_Append(struct AsyncRequestList* list, struct AsyncRequest* item) {
- AsyncRequestList_EnsureSpace(list);
- list->Requests[list->Count++] = *item;
-}
-
-static void AsyncRequestList_Prepend(struct AsyncRequestList* list, struct AsyncRequest* item) {
- int i;
- AsyncRequestList_EnsureSpace(list);
-
- for (i = list->Count; i > 0; i--) {
- list->Requests[i] = list->Requests[i - 1];
- }
- list->Requests[0] = *item;
- list->Count++;
-}
-
-static void AsyncRequestList_RemoveAt(struct AsyncRequestList* list, int i) {
- if (i < 0 || i >= list->Count) Logger_Abort("Tried to remove element at list end");
-
- for (; i < list->Count - 1; i++) {
- list->Requests[i] = list->Requests[i + 1];
- }
- list->Count--;
-}
-
-static void AsyncRequestList_Init(struct AsyncRequestList* list) {
- list->MaxElems = ASYNC_DEF_ELEMS;
- list->Count = 0;
- list->Requests = list->DefaultRequests;
-}
-
-static void AsyncRequestList_Free(struct AsyncRequestList* list) {
- if (list->Requests != list->DefaultRequests) {
- Mem_Free(list->Requests);
- }
- AsyncRequestList_Init(list);
-}
-
-static void* async_waitable;
-static void* async_workerThread;
-static void* async_pendingMutex;
-static void* async_processedMutex;
-static void* async_curRequestMutex;
-static volatile bool async_terminate;
-
-static struct AsyncRequestList async_pending;
-static struct AsyncRequestList async_processed;
-const static String async_skinServer = String_FromConst("http://static.classicube.net/skins/");
-static struct AsyncRequest async_curRequest;
-static volatile int async_curProgress = ASYNC_PROGRESS_NOTHING;
-bool AsyncDownloader_Cookies;
-
-static void AsyncDownloader_Add(const String* url, bool priority, const String* id, uint8_t type, TimeMS* lastModified, const String* etag, const String* data) {
- struct AsyncRequest req = { 0 };
- String reqUrl, reqID, reqEtag;
-
- String_InitArray(reqUrl, req.URL);
- String_Copy(&reqUrl, url);
- String_InitArray(reqID, req.ID);
- String_Copy(&reqID, id);
-
- req.RequestType = type;
- Platform_Log2("Adding %s (type %b)", &reqUrl, &type);
-
- String_InitArray(reqEtag, req.Etag);
- if (lastModified) { req.LastModified = *lastModified; }
- if (etag) { String_Copy(&reqEtag, etag); }
- /* request.Data = data; TODO: Implement this. do we need to copy or expect caller to malloc it? */
-
- Mutex_Lock(async_pendingMutex);
- {
- req.TimeAdded = DateTime_CurrentUTC_MS();
- if (priority) {
- AsyncRequestList_Prepend(&async_pending, &req);
- } else {
- AsyncRequestList_Append(&async_pending, &req);
- }
- }
- Mutex_Unlock(async_pendingMutex);
- Waitable_Signal(async_waitable);
-}
-
-void AsyncDownloader_GetSkin(const String* id, const String* skinName) {
- String url; char urlBuffer[STRING_SIZE];
- String_InitArray(url, urlBuffer);
-
- if (Utils_IsUrlPrefix(skinName, 0)) {
- String_Copy(&url, skinName);
- } else {
- String_AppendString(&url, &async_skinServer);
- String_AppendColorless(&url, skinName);
- String_AppendConst(&url, ".png");
- }
-
- AsyncDownloader_Add(&url, false, id, REQUEST_TYPE_DATA, NULL, NULL, NULL);
-}
-
-void AsyncDownloader_GetData(const String* url, bool priority, const String* id) {
- AsyncDownloader_Add(url, priority, id, REQUEST_TYPE_DATA, NULL, NULL, NULL);
-}
-
-void AsyncDownloader_GetContentLength(const String* url, bool priority, const String* id) {
- AsyncDownloader_Add(url, priority, id, REQUEST_TYPE_CONTENT_LENGTH, NULL, NULL, NULL);
-}
-
-void AsyncDownloader_PostString(const String* url, bool priority, const String* id, const String* contents) {
- AsyncDownloader_Add(url, priority, id, REQUEST_TYPE_DATA, NULL, NULL, contents);
-}
-
-void AsyncDownloader_GetDataEx(const String* url, bool priority, const String* id, TimeMS* lastModified, const String* etag) {
- AsyncDownloader_Add(url, priority, id, REQUEST_TYPE_DATA, lastModified, etag, NULL);
-}
-
-void AsyncDownloader_PurgeOldEntriesTask(struct ScheduledTask* task) {
- struct AsyncRequest* item;
- int i;
-
- Mutex_Lock(async_processedMutex);
- {
- TimeMS now = DateTime_CurrentUTC_MS();
- for (i = async_processed.Count - 1; i >= 0; i--) {
- item = &async_processed.Requests[i];
- if (item->TimeDownloaded + (10 * 1000) >= now) continue;
-
- ASyncRequest_Free(item);
- AsyncRequestList_RemoveAt(&async_processed, i);
- }
- }
- Mutex_Unlock(async_processedMutex);
-}
-
-static int AsyncRequestList_Find(const String* id, struct AsyncRequest* item) {
- String reqID;
- int i;
-
- for (i = 0; i < async_processed.Count; i++) {
- reqID = String_FromRawArray(async_processed.Requests[i].ID);
- if (!String_Equals(id, &reqID)) continue;
-
- *item = async_processed.Requests[i];
- return i;
- }
- return -1;
-}
-
-bool AsyncDownloader_Get(const String* id, struct AsyncRequest* item) {
- int i;
- Mutex_Lock(async_processedMutex);
- {
- i = AsyncRequestList_Find(id, item);
- if (i >= 0) AsyncRequestList_RemoveAt(&async_processed, i);
- }
- Mutex_Unlock(async_processedMutex);
- return i >= 0;
-}
-
-bool AsyncDownloader_GetCurrent(struct AsyncRequest* request, int* progress) {
- Mutex_Lock(async_curRequestMutex);
- {
- *request = async_curRequest;
- *progress = async_curProgress;
- }
- Mutex_Unlock(async_curRequestMutex);
- return request->ID[0];
-}
-
-void AsyncDownloader_Clear(void) {
- Mutex_Lock(async_pendingMutex);
- {
- AsyncRequestList_Free(&async_pending);
- }
- Mutex_Unlock(async_pendingMutex);
- Waitable_Signal(async_waitable);
-}
-
-static void AsyncDownloader_ProcessRequest(struct AsyncRequest* request) {
- String url = String_FromRawArray(request->URL);
- uint64_t beg, end;
- uint32_t size, elapsed;
- uintptr_t addr;
-
- Platform_Log2("Downloading from %s (type %b)", &url, &request->RequestType);
- beg = Stopwatch_Measure();
- request->Result = Http_Do(request, &async_curProgress);
- end = Stopwatch_Measure();
-
- elapsed = Stopwatch_ElapsedMicroseconds(beg, end) / 1000;
- Platform_Log3("HTTP: return code %i (http %i), in %i ms",
- &request->Result, &request->StatusCode, &elapsed);
-
- if (request->Data) {
- size = request->Size;
- addr = (uintptr_t)request->Data;
- Platform_Log2("HTTP returned data: %i bytes at %x", &size, &addr);
- }
-}
-
-static void AsyncDownloader_CompleteResult(struct AsyncRequest* request) {
- struct AsyncRequest older;
- String id = String_FromRawArray(request->ID);
- int index;
- request->TimeDownloaded = DateTime_CurrentUTC_MS();
-
- index = AsyncRequestList_Find(&id, &older);
- if (index >= 0) {
- /* very rare case - priority item was inserted, then inserted again (so put before first item), */
- /* and both items got downloaded before an external function removed them from the queue */
- if (older.TimeAdded > request->TimeAdded) {
- ASyncRequest_Free(request);
- } else {
- /* normal case, replace older request */
- ASyncRequest_Free(&older);
- async_processed.Requests[index] = *request;
- }
- } else {
- AsyncRequestList_Append(&async_processed, request);
- }
-}
-
-static void AsyncDownloader_WorkerFunc(void) {
- struct AsyncRequest request;
- bool hasRequest, stop;
-
- for (;;) {
- hasRequest = false;
-
- Mutex_Lock(async_pendingMutex);
- {
- stop = async_terminate;
- if (!stop && async_pending.Count) {
- request = async_pending.Requests[0];
- hasRequest = true;
- AsyncRequestList_RemoveAt(&async_pending, 0);
- }
- }
- Mutex_Unlock(async_pendingMutex);
-
- if (stop) return;
- /* Block until another thread submits a request to do */
- if (!hasRequest) {
- Platform_LogConst("Going back to sleep...");
- Waitable_Wait(async_waitable);
- continue;
- }
-
- Platform_LogConst("Got something to do!");
- Mutex_Lock(async_curRequestMutex);
- {
- async_curRequest = request;
- async_curProgress = ASYNC_PROGRESS_MAKING_REQUEST;
- }
- Mutex_Unlock(async_curRequestMutex);
-
- Platform_LogConst("Doing it");
- /* performing request doesn't need thread safety */
- AsyncDownloader_ProcessRequest(&request);
-
- Mutex_Lock(async_processedMutex);
- {
- AsyncDownloader_CompleteResult(&request);
- }
- Mutex_Unlock(async_processedMutex);
-
- Mutex_Lock(async_curRequestMutex);
- {
- async_curRequest.ID[0] = '\0';
- async_curProgress = ASYNC_PROGRESS_NOTHING;
- }
- Mutex_Unlock(async_curRequestMutex);
- }
-}
-
-
-/*########################################################################################################################*
-*------------------------------------------------AsyncDownloader component------------------------------------------------*
-*#########################################################################################################################*/
-static void AsyncDownloader_Init(void) {
- ScheduledTask_Add(30, AsyncDownloader_PurgeOldEntriesTask);
- AsyncRequestList_Init(&async_pending);
- AsyncRequestList_Init(&async_processed);
- Http_Init();
-
- async_waitable = Waitable_Create();
- async_pendingMutex = Mutex_Create();
- async_processedMutex = Mutex_Create();
- async_curRequestMutex = Mutex_Create();
- async_workerThread = Thread_Start(AsyncDownloader_WorkerFunc, false);
-}
-
-static void AsyncDownloader_Free(void) {
- async_terminate = true;
- AsyncDownloader_Clear();
- Thread_Join(async_workerThread);
-
- AsyncRequestList_Free(&async_pending);
- AsyncRequestList_Free(&async_processed);
- Http_Free();
-
- Waitable_Free(async_waitable);
- Mutex_Free(async_pendingMutex);
- Mutex_Free(async_processedMutex);
- Mutex_Free(async_curRequestMutex);
-}
-
-struct IGameComponent AsyncDownloader_Component = {
- AsyncDownloader_Init, /* Init */
- AsyncDownloader_Free, /* Free */
- AsyncDownloader_Clear /* Reset */
-};
diff --git a/src/AsyncDownloader.h b/src/AsyncDownloader.h
deleted file mode 100644
index 8b8226bca..000000000
--- a/src/AsyncDownloader.h
+++ /dev/null
@@ -1,63 +0,0 @@
-#ifndef CC_ASYNCDOWNLOADER_H
-#define CC_ASYNCDOWNLOADER_H
-#include "Constants.h"
-#include "Utils.h"
-/* Downloads images, texture packs, skins, etc in async manner.
- Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
-*/
-struct IGameComponent;
-struct ScheduledTask;
-#define URL_MAX_SIZE (STRING_SIZE * 2)
-
-extern struct IGameComponent AsyncDownloader_Component;
-/* TODO: Implement these */
-extern bool AsyncDownloader_Cookies;
-/* TODO: Connection pooling */
-
-enum REQUEST_TYPE { REQUEST_TYPE_DATA, REQUEST_TYPE_CONTENT_LENGTH };
-enum AsyncProgress {
- ASYNC_PROGRESS_NOTHING = -3,
- ASYNC_PROGRESS_MAKING_REQUEST = -2,
- ASYNC_PROGRESS_FETCHING_DATA = -1
-};
-
-struct AsyncRequest {
- char URL[URL_MAX_SIZE]; /* URL data is downloaded from/uploaded to. */
- char ID[STRING_SIZE]; /* Unique identifier for this request. */
- TimeMS TimeAdded; /* Time this request was added to queue of requests. */
- TimeMS TimeDownloaded; /* Time response contents were completely downloaded. */
- int StatusCode; /* HTTP status code returned in the response. */
- uint32_t ContentLength; /* HTTP content length returned in the response. */
-
- ReturnCode Result; /* 0 on success, otherwise platform-specific error. */
- void* Data; /* Contents of the response. */
- uint32_t Size; /* Size of the contents. */
-
- TimeMS LastModified; /* Time item cached at (if at all) */
- char Etag[STRING_SIZE]; /* ETag of cached item (if any) */
- uint8_t RequestType; /* Whether to fetch contents or just headers. */
-};
-
-void ASyncRequest_Free(struct AsyncRequest* request);
-
-void AsyncDownloader_GetSkin(const String* id, const String* skinName);
-/* Asynchronously downloads contents of a webpage. */
-void AsyncDownloader_GetData(const String* url, bool priority, const String* id);
-/* Asynchronously downloads Content Length header of a webpage. */
-void AsyncDownloader_GetContentLength(const String* url, bool priority, const String* id);
-/* TODO: Implement post */
-void AsyncDownloader_UNSAFE_PostData(const String* url, bool priority, const String* id, const void* data, const uint32_t size);
-/* Asynchronously downloads contents of a webpage. */
-/* Optionally also sets If-Modified-Since and If-None-Match headers. */
-void AsyncDownloader_GetDataEx(const String* url, bool priority, const String* id, TimeMS* lastModified, const String* etag);
-
-/* Attempts to retrieve a fully completed request. */
-/* Returns whether a request with a matching id was retrieved. */
-bool AsyncDownloader_Get(const String* id, struct AsyncRequest* item);
-/* Retrieves information about the request currently being processed. */
-/* Returns whether there is actually a request being currently processed. */
-bool AsyncDownloader_GetCurrent(struct AsyncRequest* request, int* progress);
-/* Clears the list of pending requests. */
-void AsyncDownloader_Clear(void);
-void AsyncDownloader_PurgeOldEntriesTask(struct ScheduledTask* task);
-#endif
diff --git a/src/ClassiCube.vcxproj b/src/ClassiCube.vcxproj
index 6f9aac369..5be88b25e 100644
--- a/src/ClassiCube.vcxproj
+++ b/src/ClassiCube.vcxproj
@@ -187,7 +187,7 @@
-
+
@@ -253,7 +253,7 @@
-
+
diff --git a/src/ClassiCube.vcxproj.filters b/src/ClassiCube.vcxproj.filters
index a2b9f04c2..d6f15809c 100644
--- a/src/ClassiCube.vcxproj.filters
+++ b/src/ClassiCube.vcxproj.filters
@@ -234,9 +234,6 @@
Header Files\Network
-
- Header Files\Network
-
Header Files\Game
@@ -318,6 +315,9 @@
Header Files\Platform
+
+ Header Files\Network
+
@@ -440,9 +440,6 @@
Source Files\Network
-
- Source Files\Network
-
Source Files\Rendering
@@ -566,5 +563,8 @@
Source Files\Platform
+
+ Source Files\Network
+
\ No newline at end of file
diff --git a/src/Entity.c b/src/Entity.c
index 7adecea58..95cb5b4db 100644
--- a/src/Entity.c
+++ b/src/Entity.c
@@ -11,7 +11,7 @@
#include "Lighting.h"
#include "Drawer2D.h"
#include "Particle.h"
-#include "AsyncDownloader.h"
+#include "Http.h"
#include "Chat.h"
#include "Model.h"
#include "Input.h"
@@ -688,7 +688,7 @@ static void Player_CheckSkin(struct Player* p) {
struct Player* first;
String url, skin = String_FromRawArray(e->SkinNameRaw);
- struct AsyncRequest item;
+ struct HttpRequest item;
struct Stream mem;
Bitmap bmp;
ReturnCode res;
@@ -696,14 +696,14 @@ static void Player_CheckSkin(struct Player* p) {
if (!p->FetchedSkin && e->Model->UsesSkin) {
first = Player_FirstOtherWithSameSkinAndFetchedSkin(p);
if (!first) {
- AsyncDownloader_GetSkin(&skin, &skin);
+ Http_AsyncGetSkin(&skin, &skin);
} else {
Player_CopySkin(p, first);
}
p->FetchedSkin = true;
}
- if (!AsyncDownloader_Get(&skin, &item)) return;
+ if (!Http_GetResult(&skin, &item)) return;
if (!item.Data) { Player_SetSkinAll(p, true); return; }
Stream_ReadonlyMemory(&mem, item.Data, item.Size);
diff --git a/src/Game.c b/src/Game.c
index 9329e4ee3..84eb033b3 100644
--- a/src/Game.c
+++ b/src/Game.c
@@ -18,7 +18,7 @@
#include "Drawer2D.h"
#include "Model.h"
#include "Particle.h"
-#include "AsyncDownloader.h"
+#include "Http.h"
#include "Inventory.h"
#include "InputHandler.h"
#include "ServerConnection.h"
@@ -459,7 +459,7 @@ static void Game_Load(void) {
Game_AddComponent(&Models_Component);
Game_AddComponent(&Entities_Component);
- Game_AddComponent(&AsyncDownloader_Component);
+ Game_AddComponent(&Http_Component);
Game_AddComponent(&Lighting_Component);
Game_AddComponent(&Animations_Component);
diff --git a/src/Http.c b/src/Http.c
new file mode 100644
index 000000000..6fec004f3
--- /dev/null
+++ b/src/Http.c
@@ -0,0 +1,637 @@
+#include "Http.h"
+#include "Platform.h"
+#include "Funcs.h"
+#include "Logger.h"
+#include "Stream.h"
+#include "GameStructs.h"
+
+#ifdef CC_BUILD_WIN
+#define WIN32_LEAN_AND_MEAN
+#define NOSERVICE
+#define NOMCX
+#define NOIME
+#define _WIN32_IE 0x0400
+#define WINVER 0x0500
+#define _WIN32_WINNT 0x0500
+#ifndef UNICODE
+#define UNICODE
+#define _UNICODE
+#endif
+
+#include
+#include
+
+#define HTTP_QUERY_ETAG 54 /* Missing from some old MingW32 headers */
+#endif
+/* POSIX is mainly shared between Linux and OSX */
+#ifdef CC_BUILD_POSIX
+#include
+#include
+#endif
+
+void HttpRequest_Free(struct HttpRequest* request) {
+ Mem_Free(request->Data);
+ request->Data = NULL;
+ request->Size = 0;
+}
+
+
+/*########################################################################################################################*
+*-------------------------------------------------System/Native interface-------------------------------------------------*
+*#########################################################################################################################*/
+#ifdef CC_BUILD_WIN
+static HINTERNET hInternet;
+/* TODO: Test last modified and etag even work */
+#define FLAG_STATUS HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER
+#define FLAG_LENGTH HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER
+#define FLAG_LASTMOD HTTP_QUERY_LAST_MODIFIED | HTTP_QUERY_FLAG_SYSTEMTIME
+
+static void Http_SysInit(void) {
+ /* TODO: Should we use INTERNET_OPEN_TYPE_PRECONFIG instead? */
+ hInternet = InternetOpenA(GAME_APP_NAME, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
+ if (!hInternet) Logger_Abort2(GetLastError(), "Failed to init WinINet");
+}
+
+static ReturnCode Http_SysMake(struct HttpRequest* req, HINTERNET* handle) {
+ String url = String_FromRawArray(req->URL);
+ char urlStr[URL_MAX_SIZE + 1];
+ Mem_Copy(urlStr, url.buffer, url.length);
+
+ urlStr[url.length] = '\0';
+ char headersBuffer[STRING_SIZE * 3];
+ String headers = String_FromArray(headersBuffer);
+
+ /* https://stackoverflow.com/questions/25308488/c-wininet-custom-http-headers */
+ if (req->Etag[0] || req->LastModified) {
+ if (req->LastModified) {
+ String_AppendConst(&headers, "If-Modified-Since: ");
+ DateTime_HttpDate(req->LastModified, &headers);
+ String_AppendConst(&headers, "\r\n");
+ }
+
+ if (req->Etag[0]) {
+ String etag = String_FromRawArray(req->Etag);
+ String_AppendConst(&headers, "If-None-Match: ");
+ String_AppendString(&headers, &etag);
+ String_AppendConst(&headers, "\r\n");
+ }
+
+ String_AppendConst(&headers, "\r\n\r\n");
+ headers.buffer[headers.length] = '\0';
+ } else { headers.buffer = NULL; }
+
+ *handle = InternetOpenUrlA(hInternet, urlStr, headers.buffer, headers.length,
+ INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_UI | INTERNET_FLAG_RELOAD, 0);
+ return *handle ? 0 : GetLastError();
+}
+
+static ReturnCode Http_SysGetHeaders(struct HttpRequest* req, HINTERNET handle) {
+ DWORD len;
+
+ len = sizeof(DWORD);
+ if (!HttpQueryInfoA(handle, FLAG_STATUS, &req->StatusCode, &len, NULL)) return GetLastError();
+
+ len = sizeof(DWORD);
+ HttpQueryInfoA(handle, FLAG_LENGTH, &req->ContentLength, &len, NULL);
+
+ SYSTEMTIME sysTime;
+ len = sizeof(SYSTEMTIME);
+ if (HttpQueryInfoA(handle, FLAG_LASTMOD, &sysTime, &len, NULL)) {
+ struct DateTime time;
+ time.Year = sysTime.wYear; time.Month = sysTime.wMonth;
+ time.Day = sysTime.wDay; time.Hour = sysTime.wHour;
+ time.Minute = sysTime.wMinute; time.Second = sysTime.wSecond;
+ time.Milli = sysTime.wMilliseconds;
+ req->LastModified = DateTime_TotalMs(&time);
+ }
+
+ String etag = String_ClearedArray(req->Etag);
+ len = etag.capacity;
+ HttpQueryInfoA(handle, HTTP_QUERY_ETAG, etag.buffer, &len, NULL);
+
+ return 0;
+}
+
+static ReturnCode Http_SysGetData(struct HttpRequest* req, HINTERNET handle, volatile int* progress) {
+ uint8_t* buffer;
+ uint32_t size, totalRead;
+ uint32_t read, avail;
+ bool success;
+
+ *progress = 0;
+ size = req->ContentLength ? req->ContentLength : 1;
+ buffer = Mem_Alloc(size, 1, "http get data");
+ totalRead = 0;
+
+ req->Data = buffer;
+ req->Size = 0;
+
+ for (;;) {
+ if (!InternetQueryDataAvailable(handle, &avail, 0, 0)) break;
+ if (!avail) break;
+
+ /* expand if buffer is too small (some servers don't give content length) */
+ if (totalRead + avail > size) {
+ size = totalRead + avail;
+ buffer = Mem_Realloc(buffer, size, 1, "http inc data");
+ req->Data = buffer;
+ }
+
+ success = InternetReadFile(handle, &buffer[totalRead], avail, &read);
+ if (!success) { Mem_Free(buffer); return GetLastError(); }
+ if (!read) break;
+
+ totalRead += read;
+ if (req->ContentLength) *progress = (int)(100.0f * totalRead / size);
+ req->Size += read;
+ }
+
+ *progress = 100;
+ return 0;
+}
+
+static ReturnCode Http_SysDo(struct HttpRequest* req, volatile int* progress) {
+ HINTERNET handle;
+ ReturnCode res = Http_SysMake(req, &handle);
+ if (res) return res;
+
+ *progress = ASYNC_PROGRESS_FETCHING_DATA;
+ res = Http_SysGetHeaders(req, handle);
+ if (res) { InternetCloseHandle(handle); return res; }
+
+ if (req->RequestType != REQUEST_TYPE_HEAD && req->StatusCode == 200) {
+ res = Http_SysGetData(req, handle, progress);
+ if (res) { InternetCloseHandle(handle); return res; }
+ }
+
+ return InternetCloseHandle(handle) ? 0 : GetLastError();
+}
+
+static ReturnCode Http_SysFree(void) {
+ return InternetCloseHandle(hInternet) ? 0 : GetLastError();
+}
+#endif
+#ifdef CC_BUILD_POSIX
+CURL* curl;
+
+static void Http_SysInit(void) {
+ CURLcode res = curl_global_init(CURL_GLOBAL_DEFAULT);
+ if (res) Logger_Abort2(res, "Failed to init curl");
+
+ curl = curl_easy_init();
+ if (!curl) Logger_Abort("Failed to init easy curl");
+}
+
+static int Http_SysProgress(int* progress, double total, double received, double a, double b) {
+ if (total == 0) return 0;
+ *progress = (int)(100 * received / total);
+ return 0;
+}
+
+static struct curl_slist* Http_SysMake(struct HttpRequest* req) {
+ String tmp; char buffer[STRING_SIZE + 1];
+ struct curl_slist* list = NULL;
+ String etag;
+
+ if (req->Etag[0]) {
+ String_InitArray_NT(tmp, buffer);
+ String_AppendConst(&tmp, "If-None-Match: ");
+
+ etag = String_FromRawArray(req->Etag);
+ String_AppendString(&tmp, &etag);
+ tmp.buffer[tmp.length] = '\0';
+ list = curl_slist_append(list, tmp.buffer);
+ }
+
+ if (req->LastModified) {
+ String_InitArray_NT(tmp, buffer);
+ String_AppendConst(&tmp, "Last-Modified: ");
+
+ DateTime_HttpDate(req->LastModified, &tmp);
+ tmp.buffer[tmp.length] = '\0';
+ list = curl_slist_append(list, tmp.buffer);
+ }
+ return list;
+}
+
+static size_t Http_SysGetHeaders(char *buffer, size_t size, size_t nitems, struct HttpRequest* req) {
+ String tmp; char tmpBuffer[STRING_SIZE + 1];
+ String line, name, value;
+ time_t time;
+
+ if (size != 1) return size * nitems; /* non byte header */
+ line = String_Init(buffer, nitems, nitems);
+ if (!String_UNSAFE_Separate(&line, ':', &name, &value)) return nitems;
+
+ /* value usually has \r\n at end */
+ if (value.length && value.buffer[value.length - 1] == '\n') value.length--;
+ if (value.length && value.buffer[value.length - 1] == '\r') value.length--;
+ if (!value.length) return nitems;
+
+ if (String_CaselessEqualsConst(&name, "ETag")) {
+ tmp = String_ClearedArray(req->Etag);
+ String_AppendString(&tmp, &value);
+ } else if (String_CaselessEqualsConst(&name, "Content-Length")) {
+ Convert_ParseInt(&value, &req->ContentLength);
+ /* TODO: Fix when ContentLength isn't RequestSize */
+ req->Size = req->ContentLength;
+ } else if (String_CaselessEqualsConst(&name, "Last-Modified")) {
+ String_InitArray_NT(tmp, tmpBuffer);
+ String_AppendString(&tmp, &value);
+ tmp.buffer[tmp.length] = '\0';
+
+ time = curl_getdate(tmp.buffer, NULL);
+ if (time == -1) return nitems;
+ req->LastModified = (uint64_t)time * 1000 + UNIX_EPOCH;
+ }
+ return nitems;
+}
+
+static size_t Http_SysGetData(char *buffer, size_t size, size_t nitems, struct HttpRequest* req) {
+ uint32_t total, left;
+ uint8_t* dst;
+
+ total = req->Size;
+ if (!total || req->RequestType == REQUEST_TYPE_HEAD) return 0;
+ if (!req->Data) req->Data = Mem_Alloc(total, 1, "http get data");
+
+ /* reuse Result as an offset */
+ left = total - req->Result;
+ left = min(left, nitems);
+ dst = (uint8_t*)req->Data + req->Result;
+
+ Mem_Copy(dst, buffer, left);
+ req->Result += left;
+ return nitems;
+}
+
+static ReturnCode Http_SysDo(struct HttpRequest* req, volatile int* progress) {
+ struct curl_slist* list;
+ String url = String_FromRawArray(req->URL);
+ char urlStr[600];
+ long status = 0;
+ CURLcode res;
+
+ Platform_ConvertString(urlStr, &url);
+ curl_easy_reset(curl);
+ list = Http_SysMake(req);
+ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
+
+ curl_easy_setopt(curl, CURLOPT_URL, urlStr);
+ curl_easy_setopt(curl, CURLOPT_USERAGENT, GAME_APP_NAME);
+ curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
+
+ curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
+ curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, Http_SysProgress);
+ curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, progress);
+
+ curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, Http_SysGetHeaders);
+ curl_easy_setopt(curl, CURLOPT_HEADERDATA, req);
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, Http_SysGetData);
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, req);
+
+ *progress = ASYNC_PROGRESS_FETCHING_DATA;
+ res = curl_easy_perform(curl);
+ *progress = 100;
+
+ curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
+ req->StatusCode = status;
+
+ curl_slist_free_all(list);
+ return res;
+}
+
+static ReturnCode Http_SysFree(void) {
+ curl_easy_cleanup(curl);
+ curl_global_cleanup();
+ return 0;
+}
+#endif
+
+
+/*########################################################################################################################*
+*-------------------------------------------------Asynchronous downloader-------------------------------------------------*
+*#########################################################################################################################*/
+#define HTTP_DEF_ELEMS 10
+struct HttpRequestList {
+ int MaxElems, Count;
+ struct HttpRequest* Requests;
+ struct HttpRequest DefaultRequests[HTTP_DEF_ELEMS];
+};
+
+static void HttpRequestList_EnsureSpace(struct HttpRequestList* list) {
+ if (list->Count < list->MaxElems) return;
+ list->Requests = Utils_Resize(list->Requests, &list->MaxElems,
+ sizeof(struct HttpRequest), HTTP_DEF_ELEMS, 10);
+}
+
+static void HttpRequestList_Append(struct HttpRequestList* list, struct HttpRequest* item) {
+ HttpRequestList_EnsureSpace(list);
+ list->Requests[list->Count++] = *item;
+}
+
+static void HttpRequestList_Prepend(struct HttpRequestList* list, struct HttpRequest* item) {
+ int i;
+ HttpRequestList_EnsureSpace(list);
+
+ for (i = list->Count; i > 0; i--) {
+ list->Requests[i] = list->Requests[i - 1];
+ }
+ list->Requests[0] = *item;
+ list->Count++;
+}
+
+static void HttpRequestList_RemoveAt(struct HttpRequestList* list, int i) {
+ if (i < 0 || i >= list->Count) Logger_Abort("Tried to remove element at list end");
+
+ for (; i < list->Count - 1; i++) {
+ list->Requests[i] = list->Requests[i + 1];
+ }
+ list->Count--;
+}
+
+static void HttpRequestList_Init(struct HttpRequestList* list) {
+ list->MaxElems = HTTP_DEF_ELEMS;
+ list->Count = 0;
+ list->Requests = list->DefaultRequests;
+}
+
+static void HttpRequestList_Free(struct HttpRequestList* list) {
+ if (list->Requests != list->DefaultRequests) {
+ Mem_Free(list->Requests);
+ }
+ HttpRequestList_Init(list);
+}
+
+static void* http_waitable;
+static void* http_workerThread;
+static void* http_pendingMutex;
+static void* http_processedMutex;
+static void* http_curRequestMutex;
+static volatile bool http_terminate;
+
+static struct HttpRequestList http_pending;
+static struct HttpRequestList http_processed;
+const static String http_skinServer = String_FromConst("http://static.classicube.net/skins/");
+static struct HttpRequest http_curRequest;
+static volatile int http_curProgress = ASYNC_PROGRESS_NOTHING;
+bool Http_UseCookies;
+
+/* Adds a request to the list of pending requests, waking up worker thread if needed. */
+static void Http_Add(const String* url, bool priority, const String* id, uint8_t type, TimeMS* lastModified, const String* etag, const String* data) {
+ struct HttpRequest req = { 0 };
+ String reqUrl, reqID, reqEtag;
+
+ String_InitArray(reqUrl, req.URL);
+ String_Copy(&reqUrl, url);
+ String_InitArray(reqID, req.ID);
+ String_Copy(&reqID, id);
+
+ req.RequestType = type;
+ Platform_Log2("Adding %s (type %b)", &reqUrl, &type);
+
+ String_InitArray(reqEtag, req.Etag);
+ if (lastModified) { req.LastModified = *lastModified; }
+ if (etag) { String_Copy(&reqEtag, etag); }
+ /* request.Data = data; TODO: Implement this. do we need to copy or expect caller to malloc it? */
+
+ Mutex_Lock(http_pendingMutex);
+ {
+ req.TimeAdded = DateTime_CurrentUTC_MS();
+ if (priority) {
+ HttpRequestList_Prepend(&http_pending, &req);
+ } else {
+ HttpRequestList_Append(&http_pending, &req);
+ }
+ }
+ Mutex_Unlock(http_pendingMutex);
+ Waitable_Signal(http_waitable);
+}
+
+void Http_AsyncGetSkin(const String* id, const String* skinName) {
+ String url; char urlBuffer[STRING_SIZE];
+ String_InitArray(url, urlBuffer);
+
+ if (Utils_IsUrlPrefix(skinName, 0)) {
+ String_Copy(&url, skinName);
+ } else {
+ String_AppendString(&url, &http_skinServer);
+ String_AppendColorless(&url, skinName);
+ String_AppendConst(&url, ".png");
+ }
+
+ Http_Add(&url, false, id, REQUEST_TYPE_GET, NULL, NULL, NULL);
+}
+
+void Http_AsyncGetData(const String* url, bool priority, const String* id) {
+ Http_Add(url, priority, id, REQUEST_TYPE_GET, NULL, NULL, NULL);
+}
+
+void Http_AsyncGetHeaders(const String* url, bool priority, const String* id) {
+ Http_Add(url, priority, id, REQUEST_TYPE_HEAD, NULL, NULL, NULL);
+}
+
+void AsyncDownloader_PostString(const String* url, bool priority, const String* id, const String* contents) {
+ Http_Add(url, priority, id, REQUEST_TYPE_GET, NULL, NULL, contents);
+}
+
+void Http_AsyncGetDataEx(const String* url, bool priority, const String* id, TimeMS* lastModified, const String* etag) {
+ Http_Add(url, priority, id, REQUEST_TYPE_GET, lastModified, etag, NULL);
+}
+
+void Http_PurgeOldEntriesTask(struct ScheduledTask* task) {
+ struct HttpRequest* item;
+ int i;
+
+ Mutex_Lock(http_processedMutex);
+ {
+ TimeMS now = DateTime_CurrentUTC_MS();
+ for (i = http_processed.Count - 1; i >= 0; i--) {
+ item = &http_processed.Requests[i];
+ if (item->TimeDownloaded + (10 * 1000) >= now) continue;
+
+ HttpRequest_Free(item);
+ HttpRequestList_RemoveAt(&http_processed, i);
+ }
+ }
+ Mutex_Unlock(http_processedMutex);
+}
+
+static int HttpRequestList_Find(const String* id, struct HttpRequest* item) {
+ String reqID;
+ int i;
+
+ for (i = 0; i < http_processed.Count; i++) {
+ reqID = String_FromRawArray(http_processed.Requests[i].ID);
+ if (!String_Equals(id, &reqID)) continue;
+
+ *item = http_processed.Requests[i];
+ return i;
+ }
+ return -1;
+}
+
+bool Http_GetResult(const String* id, struct HttpRequest* item) {
+ int i;
+ Mutex_Lock(http_processedMutex);
+ {
+ i = HttpRequestList_Find(id, item);
+ if (i >= 0) HttpRequestList_RemoveAt(&http_processed, i);
+ }
+ Mutex_Unlock(http_processedMutex);
+ return i >= 0;
+}
+
+bool Http_GetCurrent(struct HttpRequest* request, int* progress) {
+ Mutex_Lock(http_curRequestMutex);
+ {
+ *request = http_curRequest;
+ *progress = http_curProgress;
+ }
+ Mutex_Unlock(http_curRequestMutex);
+ return request->ID[0];
+}
+
+void Http_ClearPending(void) {
+ Mutex_Lock(http_pendingMutex);
+ {
+ HttpRequestList_Free(&http_pending);
+ }
+ Mutex_Unlock(http_pendingMutex);
+ Waitable_Signal(http_waitable);
+}
+
+static void Http_ProcessRequest(struct HttpRequest* request) {
+ String url = String_FromRawArray(request->URL);
+ uint64_t beg, end;
+ uint32_t size, elapsed;
+ uintptr_t addr;
+
+ Platform_Log2("Downloading from %s (type %b)", &url, &request->RequestType);
+ beg = Stopwatch_Measure();
+ request->Result = Http_SysDo(request, &http_curProgress);
+ end = Stopwatch_Measure();
+
+ elapsed = Stopwatch_ElapsedMicroseconds(beg, end) / 1000;
+ Platform_Log3("HTTP: return code %i (http %i), in %i ms",
+ &request->Result, &request->StatusCode, &elapsed);
+
+ if (request->Data) {
+ size = request->Size;
+ addr = (uintptr_t)request->Data;
+ Platform_Log2("HTTP returned data: %i bytes at %x", &size, &addr);
+ }
+}
+
+static void Http_CompleteResult(struct HttpRequest* request) {
+ struct HttpRequest older;
+ String id = String_FromRawArray(request->ID);
+ int index;
+ request->TimeDownloaded = DateTime_CurrentUTC_MS();
+
+ index = HttpRequestList_Find(&id, &older);
+ if (index >= 0) {
+ /* very rare case - priority item was inserted, then inserted again (so put before first item), */
+ /* and both items got downloaded before an external function removed them from the queue */
+ if (older.TimeAdded > request->TimeAdded) {
+ HttpRequest_Free(request);
+ } else {
+ /* normal case, replace older request */
+ HttpRequest_Free(&older);
+ http_processed.Requests[index] = *request;
+ }
+ } else {
+ HttpRequestList_Append(&http_processed, request);
+ }
+}
+
+static void Http_WorkerLoop(void) {
+ struct HttpRequest request;
+ bool hasRequest, stop;
+
+ for (;;) {
+ hasRequest = false;
+
+ Mutex_Lock(http_pendingMutex);
+ {
+ stop = http_terminate;
+ if (!stop && http_pending.Count) {
+ request = http_pending.Requests[0];
+ hasRequest = true;
+ HttpRequestList_RemoveAt(&http_pending, 0);
+ }
+ }
+ Mutex_Unlock(http_pendingMutex);
+
+ if (stop) return;
+ /* Block until another thread submits a request to do */
+ if (!hasRequest) {
+ Platform_LogConst("Going back to sleep...");
+ Waitable_Wait(http_waitable);
+ continue;
+ }
+
+ Platform_LogConst("Got something to do!");
+ Mutex_Lock(http_curRequestMutex);
+ {
+ http_curRequest = request;
+ http_curProgress = ASYNC_PROGRESS_MAKING_REQUEST;
+ }
+ Mutex_Unlock(http_curRequestMutex);
+
+ Platform_LogConst("Doing it");
+ /* performing request doesn't need thread safety */
+ Http_ProcessRequest(&request);
+
+ Mutex_Lock(http_processedMutex);
+ {
+ Http_CompleteResult(&request);
+ }
+ Mutex_Unlock(http_processedMutex);
+
+ Mutex_Lock(http_curRequestMutex);
+ {
+ http_curRequest.ID[0] = '\0';
+ http_curProgress = ASYNC_PROGRESS_NOTHING;
+ }
+ Mutex_Unlock(http_curRequestMutex);
+ }
+}
+
+
+/*########################################################################################################################*
+*-----------------------------------------------------Http component------------------------------------------------------*
+*#########################################################################################################################*/
+static void Http_Init(void) {
+ ScheduledTask_Add(30, Http_PurgeOldEntriesTask);
+ HttpRequestList_Init(&http_pending);
+ HttpRequestList_Init(&http_processed);
+ Http_SysInit();
+
+ http_waitable = Waitable_Create();
+ http_pendingMutex = Mutex_Create();
+ http_processedMutex = Mutex_Create();
+ http_curRequestMutex = Mutex_Create();
+ http_workerThread = Thread_Start(Http_WorkerLoop, false);
+}
+
+static void Http_Free(void) {
+ http_terminate = true;
+ Http_ClearPending();
+ Thread_Join(http_workerThread);
+
+ HttpRequestList_Free(&http_pending);
+ HttpRequestList_Free(&http_processed);
+ Http_SysFree();
+
+ Waitable_Free(http_waitable);
+ Mutex_Free(http_pendingMutex);
+ Mutex_Free(http_processedMutex);
+ Mutex_Free(http_curRequestMutex);
+}
+
+struct IGameComponent Http_Component = {
+ Http_Init, /* Init */
+ Http_Free, /* Free */
+ Http_ClearPending /* Reset */
+};
diff --git a/src/Http.h b/src/Http.h
new file mode 100644
index 000000000..7fbfd6a17
--- /dev/null
+++ b/src/Http.h
@@ -0,0 +1,70 @@
+#ifndef CC_HTTP_H
+#define CC_HTTP_H
+#include "Constants.h"
+#include "Utils.h"
+/* Aysnchronously performs http GET, HEAD, and POST requests.
+ Typically this is used to download skins, texture packs, etc.
+ Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
+*/
+struct IGameComponent;
+struct ScheduledTask;
+#define URL_MAX_SIZE (STRING_SIZE * 2)
+
+extern struct IGameComponent Http_Component;
+/* TODO: Implement these */
+extern bool Http_UseCookies;
+/* TODO: Connection pooling */
+
+enum HttpRequestType { REQUEST_TYPE_GET, REQUEST_TYPE_HEAD };
+enum HttpProgress {
+ ASYNC_PROGRESS_NOTHING = -3,
+ ASYNC_PROGRESS_MAKING_REQUEST = -2,
+ ASYNC_PROGRESS_FETCHING_DATA = -1
+};
+
+struct HttpRequest {
+ char URL[URL_MAX_SIZE]; /* URL data is downloaded from/uploaded to. */
+ char ID[STRING_SIZE]; /* Unique identifier for this request. */
+ TimeMS TimeAdded; /* Time this request was added to queue of requests. */
+ TimeMS TimeDownloaded; /* Time response contents were completely downloaded. */
+ int StatusCode; /* HTTP status code returned in the response. */
+ uint32_t ContentLength; /* HTTP content length returned in the response. */
+
+ ReturnCode Result; /* 0 on success, otherwise platform-specific error. */
+ void* Data; /* Contents of the response. (i.e. result data) */
+ uint32_t Size; /* Size of the contents. */
+
+ TimeMS LastModified; /* Time item cached at (if at all) */
+ char Etag[STRING_SIZE]; /* ETag of cached item (if any) */
+ uint8_t RequestType; /* Whether to fetch contents or just headers. */
+};
+
+/* Frees data from a HTTP request. */
+void HttpRequest_Free(struct HttpRequest* request);
+
+/* Aschronously performs a http GET request to download a skin. */
+/* If url is a skin, this is the same as Http_AsyncGetData. */
+/* If not, instead downloads from http://static.classicube.net/skins/[skinName].png */
+void Http_AsyncGetSkin(const String* id, const String* skinName);
+/* Asynchronously performs a http GET request. (e.g. to download data) */
+void Http_AsyncGetData(const String* url, bool priority, const String* id);
+/* Asynchronously performs a http HEAD request. (e.g. to get Content-Length header) */
+void Http_AsyncGetHeaders(const String* url, bool priority, const String* id);
+/* Asynchronously performs a http POST request. (e.g. to submit data) */
+/* NOTE: data and size MUST PERSIST until the request is completed. */
+/* TODO: maybe we shouldn't force that.. instead mem alloc data and size */
+void Http_AsyncPostData(const String* url, bool priority, const String* id, const void* data, const uint32_t size);
+/* Asynchronously performs a http GET request. (e.g. to download data) */
+/* Also sets the If-Modified-Since and If-None-Match headers. (if not NULL) */
+void Http_AsyncGetDataEx(const String* url, bool priority, const String* id, TimeMS* lastModified, const String* etag);
+
+/* Attempts to retrieve a fully completed request. */
+/* NOTE: You MUST also check Result/StatusCode, and check Size is > 0. */
+/* (because a completed request may not have completed successfully) */
+bool Http_GetResult(const String* id, struct HttpRequest* item);
+/* Retrieves information about the request currently being processed. */
+bool Http_GetCurrent(struct HttpRequest* request, int* progress);
+/* Clears the list of pending requests. */
+void Http_ClearPending(void);
+void Http_PurgeOldEntriesTask(struct ScheduledTask* task);
+#endif
diff --git a/src/LScreens.c b/src/LScreens.c
index 090ba3e58..83f3080ee 100644
--- a/src/LScreens.c
+++ b/src/LScreens.c
@@ -949,7 +949,7 @@ static void ResourcesScreen_Download(void* w, int x, int y) {
static void ResourcesScreen_Next(void* w, int x, int y) {
const static String optionsTxt = String_FromConst("options.txt");
- AsyncDownloader_Clear();
+ Http_ClearPending();
if (File_Exists(&optionsTxt)) {
Launcher_SetScreen(MainScreen_MakeInstance());
@@ -1036,7 +1036,7 @@ static void ResourcesScreen_SetStatus(const String* str) {
LWidget_Draw(w);
}
-static void ResourcesScreen_UpdateStatus(struct AsyncRequest* req) {
+static void ResourcesScreen_UpdateStatus(struct HttpRequest* req) {
String str; char strBuffer[STRING_SIZE];
String id;
BitmapCol boxCol = BITMAPCOL_CONST(120, 85, 151, 255);
@@ -1053,10 +1053,10 @@ static void ResourcesScreen_UpdateStatus(struct AsyncRequest* req) {
}
static void ResourcesScreen_UpdateProgress(struct ResourcesScreen* s) {
- struct AsyncRequest req;
+ struct HttpRequest req;
int progress;
- if (!AsyncDownloader_GetCurrent(&req, &progress)) return;
+ if (!Http_GetCurrent(&req, &progress)) return;
ResourcesScreen_UpdateStatus(&req);
/* making request still, haven't started download yet */
if (progress < 0 || progress > 100) return;
@@ -1386,9 +1386,9 @@ static void UpdatesScreen_CheckTick(struct UpdatesScreen* s) {
static void UpdatesScreen_UpdateProgress(struct UpdatesScreen* s, struct LWebTask* task) {
String str; char strBuffer[STRING_SIZE];
String identifier;
- struct AsyncRequest item;
+ struct HttpRequest item;
int progress;
- if (!AsyncDownloader_GetCurrent(&item, &progress)) return;
+ if (!Http_GetCurrent(&item, &progress)) return;
identifier = String_FromRawArray(item.ID);
if (!String_Equals(&identifier, &task->Identifier)) return;
diff --git a/src/LScreens.h b/src/LScreens.h
index 5da62ee46..2ca626fd9 100644
--- a/src/LScreens.h
+++ b/src/LScreens.h
@@ -1,6 +1,6 @@
#ifndef CC_LSCREENS_H
#define CC_LSCREENS_H
-#include "AsyncDownloader.h"
+#include "Http.h"
#include "String.h"
#include "Input.h"
/* Implements screens/menus for the launcher.
diff --git a/src/LWeb.c b/src/LWeb.c
index 8065c50c7..aeb0c9fcb 100644
--- a/src/LWeb.c
+++ b/src/LWeb.c
@@ -206,11 +206,11 @@ static void LWebTask_Reset(struct LWebTask* task) {
}
void LWebTask_Tick(struct LWebTask* task) {
- struct AsyncRequest req;
+ struct HttpRequest req;
int delta;
if (task->Completed) return;
- if (!AsyncDownloader_Get(&task->Identifier, &req)) return;
+ if (!Http_GetResult(&task->Identifier, &req)) return;
delta = (int)(DateTime_CurrentUTC_MS() - task->Start);
Platform_Log2("%s took %i", &task->Identifier, &delta);
@@ -221,7 +221,7 @@ void LWebTask_Tick(struct LWebTask* task) {
task->Completed = true;
task->Success = !task->Res && req.Data && req.Size;
if (task->Success) task->Handle(req.Data, req.Size);
- ASyncRequest_Free(&req);
+ HttpRequest_Free(&req);
}
@@ -249,7 +249,7 @@ void GetTokenTask_Run(void) {
String_InitArray(GetTokenTask.Token, tokenBuffer);
GetTokenTask.Base.Identifier = id;
- AsyncDownloader_GetData(&url, false, &id);
+ Http_AsyncGetData(&url, false, &id);
GetTokenTask.Base.Handle = GetTokenTask_Handle;
}
@@ -282,7 +282,7 @@ void SignInTask_Run(const String* user, const String* pass) {
String_Copy(&SignInTask.Username, user);
SignInTask.Base.Identifier = id;
- AsyncDownloader_GetData(&url, false, &id);
+ Http_AsyncGetData(&url, false, &id);
SignInTask.Base.Handle = SignInTask_Handle;
}
// NOTE: Remember to add &c for errors here too
@@ -353,7 +353,7 @@ void FetchServerTask_Run(const String* hash) {
String_Format1(&url, "https://www.classicube.net/api/server/%s", hash);
FetchServerTask.Base.Identifier = id;
- AsyncDownloader_GetData(&url, false, &id);
+ Http_AsyncGetData(&url, false, &id);
FetchServerTask.Base.Handle = FetchServerTask_Handle;
}
@@ -396,7 +396,7 @@ void FetchServersTask_Run(void) {
FetchServersTask.NumServers = 0;
FetchServersTask.Base.Identifier = id;
- AsyncDownloader_GetData(&url, false, &id);
+ Http_AsyncGetData(&url, false, &id);
FetchServersTask.Base.Handle = FetchServersTask_Handle;
}
@@ -444,7 +444,7 @@ void CheckUpdateTask_Run(void) {
String_InitArray(CheckUpdateTask.LatestRelease, relVersionBuffer);
CheckUpdateTask.Base.Identifier = id;
- AsyncDownloader_GetData(&url, false, &id);
+ Http_AsyncGetData(&url, false, &id);
CheckUpdateTask.Base.Handle = CheckUpdateTask_Handle;
}
@@ -494,7 +494,7 @@ void FetchUpdateTask_Run(bool release, bool d3d9) {
FetchUpdateTask.Timestamp = release ? CheckUpdateTask.RelTimestamp : CheckUpdateTask.DevTimestamp;
FetchUpdateTask.Base.Identifier = id;
- AsyncDownloader_GetData(&url, false, &id);
+ Http_AsyncGetData(&url, false, &id);
FetchUpdateTask.Base.Handle = FetchUpdateTask_Handle;
}
diff --git a/src/LWeb.h b/src/LWeb.h
index d80d9787e..da8efee25 100644
--- a/src/LWeb.h
+++ b/src/LWeb.h
@@ -1,6 +1,6 @@
#ifndef CC_LWEB_H
#define CC_LWEB_H
-#include "AsyncDownloader.h"
+#include "Http.h"
#include "String.h"
/* Implements asynchronous web tasks for the launcher.
Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
diff --git a/src/Launcher.c b/src/Launcher.c
index b9200bd9e..213fb4e91 100644
--- a/src/Launcher.c
+++ b/src/Launcher.c
@@ -11,7 +11,7 @@
#include "Window.h"
#include "GameStructs.h"
#include "Event.h"
-#include "AsyncDownloader.h"
+#include "Http.h"
#include "ExtMath.h"
#include "Funcs.h"
#include "Logger.h"
@@ -234,8 +234,8 @@ void Launcher_Run(void) {
Launcher_Framebuffer.Height = Game_Height;
Window_InitRaw(&Launcher_Framebuffer);
- AsyncDownloader_Cookies = true;
- AsyncDownloader_Component.Init();
+ Http_UseCookies = true;
+ Http_Component.Init();
Resources_CheckExistence();
CheckUpdateTask_Run();
diff --git a/src/Menus.c b/src/Menus.c
index 1889b0a99..2c54a86d4 100644
--- a/src/Menus.c
+++ b/src/Menus.c
@@ -14,7 +14,7 @@
#include "ExtMath.h"
#include "Window.h"
#include "Camera.h"
-#include "AsyncDownloader.h"
+#include "Http.h"
#include "Block.h"
#include "World.h"
#include "Formats.h"
@@ -3251,11 +3251,11 @@ static void TexPackOverlay_NoClick(void* screen, void* widget) {
}
static void TexPackOverlay_Render(void* screen, double delta) {
- struct AsyncRequest item;
+ struct HttpRequest item;
struct TexPackOverlay* s = screen;
MenuScreen_Render(s, delta);
- if (!AsyncDownloader_Get(&s->Identifier, &item)) return;
+ if (!Http_GetResult(&s->Identifier, &item)) return;
s->ContentLength = item.ContentLength;
if (!s->ContentLength) return;
@@ -3326,7 +3326,7 @@ struct Screen* TexPackOverlay_MakeInstance(const String* url) {
String_Format1(&s->Identifier, "CL_%s", url);
s->ContentLength = 0;
- AsyncDownloader_GetContentLength(url, true, &s->Identifier);
+ Http_AsyncGetHeaders(url, true, &s->Identifier);
s->VTABLE = &TexPackOverlay_VTABLE;
return (struct Screen*)s;
}
diff --git a/src/PacketHandlers.c b/src/PacketHandlers.c
index 10f442459..8de11e6e8 100644
--- a/src/PacketHandlers.c
+++ b/src/PacketHandlers.c
@@ -17,7 +17,7 @@
#include "Model.h"
#include "Funcs.h"
#include "Lighting.h"
-#include "AsyncDownloader.h"
+#include "Http.h"
#include "Drawer2D.h"
#include "Logger.h"
#include "TexturePack.h"
@@ -243,7 +243,7 @@ static void WoM_CheckMotd(void) {
applied in the new world if the async 'get env request' didn't complete before the old world was unloaded */
wom_counter++;
WoM_UpdateIdentifier();
- AsyncDownloader_GetData(&url, true, &wom_identifier);
+ Http_AsyncGetData(&url, true, &wom_identifier);
wom_sendId = true;
}
@@ -268,7 +268,7 @@ static PackedCol WoM_ParseCol(const String* value, PackedCol defaultCol) {
return col;
}
-static void WoM_ParseConfig(struct AsyncRequest* item) {
+static void WoM_ParseConfig(struct HttpRequest* item) {
String line; char lineBuffer[STRING_SIZE * 2];
struct Stream mem;
String key, value;
@@ -308,11 +308,11 @@ static void WoM_Reset(void) {
}
static void WoM_Tick(void) {
- struct AsyncRequest item;
- if (!AsyncDownloader_Get(&wom_identifier, &item)) return;
+ struct HttpRequest item;
+ if (!Http_GetResult(&wom_identifier, &item)) return;
if (item.Data) WoM_ParseConfig(&item);
- ASyncRequest_Free(&item);
+ HttpRequest_Free(&item);
}
diff --git a/src/Platform.c b/src/Platform.c
index ee9ebcfa1..58cc4e1da 100644
--- a/src/Platform.c
+++ b/src/Platform.c
@@ -4,7 +4,7 @@
#include "ExtMath.h"
#include "Drawer2D.h"
#include "Funcs.h"
-#include "AsyncDownloader.h"
+#include "Http.h"
#include "Bitmap.h"
#include "Window.h"
@@ -1320,276 +1320,6 @@ ReturnCode Socket_Poll(SocketHandle socket, int mode, bool* success) {
#endif
-/*########################################################################################################################*
-*----------------------------------------------------------Http-----------------------------------------------------------*
-*#########################################################################################################################*/
-#ifdef CC_BUILD_WIN
-static HINTERNET hInternet;
-/* TODO: Test last modified and etag even work */
-#define FLAG_STATUS HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER
-#define FLAG_LENGTH HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER
-#define FLAG_LASTMOD HTTP_QUERY_LAST_MODIFIED | HTTP_QUERY_FLAG_SYSTEMTIME
-
-void Http_Init(void) {
- /* TODO: Should we use INTERNET_OPEN_TYPE_PRECONFIG instead? */
- hInternet = InternetOpenA(GAME_APP_NAME, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
- if (!hInternet) Logger_Abort2(GetLastError(), "Failed to init WinINet");
-}
-
-static ReturnCode Http_Make(struct AsyncRequest* req, HINTERNET* handle) {
- String url = String_FromRawArray(req->URL);
- char urlStr[URL_MAX_SIZE + 1];
- Mem_Copy(urlStr, url.buffer, url.length);
-
- urlStr[url.length] = '\0';
- char headersBuffer[STRING_SIZE * 3];
- String headers = String_FromArray(headersBuffer);
-
- /* https://stackoverflow.com/questions/25308488/c-wininet-custom-http-headers */
- if (req->Etag[0] || req->LastModified) {
- if (req->LastModified) {
- String_AppendConst(&headers, "If-Modified-Since: ");
- DateTime_HttpDate(req->LastModified, &headers);
- String_AppendConst(&headers, "\r\n");
- }
-
- if (req->Etag[0]) {
- String etag = String_FromRawArray(req->Etag);
- String_AppendConst(&headers, "If-None-Match: ");
- String_AppendString(&headers, &etag);
- String_AppendConst(&headers, "\r\n");
- }
-
- String_AppendConst(&headers, "\r\n\r\n");
- headers.buffer[headers.length] = '\0';
- } else { headers.buffer = NULL; }
-
- *handle = InternetOpenUrlA(hInternet, urlStr, headers.buffer, headers.length,
- INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_UI | INTERNET_FLAG_RELOAD, 0);
- return *handle ? 0 : GetLastError();
-}
-
-static ReturnCode Http_GetHeaders(struct AsyncRequest* req, HINTERNET handle) {
- DWORD len;
-
- len = sizeof(DWORD);
- if (!HttpQueryInfoA(handle, FLAG_STATUS, &req->StatusCode, &len, NULL)) return GetLastError();
-
- len = sizeof(DWORD);
- HttpQueryInfoA(handle, FLAG_LENGTH, &req->ContentLength, &len, NULL);
-
- SYSTEMTIME sysTime;
- len = sizeof(SYSTEMTIME);
- if (HttpQueryInfoA(handle, FLAG_LASTMOD, &sysTime, &len, NULL)) {
- struct DateTime time;
- Platform_FromSysTime(&time, &sysTime);
- req->LastModified = DateTime_TotalMs(&time);
- }
-
- String etag = String_ClearedArray(req->Etag);
- len = etag.capacity;
- HttpQueryInfoA(handle, HTTP_QUERY_ETAG, etag.buffer, &len, NULL);
-
- return 0;
-}
-
-static ReturnCode Http_GetData(struct AsyncRequest* req, HINTERNET handle, volatile int* progress) {
- uint8_t* buffer;
- uint32_t size, totalRead;
- uint32_t read, avail;
- bool success;
-
- *progress = 0;
- size = req->ContentLength ? req->ContentLength : 1;
- buffer = Mem_Alloc(size, 1, "http get data");
- totalRead = 0;
-
- req->Data = buffer;
- req->Size = 0;
-
- for (;;) {
- if (!InternetQueryDataAvailable(handle, &avail, 0, 0)) break;
- if (!avail) break;
-
- /* expand if buffer is too small (some servers don't give content length) */
- if (totalRead + avail > size) {
- size = totalRead + avail;
- buffer = Mem_Realloc(buffer, size, 1, "http inc data");
- req->Data = buffer;
- }
-
- success = InternetReadFile(handle, &buffer[totalRead], avail, &read);
- if (!success) { Mem_Free(buffer); return GetLastError(); }
- if (!read) break;
-
- totalRead += read;
- if (req->ContentLength) *progress = (int)(100.0f * totalRead / size);
- req->Size += read;
- }
-
- *progress = 100;
- return 0;
-}
-
-ReturnCode Http_Do(struct AsyncRequest* req, volatile int* progress) {
- HINTERNET handle;
- ReturnCode res = Http_Make(req, &handle);
- if (res) return res;
-
- *progress = ASYNC_PROGRESS_FETCHING_DATA;
- res = Http_GetHeaders(req, handle);
- if (res) { InternetCloseHandle(handle); return res; }
-
- if (req->RequestType != REQUEST_TYPE_CONTENT_LENGTH && req->StatusCode == 200) {
- res = Http_GetData(req, handle, progress);
- if (res) { InternetCloseHandle(handle); return res; }
- }
-
- return InternetCloseHandle(handle) ? 0 : GetLastError();
-}
-
-ReturnCode Http_Free(void) {
- return InternetCloseHandle(hInternet) ? 0 : GetLastError();
-}
-#endif
-#ifdef CC_BUILD_POSIX
-CURL* curl;
-
-void Http_Init(void) {
- CURLcode res = curl_global_init(CURL_GLOBAL_DEFAULT);
- if (res) Logger_Abort2(res, "Failed to init curl");
-
- curl = curl_easy_init();
- if (!curl) Logger_Abort("Failed to init easy curl");
-}
-
-static int Http_Progress(int* progress, double total, double received, double a, double b) {
- if (total == 0) return 0;
- *progress = (int)(100 * received / total);
- return 0;
-}
-
-static struct curl_slist* Http_Make(struct AsyncRequest* req) {
- String tmp; char buffer[STRING_SIZE + 1];
- struct curl_slist* list = NULL;
- String etag;
-
- if (req->Etag[0]) {
- String_InitArray_NT(tmp, buffer);
- String_AppendConst(&tmp, "If-None-Match: ");
-
- etag = String_FromRawArray(req->Etag);
- String_AppendString(&tmp, &etag);
- tmp.buffer[tmp.length] = '\0';
- list = curl_slist_append(list, tmp.buffer);
- }
-
- if (req->LastModified) {
- String_InitArray_NT(tmp, buffer);
- String_AppendConst(&tmp, "Last-Modified: ");
-
- DateTime_HttpDate(req->LastModified, &tmp);
- tmp.buffer[tmp.length] = '\0';
- list = curl_slist_append(list, tmp.buffer);
- }
- return list;
-}
-
-static size_t Http_GetHeaders(char *buffer, size_t size, size_t nitems, struct AsyncRequest* req) {
- String tmp; char tmpBuffer[STRING_SIZE + 1];
- String line, name, value;
- time_t time;
-
- if (size != 1) return size * nitems; /* non byte header */
- line = String_Init(buffer, nitems, nitems);
- if (!String_UNSAFE_Separate(&line, ':', &name, &value)) return nitems;
-
- /* value usually has \r\n at end */
- if (value.length && value.buffer[value.length - 1] == '\n') value.length--;
- if (value.length && value.buffer[value.length - 1] == '\r') value.length--;
- if (!value.length) return nitems;
-
- if (String_CaselessEqualsConst(&name, "ETag")) {
- tmp = String_ClearedArray(req->Etag);
- String_AppendString(&tmp, &value);
- } else if (String_CaselessEqualsConst(&name, "Content-Length")) {
- Convert_ParseInt(&value, &req->ContentLength);
- /* TODO: Fix when ContentLength isn't RequestSize */
- req->Size = req->ContentLength;
- } else if (String_CaselessEqualsConst(&name, "Last-Modified")) {
- String_InitArray_NT(tmp, tmpBuffer);
- String_AppendString(&tmp, &value);
- tmp.buffer[tmp.length] = '\0';
-
- time = curl_getdate(tmp.buffer, NULL);
- if (time == -1) return nitems;
- req->LastModified = (uint64_t)time * 1000 + UNIX_EPOCH;
- }
- return nitems;
-}
-
-static size_t Http_GetData(char *buffer, size_t size, size_t nitems, struct AsyncRequest* req) {
- uint32_t total, left;
- uint8_t* dst;
-
- total = req->Size;
- if (!total || req->RequestType == REQUEST_TYPE_CONTENT_LENGTH) return 0;
- if (!req->Data) req->Data = Mem_Alloc(total, 1, "http get data");
-
- /* reuse Result as an offset */
- left = total - req->Result;
- left = min(left, nitems);
- dst = (uint8_t*)req->Data + req->Result;
-
- Mem_Copy(dst, buffer, left);
- req->Result += left;
- return nitems;
-}
-
-ReturnCode Http_Do(struct AsyncRequest* req, volatile int* progress) {
- struct curl_slist* list;
- String url = String_FromRawArray(req->URL);
- char urlStr[600];
- long status = 0;
- CURLcode res;
-
- Platform_ConvertString(urlStr, &url);
- curl_easy_reset(curl);
- list = Http_Make(req);
- curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
-
- curl_easy_setopt(curl, CURLOPT_URL, urlStr);
- curl_easy_setopt(curl, CURLOPT_USERAGENT, GAME_APP_NAME);
- curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
-
- curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
- curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, Http_Progress);
- curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, progress);
-
- curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, Http_GetHeaders);
- curl_easy_setopt(curl, CURLOPT_HEADERDATA, req);
- curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, Http_GetData);
- curl_easy_setopt(curl, CURLOPT_WRITEDATA, req);
-
- *progress = ASYNC_PROGRESS_FETCHING_DATA;
- res = curl_easy_perform(curl);
- *progress = 100;
-
- curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
- req->StatusCode = status;
-
- curl_slist_free_all(list);
- return res;
-}
-
-ReturnCode Http_Free(void) {
- curl_easy_cleanup(curl);
- curl_global_cleanup();
- return 0;
-}
-#endif
-
-
/*########################################################################################################################*
*----------------------------------------------------------Audio----------------------------------------------------------*
*#########################################################################################################################*/
diff --git a/src/Platform.h b/src/Platform.h
index 1ea928797..ff0606cc3 100644
--- a/src/Platform.h
+++ b/src/Platform.h
@@ -6,7 +6,7 @@
Copyright 2017 ClassicalSharp | Licensed under BSD-3
*/
struct DrawTextArgs;
-struct AsyncRequest;
+struct HttpRequest;
struct DateTime;
enum Socket_PollMode { SOCKET_POLL_READ, SOCKET_POLL_WRITE };
@@ -221,14 +221,6 @@ ReturnCode Socket_Close(SocketHandle socket);
/* NOTE: A socket is considered writable once it has finished connecting. */
ReturnCode Socket_Poll(SocketHandle socket, int mode, bool* success);
-/* Initalises the platform specific http library state. */
-void Http_Init(void);
-/* Performs a http request, setting progress as data is received. */
-/* NOTE: NOT thread safe - you should ALWAYS use AsyncDownloader for making requests. */
-ReturnCode Http_Do(struct AsyncRequest* req, volatile int* progress);
-/* Frees the platform specific http library state. */
-ReturnCode Http_Free(void);
-
#define AUDIO_MAX_BUFFERS 4
/* Information about a source of audio. */
struct AudioFormat { uint16_t Channels, BitsPerSample; int SampleRate; };
diff --git a/src/Program.c b/src/Program.c
index 3e21e38b9..130291102 100644
--- a/src/Program.c
+++ b/src/Program.c
@@ -87,9 +87,9 @@ int main(int argc, char** argv) {
argsCount = Platform_GetCommandLineArgs(argc, argv, args);
/* NOTE: Make sure to comment this out before pushing a commit */
- /* String rawArgs = String_FromConst("UnknownShadow200 fffff 127.0.0.1 25565"); */
+ String rawArgs = String_FromConst("UnknownShadow200 fffff 127.0.0.1 25565");
/* String rawArgs = String_FromConst("UnknownShadow200"); */
- /* argsCount = String_UNSAFE_Split(&rawArgs, ' ', args, 4); */
+ argsCount = String_UNSAFE_Split(&rawArgs, ' ', args, 4);
if (argsCount == 0) {
Launcher_Run();
diff --git a/src/Resources.c b/src/Resources.c
index 87431d18c..246a87748 100644
--- a/src/Resources.c
+++ b/src/Resources.c
@@ -651,7 +651,7 @@ static void SoundPatcher_DecodeAudio(struct Stream* s, struct VorbisState* ctx)
Mem_Free(samples);
}
-static void SoundPatcher_Save(struct ResourceSound* sound, struct AsyncRequest* req) {
+static void SoundPatcher_Save(struct ResourceSound* sound, struct HttpRequest* req) {
String path; char pathBuffer[STRING_SIZE];
uint8_t buffer[OGG_BUFFER_SIZE];
struct Stream src, ogg, dst;
@@ -675,7 +675,7 @@ static void SoundPatcher_Save(struct ResourceSound* sound, struct AsyncRequest*
if (res) Logger_Warn(res, "closing .wav file");
}
-static void MusicPatcher_Save(struct ResourceMusic* music, struct AsyncRequest* req) {
+static void MusicPatcher_Save(struct ResourceMusic* music, struct HttpRequest* req) {
String path; char pathBuffer[STRING_SIZE];
ReturnCode res;
@@ -701,7 +701,7 @@ CC_NOINLINE static void Fetcher_DownloadAudio(const char* name, const char* hash
String_InitArray(url, urlBuffer);
String_Format3(&url, "http://resources.download.minecraft.net/%r%r/%c",
&hash[0], &hash[1], hash);
- AsyncDownloader_GetData(&url, false, &id);
+ Http_AsyncGetData(&url, false, &id);
}
void Fetcher_Run(void) {
@@ -721,7 +721,7 @@ void Fetcher_Run(void) {
id = String_FromReadonly(Resources_Files[i].Name);
url = String_FromReadonly(Resources_Files[i].Url);
- AsyncDownloader_GetData(&url, false, &id);
+ Http_AsyncGetData(&url, false, &id);
}
for (i = 0; i < Array_Elems(Resources_Music); i++) {
@@ -739,8 +739,8 @@ static void Fetcher_Finish(void) {
Fetcher_Working = false;
}
-CC_NOINLINE static bool Fetcher_Get(const String* id, struct AsyncRequest* req) {
- if (!AsyncDownloader_Get(id, req)) return false;
+CC_NOINLINE static bool Fetcher_Get(const String* id, struct HttpRequest* req) {
+ if (!Http_GetResult(id, req)) return false;
if (req->Result) {
Fetcher_Error = req->Result;
@@ -762,7 +762,7 @@ CC_NOINLINE static bool Fetcher_Get(const String* id, struct AsyncRequest* req)
static void Fetcher_CheckFile(struct ResourceFile* file) {
String id = String_FromReadonly(file->Name);
- struct AsyncRequest req;
+ struct HttpRequest req;
if (!Fetcher_Get(&id, &req)) return;
file->Downloaded = true;
@@ -773,21 +773,21 @@ static void Fetcher_CheckFile(struct ResourceFile* file) {
static void Fetcher_CheckMusic(struct ResourceMusic* music) {
String id = String_FromReadonly(music->Name);
- struct AsyncRequest req;
+ struct HttpRequest req;
if (!Fetcher_Get(&id, &req)) return;
music->Downloaded = true;
MusicPatcher_Save(music, &req);
- ASyncRequest_Free(&req);
+ HttpRequest_Free(&req);
}
static void Fetcher_CheckSound(struct ResourceSound* sound) {
String id = String_FromReadonly(sound->Name);
- struct AsyncRequest req;
+ struct HttpRequest req;
if (!Fetcher_Get(&id, &req)) return;
SoundPatcher_Save(sound, &req);
- ASyncRequest_Free(&req);
+ HttpRequest_Free(&req);
}
/* TODO: Implement this.. */
diff --git a/src/Screens.c b/src/Screens.c
index 7c665a487..0b9caf321 100644
--- a/src/Screens.c
+++ b/src/Screens.c
@@ -15,7 +15,7 @@
#include "ExtMath.h"
#include "Window.h"
#include "Camera.h"
-#include "AsyncDownloader.h"
+#include "Http.h"
#include "Block.h"
#include "Menus.h"
#include "World.h"
@@ -816,12 +816,12 @@ static void ChatScreen_SetInitialMessages(struct ChatScreen* s) {
static void ChatScreen_CheckOtherStatuses(struct ChatScreen* s) {
const static String texPack = String_FromConst("texturePack");
String str; char strBuffer[STRING_SIZE];
- struct AsyncRequest request;
+ struct HttpRequest request;
int progress;
bool hasRequest;
String identifier;
- hasRequest = AsyncDownloader_GetCurrent(&request, &progress);
+ hasRequest = Http_GetCurrent(&request, &progress);
identifier = String_FromRawArray(request.ID);
/* Is terrain / texture pack currently being downloaded? */
diff --git a/src/ServerConnection.c b/src/ServerConnection.c
index e261a3ed8..2765b2155 100644
--- a/src/ServerConnection.c
+++ b/src/ServerConnection.c
@@ -5,7 +5,7 @@
#include "Chat.h"
#include "Block.h"
#include "Event.h"
-#include "AsyncDownloader.h"
+#include "Http.h"
#include "Funcs.h"
#include "Entity.h"
#include "Graphics.h"
@@ -74,13 +74,13 @@ void ServerConnection_DownloadTexturePack(const String* url) {
}
TexturePack_ExtractCurrent(url);
- AsyncDownloader_GetDataEx(url, true, &texPack, &lastModified, &etag);
+ Http_AsyncGetDataEx(url, true, &texPack, &lastModified, &etag);
}
void ServerConnection_CheckAsyncResources(void) {
const static String texPack = String_FromConst("texturePack");
- struct AsyncRequest item;
- if (!AsyncDownloader_Get(&texPack, &item)) return;
+ struct HttpRequest item;
+ if (!Http_GetResult(&texPack, &item)) return;
if (item.Data) {
TexturePack_Extract_Req(&item);
diff --git a/src/TexturePack.c b/src/TexturePack.c
index 27fa47c42..557486469 100644
--- a/src/TexturePack.c
+++ b/src/TexturePack.c
@@ -6,7 +6,7 @@
#include "Graphics.h"
#include "Event.h"
#include "Game.h"
-#include "AsyncDownloader.h"
+#include "Http.h"
#include "Platform.h"
#include "Deflate.h"
#include "Stream.h"
@@ -706,7 +706,7 @@ void TexturePack_ExtractCurrent(const String* url) {
}
}
-void TexturePack_Extract_Req(struct AsyncRequest* item) {
+void TexturePack_Extract_Req(struct HttpRequest* item) {
String url, etag;
void* data; uint32_t len;
struct Stream mem;
@@ -729,5 +729,5 @@ void TexturePack_Extract_Req(struct AsyncRequest* item) {
: TexturePack_ExtractZip(&mem);
if (res) Logger_Warn2(res, png ? "decoding" : "extracting", &url);
- ASyncRequest_Free(item);
+ HttpRequest_Free(item);
}
diff --git a/src/TexturePack.h b/src/TexturePack.h
index 475fea231..e8bcbc2d8 100644
--- a/src/TexturePack.h
+++ b/src/TexturePack.h
@@ -10,7 +10,7 @@
Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3 */
struct Stream;
-struct AsyncRequest;
+struct HttpRequest;
struct IGameComponent;
extern struct IGameComponent Animations_Component;
@@ -97,5 +97,5 @@ void TextureCache_SetLastModified(const String* url, const TimeMS* lastModified)
void TexturePack_ExtractZip_File(const String* filename);
void TexturePack_ExtractDefault(void);
void TexturePack_ExtractCurrent(const String* url);
-void TexturePack_Extract_Req(struct AsyncRequest* item);
+void TexturePack_Extract_Req(struct HttpRequest* item);
#endif