Commit Graph
16 Commits
Author SHA1 Message Date
sganggs 893d17e725 0.2.6-dev: /data/assets.json and /data/local-assets.json are served with content-hashed URLs (/assets/~<hash>/…, one hash per Spine model, the committed files unchanged); the ~hash routes of /assets/ /fonts/ /media/ answer immutable when the hash names the file and the current file with no-cache otherwise; content ETags — host bandwidth layer 1.2; golden: unchanged 2026-10-12 16:24:03 +08:00
sganggs 521dd984e7 0.2.6-dev: a background content-hash index of public/assets and public/fonts (SHA-256, 16 hex; cached by path + size + mtime in .cache/asset-hashes.json; Spine models share one hash; SP_ASSET_INDEX=0 turns it off) — host bandwidth layer 1.1; golden: unchanged 2026-10-12 16:20:17 +08:00
sganggs be8d382c05 0.2.6-dev: traffic counters — HTTP body bytes by category (assets / audio / code / data) and WebSocket wire / payload bytes since the start at GET /healthz?traffic=1, and the page's own downloads (Resource Timing transferSize) as a traffic line in the 问题反馈 diagnostics (host bandwidth layer 0.4); golden: unchanged 2026-10-12 16:05:49 +08:00
sganggs 8edda589f3 0.2.6-dev: WebSocket permessage-deflate for frames from 1 KB (no server context takeover, 2 KB server window, memLevel 7; a client offering a narrower window connects uncompressed) — host bandwidth layer 0.2; golden: unchanged 2026-10-12 15:57:33 +08:00
LimitlessHPPK 51c53de189 feedback7 G-TOOLS: listen on :: by default so one socket serves IPv6 and IPv4 (PR #291 by @LimitlessHPPK)
Ported only the dual-stack listen from PR #291 (the change accepted as #188). With HOST unset the server binds :: and, if that fails with EAFNOSUPPORT, EADDRNOTAVAIL or EINVAL, retries 0.0.0.0. An explicit HOST, including 0.0.0.0 and 127.0.0.1, is tried once. The boot banner and doctor list shareable IPv6 addresses in brackets, skip fe80::, and keep one URL per /64. An explicit IPv6 literal in the local URL is bracketed. The Windows service listing no longer drops those bracketed lines.

Not ported: /dev/grant, the settings-default migration, and the firewall scripts. The Docker image stays on 0.0.0.0; the alpine fallback was not booted.

Tests: node --test test/ipv6-bind.test.js test/doctor.test.js test/ci.test.js — 20 pass, 0 fail (8 bind, 4 doctor, 8 ci).
2026-10-08 18:53:24 +08:00
sganggs d6e40c7235 fb5-patch-pkg: the update package's boot step and install check (server/update.js) — before the server starts (runMain: npm start, launch.mjs, the Windows service's run-server.cmd, NSSM, systemd; launch.mjs also before setup) an extracted UPDATE.json is checked: malformed → logged and skipped; the install verified against MANIFEST.json, and a missing or different file the server or browser runs stops the start with the bilingual "download the full package" message (nothing deleted, UPDATE.json kept); else each removed file still holding a base's bytes is deleted (never a changed file, a player's pack, a symlink, a per-machine name or a path outside the install) and UPDATE.json becomes .update-applied.json; doctor gets a MANIFEST.json row; test/update-boot.test.js (10) 2026-10-07 11:23:42 +08:00
sganggs 25b2a87b26 feedback5 WAD: language packs are the first type of content packs — a language is a file in a language folder (public/i18n/<code>.json, optional data/i18n/<code>.json) or a pack folder (packs/<id>/pack.json); the server lists them live at /packs/index.json (server/packs.js), the menu shows every pack, strings fall back pack → base → declared fallback (English) → Chinese, broken placeholders are skipped, plurals follow Intl.PluralRules (English unchanged), English carries a _meta manifest like any pack; tools: i18n.mjs template / check <code>, packs.mjs list / index, build-i18n --lang ja|ko|zh-TW (the official JP / KR / TW clients); the release zip ships packs/ and a generated packs/index.json; golden unchanged 2026-10-07 02:38:22 +08:00
sganggs 1b38e30819 feedback5 R1: startServer and main become wiring — PORT / HOST / TRUST_PROXY and the option picks go to http/config.js, the session stack and the /ws upgrade to http/websocket.js, the request listener and /healthz to http/routes.js (new), the security headers and the clientError 400 to http/common.js, the banner, signals and entry check to http/boot.js
Same order of construction, listeners and headers as before; a scripted fingerprint (export list, 51 HTTP requests'
status / header order / body hash, raw upgrade and malformed-request replies) and the process run (banner, port in
use, SIGINT) match the pre-split server exactly. test/version.test.js reads the banner and /healthz from their new
files; module headers describe each piece.
2026-10-05 16:08:41 +08:00
sganggs b48a67caec feedback5 R1: pure move — the top-level code of server/index.js goes to server/http/ (config, common, files, static, media, buildTag, websocket, boot) verbatim; index.js imports it and re-exports the same 15 names, startServer and main are untouched
Only changes besides the move: `export` on helpers another module now needs (sendError, sendJson, splitUrl, GzipCache,
isNotModified, serveFile, serveMedia, noopLog, makeLogger), ROOT resolves two levels up from server/http/config.js
(same path), and short headers on the new files.
2026-10-05 16:02:33 +08:00
shanzhaikabi e90e7a30fc 修复:部署无法到达已打开的页面(新增构建版本标记 + 陈旧页面自动重载) (#39) 2026-10-04 14:19:53 +08:00
sganggs 7ab852ef57 feedback2: merge WE — setup downloads the battle emotes and 玩法说明 pages from the public mirror, accurate deployment docs (GitHub #42); English title Stronghold Protocol: Alliance; doctor comment after PR #27 2026-10-03 23:51:56 +08:00
sganggs 380af1ba80 feedback2 WE: the English title is the official Stronghold Protocol: Alliance (EN activity_table act2autochess) — README, server banner, package name; was Covenant (#38) 2026-10-03 23:01:49 +08:00
kanomahoro1224 cfa51e5f1b 按 review 意见:/media/ 的路径与扩展名列表提到 shared/ 共用
- server/index.js 开头的路由说明补上 /media/
- AUDIO_EXTS 原先客户端(public/js/media.js)与服务端各一份,只改一边就会悄悄漂移:
  现在两边都从 shared/media.js 取;服务端那份不再 export
- isMediaUrl 只有测试在用,删掉(新增 shared/media.js,测试改从那里取前缀/扩展名)
- 顺手做了 review 里「可选」的那点:有些静态托管对不存在的路径回 200 + index.html,
  这种响应解码会静默失败,所以除了 404,声明了非 audio/* 类型的响应也回退到原地址
  (完全没声明 content-type 的不算错——没有证据表明它不是音频)
2026-10-03 22:33:20 +08:00
kanomahoro1224 a069be4538 音频改走无扩展名的 /media 路由:IDM / 迅雷 这类下载管理器不再弹「下载文件信息」
玩家那边遇到的是:游戏放着 BGM,突然弹出下载管理器的「下载文件信息」框,有时还会把整条
音轨抢去下载。原因是这些工具会嗅探以媒体扩展名结尾的 XHR/fetch。改成客户端统一请求不带
扩展名的 `/media/<原路径去掉 .mp3>`,服务端再解析回 `public/assets/audio/…`。

- `public/js/media.js`:`mediaUrl()` 把 `/assets/audio/**.mp3` 换算成 `/media/**`,只处理同源、
  且扩展名在名单内的地址;跨域、目录、`..`、点开头、不认识的扩展名一律原样返回。
- `server/index.js`:新增 `/media/` 路由。按 `AUDIO_EXTS` 顺序找 `.mp3/.m4a/.aac/.ogg/.oga/.opus/.wav`,
  显式写了扩展名的以它为准;Range/ETag/Content-Type/缓存策略都复用 `serveFile`,所以和直接请求
  `/assets/audio/…` 行为一致(一天缓存、支持 Range)。
- 直接请求 `/assets/audio/…` 仍然可用 —— 这是给不支持 `/media/` 的纯静态托管留的退路,客户端
  在 `/media/` 404 时才回退到原地址。

安全:`/media/` 的路径只接受正常片段,`..`/`.` 直接 403,点开头或点结尾的片段 404,解析出的
绝对路径必须落在 `public/assets/audio` 之内,且只允许上面那几个音频扩展名 —— 不会变成任意文件读取。

测试:
- `test/media-url.test.js`:`mediaUrl()` 的换算与各种「别动它」的边界。
- `test/lobby.test.js`:真实服务器上的 `/media` 路由(正常解析、显式扩展名优先、Range、HEAD、
  目录与穿越请求被拒、客户端回退用到的 `/media/bgm.mp3` 仍 200)。
- `test/ui/audio.test.js`:音频管理器现在先请求无扩展名地址,404 才回退原地址;断言跟着
  `mediaUrl()` 换算后再比对(原先拿 manifest 原地址比对,等于断言一个客户端永不请求的 URL)。
2026-10-03 22:33:19 +08:00
sganggs a1b1b1ae51 Open-source release 0.1.0: GPL-3.0, notices, README 2026-10-02 15:32:31 +08:00
sganggs 01a44cd288 卫戍协议:盟约 web remake — initial import
Online co-op browser remake of Arknights' Stronghold Protocol: Alliance
(client-simulated combat, official waves/bonds/items/strategies, 3D board,
facing wheel, operator loadout, official emotes, deployment scripts).
2026-09-29 16:21:31 +08:00