cleanup http requests (part 1)

This commit is contained in:
MihailRis 2026-09-09 23:43:44 +03:00
parent 9a87c20823
commit 74bb695807
6 changed files with 73 additions and 143 deletions

View file

@ -3,6 +3,7 @@
#include "engine/Engine.hpp" #include "engine/Engine.hpp"
#include "network/Network.hpp" #include "network/Network.hpp"
#include "devtools/Project.hpp" #include "devtools/Project.hpp"
#include "util/stringutil.hpp"
#include <variant> #include <variant>
#include <utility> #include <utility>
@ -91,24 +92,26 @@ static int perform_get(lua::State* L, network::Network& network, bool binary) {
int currentRequestId = request_id++; int currentRequestId = request_id++;
network.get( network::HttpRequest request {};
url, request.url = std::move(url);
request.onResponse =
[currentRequestId, binary](std::vector<char> bytes) { [currentRequestId, binary](std::vector<char> bytes) {
push_event(NetworkEvent( push_event(NetworkEvent(
RESPONSE, RESPONSE,
ResponseEventDto { ResponseEventDto {
200, binary, currentRequestId, std::move(bytes)} 200, binary, currentRequestId, std::move(bytes)}
)); ));
}, };
request.onReject =
[currentRequestId, binary](int code, std::vector<char> bytes) { [currentRequestId, binary](int code, std::vector<char> bytes) {
push_event(NetworkEvent( push_event(NetworkEvent(
RESPONSE, RESPONSE,
ResponseEventDto { ResponseEventDto {
code, binary, currentRequestId, std::move(bytes)} code, binary, currentRequestId, std::move(bytes)}
)); ));
}, };
std::move(headers) request.headers = std::move(headers);
); network.request(std::move(request));
return lua::pushinteger(L, currentRequestId); return lua::pushinteger(L, currentRequestId);
} }
@ -134,25 +137,28 @@ static int l_post(lua::State* L, network::Network& network) {
auto headers = read_headers(L, 3); auto headers = read_headers(L, 3);
int currentRequestId = request_id++; int currentRequestId = request_id++;
network.post( network::HttpRequest request {};
url, request.url = std::move(url);
string, request.body = string;
request.headers = std::move(headers);
request.headers.emplace_back("Content-Type: application/json");
request.onResponse =
[currentRequestId](std::vector<char> bytes) { [currentRequestId](std::vector<char> bytes) {
push_event(NetworkEvent( push_event(NetworkEvent(
RESPONSE, RESPONSE,
ResponseEventDto { ResponseEventDto {
200, false, currentRequestId, std::move(bytes)} 200, false, currentRequestId, std::move(bytes)}
)); ));
}, };
request.onReject =
[currentRequestId](int code, std::vector<char> bytes) { [currentRequestId](int code, std::vector<char> bytes) {
push_event(NetworkEvent( push_event(NetworkEvent(
RESPONSE, RESPONSE,
ResponseEventDto { ResponseEventDto {
code, false, currentRequestId, std::move(bytes)} code, false, currentRequestId, std::move(bytes)}
)); ));
}, };
std::move(headers) network.request(std::move(request));
);
return lua::pushinteger(L, currentRequestId); return lua::pushinteger(L, currentRequestId);
} }

View file

