Merge pull request #432 from MihailRis/http-post

add network.post
This commit is contained in:
MihailRis 2025-01-08 18:33:01 +03:00 committed by GitHub
commit 010ed78aba
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 101 additions and 10 deletions

View File

@ -16,6 +16,11 @@ end)
-- A variant for binary files, with a byte array instead of a string in the response.
network.get_binary(url: str, callback: function(table|ByteArray))
-- Performs a POST request to the specified URL.
-- Currently, only `Content-Type: application/json` is supported
-- After receiving the response, passes the text to the callback function.
network.post(url: str, data: table, callback: function(str))
```
## TCP Connections

View File

@ -16,6 +16,11 @@ end)
-- Вариант для двоичных файлов, с массивом байт вместо строки в ответе.
network.get_binary(url: str, callback: function(table|ByteArray))
-- Выполняет POST запрос к указанному URL.
-- На данный момент реализована поддержка только `Content-Type: application/json`
-- После получения ответа, передаёт текст в функцию callback.
network.post(url: str, data: table, callback: function(str))
```
## TCP-Соединения

View File

@ -2,6 +2,7 @@
#include "engine/Engine.hpp"
#include "network/Network.hpp"
#include "coders/json.hpp"
using namespace scripting;
@ -36,6 +37,25 @@ static int l_get_binary(lua::State* L) {
return 0;
}
static int l_post(lua::State* L) {
std::string url(lua::require_lstring(L, 1));
auto data = lua::tovalue(L, 2);
lua::pushvalue(L, 3);
auto onResponse = lua::create_lambda_nothrow(L);
auto string = json::stringify(data, false);
engine->getNetwork().post(url, string, [onResponse](std::vector<char> bytes) {
auto buffer = std::make_shared<util::Buffer<ubyte>>(
reinterpret_cast<const ubyte*>(bytes.data()), bytes.size()
);
engine->postRunnable([=]() {
onResponse({std::string(bytes.data(), bytes.size())});
});
});
return 0;
}
static int l_connect(lua::State* L) {
std::string address = lua::require_string(L, 1);
int port = lua::tointeger(L, 2);
@ -200,6 +220,7 @@ static int l_get_total_download(lua::State* L) {
const luaL_Reg networklib[] = {
{"get", lua::wrap<l_get>},
{"get_binary", lua::wrap<l_get_binary>},
{"post", lua::wrap<l_post>},
{"get_total_upload", lua::wrap<l_get_total_upload>},
{"get_total_download", lua::wrap<l_get_total_download>},
{"__open", lua::wrap<l_open>},

View File

@ -42,12 +42,18 @@ static size_t write_callback(
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;
};
class CurlRequests : public Requests {
@ -73,22 +79,33 @@ public:
curl_easy_cleanup(curl);
curl_multi_cleanup(multiHandle);
}
void get(
const std::string& url,
OnResponse onResponse,
OnReject onReject,
long maxSize
) override {
Request request {url, onResponse, onReject, maxSize};
if (url.empty()) {
processRequest(request);
} else {
requests.push(request);
}
Request request {RequestType::GET, url, onResponse, onReject, maxSize};
processRequest(std::move(request));
}
void processRequest(const Request& request) {
void post(
const std::string& url,
const std::string& data,
OnResponse onResponse,
OnReject onReject=nullptr,
long maxSize=0
) override {
Request request {RequestType::POST, url, onResponse, onReject, maxSize};
request.data = data;
processRequest(std::move(request));
}
void processRequest(Request request) {
if (!url.empty()) {
requests.push(request);
return;
}
onResponse = request.onResponse;
onReject = request.onReject;
url = request.url;
@ -96,9 +113,25 @@ public:
buffer.clear();
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_POST, request.type == RequestType::POST);
curl_slist* hs = NULL;
switch (request.type) {
case RequestType::GET:
break;
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_FOLLOWLOCATION, request.followLocation);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, request.followLocation);
curl_easy_setopt(curl, CURLOPT_USERAGENT, "curl/7.81.0");
if (request.maxSize == 0) {
curl_easy_setopt(
@ -164,7 +197,7 @@ public:
if (url.empty() && !requests.empty()) {
auto request = std::move(requests.front());
requests.pop();
processRequest(request);
processRequest(std::move(request));
}
}
@ -562,6 +595,16 @@ void Network::get(
requests->get(url, onResponse, onReject, maxSize);
}
void Network::post(
const std::string& url,
const std::string& fieldsData,
OnResponse onResponse,
OnReject onReject,
long maxSize
) {
requests->post(url, fieldsData, onResponse, onReject, maxSize);
}
Connection* Network::getConnection(u64id_t id) {
std::lock_guard lock(connectionsMutex);

View File

@ -23,6 +23,15 @@ namespace network {
OnReject onReject=nullptr,
long maxSize=0
) = 0;
virtual void post(
const std::string& url,
const std::string& data,
OnResponse onResponse,
OnReject onReject=nullptr,
long maxSize=0
) = 0;
virtual size_t getTotalUpload() const = 0;
virtual size_t getTotalDownload() const = 0;
@ -84,6 +93,14 @@ namespace network {
long maxSize=0
);
void post(
const std::string& url,
const std::string& fieldsData,
OnResponse onResponse,
OnReject onReject = nullptr,
long maxSize=0
);
[[nodiscard]] Connection* getConnection(u64id_t id);
[[nodiscard]] TcpServer* getServer(u64id_t id) const;