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.
- package/lib/routes/site-media.js +49 -1
- package/package.json +1 -1
package/lib/routes/site-media.js
CHANGED
|
@@ -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
|
-
|
|
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); }
|