Proposal: HTTP client standard library (Http.*) — async poll-based, TLS, JSON #6
Labels
No labels
area:ci
area:docs
area:input
area:net
area:rendering
area:repo
area:stdlib
area:tooling
area:types
cleanup
dx
priority:high
priority:low
priority:medium
proposal
status:in-progress
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: workshopsoft/ludic#6
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
Modern games talk to the web: leaderboards, cloud saves, remote config/feature flags, analytics, news/MOTD, asset downloads, and simple web APIs. Ludic has raw sockets via the networking primitives (
net_send/net_poll, see theNet.*proposal in #2) but no HTTP. This proposes anHttp.*standard-library client, modeled on Go'snet/http(client, methods, headers, timeouts, TLS) and Godot'sHTTPRequest(async, TLS with certificate verification).Async model — never block the frame
A game loop can't stall on a socket. Two complementary forms:
net_polland the deterministic frame loop, no threads/promises):Request / response
GET POST PUT PATCH DELETE HEAD.Http.form(...),Http.multipart(...).stror raw bytes (for downloads);res.json()returns a parsed value.timeout,retry(Go go-resty styleWithRetry/WithTimeout), redirect policy, default headers, base-URL client (Http.client(base_url, headers)reused across calls, like Go'shttp.Client).JSON companion (
Json.)HTTP needs (de)serialization:
Json.parse(str) -> value,Json.stringify(value) -> str. This depends on a dynamic/tagged value type (see the tagged-union enums in #1); until then, parse intopropertyrecords by shape.Security
Authorizationheader helper.Platform mapping
fetch()— sameHttp.*surface, different backend. (CORS applies on web.)Phasing
Http.get/post+ handle/poll+Response{status, text, ok}+ TLS.Json.parse/stringify.Http.client(base_url), retries, redirects, downloads to bytes.fetchbackend.References
net/httpclient (Client, methods, headers, timeouts, TLS); go-resty async/retry patterns.HTTPRequest/HTTPClient(async, TLS + certificate verification).Net.*transport in #2;option/tagged-union value in #1.Async, poll-based HTTP that respects the frame loop and stays out of the deterministic sim.
Shipped in
3df6640— a poll-basedHttp.*client. The JSON companion the proposal asked for already landed asJson.*in #44, so pair them:Json.parse(Http.text(h)).Async model — handle + poll (the proposal's primary form). Ludic has no closures, so the callback-sugar variant isn't expressible; the poll form is the whole API and matches the deterministic frame loop:
Http.open(method, url)+Http.set(h, name, value)+Http.body(h, ...)/Http.body_bytes(h, ptr, len)+Http.send(h)build a request up before dispatch;Http.get/Http.post/Http.requestare the one-shots. Response side:Http.status/Http.ok/Http.text/Http.body_len/Http.header(h, name)(case-insensitive) /Http.free.Transport & TLS.
runtime/native/http.lldrives NSURLConnection through the objc runtime's C ABI — the same hand-written-IR, no-ObjC/no-C style as cocoa.ll — on a detached pthread, so the frame never blocks. A fixed slot pool holds each in-flight request; the worker publishes status/body/the retained response behind an atomic done flag (release/acquire), which the poller reads. TLS is the system's, on by default with certificate verification (anhttps://URL just works), as required. It's spliced and links Foundation only when a program actually usesHttp.*.Pure parser.
Http.parse(bytes, len)+ the header lookup are pure Ludic and transport-independent (useful for caches / custom transports / tests), so the suite exercises them offline with no network.Determinism. HTTP depends on the network and wall clock and is explicitly out-of-band — it never feeds the lockstep/replay sim, exactly as the proposal (and
Net.*/Time.now) require.Scope notes. The transport is macOS-only for now (the toolchain's platform); the parser is portable. Redirects/retry policy and a reusable base-URL client are natural follow-ups. Also added the
\rstring escape the protocol needs.Verified end-to-end against real endpoints — HTTPS GET (
200+Content-Type+ body) and POST (JSON body + custom header,200/ok). Full + self-host suites green (81 + 29), including a Darwin-gatedexamples/library/http.ludicthat self-checks the parser.