Merge branch 'The-Powder-Toy:master' into dev
This commit is contained in:
commit
66986538c2
@ -10,10 +10,6 @@ namespace http
|
||||
AuthHeaders(ByteString::Build(user.UserID), user.SessionID);
|
||||
}
|
||||
|
||||
APIRequest::~APIRequest()
|
||||
{
|
||||
}
|
||||
|
||||
APIRequest::Result APIRequest::Finish()
|
||||
{
|
||||
Result result;
|
||||
|
@ -17,7 +17,6 @@ namespace http
|
||||
};
|
||||
|
||||
APIRequest(ByteString url);
|
||||
virtual ~APIRequest();
|
||||
|
||||
Result Finish();
|
||||
};
|
||||
|
@ -9,10 +9,6 @@ namespace http
|
||||
{
|
||||
}
|
||||
|
||||
GetUserInfoRequest::~GetUserInfoRequest()
|
||||
{
|
||||
}
|
||||
|
||||
std::unique_ptr<UserInfo> GetUserInfoRequest::Finish()
|
||||
{
|
||||
std::unique_ptr<UserInfo> user_info;
|
||||
|
@ -9,7 +9,6 @@ namespace http
|
||||
{
|
||||
public:
|
||||
GetUserInfoRequest(ByteString username);
|
||||
virtual ~GetUserInfoRequest();
|
||||
|
||||
std::unique_ptr<UserInfo> Finish();
|
||||
};
|
||||
|
@ -9,9 +9,6 @@ namespace http
|
||||
size(size)
|
||||
{}
|
||||
|
||||
ImageRequest::~ImageRequest()
|
||||
{}
|
||||
|
||||
std::unique_ptr<VideoBuffer> ImageRequest::Finish()
|
||||
{
|
||||
auto [ status, data ] = Request::Finish();
|
||||
|
@ -15,7 +15,6 @@ namespace http
|
||||
|
||||
public:
|
||||
ImageRequest(ByteString url, Vec2<int> size);
|
||||
virtual ~ImageRequest();
|
||||
|
||||
std::unique_ptr<VideoBuffer> Finish();
|
||||
};
|
||||
|
11
src/client/http/PostData.h
Normal file
11
src/client/http/PostData.h
Normal file
@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
#include "common/String.h"
|
||||
#include <map>
|
||||
#include <variant>
|
||||
|
||||
namespace http
|
||||
{
|
||||
using StringData = ByteString;
|
||||
using FormData = std::map<ByteString, ByteString>;
|
||||
using PostData = std::variant<StringData, FormData>;
|
||||
};
|
@ -1,6 +1,7 @@
|
||||
#include "Request.h"
|
||||
#include "requestmanager/RequestManager.h"
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
|
||||
namespace http
|
||||
{
|
||||
@ -30,12 +31,12 @@ namespace http
|
||||
handle->headers.push_back(header);
|
||||
}
|
||||
|
||||
void Request::AddPostData(std::map<ByteString, ByteString> data)
|
||||
void Request::AddPostData(PostData data)
|
||||
{
|
||||
assert(handle->state == RequestHandle::ready);
|
||||
// Even if the map is empty, calling this function signifies you want to do a POST request
|
||||
handle->isPost = true;
|
||||
handle->postData.insert(data.begin(), data.end());
|
||||
handle->postData = data;
|
||||
}
|
||||
|
||||
void Request::AuthHeaders(ByteString ID, ByteString session)
|
||||
@ -97,17 +98,31 @@ namespace http
|
||||
return { handle->statusCode, std::move(handle->responseData) };
|
||||
}
|
||||
|
||||
std::pair<int, ByteString> Request::Simple(ByteString uri, std::map<ByteString, ByteString> post_data)
|
||||
void RequestHandle::MarkDone()
|
||||
{
|
||||
return SimpleAuth(uri, "", "", post_data);
|
||||
{
|
||||
std::lock_guard lk(stateMx);
|
||||
assert(state == RequestHandle::running);
|
||||
state = RequestHandle::done;
|
||||
}
|
||||
stateCv.notify_one();
|
||||
if (error.size())
|
||||
{
|
||||
std::cerr << error << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<int, ByteString> Request::SimpleAuth(ByteString uri, ByteString ID, ByteString session, std::map<ByteString, ByteString> post_data)
|
||||
std::pair<int, ByteString> Request::Simple(ByteString uri, FormData postData)
|
||||
{
|
||||
return SimpleAuth(uri, "", "", postData);
|
||||
}
|
||||
|
||||
std::pair<int, ByteString> Request::SimpleAuth(ByteString uri, ByteString ID, ByteString session, FormData postData)
|
||||
{
|
||||
auto request = std::make_unique<Request>(uri);
|
||||
if (!post_data.empty())
|
||||
if (!postData.empty())
|
||||
{
|
||||
request->AddPostData(post_data);
|
||||
request->AddPostData(postData);
|
||||
}
|
||||
request->AuthHeaders(ID, session);
|
||||
request->Start();
|
||||
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "common/String.h"
|
||||
#include "PostData.h"
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
@ -22,7 +23,8 @@ namespace http
|
||||
|
||||
void Verb(ByteString newVerb);
|
||||
void AddHeader(ByteString header);
|
||||
void AddPostData(std::map<ByteString, ByteString> data);
|
||||
|
||||
void AddPostData(PostData data);
|
||||
void AuthHeaders(ByteString ID, ByteString session);
|
||||
|
||||
void Start();
|
||||
@ -32,8 +34,8 @@ namespace http
|
||||
const std::vector<ByteString> &ResponseHeaders() const;
|
||||
std::pair<int, ByteString> Finish(); // status, data
|
||||
|
||||
static std::pair<int, ByteString> Simple(ByteString uri, std::map<ByteString, ByteString> post_data = {});
|
||||
static std::pair<int, ByteString> SimpleAuth(ByteString uri, ByteString ID, ByteString session, std::map<ByteString, ByteString> post_data = {});
|
||||
static std::pair<int, ByteString> Simple(ByteString uri, FormData postData = {});
|
||||
static std::pair<int, ByteString> SimpleAuth(ByteString uri, ByteString ID, ByteString session, FormData postData = {});
|
||||
|
||||
friend class RequestManager;
|
||||
};
|
||||
|
@ -7,16 +7,12 @@ namespace http
|
||||
SaveUserInfoRequest::SaveUserInfoRequest(UserInfo &info) :
|
||||
APIRequest(ByteString::Build(SCHEME, SERVER, "/Profile.json"))
|
||||
{
|
||||
AddPostData({
|
||||
AddPostData(FormData{
|
||||
{ "Location", info.location.ToUtf8() },
|
||||
{ "Biography", info.biography.ToUtf8() }
|
||||
});
|
||||
}
|
||||
|
||||
SaveUserInfoRequest::~SaveUserInfoRequest()
|
||||
{
|
||||
}
|
||||
|
||||
bool SaveUserInfoRequest::Finish()
|
||||
{
|
||||
auto result = APIRequest::Finish();
|
||||
|
@ -9,7 +9,6 @@ namespace http
|
||||
{
|
||||
public:
|
||||
SaveUserInfoRequest(UserInfo &info);
|
||||
virtual ~SaveUserInfoRequest();
|
||||
|
||||
bool Finish();
|
||||
};
|
||||
|
@ -11,9 +11,5 @@ namespace http
|
||||
), size)
|
||||
{
|
||||
}
|
||||
|
||||
ThumbnailRequest::~ThumbnailRequest()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,5 @@ namespace http
|
||||
{
|
||||
public:
|
||||
ThumbnailRequest(int saveID, int saveDate, Vec2<int> size);
|
||||
virtual ~ThumbnailRequest();
|
||||
};
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
#include "RequestManager.h"
|
||||
#include "client/http/Request.h"
|
||||
#include "Config.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace http
|
||||
{
|
||||
@ -19,85 +18,22 @@ namespace http
|
||||
"; ", IDENT,
|
||||
") TPTPP/", SAVE_VERSION, ".", MINOR_VERSION, ".", BUILD_NUM, IDENT_RELTYPE, ".", SNAPSHOT_ID
|
||||
);
|
||||
worker = std::thread([this]() {
|
||||
Worker();
|
||||
});
|
||||
}
|
||||
|
||||
RequestManager::~RequestManager()
|
||||
{
|
||||
{
|
||||
std::lock_guard lk(sharedStateMx);
|
||||
running = false;
|
||||
}
|
||||
worker.join();
|
||||
}
|
||||
|
||||
void RequestManager::Worker()
|
||||
{
|
||||
InitWorker();
|
||||
while (true)
|
||||
{
|
||||
{
|
||||
std::lock_guard lk(sharedStateMx);
|
||||
for (auto &requestHandle : requestHandles)
|
||||
{
|
||||
if (requestHandle->statusCode)
|
||||
{
|
||||
requestHandlesToUnregister.push_back(requestHandle);
|
||||
}
|
||||
}
|
||||
for (auto &requestHandle : requestHandlesToRegister)
|
||||
{
|
||||
requestHandles.push_back(requestHandle);
|
||||
RegisterRequestHandle(requestHandle);
|
||||
}
|
||||
requestHandlesToRegister.clear();
|
||||
for (auto &requestHandle : requestHandlesToUnregister)
|
||||
{
|
||||
auto eraseFrom = std::remove(requestHandles.begin(), requestHandles.end(), requestHandle);
|
||||
if (eraseFrom != requestHandles.end())
|
||||
{
|
||||
assert(eraseFrom + 1 == requestHandles.end());
|
||||
UnregisterRequestHandle(requestHandle);
|
||||
requestHandles.erase(eraseFrom, requestHandles.end());
|
||||
if (requestHandle->error.size())
|
||||
{
|
||||
std::cerr << requestHandle->error << std::endl;
|
||||
}
|
||||
{
|
||||
std::lock_guard lk(requestHandle->stateMx);
|
||||
requestHandle->state = RequestHandle::done;
|
||||
}
|
||||
requestHandle->stateCv.notify_one();
|
||||
}
|
||||
}
|
||||
requestHandlesToUnregister.clear();
|
||||
if (!running)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
Tick();
|
||||
}
|
||||
assert(!requestHandles.size());
|
||||
ExitWorker();
|
||||
}
|
||||
|
||||
bool RequestManager::DisableNetwork() const
|
||||
{
|
||||
return disableNetwork;
|
||||
}
|
||||
|
||||
void RequestManager::RegisterRequest(Request &request)
|
||||
{
|
||||
std::lock_guard lk(sharedStateMx);
|
||||
requestHandlesToRegister.push_back(request.handle);
|
||||
if (disableNetwork)
|
||||
{
|
||||
request.handle->statusCode = 604;
|
||||
request.handle->error = "network disabled upon request";
|
||||
request.handle->MarkDone();
|
||||
return;
|
||||
}
|
||||
RegisterRequestImpl(request);
|
||||
}
|
||||
|
||||
void RequestManager::UnregisterRequest(Request &request)
|
||||
{
|
||||
std::lock_guard lk(sharedStateMx);
|
||||
requestHandlesToUnregister.push_back(request.handle);
|
||||
UnregisterRequestImpl(request);
|
||||
}
|
||||
}
|
||||
|
@ -96,224 +96,67 @@ namespace http
|
||||
{
|
||||
using RequestManager::RequestManager;
|
||||
|
||||
RequestManagerImpl(ByteString newProxy, ByteString newCafile, ByteString newCapath, bool newDisableNetwork);
|
||||
~RequestManagerImpl();
|
||||
|
||||
std::thread worker;
|
||||
void Worker();
|
||||
void WorkerInit();
|
||||
void WorkerPerform();
|
||||
void WorkerExit();
|
||||
|
||||
// State shared between Request threads and the worker thread.
|
||||
std::vector<std::shared_ptr<RequestHandle>> requestHandlesToRegister;
|
||||
std::vector<std::shared_ptr<RequestHandle>> requestHandlesToUnregister;
|
||||
bool running = true;
|
||||
std::mutex sharedStateMx;
|
||||
|
||||
std::vector<std::shared_ptr<RequestHandle>> requestHandles;
|
||||
void RegisterRequestHandle(std::shared_ptr<RequestHandle> requestHandle);
|
||||
void UnregisterRequestHandle(std::shared_ptr<RequestHandle> requestHandle);
|
||||
|
||||
bool curlGlobalInit = false;
|
||||
CURLM *curlMulti = NULL;
|
||||
};
|
||||
|
||||
void RequestManager::InitWorker()
|
||||
RequestManagerImpl::RequestManagerImpl(ByteString newProxy, ByteString newCafile, ByteString newCapath, bool newDisableNetwork) :
|
||||
RequestManager(newProxy, newCafile, newCapath, newDisableNetwork)
|
||||
{
|
||||
worker = std::thread([this]() {
|
||||
Worker();
|
||||
});
|
||||
}
|
||||
|
||||
RequestManagerImpl::~RequestManagerImpl()
|
||||
{
|
||||
{
|
||||
std::lock_guard lk(sharedStateMx);
|
||||
running = false;
|
||||
}
|
||||
worker.join();
|
||||
}
|
||||
|
||||
void RequestManagerImpl::WorkerInit()
|
||||
{
|
||||
auto manager = static_cast<RequestManagerImpl *>(this);
|
||||
if (!curl_global_init(CURL_GLOBAL_DEFAULT))
|
||||
{
|
||||
manager->curlGlobalInit = true;
|
||||
manager->curlMulti = curl_multi_init();
|
||||
if (manager->curlMulti)
|
||||
curlGlobalInit = true;
|
||||
curlMulti = curl_multi_init();
|
||||
if (curlMulti)
|
||||
{
|
||||
HandleCURLMcode(curl_multi_setopt(manager->curlMulti, CURLMOPT_MAX_HOST_CONNECTIONS, curlMaxHostConnections));
|
||||
HandleCURLMcode(curl_multi_setopt(curlMulti, CURLMOPT_MAX_HOST_CONNECTIONS, curlMaxHostConnections));
|
||||
#if defined(CURL_AT_LEAST_VERSION) && CURL_AT_LEAST_VERSION(7, 67, 0)
|
||||
HandleCURLMcode(curl_multi_setopt(manager->curlMulti, CURLMOPT_MAX_CONCURRENT_STREAMS, curlMaxConcurrentStreams));
|
||||
HandleCURLMcode(curl_multi_setopt(curlMulti, CURLMOPT_MAX_CONCURRENT_STREAMS, curlMaxConcurrentStreams));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RequestManager::ExitWorker()
|
||||
void RequestManagerImpl::WorkerPerform()
|
||||
{
|
||||
auto manager = static_cast<RequestManagerImpl *>(this);
|
||||
curl_multi_cleanup(manager->curlMulti);
|
||||
manager->curlMulti = NULL;
|
||||
curl_global_cleanup();
|
||||
}
|
||||
|
||||
void RequestManager::RegisterRequestHandle(std::shared_ptr<RequestHandle> requestHandle)
|
||||
{
|
||||
auto manager = static_cast<RequestManagerImpl *>(this);
|
||||
auto handle = static_cast<RequestHandleHttp *>(requestHandle.get());
|
||||
auto failEarly = [&requestHandle](int statusCode, ByteString error) {
|
||||
requestHandle->statusCode = statusCode;
|
||||
requestHandle->error = error;
|
||||
};
|
||||
if (disableNetwork)
|
||||
{
|
||||
return failEarly(604, "network disabled upon request");
|
||||
}
|
||||
if (!manager->curlGlobalInit)
|
||||
{
|
||||
return failEarly(600, "no CURL");
|
||||
}
|
||||
if (!manager->curlMulti)
|
||||
{
|
||||
return failEarly(600, "no CURL multi handle");
|
||||
}
|
||||
try
|
||||
{
|
||||
handle->curlEasy = curl_easy_init();
|
||||
if (!handle->curlEasy)
|
||||
{
|
||||
return failEarly(600, "no CURL easy handle");
|
||||
}
|
||||
for (auto &header : handle->headers)
|
||||
{
|
||||
auto *newHeaders = curl_slist_append(handle->curlHeaders, header.c_str());
|
||||
if (!newHeaders)
|
||||
{
|
||||
// Hopefully this is what a NULL from curl_slist_append means.
|
||||
HandleCURLcode(CURLE_OUT_OF_MEMORY);
|
||||
}
|
||||
handle->curlHeaders = newHeaders;
|
||||
}
|
||||
{
|
||||
auto postData = handle->postData;
|
||||
if (postData.size())
|
||||
{
|
||||
#ifdef REQUEST_USE_CURL_MIMEPOST
|
||||
handle->curlPostFields = curl_mime_init(handle->curlEasy);
|
||||
if (!handle->curlPostFields)
|
||||
{
|
||||
// Hopefully this is what a NULL from curl_mime_init means.
|
||||
HandleCURLcode(CURLE_OUT_OF_MEMORY);
|
||||
}
|
||||
for (auto &field : postData)
|
||||
{
|
||||
curl_mimepart *part = curl_mime_addpart(handle->curlPostFields);
|
||||
if (!part)
|
||||
{
|
||||
// Hopefully this is what a NULL from curl_mime_addpart means.
|
||||
HandleCURLcode(CURLE_OUT_OF_MEMORY);
|
||||
}
|
||||
HandleCURLcode(curl_mime_data(part, &field.second[0], field.second.size()));
|
||||
if (auto split = field.first.SplitBy(':'))
|
||||
{
|
||||
HandleCURLcode(curl_mime_name(part, split.Before().c_str()));
|
||||
HandleCURLcode(curl_mime_filename(part, split.After().c_str()));
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleCURLcode(curl_mime_name(part, field.first.c_str()));
|
||||
}
|
||||
}
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_MIMEPOST, handle->curlPostFields));
|
||||
#else
|
||||
for (auto &field : postData)
|
||||
{
|
||||
if (auto split = field.first.SplitBy(':'))
|
||||
{
|
||||
HandleCURLFORMcode(curl_formadd(&handle->curlPostFieldsFirst, &handle->curlPostFieldsLast,
|
||||
CURLFORM_COPYNAME, split.Before().c_str(),
|
||||
CURLFORM_BUFFER, split.After().c_str(),
|
||||
CURLFORM_BUFFERPTR, &field.second[0],
|
||||
CURLFORM_BUFFERLENGTH, field.second.size(),
|
||||
CURLFORM_END));
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleCURLFORMcode(curl_formadd(&handle->curlPostFieldsFirst, &handle->curlPostFieldsLast,
|
||||
CURLFORM_COPYNAME, field.first.c_str(),
|
||||
CURLFORM_PTRCONTENTS, &field.second[0],
|
||||
CURLFORM_CONTENTLEN, field.second.size(),
|
||||
CURLFORM_END));
|
||||
}
|
||||
}
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_HTTPPOST, handle->curlPostFieldsFirst));
|
||||
#endif
|
||||
}
|
||||
else if (handle->isPost)
|
||||
{
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_POST, 1L));
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_POSTFIELDS, ""));
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_HTTPGET, 1L));
|
||||
}
|
||||
if (handle->verb.size())
|
||||
{
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_CUSTOMREQUEST, handle->verb.c_str()));
|
||||
}
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_FOLLOWLOCATION, 1L));
|
||||
if constexpr (ENFORCE_HTTPS)
|
||||
{
|
||||
#if defined(CURL_AT_LEAST_VERSION) && CURL_AT_LEAST_VERSION(7, 85, 0)
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_PROTOCOLS_STR, "https"));
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_REDIR_PROTOCOLS_STR, "https"));
|
||||
#else
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS));
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(CURL_AT_LEAST_VERSION) && CURL_AT_LEAST_VERSION(7, 85, 0)
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_PROTOCOLS_STR, "https,http"));
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_REDIR_PROTOCOLS_STR, "https,http"));
|
||||
#else
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP));
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP));
|
||||
#endif
|
||||
}
|
||||
SetupCurlEasyCiphers(handle->curlEasy);
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_MAXREDIRS, 10L));
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_ERRORBUFFER, handle->curlErrorBuffer));
|
||||
handle->curlErrorBuffer[0] = 0;
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_CONNECTTIMEOUT, curlConnectTimeoutS));
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_HTTPHEADER, handle->curlHeaders));
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_URL, handle->uri.c_str()));
|
||||
if (proxy.size())
|
||||
{
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_PROXY, proxy.c_str()));
|
||||
}
|
||||
if (cafile.size())
|
||||
{
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_CAINFO, cafile.c_str()));
|
||||
}
|
||||
if (capath.size())
|
||||
{
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_CAPATH, capath.c_str()));
|
||||
}
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_PRIVATE, (void *)handle));
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_USERAGENT, userAgent.c_str()));
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_HEADERDATA, (void *)handle));
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_HEADERFUNCTION, &RequestHandleHttp::HeaderDataHandler));
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_WRITEDATA, (void *)handle));
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_WRITEFUNCTION, &RequestHandleHttp::WriteDataHandler));
|
||||
}
|
||||
}
|
||||
catch (const CurlError &ex)
|
||||
{
|
||||
return failEarly(600, ex.what());
|
||||
}
|
||||
HandleCURLMcode(curl_multi_add_handle(manager->curlMulti, handle->curlEasy));
|
||||
handle->curlAddedToMulti = true;
|
||||
}
|
||||
|
||||
void RequestManager::UnregisterRequestHandle(std::shared_ptr<RequestHandle> requestHandle)
|
||||
{
|
||||
auto manager = static_cast<RequestManagerImpl *>(this);
|
||||
auto handle = static_cast<RequestHandleHttp *>(requestHandle.get());
|
||||
if (handle->curlAddedToMulti)
|
||||
{
|
||||
HandleCURLMcode(curl_multi_remove_handle(manager->curlMulti, handle->curlEasy));
|
||||
handle->curlAddedToMulti = false;
|
||||
}
|
||||
curl_easy_cleanup(handle->curlEasy);
|
||||
#ifdef REQUEST_USE_CURL_MIMEPOST
|
||||
curl_mime_free(handle->curlPostFields);
|
||||
#else
|
||||
curl_formfree(handle->curlPostFieldsFirst);
|
||||
#endif
|
||||
curl_slist_free_all(handle->curlHeaders);
|
||||
}
|
||||
|
||||
void RequestManager::Tick()
|
||||
{
|
||||
if (!requestHandles.size())
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(TickMs));
|
||||
return;
|
||||
}
|
||||
auto manager = static_cast<RequestManagerImpl *>(this);
|
||||
int dontcare;
|
||||
HandleCURLMcode(curl_multi_wait(manager->curlMulti, NULL, 0, TickMs, &dontcare));
|
||||
HandleCURLMcode(curl_multi_poll(manager->curlMulti, NULL, 0, 1000, &dontcare));
|
||||
HandleCURLMcode(curl_multi_perform(manager->curlMulti, &dontcare));
|
||||
while (auto msg = curl_multi_info_read(manager->curlMulti, &dontcare))
|
||||
{
|
||||
@ -389,6 +232,254 @@ namespace http
|
||||
}
|
||||
}
|
||||
|
||||
void RequestManagerImpl::WorkerExit()
|
||||
{
|
||||
curl_multi_cleanup(curlMulti);
|
||||
curlMulti = NULL;
|
||||
curl_global_cleanup();
|
||||
}
|
||||
|
||||
void RequestManagerImpl::Worker()
|
||||
{
|
||||
WorkerInit();
|
||||
while (true)
|
||||
{
|
||||
{
|
||||
std::lock_guard lk(sharedStateMx);
|
||||
for (auto &requestHandle : requestHandles)
|
||||
{
|
||||
if (requestHandle->statusCode)
|
||||
{
|
||||
requestHandlesToUnregister.push_back(requestHandle);
|
||||
}
|
||||
}
|
||||
for (auto &requestHandle : requestHandlesToRegister)
|
||||
{
|
||||
requestHandles.push_back(requestHandle);
|
||||
RegisterRequestHandle(requestHandle);
|
||||
}
|
||||
requestHandlesToRegister.clear();
|
||||
for (auto &requestHandle : requestHandlesToUnregister)
|
||||
{
|
||||
auto eraseFrom = std::remove(requestHandles.begin(), requestHandles.end(), requestHandle);
|
||||
if (eraseFrom != requestHandles.end())
|
||||
{
|
||||
assert(eraseFrom + 1 == requestHandles.end());
|
||||
UnregisterRequestHandle(requestHandle);
|
||||
requestHandles.erase(eraseFrom, requestHandles.end());
|
||||
requestHandle->MarkDone();
|
||||
}
|
||||
}
|
||||
requestHandlesToUnregister.clear();
|
||||
if (!running)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
WorkerPerform();
|
||||
}
|
||||
assert(!requestHandles.size());
|
||||
WorkerExit();
|
||||
}
|
||||
|
||||
void RequestManager::RegisterRequestImpl(Request &request)
|
||||
{
|
||||
auto manager = static_cast<RequestManagerImpl *>(this);
|
||||
std::lock_guard lk(manager->sharedStateMx);
|
||||
manager->requestHandlesToRegister.push_back(request.handle);
|
||||
curl_multi_wakeup(manager->curlMulti);
|
||||
}
|
||||
|
||||
void RequestManager::UnregisterRequestImpl(Request &request)
|
||||
{
|
||||
auto manager = static_cast<RequestManagerImpl *>(this);
|
||||
std::lock_guard lk(manager->sharedStateMx);
|
||||
manager->requestHandlesToUnregister.push_back(request.handle);
|
||||
curl_multi_wakeup(manager->curlMulti);
|
||||
}
|
||||
|
||||
void RequestManagerImpl::RegisterRequestHandle(std::shared_ptr<RequestHandle> requestHandle)
|
||||
{
|
||||
auto manager = static_cast<RequestManagerImpl *>(this);
|
||||
auto handle = static_cast<RequestHandleHttp *>(requestHandle.get());
|
||||
auto failEarly = [&requestHandle](int statusCode, ByteString error) {
|
||||
requestHandle->statusCode = statusCode;
|
||||
requestHandle->error = error;
|
||||
};
|
||||
if (!manager->curlGlobalInit)
|
||||
{
|
||||
return failEarly(600, "no CURL");
|
||||
}
|
||||
if (!manager->curlMulti)
|
||||
{
|
||||
return failEarly(600, "no CURL multi handle");
|
||||
}
|
||||
try
|
||||
{
|
||||
handle->curlEasy = curl_easy_init();
|
||||
if (!handle->curlEasy)
|
||||
{
|
||||
return failEarly(600, "no CURL easy handle");
|
||||
}
|
||||
for (auto &header : handle->headers)
|
||||
{
|
||||
auto *newHeaders = curl_slist_append(handle->curlHeaders, header.c_str());
|
||||
if (!newHeaders)
|
||||
{
|
||||
// Hopefully this is what a NULL from curl_slist_append means.
|
||||
HandleCURLcode(CURLE_OUT_OF_MEMORY);
|
||||
}
|
||||
handle->curlHeaders = newHeaders;
|
||||
}
|
||||
{
|
||||
auto &postData = handle->postData;
|
||||
if (std::holds_alternative<http::FormData>(postData) && std::get<http::FormData>(postData).size())
|
||||
{
|
||||
auto &formData = std::get<http::FormData>(postData);
|
||||
#ifdef REQUEST_USE_CURL_MIMEPOST
|
||||
handle->curlPostFields = curl_mime_init(handle->curlEasy);
|
||||
if (!handle->curlPostFields)
|
||||
{
|
||||
// Hopefully this is what a NULL from curl_mime_init means.
|
||||
HandleCURLcode(CURLE_OUT_OF_MEMORY);
|
||||
}
|
||||
for (auto &field : formData)
|
||||
{
|
||||
curl_mimepart *part = curl_mime_addpart(handle->curlPostFields);
|
||||
if (!part)
|
||||
{
|
||||
// Hopefully this is what a NULL from curl_mime_addpart means.
|
||||
HandleCURLcode(CURLE_OUT_OF_MEMORY);
|
||||
}
|
||||
HandleCURLcode(curl_mime_data(part, &field.second[0], field.second.size()));
|
||||
if (auto split = field.first.SplitBy(':'))
|
||||
{
|
||||
HandleCURLcode(curl_mime_name(part, split.Before().c_str()));
|
||||
HandleCURLcode(curl_mime_filename(part, split.After().c_str()));
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleCURLcode(curl_mime_name(part, field.first.c_str()));
|
||||
}
|
||||
}
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_MIMEPOST, handle->curlPostFields));
|
||||
#else
|
||||
for (auto &field : formData)
|
||||
{
|
||||
if (auto split = field.first.SplitBy(':'))
|
||||
{
|
||||
HandleCURLFORMcode(curl_formadd(&handle->curlPostFieldsFirst, &handle->curlPostFieldsLast,
|
||||
CURLFORM_COPYNAME, split.Before().c_str(),
|
||||
CURLFORM_BUFFER, split.After().c_str(),
|
||||
CURLFORM_BUFFERPTR, &field.second[0],
|
||||
CURLFORM_BUFFERLENGTH, field.second.size(),
|
||||
CURLFORM_END));
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleCURLFORMcode(curl_formadd(&handle->curlPostFieldsFirst, &handle->curlPostFieldsLast,
|
||||
CURLFORM_COPYNAME, field.first.c_str(),
|
||||
CURLFORM_PTRCONTENTS, &field.second[0],
|
||||
CURLFORM_CONTENTLEN, field.second.size(),
|
||||
CURLFORM_END));
|
||||
}
|
||||
}
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_HTTPPOST, handle->curlPostFieldsFirst));
|
||||
#endif
|
||||
}
|
||||
else if (std::holds_alternative<http::StringData>(postData) && std::get<http::StringData>(postData).size())
|
||||
{
|
||||
auto &stringData = std::get<http::StringData>(postData);
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_POSTFIELDS, &stringData[0]));
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_POSTFIELDSIZE_LARGE, curl_off_t(stringData.size())));
|
||||
}
|
||||
else if (handle->isPost)
|
||||
{
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_POST, 1L));
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_POSTFIELDS, ""));
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_HTTPGET, 1L));
|
||||
}
|
||||
if (handle->verb.size())
|
||||
{
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_CUSTOMREQUEST, handle->verb.c_str()));
|
||||
}
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_FOLLOWLOCATION, 1L));
|
||||
if constexpr (ENFORCE_HTTPS)
|
||||
{
|
||||
#if defined(CURL_AT_LEAST_VERSION) && CURL_AT_LEAST_VERSION(7, 85, 0)
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_PROTOCOLS_STR, "https"));
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_REDIR_PROTOCOLS_STR, "https"));
|
||||
#else
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS));
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(CURL_AT_LEAST_VERSION) && CURL_AT_LEAST_VERSION(7, 85, 0)
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_PROTOCOLS_STR, "https,http"));
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_REDIR_PROTOCOLS_STR, "https,http"));
|
||||
#else
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP));
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP));
|
||||
#endif
|
||||
}
|
||||
SetupCurlEasyCiphers(handle->curlEasy);
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_MAXREDIRS, 10L));
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_ERRORBUFFER, handle->curlErrorBuffer));
|
||||
handle->curlErrorBuffer[0] = 0;
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_CONNECTTIMEOUT, curlConnectTimeoutS));
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_HTTPHEADER, handle->curlHeaders));
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_URL, handle->uri.c_str()));
|
||||
if (proxy.size())
|
||||
{
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_PROXY, proxy.c_str()));
|
||||
}
|
||||
if (cafile.size())
|
||||
{
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_CAINFO, cafile.c_str()));
|
||||
}
|
||||
if (capath.size())
|
||||
{
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_CAPATH, capath.c_str()));
|
||||
}
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_PRIVATE, (void *)handle));
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_USERAGENT, userAgent.c_str()));
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_HEADERDATA, (void *)handle));
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_HEADERFUNCTION, &RequestHandleHttp::HeaderDataHandler));
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_WRITEDATA, (void *)handle));
|
||||
HandleCURLcode(curl_easy_setopt(handle->curlEasy, CURLOPT_WRITEFUNCTION, &RequestHandleHttp::WriteDataHandler));
|
||||
}
|
||||
}
|
||||
catch (const CurlError &ex)
|
||||
{
|
||||
return failEarly(600, ex.what());
|
||||
}
|
||||
HandleCURLMcode(curl_multi_add_handle(manager->curlMulti, handle->curlEasy));
|
||||
handle->curlAddedToMulti = true;
|
||||
}
|
||||
|
||||
void RequestManagerImpl::UnregisterRequestHandle(std::shared_ptr<RequestHandle> requestHandle)
|
||||
{
|
||||
auto manager = static_cast<RequestManagerImpl *>(this);
|
||||
auto handle = static_cast<RequestHandleHttp *>(requestHandle.get());
|
||||
if (handle->curlAddedToMulti)
|
||||
{
|
||||
HandleCURLMcode(curl_multi_remove_handle(manager->curlMulti, handle->curlEasy));
|
||||
handle->curlAddedToMulti = false;
|
||||
}
|
||||
curl_easy_cleanup(handle->curlEasy);
|
||||
#ifdef REQUEST_USE_CURL_MIMEPOST
|
||||
curl_mime_free(handle->curlPostFields);
|
||||
#else
|
||||
curl_formfree(handle->curlPostFieldsFirst);
|
||||
#endif
|
||||
curl_slist_free_all(handle->curlHeaders);
|
||||
}
|
||||
|
||||
RequestManagerPtr RequestManager::Create(ByteString newProxy, ByteString newCafile, ByteString newCapath, bool newDisableNetwork)
|
||||
{
|
||||
return RequestManagerPtr(new RequestManagerImpl(newProxy, newCafile, newCapath, newDisableNetwork));
|
||||
|
@ -8,29 +8,17 @@ namespace http
|
||||
return std::make_shared<RequestHandle>(CtorTag{});
|
||||
}
|
||||
|
||||
void RequestManager::InitWorker()
|
||||
void RequestManager::RegisterRequestImpl(Request &request)
|
||||
{
|
||||
request.handle->statusCode = 604;
|
||||
request.handle->error = "network support not compiled in";
|
||||
request.handle->MarkDone();
|
||||
}
|
||||
|
||||
void RequestManager::ExitWorker()
|
||||
void RequestManager::UnregisterRequestImpl(Request &request)
|
||||
{
|
||||
}
|
||||
|
||||
void RequestManager::RegisterRequestHandle(std::shared_ptr<RequestHandle> requestHandle)
|
||||
{
|
||||
requestHandle->statusCode = 604;
|
||||
requestHandle->error = "network support not compiled in";
|
||||
}
|
||||
|
||||
void RequestManager::UnregisterRequestHandle(std::shared_ptr<RequestHandle> requestHandle)
|
||||
{
|
||||
}
|
||||
|
||||
void RequestManager::Tick()
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(TickMs));
|
||||
}
|
||||
|
||||
RequestManagerPtr RequestManager::Create(ByteString newProxy, ByteString newCafile, ByteString newCapath, bool newDisableNetwork)
|
||||
{
|
||||
return RequestManagerPtr(new RequestManager(newProxy, newCafile, newCapath, newDisableNetwork));
|
||||
|
@ -1,12 +1,12 @@
|
||||
#pragma once
|
||||
#include "common/ExplicitSingleton.h"
|
||||
#include "common/String.h"
|
||||
#include "client/http/PostData.h"
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <map>
|
||||
#include <condition_variable>
|
||||
|
||||
namespace http
|
||||
@ -24,7 +24,7 @@ namespace http
|
||||
ByteString uri;
|
||||
ByteString verb;
|
||||
bool isPost = false;
|
||||
std::map<ByteString, ByteString> postData;
|
||||
PostData postData;
|
||||
std::vector<ByteString> headers;
|
||||
|
||||
enum State
|
||||
@ -51,6 +51,8 @@ namespace http
|
||||
RequestHandle(const RequestHandle &) = delete;
|
||||
RequestHandle &operator =(const RequestHandle &) = delete;
|
||||
|
||||
void MarkDone();
|
||||
|
||||
static std::shared_ptr<RequestHandle> Create();
|
||||
};
|
||||
|
||||
@ -62,41 +64,27 @@ namespace http
|
||||
using RequestManagerPtr = std::unique_ptr<RequestManager, RequestManagerDeleter>;
|
||||
class RequestManager : public ExplicitSingleton<RequestManager>
|
||||
{
|
||||
protected:
|
||||
ByteString proxy;
|
||||
ByteString cafile;
|
||||
ByteString capath;
|
||||
ByteString userAgent;
|
||||
bool disableNetwork;
|
||||
|
||||
std::thread worker;
|
||||
void InitWorker();
|
||||
void Worker();
|
||||
void ExitWorker();
|
||||
|
||||
std::vector<std::shared_ptr<RequestHandle>> requestHandles;
|
||||
void RegisterRequestHandle(std::shared_ptr<RequestHandle> requestHandle);
|
||||
void UnregisterRequestHandle(std::shared_ptr<RequestHandle> requestHandle);
|
||||
void Tick();
|
||||
|
||||
// State shared between Request threads and the worker thread.
|
||||
std::vector<std::shared_ptr<RequestHandle>> requestHandlesToRegister;
|
||||
std::vector<std::shared_ptr<RequestHandle>> requestHandlesToUnregister;
|
||||
bool running = true;
|
||||
std::mutex sharedStateMx;
|
||||
|
||||
protected:
|
||||
RequestManager(ByteString newProxy, ByteString newCafile, ByteString newCapath, bool newDisableNetwork);
|
||||
|
||||
public:
|
||||
~RequestManager();
|
||||
void RegisterRequestImpl(Request &request);
|
||||
void UnregisterRequestImpl(Request &request);
|
||||
|
||||
public:
|
||||
void RegisterRequest(Request &request);
|
||||
void UnregisterRequest(Request &request);
|
||||
|
||||
bool DisableNetwork() const;
|
||||
bool DisableNetwork() const
|
||||
{
|
||||
return disableNetwork;
|
||||
}
|
||||
|
||||
static RequestManagerPtr Create(ByteString newProxy, ByteString newCafile, ByteString newCapath, bool newDisableNetwork);
|
||||
};
|
||||
|
||||
constexpr int TickMs = 100;
|
||||
}
|
||||
|
@ -442,7 +442,7 @@ static Rect<int> SaneSaveRect(Vec2<int> point1, Vec2<int> point2)
|
||||
auto tly = std::min(point1.Y, point2.Y);
|
||||
auto brx = std::max(point1.X, point2.X);
|
||||
auto bry = std::max(point1.Y, point2.Y);
|
||||
return RectBetween(Vec2{ tlx, tly } / CELL, Vec2{ brx, bry } / CELL);
|
||||
return RectBetween(Vec2{ tlx, tly }, Vec2{ brx, bry });
|
||||
}
|
||||
|
||||
ByteString GameController::StampRegion(ui::Point point1, ui::Point point2)
|
||||
@ -1146,7 +1146,7 @@ void GameController::OpenSearch(String searchText)
|
||||
void GameController::OpenLocalSaveWindow(bool asCurrent)
|
||||
{
|
||||
Simulation * sim = gameModel->GetSimulation();
|
||||
auto gameSave = sim->Save(gameModel->GetIncludePressure() != gameView->ShiftBehaviour(), CELLS.OriginRect());
|
||||
auto gameSave = sim->Save(gameModel->GetIncludePressure() != gameView->ShiftBehaviour(), RES.OriginRect());
|
||||
if(!gameSave)
|
||||
{
|
||||
new ErrorMessage("Error", "Unable to build save.");
|
||||
@ -1357,7 +1357,7 @@ void GameController::OpenSaveWindow()
|
||||
if(gameModel->GetUser().UserID)
|
||||
{
|
||||
Simulation * sim = gameModel->GetSimulation();
|
||||
auto gameSave = sim->Save(gameModel->GetIncludePressure() != gameView->ShiftBehaviour(), CELLS.OriginRect());
|
||||
auto gameSave = sim->Save(gameModel->GetIncludePressure() != gameView->ShiftBehaviour(), RES.OriginRect());
|
||||
if(!gameSave)
|
||||
{
|
||||
new ErrorMessage("Error", "Unable to build save.");
|
||||
@ -1399,7 +1399,7 @@ void GameController::SaveAsCurrent()
|
||||
if(gameModel->GetSave() && gameModel->GetUser().UserID && gameModel->GetUser().Username == gameModel->GetSave()->GetUserName())
|
||||
{
|
||||
Simulation * sim = gameModel->GetSimulation();
|
||||
auto gameSave = sim->Save(gameModel->GetIncludePressure() != gameView->ShiftBehaviour(), CELLS.OriginRect());
|
||||
auto gameSave = sim->Save(gameModel->GetIncludePressure() != gameView->ShiftBehaviour(), RES.OriginRect());
|
||||
if(!gameSave)
|
||||
{
|
||||
new ErrorMessage("Error", "Unable to build save.");
|
||||
|
@ -46,7 +46,7 @@ private:
|
||||
}
|
||||
|
||||
public:
|
||||
static int Make(lua_State *l, const ByteString &uri, bool isPost, const ByteString &verb, RequestType type, const std::map<ByteString, ByteString> &post_data, const std::vector<ByteString> &headers)
|
||||
static int Make(lua_State *l, const ByteString &uri, bool isPost, const ByteString &verb, RequestType type, const http::PostData &postData, const std::vector<ByteString> &headers)
|
||||
{
|
||||
auto authUser = Client::Ref().GetAuthUser();
|
||||
if (type == getAuthToken && !authUser.UserID)
|
||||
@ -73,7 +73,7 @@ public:
|
||||
}
|
||||
if (isPost)
|
||||
{
|
||||
rh->request->AddPostData(post_data);
|
||||
rh->request->AddPostData(postData);
|
||||
}
|
||||
if (type == getAuthToken)
|
||||
{
|
||||
@ -220,7 +220,7 @@ static int http_request_finish(lua_State *l)
|
||||
static int http_request(lua_State *l, bool isPost)
|
||||
{
|
||||
ByteString uri = tpt_lua_checkByteString(l, 1);
|
||||
std::map<ByteString, ByteString> post_data;
|
||||
http::PostData postData;
|
||||
auto headersIndex = 2;
|
||||
auto verbIndex = 3;
|
||||
|
||||
@ -228,13 +228,19 @@ static int http_request(lua_State *l, bool isPost)
|
||||
{
|
||||
headersIndex += 1;
|
||||
verbIndex += 1;
|
||||
if (lua_istable(l, 2))
|
||||
if (lua_isstring(l, 2))
|
||||
{
|
||||
postData = tpt_lua_toByteString(l, 2);
|
||||
}
|
||||
else if (lua_istable(l, 2))
|
||||
{
|
||||
postData = http::FormData{};
|
||||
auto &formData = std::get<http::FormData>(postData);
|
||||
lua_pushnil(l);
|
||||
while (lua_next(l, 2))
|
||||
{
|
||||
lua_pushvalue(l, -2);
|
||||
post_data.emplace(tpt_lua_toByteString(l, -1), tpt_lua_toByteString(l, -2));
|
||||
formData.emplace(tpt_lua_toByteString(l, -1), tpt_lua_toByteString(l, -2));
|
||||
lua_pop(l, 2);
|
||||
}
|
||||
}
|
||||
@ -267,7 +273,7 @@ static int http_request(lua_State *l, bool isPost)
|
||||
}
|
||||
|
||||
auto verb = tpt_lua_optByteString(l, verbIndex, "");
|
||||
return RequestHandle::Make(l, uri, isPost, verb, RequestHandle::normal, post_data, headers);
|
||||
return RequestHandle::Make(l, uri, isPost, verb, RequestHandle::normal, postData, headers);
|
||||
}
|
||||
|
||||
static int http_get_auth_token(lua_State *l)
|
||||
|
@ -19,7 +19,7 @@ extern int Element_LOLZ_lolz[XRES/9][YRES/9];
|
||||
extern int Element_LOVE_RuleTable[9][9];
|
||||
extern int Element_LOVE_love[XRES/9][YRES/9];
|
||||
|
||||
void Simulation::Load(const GameSave *originalSave, bool includePressure, Vec2<int> blockP)
|
||||
void Simulation::Load(const GameSave *originalSave, bool includePressure, Vec2<int> blockP) // block coordinates
|
||||
{
|
||||
auto save = std::unique_ptr<GameSave>(new GameSave(*originalSave));
|
||||
|
||||
@ -335,10 +335,10 @@ void Simulation::Load(const GameSave *originalSave, bool includePressure, Vec2<i
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<GameSave> Simulation::Save(bool includePressure, Rect<int> blockR)
|
||||
std::unique_ptr<GameSave> Simulation::Save(bool includePressure, Rect<int> partR) // particle coordinates
|
||||
{
|
||||
auto blockR = RectBetween(partR.TopLeft / CELL, partR.BottomRight / CELL);
|
||||
auto blockP = blockR.TopLeft;
|
||||
auto partR = RectSized(blockR.TopLeft * CELL, blockR.Size() * CELL);
|
||||
|
||||
auto newSave = std::make_unique<GameSave>(blockR.Size());
|
||||
auto &possiblyCarriesType = Particle::PossiblyCarriesType();
|
||||
|
@ -121,8 +121,8 @@ public:
|
||||
uint64_t frameCount;
|
||||
bool ensureDeterminism;
|
||||
|
||||
void Load(const GameSave *save, bool includePressure, Vec2<int> blockP);
|
||||
std::unique_ptr<GameSave> Save(bool includePressure, Rect<int> blockR);
|
||||
void Load(const GameSave *save, bool includePressure, Vec2<int> blockP); // block coordinates
|
||||
std::unique_ptr<GameSave> Save(bool includePressure, Rect<int> partR); // particle coordinates
|
||||
void SaveSimOptions(GameSave &gameSave);
|
||||
SimulationSample GetSample(int x, int y);
|
||||
|
||||
|
Reference in New Issue
Block a user