dsh-folia 4.15.2 → 4.15.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -276,6 +276,47 @@ export function registerSiteMediaRoutes(webServer, c) {
276
276
  }
277
277
  }
278
278
 
279
+ // ── 计数与统计:别的机器"慢"到底慢在哪,必须有可读的数字,而不是靠感觉 ──────────
280
+ // hits/misses 区分"没缓存所以每次都要下"与"缓存生效但网络慢";
281
+ // bytes/ms 给出每次都真实吞吐;writable 说明那台机器的缓存目录到底能不能写。
282
+ const stats = { hits: 0, misses: 0, bytes: 0, ms: 0, failures: 0, since: Date.now() };
283
+
284
+ disposers.push(webServer.register({
285
+ kind: 'exact',
286
+ path: `${BASE}/site-media-stats`,
287
+ handler: (req, res) => {
288
+ let total = 0;
289
+ let files = 0;
290
+ try {
291
+ const dir = cacheRoot();
292
+ for (const name of readdirSync(dir)) {
293
+ if (name.endsWith('.part') || name.endsWith('.part.json')) continue;
294
+ try { total += statSync(join(dir, name)).size; files += 1; } catch { /* ignore */ }
295
+ }
296
+ } catch { /* 目录不存在即 0 */ }
297
+ const dirRoot = cacheRoot();
298
+ const body = JSON.stringify({
299
+ ok: true,
300
+ root: dirRoot,
301
+ writable: ensureCache(dirRoot),
302
+ files,
303
+ bytesOnDisk: total,
304
+ capBytes: capBytes(),
305
+ hits: stats.hits,
306
+ misses: stats.misses,
307
+ failures: stats.failures,
308
+ avgMBps: stats.ms > 0 ? Number(((stats.bytes / 1048576) / (stats.ms / 1000)).toFixed(2)) : null,
309
+ uptimeSec: Math.round((Date.now() - stats.since) / 1000),
310
+ });
311
+ try {
312
+ res.statusCode = 200;
313
+ res.setHeader('content-type', 'application/json; charset=utf-8');
314
+ res.setHeader('cache-control', 'no-store');
315
+ res.end(body);
316
+ } catch { /* ignore */ }
317
+ },
318
+ }));
319
+
279
320
  disposers.push(webServer.register({
280
321
  kind: 'prefix',
281
322
  // 路径尾部只是给客户端留一个"像文件名"的段(客户端按 `url.split('/').pop()` 取 token 做
@@ -301,6 +342,7 @@ export function registerSiteMediaRoutes(webServer, c) {
301
342
  const abs = join(dir, key);
302
343
 
303
344
  if (ensureCache(dir) && existsSync(abs)) {
345
+ stats.hits += 1;
304
346
  touch(abs);
305
347
  // 与 miss 对称的可观测头:页签/诊断据此区分"网络慢"与"我们没有缓存"。
306
348
  try { res.setHeader('x-folia-cache', 'hit'); } catch { /* ignore */ }
@@ -317,7 +359,13 @@ export function registerSiteMediaRoutes(webServer, c) {
317
359
  redirect(res, u);
318
360
  return;
319
361
  }
320
- const task = download(u, key, req, res, headOnly);
362
+ stats.misses += 1;
363
+ const t0 = Date.now();
364
+ const task = download(u, key, req, res, headOnly).then((ok) => {
365
+ stats.ms += Date.now() - t0;
366
+ if (ok) { try { stats.bytes += statSync(abs).size; } catch { /* ignore */ } }
367
+ return ok;
368
+ }).catch((e) => { stats.failures += 1; throw e; });
321
369
  inflight.set(key, task);
322
370
  let ok = false;
323
371
  try { ok = await task; } finally { inflight.delete(key); }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-folia",
3
- "version": "4.15.2",
3
+ "version": "4.15.3",
4
4
  "description": "Folia 壁纸引擎:把本机 Wallpaper Engine 壁纸搬进 DSH 界面(场景实时渲染 / 视频 / 网页),内置液态玻璃与 Folia 吉祥物,并可从自建站点拉取壁纸。单包形态(组件已合并)。",
5
5
  "type": "module",
6
6
  "engines": {