@ -23,21 +23,6 @@ static size_t write_callback(
return size * nmemb; return size * nmemb;
} }
enum class RequestType {
GET, POST
};
struct Request {
RequestType type;
std::string url;
OnResponse onResponse;
OnReject onReject;
long maxSize;
bool followLocation = false;
std::string data;
std::vector<std::string> headers;
};
class CurlRequests : public Requests { class CurlRequests : public Requests {
CURLM* multiHandle; CURLM* multiHandle;
CURL* curl; CURL* curl;
@ -50,7 +35,7 @@ class CurlRequests : public Requests {
std::vector<char> buffer; std::vector<char> buffer;
std::string url; std::string url;
std::queue<Request> requests; std::queue<HttpRequest> requests;
public: public:
CurlRequests(CURLM* multiHandle, CURL* curl) CurlRequests(CURLM* multiHandle, CURL* curl)
: multiHandle(multiHandle), curl(curl) { : multiHandle(multiHandle), curl(curl) {
@ -61,47 +46,12 @@ public:
curl_easy_cleanup(curl); curl_easy_cleanup(curl);
curl_multi_cleanup(multiHandle); curl_multi_cleanup(multiHandle);
} }
void get(
const std::string& url, void request(HttpRequest request) override {
OnResponse onResponse,
OnReject onReject,
std::vector<std::string> headers,
long maxSize
) override {
Request request {
RequestType::GET,
url,
onResponse,
onReject,
maxSize,
true,
"",
std::move(headers)};
processRequest(std::move(request)); processRequest(std::move(request));
} }
void post( void processRequest(HttpRequest request) {
const std::string& url,
const std::string& data,
OnResponse onResponse,
OnReject onReject=nullptr,
std::vector<std::string> headers = {},
long maxSize=0
) override {
Request request {
RequestType::POST,
url,
onResponse,
onReject,
maxSize,
false,
"",
std::move(headers)};
request.data = data;
processRequest(std::move(request));
}
void processRequest(Request request) {
if (!url.empty()) { if (!url.empty()) {
requests.push(request); requests.push(request);
return; return;
@ -113,7 +63,19 @@ public:
buffer.clear(); buffer.clear();
curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_POST, request.type == RequestType::POST); switch (request.method) {
case HttpMethod::GET:
break;
case HttpMethod::POST:
curl_easy_setopt(curl, CURLOPT_POST, true);
break;
case HttpMethod::PUT:
curl_easy_setopt(curl, CURLOPT_UPLOAD, true);
break;
case HttpMethod::DELETE:
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
break;
}
curl_slist* hs = nullptr; curl_slist* hs = nullptr;
@ -121,16 +83,9 @@ public:
hs = curl_slist_append(hs, header.c_str()); hs = curl_slist_append(hs, header.c_str());
} }
switch (request.type) { if (!request.body.empty()) {
case RequestType::GET: curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, request.body.length());
break; curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, request.body.data());
case RequestType::POST:
hs = curl_slist_append(hs, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, request.data.length());
curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, request.data.c_str());
break;
default:
throw std::runtime_error("not implemented");
} }
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, hs); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, hs);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, request.followLocation); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, request.followLocation);

View file

