mirror of
https://github.com/alicealys/t5-gsc-utils.git
synced 2025-04-18 20:22:52 +00:00
HTTP functions #5
This commit is contained in:
parent
2111db394d
commit
8c0d999a2a
@ -57,7 +57,7 @@ namespace command
|
||||
const scripting::entity player = game::Scr_GetEntityId(game::SCRIPTINSTANCE_SERVER, client_num, 0, 0);
|
||||
|
||||
const auto command = utils::string::to_lower(params[0]);
|
||||
const auto message = params.join(1);
|
||||
const auto message = params.join(1).substr(1);
|
||||
|
||||
for (const auto& callback : chat_callbacks)
|
||||
{
|
||||
|
@ -207,6 +207,18 @@ namespace gsc
|
||||
|
||||
return scr_get_builtin_hook.invoke<unsigned int>(inst, func_name);
|
||||
}
|
||||
|
||||
// Scr_NotifyId doesn't exist, Scr_NotifyNum_Internal calls FindVariableId to get the variable id from entnum, classnum & clientNum
|
||||
// to not have to recreate Scr_NotifyId we simply make FindVariableId return `entnum` (which in this case will be the id) if `clientNum` == -1
|
||||
unsigned int find_variable_id_stub(int inst, int entnum, unsigned int classnum, int client_num)
|
||||
{
|
||||
if (client_num == -1)
|
||||
{
|
||||
return entnum;
|
||||
}
|
||||
|
||||
return utils::hook::invoke<unsigned int>(SELECT_VALUE(0x5E96E0, 0x40BEF0), inst, entnum, classnum, client_num);
|
||||
}
|
||||
}
|
||||
|
||||
namespace function
|
||||
@ -251,6 +263,8 @@ namespace gsc
|
||||
utils::hook::set<char>(SELECT_VALUE(0x9FC5C0 + 40, 0xAABA68 + 40), '\n');
|
||||
utils::hook::set<char>(SELECT_VALUE(0x9FC5C0 + 41, 0xAABA68 + 41), '\0');
|
||||
|
||||
utils::hook::call(SELECT_VALUE(0x41D2B5, 0x416325), find_variable_id_stub);
|
||||
|
||||
gsc::function::add("array", [](const scripting::variadic_args& va)
|
||||
{
|
||||
scripting::array array{};
|
||||
@ -267,6 +281,30 @@ namespace gsc
|
||||
{
|
||||
return value.type_name();
|
||||
}, "typeof", "type");
|
||||
|
||||
gsc::function::add("debug::get_var_count", []()
|
||||
{
|
||||
auto count = 0;
|
||||
|
||||
if (game::environment::is_sp())
|
||||
{
|
||||
for (auto i = 1; i < 0x5FFE; i++)
|
||||
{
|
||||
const auto var = game::scr_VarGlob->variableList_mp[i];
|
||||
count += var.w.status != 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto i = 1; i < 0x7FFE; i++)
|
||||
{
|
||||
const auto var = game::scr_VarGlob->variableList_mp[i];
|
||||
count += var.w.status != 0;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
177
src/component/http.cpp
Normal file
177
src/component/http.cpp
Normal file
@ -0,0 +1,177 @@
|
||||
#include <stdinc.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
|
||||
#include "game/structs.hpp"
|
||||
#include "game/game.hpp"
|
||||
|
||||
#include "gsc.hpp"
|
||||
#include "scheduler.hpp"
|
||||
#include "scripting.hpp"
|
||||
|
||||
#include <utils/http.hpp>
|
||||
#include <curl/curl.h>
|
||||
|
||||
namespace http
|
||||
{
|
||||
std::unordered_map<uint64_t, bool> active_requests{};
|
||||
uint64_t request_id{};
|
||||
|
||||
class component final : public component_interface
|
||||
{
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
scripting::on_shutdown([]()
|
||||
{
|
||||
active_requests.clear();
|
||||
});
|
||||
|
||||
gsc::function::add_multiple([](const std::string& url)
|
||||
{
|
||||
const auto id = request_id++;
|
||||
active_requests[id] = true;
|
||||
|
||||
const auto object = scripting::object{};
|
||||
const auto object_id = object.get_entity_id();
|
||||
|
||||
scheduler::once([id, object_id, url]()
|
||||
{
|
||||
const auto data = utils::http::get_data(url);
|
||||
scheduler::once([id, object_id, data]()
|
||||
{
|
||||
if (active_requests.find(id) == active_requests.end())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!data.has_value())
|
||||
{
|
||||
scripting::notify(object_id, "done", {{}, false, "Unknown error"});
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& result = data.value();
|
||||
const auto error = curl_easy_strerror(result.code);
|
||||
|
||||
if (result.code != CURLE_OK)
|
||||
{
|
||||
scripting::notify(object_id, "done", {{}, false, error});
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.buffer.size() >= 0x5000)
|
||||
{
|
||||
printf("^3WARNING: http result size bigger than 20480 bytes (%i), truncating!", static_cast<int>(result.buffer.size()));
|
||||
}
|
||||
|
||||
scripting::notify(object_id, "done", {result.buffer.substr(0, 0x5000), true});
|
||||
}, scheduler::pipeline::server);
|
||||
}, scheduler::pipeline::async);
|
||||
|
||||
return object;
|
||||
}, "http::get", "httpget", "curl");
|
||||
|
||||
gsc::function::add("http::request", [](const std::string& url, const scripting::variadic_args& va)
|
||||
{
|
||||
const auto id = request_id++;
|
||||
active_requests[id] = true;
|
||||
|
||||
const auto object = scripting::object{};
|
||||
const auto object_id = object.get_entity_id();
|
||||
|
||||
std::string fields_string{};
|
||||
std::unordered_map<std::string, std::string> headers_map{};
|
||||
|
||||
if (va.size() > 0)
|
||||
{
|
||||
const auto options = va[0].as<scripting::array>();
|
||||
|
||||
const auto fields = options["parameters"];
|
||||
const auto body = options["body"];
|
||||
const auto headers = options["headers"];
|
||||
|
||||
if (fields.is<scripting::array>())
|
||||
{
|
||||
const auto fields_ = fields.as<scripting::array>();
|
||||
const auto keys = fields_.get_keys();
|
||||
|
||||
for (const auto& key : keys)
|
||||
{
|
||||
if (!key.is<std::string>())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto key_ = key.as<std::string>();
|
||||
const auto value = fields_[key].to_string();
|
||||
fields_string += key_ + "=" + value + "&";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (body.is<std::string>())
|
||||
{
|
||||
fields_string = body.as<std::string>();
|
||||
}
|
||||
|
||||
if (headers.is<scripting::array>())
|
||||
{
|
||||
const auto headers_ = headers.as<scripting::array>();
|
||||
const auto keys = headers_.get_keys();
|
||||
|
||||
for (const auto& key : keys)
|
||||
{
|
||||
if (!key.is<std::string>())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto key_ = key.as<std::string>();
|
||||
const auto value = headers_[key].to_string();
|
||||
|
||||
headers_map[key_] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scheduler::once([id, object_id, url, fields_string, headers_map]()
|
||||
{
|
||||
const auto data = utils::http::get_data(url, fields_string, headers_map);
|
||||
scheduler::once([data, object_id, id]
|
||||
{
|
||||
if (active_requests.find(id) == active_requests.end())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!data.has_value())
|
||||
{
|
||||
scripting::notify(object_id, "done", {{}, false, "Unknown error"});
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& result = data.value();
|
||||
const auto error = curl_easy_strerror(result.code);
|
||||
|
||||
if (result.code != CURLE_OK)
|
||||
{
|
||||
scripting::notify(object_id, "done", {{}, false, error});
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.buffer.size() >= 0x5000)
|
||||
{
|
||||
printf("^3WARNING: http result size bigger than 20480 bytes (%i), truncating!", static_cast<int>(result.buffer.size()));
|
||||
}
|
||||
|
||||
scripting::notify(object_id, "done", {result.buffer.substr(0, 0x5000), true});
|
||||
}, scheduler::pipeline::server);
|
||||
}, scheduler::pipeline::async);
|
||||
|
||||
return object;
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
REGISTER_COMPONENT(http::component)
|
@ -172,11 +172,14 @@ namespace string
|
||||
|
||||
gsc::function::add("print", [](const scripting::variadic_args& va)
|
||||
{
|
||||
std::string buffer{};
|
||||
|
||||
for (const auto& arg : va)
|
||||
{
|
||||
printf("%s\t", arg.to_string().data());
|
||||
buffer.append(utils::string::va("%s\t", arg.to_string().data()));
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("%s\n", buffer.data());
|
||||
});
|
||||
|
||||
gsc::function::add_multiple(utils::string::to_upper, "toupper", "string::to_upper");
|
||||
|
@ -67,6 +67,12 @@ namespace game
|
||||
return utils::hook::invoke<unsigned int>(func, inst);
|
||||
}
|
||||
|
||||
void Scr_NotifyId(scriptInstance_t inst, int /*client_num*/, unsigned int id,
|
||||
unsigned int string_value, unsigned int paramcount)
|
||||
{
|
||||
game::Scr_NotifyNum_Internal(inst, -1, id, 0, string_value, paramcount);
|
||||
}
|
||||
|
||||
VariableValue Scr_GetArrayIndexValue(scriptInstance_t, unsigned int name)
|
||||
{
|
||||
VariableValue value{};
|
||||
|
@ -65,6 +65,9 @@ namespace game
|
||||
|
||||
VariableValue Scr_GetArrayIndexValue(scriptInstance_t inst, unsigned int name);
|
||||
unsigned int Scr_GetSelf(scriptInstance_t inst, unsigned int threadId);
|
||||
|
||||
void Scr_NotifyId(scriptInstance_t inst, int client_num, unsigned int id,
|
||||
unsigned int string_value, unsigned int paramcount);
|
||||
}
|
||||
|
||||
#include "symbols.hpp"
|
||||
|
@ -72,6 +72,8 @@ namespace scripting
|
||||
{
|
||||
return {this->id_, this->get_value_id(key.as<S>())};
|
||||
}
|
||||
|
||||
throw std::runtime_error("Invalid key type");
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -63,17 +63,7 @@ namespace scripting
|
||||
|
||||
object::object()
|
||||
{
|
||||
this->id_ = make_object();
|
||||
}
|
||||
|
||||
object::object(std::unordered_map<std::string, script_value> values)
|
||||
{
|
||||
this->id_ = make_object();
|
||||
|
||||
for (const auto& value : values)
|
||||
{
|
||||
this->set(value.first, value.second);
|
||||
}
|
||||
this->id_ = game::AllocObject(game::SCRIPTINSTANCE_SERVER);
|
||||
}
|
||||
|
||||
object::~object()
|
||||
@ -157,14 +147,14 @@ namespace scripting
|
||||
return game::Scr_GetSelf(game::SCRIPTINSTANCE_SERVER, this->id_);
|
||||
}
|
||||
|
||||
void object::erase(const std::string& key) const
|
||||
void object::erase(const std::string& /*key*/) const
|
||||
{
|
||||
const auto string_value = game::SL_GetCanonicalString(key.data(), 0);
|
||||
/*const auto string_value = game::SL_GetCanonicalString(key.data(), 0);
|
||||
const auto variable_id = game::FindVariable(game::SCRIPTINSTANCE_SERVER, this->id_, string_value);
|
||||
if (variable_id)
|
||||
{
|
||||
game::RemoveVariableValue(game::SCRIPTINSTANCE_SERVER, this->id_, variable_id);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
script_value object::get(const std::string& /*key*/) const
|
||||
|
@ -19,8 +19,6 @@ namespace scripting
|
||||
object();
|
||||
object(const unsigned int);
|
||||
|
||||
object(std::unordered_map<std::string, script_value>);
|
||||
|
||||
object(const object& other);
|
||||
object(object&& other) noexcept;
|
||||
|
||||
|
@ -41,7 +41,7 @@ namespace game
|
||||
|
||||
WEAK symbol<void(scriptInstance_t inst)> Scr_ClearOutParams{0x654D10, 0x588680};
|
||||
|
||||
WEAK symbol<unsigned int(scriptInstance_t inst)> AllocObject{0x0, 0x0};
|
||||
WEAK symbol<unsigned int(scriptInstance_t inst)> AllocObject{0x603400, 0x6970B0};
|
||||
WEAK symbol<unsigned int(scriptInstance_t inst, unsigned int id)> AllocThread{0x69E140, 0x43CA60};
|
||||
WEAK symbol<void(scriptInstance_t inst, unsigned int id)> RemoveRefToObject{0x5517B0, 0x698FA0};
|
||||
WEAK symbol<void(scriptInstance_t inst, const float* vectorValue)> RemoveRefToVector{0x0, 0x0};
|
||||
@ -69,7 +69,8 @@ namespace game
|
||||
WEAK symbol<VariableValue(scriptInstance_t inst, unsigned int classnum, int entnum, int clientNum, int offset)> GetEntityFieldValue{0x0, 0x0};
|
||||
|
||||
WEAK symbol<void(gentity_s* ent, unsigned int stringValue, unsigned int paramcount)> Scr_Notify{0x0, 0x0};
|
||||
WEAK symbol<void(scriptInstance_t inst, int clientNum, unsigned int id, unsigned int stringValue, unsigned int paramcount)> Scr_NotifyId{0x0, 0x0};
|
||||
WEAK symbol<void(scriptInstance_t inst, int clientNum, int entnum,
|
||||
unsigned int classnum, unsigned int stringValue, unsigned int paramcount)> Scr_NotifyNum_Internal{0x41D270, 0x4162E0};
|
||||
WEAK symbol<void(int entnum, unsigned int classnum, unsigned int stringValue, unsigned int paramcount)> Scr_NotifyNum{0x0, 0x0};
|
||||
|
||||
WEAK symbol<unsigned int(const char* str, unsigned int user, scriptInstance_t inst)> SL_GetString{0x463130, 0x4B1770};
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include <stdinc.hpp>
|
||||
#include "http.hpp"
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include <gsl/gsl>
|
||||
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
@ -45,7 +45,8 @@ namespace utils::http
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<std::string> get_data(const std::string& url, const headers& headers, const std::function<void(size_t)>& callback)
|
||||
std::optional<result> get_data(const std::string& url, const std::string& fields,
|
||||
const headers& headers, const std::function<void(size_t)>& callback)
|
||||
{
|
||||
curl_slist* header_list = nullptr;
|
||||
auto* curl = curl_easy_init();
|
||||
@ -78,9 +79,27 @@ namespace utils::http
|
||||
curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &helper);
|
||||
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
|
||||
|
||||
if (curl_easy_perform(curl) == CURLE_OK)
|
||||
if (!fields.empty())
|
||||
{
|
||||
return {std::move(buffer)};
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, fields.data());
|
||||
}
|
||||
|
||||
const auto code = curl_easy_perform(curl);
|
||||
|
||||
if (code == CURLE_OK)
|
||||
{
|
||||
result result;
|
||||
result.code = code;
|
||||
result.buffer = std::move(buffer);
|
||||
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
result result;
|
||||
result.code = code;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if (helper.exception)
|
||||
@ -90,12 +109,4 @@ namespace utils::http
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::future<std::optional<std::string>> get_data_async(const std::string& url, const headers& headers)
|
||||
{
|
||||
return std::async(std::launch::async, [url, headers]()
|
||||
{
|
||||
return get_data(url, headers);
|
||||
});
|
||||
}
|
||||
}
|
@ -4,10 +4,18 @@
|
||||
#include <optional>
|
||||
#include <future>
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
namespace utils::http
|
||||
{
|
||||
struct result
|
||||
{
|
||||
CURLcode code;
|
||||
std::string buffer;
|
||||
};
|
||||
|
||||
using headers = std::unordered_map<std::string, std::string>;
|
||||
|
||||
std::optional<std::string> get_data(const std::string& url, const headers& headers = {}, const std::function<void(size_t)>& callback = {});
|
||||
std::future<std::optional<std::string>> get_data_async(const std::string& url, const headers& headers = {});
|
||||
std::optional<result> get_data(const std::string& url, const std::string& fields = {},
|
||||
const headers& headers = {}, const std::function<void(size_t)>& callback = {});
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user