Organize scripts and add TWS plugins with HTTP timeouts

Vendor pinned T5 and T6 plugin sources under the new plugins layout. Add native HTTP deadlines, status and timing diagnostics, telemetry integration, and build/test tooling.
This commit is contained in:
2026-10-09 11:02:20 -04:00
parent b172086301
commit 1121b44857
253 changed files with 28028 additions and 59 deletions
+94
View File
@@ -0,0 +1,94 @@
int main()
{
using namespace scripting;
http::http_request_params_t params{};
array options;
http::parse_request_options(params, options);
assert(params.limits.connect_timeout_ms == 5000 && params.limits.timeout_ms == 15000);
options["connect_timeout_ms"] = 120;
options["timeout_ms"] = 450;
options["method"] = "POST";
options["body"] = "snapshot";
array headers;
headers["Authorization"] = "Bearer test-only";
options["headers"] = headers;
http::parse_request_options(params, options);
assert(params.limits.connect_timeout_ms == 120 && params.limits.timeout_ms == 450);
assert(params.method == "POST" && params.fields == "snapshot" && params.headers.at("Authorization") == "Bearer test-only");
for (const auto* key : {"connect_timeout_ms", "timeout_ms"})
{
for (script_value value : {script_value(0), script_value(-1), script_value(1.5), script_value("150")})
{
array bad;
bad[key] = value;
bool rejected = false;
try { http::parse_request_options(params, bad); }
catch (const std::runtime_error&) { rejected = true; }
assert(rejected);
}
}
http::parse_request_options(params, options);
auto send = [&]()
{
notifications.clear();
http::create_request(params);
http::check_requests();
assert(notifications.empty()); // Incomplete work never notifies early.
scheduler::thread_pool.run();
http::check_requests();
assert(notifications.size() == 1 && notifications.front().size() == 4);
assert(utils::http::observed_limits.connect_timeout_ms == 120 && utils::http::observed_limits.timeout_ms == 450);
auto diagnostics = notifications.front()[3].as<array>();
assert(diagnostics["worker_queue_ms"].as<double>() >= 0 && diagnostics["notify_ms"].as<double>() >= 0);
assert(diagnostics["connect_timeout_ms"].as<int>() == 120 && diagnostics["timeout_ms"].as<int>() == 450);
assert(diagnostics.data->size() == 11);
http::check_requests();
assert(notifications.size() == 1); // Exactly one completion.
return diagnostics;
};
utils::http::result successful;
successful.code = CURLE_OK;
successful.status = 200;
successful.buffer = "accepted";
successful.dns_ms = 1;
successful.connect_ms = 2;
successful.tls_ms = 3;
successful.first_byte_ms = 4;
successful.total_ms = 5;
utils::http::next_result = successful;
auto diagnostics = send();
assert(notifications.front()[0].as<std::string>() == "accepted" && notifications.front()[1].as<bool>());
assert(notifications.front()[2].get_raw().type == game::SCRIPT_NONE);
assert(diagnostics["http_status"].as<int>() == 200 && diagnostics["curl_code"].as<int>() == 0);
assert(diagnostics["dns_ms"].as<double>() == 1 && diagnostics["connect_ms"].as<double>() == 2);
assert(diagnostics["tls_ms"].as<double>() == 3 && diagnostics["first_byte_ms"].as<double>() == 4 && diagnostics["total_ms"].as<double>() == 5);
utils::http::next_result->status = 500;
assert(send()["http_status"].as<int>() == 500 && notifications.front()[1].as<bool>());
utils::http::next_result->code = CURLE_OPERATION_TIMEDOUT;
assert(send()["curl_code"].as<int>() == 28 && !notifications.front()[1].as<bool>());
assert(notifications.front()[0].get_raw().type == game::SCRIPT_NONE && notifications.front()[2].is<std::string>());
utils::http::next_result = std::nullopt;
send();
assert(!notifications.front()[1].as<bool>());
utils::http::throw_from_transfer = true;
send();
assert(!notifications.front()[1].as<bool>());
utils::http::throw_from_transfer = false;
utils::http::next_result = successful;
utils::http::next_result->buffer = std::string(0x5001, 'x');
send();
assert(notifications.front()[0].as<std::string>().size() == 0x5000);
// A resumed waiter can enqueue enough work to reallocate the pending vector.
utils::http::next_result = successful;
notifications.clear();
http::create_request(params);
scheduler::thread_pool.run();
after_notify = [&]() { for (int i = 0; i < 100; ++i) http::create_request(params); };
http::check_requests();
after_notify = {};
assert(http::requests.size() == 100 && notifications.size() == 1);
scheduler::thread_pool.run();
http::check_requests();
assert(http::requests.empty() && notifications.size() == 101);
puts("\nPASS component: option validation, metadata, compatible argument order, single completion on failures/exceptions, reentrant queue");
}