From 5f0830cdc57c1c73be989262d3d055b7b7845433 Mon Sep 17 00:00:00 2001 From: sganggs Date: Mon, 5 Oct 2026 16:11:30 +0800 Subject: [PATCH] =?UTF-8?q?feedback5=20R1:=20docs=20and=20comments=20follo?= =?UTF-8?q?w=20the=20split=20=E2=80=94=20DESIGN=20=C2=A72=20layout=20lists?= =?UTF-8?q?=20server/http/,=20the=20README=20table=20names=20the=20entry?= =?UTF-8?q?=20and=20http/,=20path=20comments=20in=20shared/media.js,=20pub?= =?UTF-8?q?lic/js/media.js,=20buildGuard.js,=20net.js=20and=20three=20test?= =?UTF-8?q?s=20point=20at=20the=20new=20modules;=20.git-blame-ignore-revs?= =?UTF-8?q?=20lists=20the=20pure-move=20commit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .git-blame-ignore-revs | 7 +++++++ README.md | 2 +- docs/DESIGN.md | 12 +++++++++++- public/js/media.js | 2 +- public/js/ui/buildGuard.js | 2 +- server/net.js | 2 +- shared/media.js | 4 ++-- test/build.test.js | 5 +++-- test/client-static.test.js | 2 +- test/ui/localArt.test.js | 2 +- 10 files changed, 29 insertions(+), 11 deletions(-) create mode 100644 .git-blame-ignore-revs diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 00000000..b8df9954 --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,7 @@ +# Commits that only move code. Blame across them with +# git blame -C -C --ignore-revs-file .git-blame-ignore-revs +# (or once: git config blame.ignoreRevsFile .git-blame-ignore-revs; -C -C follows lines into the new files of a split). +# Pure moves only (0.2.0 refactor plan, rule 3): a commit listed here changes nothing but where the code lives. + +# feedback5 R1: server/index.js top-level code → server/http/ (config, common, files, static, media, buildTag, websocket, boot) +b48a67caec5ba0699097e21f3db4d4dbb35a2aed diff --git a/README.md b/README.md index f3777127..da9a0f17 100644 --- a/README.md +++ b/README.md @@ -195,7 +195,7 @@ GOLDEN_FULL=1 node --test test/golden.test.js # 黄金结果:固定 | 路径 | 内容 | |---|---| -| `server/` | Node HTTP 静态服务 + WebSocket(`/ws`)、大厅、对局引擎(`match/`)、战斗模拟(`sim/`,浏览器与服务器共用) | +| `server/` | 入口 `index.js`;Node HTTP 静态服务 + WebSocket(`/ws`,代码在 `http/`)、大厅、对局引擎(`match/`)、战斗模拟(`sim/`,浏览器与服务器共用) | | `shared/` | 前后端共用的常量与网络协议 | | `public/` | 浏览器客户端(原生 ES 模块,PixiJS + pixi-spine、three.js 3D 棋盘、Preact + htm UI) | | `data/` | 由官方数据表生成的游戏数据与素材清单 `assets.json` | diff --git a/docs/DESIGN.md b/docs/DESIGN.md index 54821f00..2909813b 100644 --- a/docs/DESIGN.md +++ b/docs/DESIGN.md @@ -41,7 +41,17 @@ Run: `npm install && npm run assets && npm start` → `http://localhost:3000`. F ``` server/ - index.js HTTP static server (gzip for .skel/.atlas/.json/.js/.css), WebSocket upgrade at /ws, boot + index.js process entry: startServer() wires server/http/ (plain node:http + ws); boots when run directly + http/ + config.js ROOT, served dirs, env (PORT, HOST, TRUST_PROXY, DEBUG), options handed to net.js / lobby.js + websocket.js session wiring (SessionRegistry → Lobby → Network), WebSocket upgrade at /ws (64 KB frames) + static.js mounts / → public, /data/, /shared/, /sim/ (.js only), the /data.js browser stand-in, path guards + media.js /media/… extension-less audio → public/assets/audio + files.js one file → response: MIME, gzip (.skel/.atlas/.json/.js/.css …), ETag / 304, cache policy, ranges + buildTag.js build tag of the served browser runtime (/healthz build, public/js/ui/buildGuard.js) + routes.js request listener: 414 / 400 / 405 guards, GET /healthz, then static files + common.js security headers, URL split, error page, JSON replies, bare 400 for unparseable requests + boot.js boot banner (Local / LAN / tunnel URLs), port-in-use hint, graceful SIGINT / SIGTERM net.js session registry, send helpers, per-connection rate limit, message validation (uses shared/protocol.js) lobby.js rooms (4-letter codes), seats, host, AI seats, ready/start, reconnect tokens, room→Match wiring data.js loads data/*.json once, builds indexes (getChess, getBond, …); frozen objects diff --git a/public/js/media.js b/public/js/media.js index 7d125407..1d716ac1 100644 --- a/public/js/media.js +++ b/public/js/media.js @@ -9,7 +9,7 @@ // // /assets/audio/bgm/act1.mp3 → /media/bgm/act1 // -// `server/index.js` resolves /media/… back to the real file under public/assets/audio and still answers with +// `server/http/media.js` resolves /media/… back to the real file under public/assets/audio and still answers with // `Content-Type: audio/mpeg` + range support; Web Audio sniffs the container, so the URL is all the same to it. // A host that does not implement /media/ keeps working: `audio.js` falls back to the original URL whenever the // /media/ response is unusable (a 404, or a 200 that is not audio at all — some static hosts answer a missing diff --git a/public/js/ui/buildGuard.js b/public/js/ui/buildGuard.js index c9ed37ec..2be1c196 100644 --- a/public/js/ui/buildGuard.js +++ b/public/js/ui/buildGuard.js @@ -5,7 +5,7 @@ // reload. A client-only battle fix shipped exactly that way and stayed invisible on the reporting player's page: the // nginx log shows the page loaded the PRE-fix module blob and made no module request at all for the rest of the session. // -// HOW: the server stamps a short hash of the runtime it serves into `/healthz.build` (server/index.js computeBuildTag). +// HOW: the server stamps a short hash of the runtime it serves into `/healthz.build` (server/http/buildTag.js). // The first successful check of a page records that tag as "the build this page runs" — IN MEMORY, because one page is // one set of loaded modules: nothing must survive a reload, and a duplicated tab must not inherit the first tab's tag. // A later check reporting a DIFFERENT tag means the server changed under this page: diff --git a/server/net.js b/server/net.js index 092f40ff..ed022df8 100644 --- a/server/net.js +++ b/server/net.js @@ -525,7 +525,7 @@ export class Network { get connectionCount() { return this.conns.size; } /** - * Upgrade-time admission check (server/index.js): null to accept, otherwise the reason to refuse. + * Upgrade-time admission check (server/http/websocket.js): null to accept, otherwise the reason to refuse. * @param {import('node:http').IncomingMessage} req * @returns {null | 'shutdown' | 'full' | 'per-address'} */ diff --git a/shared/media.js b/shared/media.js index e35355b1..c802ade5 100644 --- a/shared/media.js +++ b/shared/media.js @@ -6,14 +6,14 @@ // // /assets/audio/bgm/act1.mp3 → /media/bgm/act1 // -// — and `server/index.js` resolves it back to the real file under public/assets/audio, still answering with +// — and `server/http/media.js` resolves it back to the real file under public/assets/audio, still answering with // `Content-Type: audio/mpeg`, Range support and the ETag of the file it resolved. // // Both sides import this module: the browser to decide which URLs to rewrite (`public/js/media.js`), the server to // decide which extensions a `/media/…` request may resolve to. A second copy of the list on one side would let them // drift apart silently — the client would rewrite to a path the server no longer accepts. -/** Prefix of the extension-less audio route served by `server/index.js`. */ +/** Prefix of the extension-less audio route served by `server/http/media.js`. */ export const MEDIA_PREFIX = '/media/'; /** Extensions a `/media/…` request may resolve to, in the order the server tries them. */ diff --git a/test/build.test.js b/test/build.test.js index 2102b3ef..a3979c2f 100644 --- a/test/build.test.js +++ b/test/build.test.js @@ -1,5 +1,6 @@ -// test/build.test.js — the served-runtime build tag (server/index.js computeBuildTag / buildTag): the signal that lets -// an already-open page notice a deploy (public/js/ui/buildGuard.js; /healthz `build`). +// test/build.test.js — the served-runtime build tag (server/http/buildTag.js computeBuildTag / buildTag, exported by +// server/index.js): the signal that lets an already-open page notice a deploy (public/js/ui/buildGuard.js; +// /healthz `build`). import { test } from 'node:test'; import assert from 'node:assert/strict'; import fs from 'node:fs'; diff --git a/test/client-static.test.js b/test/client-static.test.js index aef24b20..c7982468 100644 --- a/test/client-static.test.js +++ b/test/client-static.test.js @@ -36,7 +36,7 @@ function walk(dir, ext, out = []) { return out; } -/** URL path served by the server → file on disk (mirrors server/index.js mounts). */ +/** URL path served by the server → file on disk (mirrors the server/http/static.js mounts). */ function urlPathToFile(urlPath) { const clean = decodeURIComponent(urlPath.split(/[?#]/)[0]); if (clean.startsWith('/shared/')) return path.join(ROOT, clean); diff --git a/test/ui/localArt.test.js b/test/ui/localArt.test.js index dda71f3b..956f6cba 100644 --- a/test/ui/localArt.test.js +++ b/test/ui/localArt.test.js @@ -23,7 +23,7 @@ const manifest = { 'ui/battle': { img_chess_level_3: { path: '/assets/local/ui/battle/img_chess_level_3.png', w: 45, h: 45 } }, }, }; -// what server/index.js serves when data/local-assets.json is absent +// what the server (server/http/static.js) serves when data/local-assets.json is absent const EMPTY_LOCAL = { version: 1, source: 'none', count: 0, groups: {} }; let mode = 'ok'; // data/local-assets.json: 'ok' (the manifest above) | 'empty' (the server's stand-in) | 'missing' (404)