Address #14 with request correlation, bounded parser reasons, startup version reporting, and rate-limited storage and settlement logs. Preserve accounting and API identity contracts, extend portable tests, and update release versions and rollout guidance.
tws-t6-gsc-utils
Source: alicealys/t6-gsc-utils. The baseline commit and dependency revisions are in tws-t6-gsc-utils/upstream.json. Source is tracked here directly; dependency checkouts are restored from that manifest and ignored. Follow the build instructions. Upstream API documentation is in tws-t6-gsc-utils/README.md.
HTTP deadlines and diagnostics
All native HTTP requests default to connect_timeout_ms = 5000 and
timeout_ms = 15000. The latter includes connection setup; the shorter limit
wins during connection. Both can be overridden in the existing options array
with positive integer milliseconds. Zero, negative and non-integer overrides
are rejected before a request is created. Neither retries nor redirects are
added. TLS certificate verification remains enabled.
These are libcurl transfer deadlines, starting when a worker begins the request.
Time waiting for a worker or the game thread to deliver completion is measured
separately. A native timeout releases the request and emits done with
success = false, a transport error, and diagnostics. Each request is sent once.
The telemetry sender retries start/end reports at the head of its ordered queue.
A timeout does not prove the API did not already accept the event.
The existing completion values remain in the same positions. An optional fourth value adds diagnostics:
request waittill("done", response, success, error, diagnostics);
success continues to mean transport success, including completed HTTP 4xx/5xx
responses. Existing scripts that read only the first three values still work.
Current reporters also require the native telemetry helpers below; deploy the
matching DLL and restart the process before loading the updated scripts.
| Field | Meaning |
|---|---|
http_status |
HTTP response code; 0 if none was received |
curl_code |
libcurl result; 0 is transport success, 28 is timeout |
dns_ms |
Time to finish name resolution |
connect_ms |
Time to establish TCP |
tls_ms |
Time to finish TLS; 0 if no TLS handshake completed |
first_byte_ms |
Time to first response byte; 0 if none arrived |
total_ms |
Total native transfer duration |
worker_queue_ms |
Time waiting for the plugin worker pool |
notify_ms |
Time from native completion to notifying GSC |
connect_timeout_ms, timeout_ms |
Effective native deadlines |
Curl milestone times are cumulative from transfer start, not durations to add together. Diagnostics are provided for failures as well as successful transfers; an unfinished milestone can be zero. No request headers, tokens or URLs are included in diagnostics. Responses retain the existing 20 KiB truncation behavior.
Telemetry logs the status and timings for each completion at log level 1.
Non-2xx responses log at level 0 with a bounded response preview. Health counters
keep transport completed/failed and track http_rejected separately; an HTTP
rejection is a completed transport. accepted counts only 2xx replies with the
JSON boolean ok: true. Report identities, retry behavior, heartbeat coalescing
and persistence are described in the shared
delivery and rollout notes.
Durable telemetry helpers
The paired component/telemetry.cpp and utils/telemetry.* provide:
telemetryNewMatch(): a random process token plus a process-local match counter.telemetryLoad(server, endpoint): ordered saved boundary entries, or undefined on an unreadable/corrupt outbox. An empty outbox returns an empty GSC array.telemetryStore(server, endpoint, body): idempotently commit an exact boundary snapshot; false on storage, validation or capacity failure.telemetryRemove(server, endpoint, match, seq): atomically remove a resolved entry; false on failure. The old committed file remains available on failure.telemetryResponse(body): parse bounded JSON without throwing on malformed responses, returningaccepted(strict booleanok) andmatch_id(a string). The GSC reporter separately checks the HTTP status before accepting it.
The native helpers avoid the generic JSON-to-GSC converter's boolean handling.
Outbox files are scoped by game, server and endpoint under fs_homepath/tws-telemetry.
They contain snapshots, never authentication headers. One writer per scope is
required. Writes replace the old file with MoveFileExW; stale .tmp files are
ignored during recovery. Native memory supplies identity only; pending reports
come from disk after every script or process restart.
Validation and rollout
Run python3 tools/test_plugin_http.py from the repository root for portable
native HTTP tests, and python3 tools/test_plugin_telemetry.py for outbox and
acknowledgment tests (requires the pinned JSON headers). Deploy Electric Cherry
#144 first as described in the shared rollout notes. Build the x86 DLL on Windows, then on a test game server check:
- Updated telemetry reports HTTP status and all timing fields on normal requests.
- An endpoint that accepts a connection but does not reply produces a native timeout near 15 seconds; a start/end is retried before the next queued report.
- HTTP 401 is terminal; 429/500 retain start/end at the queue head and retry.
Non-2xx replies increment
http_rejected; transport errors incrementfailed. - Leaderboard and older three-value HTTP consumers still receive completion.
- After a full server-process restart, verify all four telemetry event types in Electric Cherry. A successful transport alone is not API acceptance.
The localhost tests compile the actual HTTP utility against the host libcurl. They do not validate Windows linking, its Schannel backend or game VM notification handling. Those checks require the Windows build and a running Plutonium server.
Bank support (TWS 1.1.0)
bankLoad, bankStore, bankRemove and bankResponse provide durable transfer
decisions and strict response validation for the new bank script. Build and
install the DLL, then restart the full process. No upstream pins or external
dependencies changed. See bank setup and recovery.
Portable checks: python3 tools/test_plugin_bank.py.
Bank diagnostics (TWS 1.2.0)
bankVersion() returns the loaded DLL's TWS component version, independently of
upstream pins and the native loader's unchanged plugin_version() value.
bankResponse() now also returns reason: ok on success, otherwise one of
empty_body, body_limit, invalid_json, schema, field_limit, state,
amount_range, ok_state, missing_id, or zero_transfer. Invalid responses
clear all parsed fields. Existing acknowledgment acceptance rules are unchanged.
The returned code on valid responses remains API data; bank scripts allowlist
it before logging. Callers must never log arbitrary response fields.
Native journal logs name load/write/remove, limit identical failures to one
per 30 seconds, and log recovery with suppressed counts. Exception text, journal
contents and credentials are excluded. The new scripts require this DLL even
when disabled by dvar because bankVersion() must link. No new third-party
dependencies or upstream pin changes are required. Rebuild/install the DLL and
restart the full server process; see the diagnostic rollout.
Portable checks: python3 tools/test_plugin_bank.py executes the real parser,
storage and native registration adapter with sanitizers and engine shims.