@ -51,27 +51,8 @@ Network::Network(std::unique_ptr<Requests> requests)
Network::~Network() = default; Network::~Network() = default;
void Network::get( void Network::request(HttpRequest request) {
const std::string& url, requests->request(std::move(request));
OnResponse onResponse,
OnReject onReject,
std::vector<std::string> headers,
long maxSize
) {
requests->get(url, onResponse, onReject, std::move(headers), maxSize);
}
void Network::post(
const std::string& url,
const std::string& fieldsData,
OnResponse onResponse,
OnReject onReject,
std::vector<std::string> headers,
long maxSize
) {
requests->post(
url, fieldsData, onResponse, onReject, std::move(headers), maxSize
);
} }
Connection* Network::getConnection(u64id_t id, bool includePrivate) { Connection* Network::getConnection(u64id_t id, bool includePrivate) {

View file

@ -68,22 +68,7 @@ namespace network {
Network(std::unique_ptr<Requests> requests); Network(std::unique_ptr<Requests> requests);
~Network(); ~Network();
void get( void request(HttpRequest request);
const std::string& url,
OnResponse onResponse,
OnReject onReject = nullptr,
std::vector<std::string> headers = {},
long maxSize=0
);
void post(
const std::string& url,
const std::string& fieldsData,
OnResponse onResponse,
OnReject onReject = nullptr,
std::vector<std::string> headers = {},
long maxSize=0
);
[[nodiscard]] Connection* getConnection(u64id_t id, bool includePrivate); [[nodiscard]] Connection* getConnection(u64id_t id, bool includePrivate);
[[nodiscard]] Server* getServer(u64id_t id, bool includePrivate) const; [[nodiscard]] Server* getServer(u64id_t id, bool includePrivate) const;

View file

@ -10,6 +10,10 @@
#include <mutex> #include <mutex>
namespace network { namespace network {
enum class HttpMethod {
GET, POST, PUT, DELETE,
};
using OnResponse = std::function<void(std::vector<char>)>; using OnResponse = std::function<void(std::vector<char>)>;
using OnReject = std::function<void(int, std::vector<char>)>; using OnReject = std::function<void(int, std::vector<char>)>;
using ConnectCallback = std::function<void(u64id_t, u64id_t)>; using ConnectCallback = std::function<void(u64id_t, u64id_t)>;
@ -17,26 +21,23 @@ namespace network {
using ServerDatagramCallback = std::function<void(u64id_t sid, const std::string& addr, int port, const char* buffer, size_t length)>; using ServerDatagramCallback = std::function<void(u64id_t sid, const std::string& addr, int port, const char* buffer, size_t length)>;
using ClientDatagramCallback = std::function<void(u64id_t cid, const char* buffer, size_t length)>; using ClientDatagramCallback = std::function<void(u64id_t cid, const char* buffer, size_t length)>;
struct HttpRequest {
HttpMethod method;
std::string url;
std::string body;
std::vector<std::string> headers;
OnResponse onResponse;
OnReject onReject;
bool followLocation = false;
long maxSize = -1;
};
class Requests { class Requests {
public: public:
virtual ~Requests() {} virtual ~Requests() {}
virtual void get( virtual void request(HttpRequest request) = 0;
const std::string& url,
OnResponse onResponse,
OnReject onReject=nullptr,
std::vector<std::string> headers = {},
long maxSize=0
) = 0;
virtual void post(
const std::string& url,
const std::string& data,
OnResponse onResponse,
OnReject onReject=nullptr,
std::vector<std::string> headers = {},
long maxSize=0
) = 0;
[[nodiscard]] virtual size_t getTotalUpload() const = 0; [[nodiscard]] virtual size_t getTotalUpload() const = 0;
[[nodiscard]] virtual size_t getTotalDownload() const = 0; [[nodiscard]] virtual size_t getTotalDownload() const = 0;

View file

@ -6,18 +6,20 @@
TEST(curltest, curltest) { TEST(curltest, curltest) {
NetworkSettings settings {}; NetworkSettings settings {};
auto network = network::Network::create(settings); auto network = network::Network::create(settings);
network->get(
"https://raw.githubusercontent.com/MihailRis/VoxelEngine-Cpp/refs/" network::HttpRequest request {};
"heads/curl/res/content/base/blocks/lamp.json", request.url = "https://raw.githubusercontent.com/MihailRis/VoxelEngine-Cpp/refs/"
[](std::vector<char> data) { "heads/curl/res/content/base/blocks/lamp.json";
if (data.empty()) { request.onResponse = [](std::vector<char> data) {
return; if (data.empty()) {
} return;
auto view = std::string_view(data.data(), data.size()); }
auto value = json::parse(view); auto view = std::string_view(data.data(), data.size());
std::cout << value << std::endl; auto value = json::parse(view);
}, [](auto, auto){} std::cout << value << std::endl;
); };
network->request(std::move(request));
std::cout << "upload: " << network->getTotalUpload() << " B" << std::endl; std::cout << "upload: " << network->getTotalUpload() << " B" << std::endl;
std::cout << "download: " << network->getTotalDownload() << " B" << std::endl; std::cout << "download: " << network->getTotalDownload() << " B" << std::endl;
} }