From 13f15dcf1171da9295e142d486bd0a22fb83ec7c Mon Sep 17 00:00:00 2001 From: divocat Date: Sat, 18 Oct 2025 23:06:07 +0300 Subject: [PATCH] feat: add pause for log watcher when tab not visible --- .../services/podkopLogWatcher.service.ts | 46 +++++++++++++++---- .../luci-static/resources/view/podkop/main.js | 39 +++++++++++++--- 2 files changed, 69 insertions(+), 16 deletions(-) diff --git a/fe-app-podkop/src/podkop/services/podkopLogWatcher.service.ts b/fe-app-podkop/src/podkop/services/podkopLogWatcher.service.ts index 9548408..e09b288 100644 --- a/fe-app-podkop/src/podkop/services/podkopLogWatcher.service.ts +++ b/fe-app-podkop/src/podkop/services/podkopLogWatcher.service.ts @@ -15,8 +15,16 @@ export class PodkopLogWatcher { private lastLines = new Set(); private timer?: ReturnType; private running = false; + private paused = false; - private constructor() {} + private constructor() { + if (typeof document !== 'undefined') { + document.addEventListener('visibilitychange', () => { + if (document.hidden) this.pause(); + else this.resume(); + }); + } + } static getInstance(): PodkopLogWatcher { if (!PodkopLogWatcher.instance) { @@ -29,6 +37,10 @@ export class PodkopLogWatcher { this.fetcher = fetcher; this.onNewLog = options?.onNewLog; this.intervalMs = options?.intervalMs ?? 5000; + logger.info( + '[PodkopLogWatcher]', + `initialized (interval: ${this.intervalMs}ms)`, + ); } async checkOnce(): Promise { @@ -37,6 +49,11 @@ export class PodkopLogWatcher { return; } + if (this.paused) { + logger.debug('[PodkopLogWatcher]', 'skipped check — tab not visible'); + return; + } + try { const raw = await this.fetcher(); const lines = raw.split('\n').filter(Boolean); @@ -44,10 +61,7 @@ export class PodkopLogWatcher { for (const line of lines) { if (!this.lastLines.has(line)) { this.lastLines.add(line); - - if (this.onNewLog) { - this.onNewLog(line); - } + this.onNewLog?.(line); } } @@ -63,14 +77,15 @@ export class PodkopLogWatcher { start(): void { if (this.running) return; if (!this.fetcher) { - logger.warn('[PodkopLogWatcher]', 'Try to start without fetcher.'); + logger.warn('[PodkopLogWatcher]', 'attempted to start without fetcher'); return; } this.running = true; this.timer = setInterval(() => this.checkOnce(), this.intervalMs); logger.info( - `[PodkopLogWatcher]', 'Started with interval ${this.intervalMs} ms`, + '[PodkopLogWatcher]', + `started (interval: ${this.intervalMs}ms)`, ); } @@ -78,11 +93,24 @@ export class PodkopLogWatcher { if (!this.running) return; this.running = false; if (this.timer) clearInterval(this.timer); - logger.info('[PodkopLogWatcher]', 'Stopped'); + logger.info('[PodkopLogWatcher]', 'stopped'); + } + + pause(): void { + if (!this.running || this.paused) return; + this.paused = true; + logger.info('[PodkopLogWatcher]', 'paused (tab not visible)'); + } + + resume(): void { + if (!this.running || !this.paused) return; + this.paused = false; + logger.info('[PodkopLogWatcher]', 'resumed (tab active)'); + this.checkOnce(); // сразу проверить, не появились ли новые логи } reset(): void { this.lastLines.clear(); - logger.info('[PodkopLogWatcher]', 'logs history was reset'); + logger.info('[PodkopLogWatcher]', 'log history reset'); } } diff --git a/luci-app-podkop/htdocs/luci-static/resources/view/podkop/main.js b/luci-app-podkop/htdocs/luci-static/resources/view/podkop/main.js index 822440a..27c52c5 100644 --- a/luci-app-podkop/htdocs/luci-static/resources/view/podkop/main.js +++ b/luci-app-podkop/htdocs/luci-static/resources/view/podkop/main.js @@ -1240,6 +1240,13 @@ var PodkopLogWatcher = class _PodkopLogWatcher { this.intervalMs = 5e3; this.lastLines = /* @__PURE__ */ new Set(); this.running = false; + this.paused = false; + if (typeof document !== "undefined") { + document.addEventListener("visibilitychange", () => { + if (document.hidden) this.pause(); + else this.resume(); + }); + } } static getInstance() { if (!_PodkopLogWatcher.instance) { @@ -1251,21 +1258,27 @@ var PodkopLogWatcher = class _PodkopLogWatcher { this.fetcher = fetcher; this.onNewLog = options?.onNewLog; this.intervalMs = options?.intervalMs ?? 5e3; + logger.info( + "[PodkopLogWatcher]", + `initialized (interval: ${this.intervalMs}ms)` + ); } async checkOnce() { if (!this.fetcher) { logger.warn("[PodkopLogWatcher]", "fetcher not found"); return; } + if (this.paused) { + logger.debug("[PodkopLogWatcher]", "skipped check \u2014 tab not visible"); + return; + } try { const raw = await this.fetcher(); const lines = raw.split("\n").filter(Boolean); for (const line of lines) { if (!this.lastLines.has(line)) { this.lastLines.add(line); - if (this.onNewLog) { - this.onNewLog(line); - } + this.onNewLog?.(line); } } if (this.lastLines.size > 500) { @@ -1279,24 +1292,36 @@ var PodkopLogWatcher = class _PodkopLogWatcher { start() { if (this.running) return; if (!this.fetcher) { - logger.warn("[PodkopLogWatcher]", "Try to start without fetcher."); + logger.warn("[PodkopLogWatcher]", "attempted to start without fetcher"); return; } this.running = true; this.timer = setInterval(() => this.checkOnce(), this.intervalMs); logger.info( - `[PodkopLogWatcher]', 'Started with interval ${this.intervalMs} ms` + "[PodkopLogWatcher]", + `started (interval: ${this.intervalMs}ms)` ); } stop() { if (!this.running) return; this.running = false; if (this.timer) clearInterval(this.timer); - logger.info("[PodkopLogWatcher]", "Stopped"); + logger.info("[PodkopLogWatcher]", "stopped"); + } + pause() { + if (!this.running || this.paused) return; + this.paused = true; + logger.info("[PodkopLogWatcher]", "paused (tab not visible)"); + } + resume() { + if (!this.running || !this.paused) return; + this.paused = false; + logger.info("[PodkopLogWatcher]", "resumed (tab active)"); + this.checkOnce(); } reset() { this.lastLines.clear(); - logger.info("[PodkopLogWatcher]", "logs history was reset"); + logger.info("[PodkopLogWatcher]", "log history reset"); } };