gitoriaLog in with ident

gitoria

All repositories: gitoria

ReadmeCodePull requestsReleasesTicketsSettings
Branchmain4f47843egate: ticket links use the tickets short URL (/<slug>/<n>, tickets#25)mremain/plugins/http1/native_http_server.hl

4.2 KB

  1. \* hl:http1 — the native HTTP/1.1 server. Subclass it (`inherit
  2. NativeHttpServer`) and answer `on request(req)` with a Response.
  3. AUTO-LISTEN: the file root IS the constructor and its last statement is
  4. listen(), so `new NativeHttpServer(port = 8888)` binds 8888 with no
  5. explicit call. *\
  6. /* Split from the former multi-class server.hl (mission 027). listen() is
  7. idempotent (the `listening` guard). A SUBCLASS does NOT inherit this run
  8. body — parent run bodies never run — so subclasses call listen() from
  9. their own root. No base `on request` handler here: the loop dispatches to
  10. the concrete instance's handlers, and old-form inheritance copies
  11. handlers — a base default would double-fire (mission 052). */
  12. \* One HTTP request reached this server — answer a Response (or hold
  13. req.respond for the streaming/deferred forms). *\
  14. emit request(
  15. Hybrid req \\ method, path, headers, body, bytes, params, respond
  16. )
  17. Number port = 8080 \\ the port bind() takes
  18. String host = "0.0.0.0" \\ the interface to bind
  19. String tls_cert = null \\ PEM certificate path — with tls_key, serve https
  20. String tls_key = null \\ PEM key path
  21. Number threads = 4 \\ I/O worker threads
  22. Boolean listening = false \\ true after a successful bind
  23. Number #srcId = 0
  24. handleError(err) {
  25. console.log("Server error: " + err)
  26. }
  27. \* Bind the configured port (idempotent — an extra listen() is harmless).
  28. A FAILED BIND IS A REFUSAL, NOT A LINE OF PROSE (mission 286). This used
  29. to print `listen() failed: …` on stderr and return, so the process stayed
  30. alive with no socket and — because the event loop was still running for
  31. whatever else had registered — exited 0 or never exited at all. Every
  32. supervisor, deploy script and CI step was told the server started. A
  33. server that cannot serve says so and fails; the located form is below. *\
  34. listen() {
  35. if (listening == true) {
  36. return null
  37. }
  38. if (this.bind() != true) {
  39. hlError("hl:http1: listen() failed: could not bind port " + port + " on " + host + " — the port is already taken. The line just above, 'bind() failed on port " + port + "', names the process holding it: stop that process, or start this app on another port (--port N, or HL_PORT=N)")
  40. }
  41. return null
  42. }
  43. \* The bind itself, without the idempotence guard: a subclass that answers
  44. for its own double-listen policy (hl:web refuses one) still needs the one
  45. place where the socket is actually opened.
  46. ANSWERS true/false RATHER THAN RAISING (mission 286), because the caller
  47. owns the wording AND the location: hl:web can point its refusal at the
  48. manifest member that chose the port, which this file cannot see. Every
  49. caller must treat false as fatal — there is no third answer. *\
  50. bind() {
  51. srv = __native("http1.create_server", port, host, tls_cert, tls_key, threads)
  52. if (srv == null) {
  53. return false
  54. }
  55. listening = true
  56. #srcId = __native("eventloop.register", srv, "request")
  57. return true
  58. }
  59. \* Turn ON the RFC 6455 WebSocket engine for the port this server already
  60. bound: an Upgrade is answered inline in the I/O worker and
  61. the raw stream arrives at your own `on wsEvent` — WebSockets on the same
  62. port, no second listener. Separate from bind() because a plain HTTP
  63. server has no reason to start the engine thread. *\
  64. sockets() {
  65. __native("eventloop.register", __native("http1.ws_events"), "wsEvent")
  66. }
  67. \* Stop this server: the event source is retired (the loop can end by
  68. itself) and the native side joins the workers and closes the listener —
  69. the port is immediately free for a new bind(). Answers false when the
  70. server was not listening.
  71. SAFE FROM INSIDE A HANDLER (mission 260), and immediate — never deferred.
  72. The request you are answering is untouched: its socket is already your
  73. `req.respond` handle, so returning a Response after close() still reaches
  74. the client. A request that was parsed but can no longer be dispatched
  75. (the source is gone) is refused `503 Service Unavailable`; a connection
  76. accepted but not yet parsed is simply closed. *\
  77. close() {
  78. if (listening == false) {
  79. return false
  80. }
  81. listening = false
  82. __native("eventloop.unregister", #srcId)
  83. return __native("http1.close", port)
  84. }
  85. // Run body: the constructor's last act — bind the configured port.
  86. listen()

Branches

  • mainmain branch

Latest commits

  • 4f47843egate: ticket links use the tickets short URL (/<slug>/<n>, tickets#25)mre
  • 86605446mission 002 (code order) 4/4: README file map + import order + 'Same output' test + gate run with a tickets HEAD copy, STATUS (entry, lessons), LOG, report; tests/realdata-baseline.mjs + realdata-compare.py (a cleanup answers the same on live data: pages, modules, API, git over HTTPS and SSH, faces), tests/letcount.pymre
  • cc7bf7bamission 002 (code order) 3/4: let only where a variable is reassigned or re-bound in a loop body (289 lets → plain declarations; 213 left: 125 reassigned, 88 loop-bound; no member/import/param clash). gates 200/0, 46/0, 44/0; real-data reads + writes identical (browser modules: var → const only)mre
  • 090a20c6mission 002 (code order) 2/4: one lib/ file per topic — git.hl split into git (calls, branches, init, temp folder) / homepage / code / pulls / releases (+ git-helpers: paths, ids, |||PR/|||RL markers); repos-helpers, tickets-helpers, transport-helpers; util.hl = localtime + env, storage dir, addresses, lists, text checks, one newest-first sort (was 3 copies); the function routes out of project.hl into lib/api.hl (thin; plumbing in api-helpers.hl), sshgate.hl folded into api.hl + sshkeys.hl keyLine + repos.hl mayPush; 'Make main' and the merge answer out of the faces (code.hl makeMain, pulls.hl pullsView), one login helper (users.hl userOfLoginCode); project.hl is the map. Session-writing routes get &req + &server.sessions. gates 200/0, 46/0, 44/0; real-data identical except /login/failed now shows the parked reason for a browser that already had a session (the old copy-of-req lost it)mre
  • 110c2799mission 002 (code order) 1/4: .hl files out of the root — lib/ (api, git, localtime, markdown, repos, sshgate, sshkeys, tickets, tokens, transport, users), components/styles.hl; jsoncheck.hl removed (imported nowhere); import paths only. gates 200/0, 46/0, 44/0; real-data reads + writes identicalmre
  • fdfb4b1bgitoria: Hybriel master 06617221 (plugin allocators 3a781359 + 413f60e4, mpackdb 2cb7ae5e, http1 773de63e); gates 200/0, 46/0, 44/0mre
  • 5b46ac84antcolony#40: LOG.md — missions 069/072 are antcolony missions (report paths on Byrodin)mre
  • 5602ff41gitoria: Hybriel master 190aa11d (fc838894 GC correctness, #127 mountKids by reference, #126, #48) — tracker README flat; gates 200/0, 46/0, 44/0mre
  • e85eaf01gitoria: 069 round 2 — hybriel 1a096ad3 not adopted (Markdown SSR still grows); browser gate waits for the server-side logout before restartmre
  • 09ce4f3fgitoria: mission 069 re-vendor hybriel 8efba065 stopped (big SSR pages grow + slow down); lambda audit clean; old vendor keptmre
  • 3dc43108antcolony#40: mission references point to the moved missionsmre
  • 8d9450fdantcolony#40: history (LOG.md), worker briefs (missions/) and reports moved here from antcolony, numbered per project; old numbers in antcolony docs/mission-map.mdmre
  • 205d5fe4gitoria: Hybriel master ff51cf46; ssh keys/tokens no double rows (session sync); gates follow #20mre
  • 9b27cb26gitoria#21: installable app (manifest, service worker, offline start page), own iconmre
  • 68dcb603deploy.sh: back up live storage/.sessions/.env before every deploy (newest 5 kept)mre
  • e2deed6dgitoria#20: "Add code" only on the Code page of an empty repository, no collapsiblemre
  • 8bb97ffddeploy.sh: never send .git or .gitignore to Byrodinmre
  • fd981932State of 2026-09-27; bin/ no longer tracked (Hybriel commit is in README)mre
  • 4a2d7125initial commitmre