mirror of
https://github.com/alicealys/t5-gsc-utils.git
synced 2025-04-19 12:32:53 +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 scripting::entity player = game::Scr_GetEntityId(game::SCRIPTINSTANCE_SERVER, client_num, 0, 0);
|
||||||
|
|
||||||
const auto command = utils::string::to_lower(params[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)
|
for (const auto& callback : chat_callbacks)
|
||||||
{
|
{
|
||||||
|
@ -207,6 +207,18 @@ namespace gsc
|
|||||||
|
|
||||||
return scr_get_builtin_hook.invoke<unsigned int>(inst, func_name);
|
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
|
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 + 40, 0xAABA68 + 40), '\n');
|
||||||
utils::hook::set<char>(SELECT_VALUE(0x9FC5C0 + 41, 0xAABA68 + 41), '\0');
|
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)
|
gsc::function::add("array", [](const scripting::variadic_args& va)
|
||||||
{
|
{
|
||||||
scripting::array array{};
|
scripting::array array{};
|
||||||
@ -267,6 +281,30 @@ namespace gsc
|
|||||||
{
|
{
|
||||||
return value.type_name();
|
return value.type_name();
|
||||||
}, "typeof", "type");
|
}, "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)
|
gsc::function::add("print", [](const scripting::variadic_args& va)
|
||||||
{
|
{
|
||||||
|
std::string buffer{};
|
||||||
|
|
||||||
for (const auto& arg : va)
|
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");
|
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);
|
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 Scr_GetArrayIndexValue(scriptInstance_t, unsigned int name)
|
||||||
{
|
{
|
||||||
VariableValue value{};
|
VariableValue value{};
|
||||||
|
@ -65,6 +65,9 @@ namespace game
|
|||||||
|
|
||||||
VariableValue Scr_GetArrayIndexValue(scriptInstance_t inst, unsigned int name);
|
VariableValue Scr_GetArrayIndexValue(scriptInstance_t inst, unsigned int name);
|
||||||
unsigned int Scr_GetSelf(scriptInstance_t inst, unsigned int threadId);
|
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"
|
#include "symbols.hpp"
|
||||||
|
@ -72,6 +72,8 @@ namespace scripting
|
|||||||
{
|
{
|
||||||
return {this->id_, this->get_value_id(key.as<S>())};
|
return {this->id_, this->get_value_id(key.as<S>())};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
throw std::runtime_error("Invalid key type");
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -63,17 +63,7 @@ namespace scripting
|
|||||||
|
|
||||||
object::object()
|
object::object()
|
||||||
{
|
{
|
||||||
this->id_ = make_object();
|
this->id_ = game::AllocObject(game::SCRIPTINSTANCE_SERVER);
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object::~object()
|
object::~object()
|
||||||
@ -157,14 +147,14 @@ namespace scripting
|
|||||||
return game::Scr_GetSelf(game::SCRIPTINSTANCE_SERVER, this->id_);
|
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);
|
const auto variable_id = game::FindVariable(game::SCRIPTINSTANCE_SERVER, this->id_, string_value);
|
||||||
if (variable_id)
|
if (variable_id)
|
||||||
{
|
{
|
||||||
game::RemoveVariableValue(game::SCRIPTINSTANCE_SERVER, this->id_, variable_id);
|
game::RemoveVariableValue(game::SCRIPTINSTANCE_SERVER, this->id_, variable_id);
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
script_value object::get(const std::string& /*key*/) const
|
script_value object::get(const std::string& /*key*/) const
|
||||||
|
@ -19,8 +19,6 @@ namespace scripting
|
|||||||
object();
|
object();
|
||||||
object(const unsigned int);
|
object(const unsigned int);
|
||||||
|
|
||||||
object(std::unordered_map<std::string, script_value>);
|
|
||||||
|
|
||||||
object(const object& other);
|
object(const object& other);
|
||||||
object(object&& other) noexcept;
|
object(object&& other) noexcept;
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ namespace game
|
|||||||
|
|
||||||
WEAK symbol<void(scriptInstance_t inst)> Scr_ClearOutParams{0x654D10, 0x588680};
|
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<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, unsigned int id)> RemoveRefToObject{0x5517B0, 0x698FA0};
|
||||||
WEAK symbol<void(scriptInstance_t inst, const float* vectorValue)> RemoveRefToVector{0x0, 0x0};
|
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<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(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<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};
|
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 <stdinc.hpp>
|
||||||
#include "http.hpp"
|
#include "http.hpp"
|
||||||
#include <curl/curl.h>
|
|
||||||
#include <gsl/gsl>
|
#include <gsl/gsl>
|
||||||
|
|
||||||
#pragma comment(lib, "ws2_32.lib")
|
#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;
|
curl_slist* header_list = nullptr;
|
||||||
auto* curl = curl_easy_init();
|
auto* curl = curl_easy_init();
|
||||||
@ -78,9 +79,27 @@ namespace utils::http
|
|||||||
curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &helper);
|
curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &helper);
|
||||||
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
|
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)
|
if (helper.exception)
|
||||||
@ -90,12 +109,4 @@ namespace utils::http
|
|||||||
|
|
||||||
return {};
|
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 <optional>
|
||||||
#include <future>
|
#include <future>
|
||||||
|
|
||||||
|
#include <curl/curl.h>
|
||||||
|
|
||||||
namespace utils::http
|
namespace utils::http
|
||||||
{
|
{
|
||||||
|
struct result
|
||||||
|
{
|
||||||
|
CURLcode code;
|
||||||
|
std::string buffer;
|
||||||
|
};
|
||||||
|
|
||||||
using headers = std::unordered_map<std::string, std::string>;
|
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::optional<result> get_data(const std::string& url, const std::string& fields = {},
|
||||||
std::future<std::optional<std::string>> get_data_async(const std::string& url, const headers& headers = {});
|
const headers& headers = {}, const std::function<void(size_t)>& callback = {});
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user