diff --git a/bun.lockb b/bun.lockb index a2869d8..32bf4d5 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 286e904..a9607d3 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "@alikia/random-key": "npm:@jsr/alikia__random-key", "@electron/remote": "^2.1.2", "@hono/node-server": "^1.13.7", + "@types/node-os-utils": "^1.3.4", "@unly/universal-language-detector": "^2.0.3", "better-sqlite3": "^11.6.0", "dayjs": "^1.11.13", @@ -41,6 +42,7 @@ "image-size": "^1.1.1", "jotai": "^2.11.0", "memory-cache": "^0.2.0", + "node-os-utils": "^1.3.7", "pino": "^9.6.0", "react": "^18.3.1", "react-dom": "^18.3.1", diff --git a/src/electron/backend/scheduler.ts b/src/electron/backend/scheduler.ts index 1344e7c..d15e52d 100644 --- a/src/electron/backend/scheduler.ts +++ b/src/electron/backend/scheduler.ts @@ -1,3 +1,5 @@ +import osu from "node-os-utils"; + type TaskId = string; type TaskFunction = () => void; @@ -9,6 +11,7 @@ interface Task { nextRun?: number; isPaused: boolean; delayUntil?: number; + requiredSystemState: SystemState; } export interface TaskStatus { @@ -17,15 +20,27 @@ export interface TaskStatus { nextRun?: string; } +type SystemState = "ANY" | "LOW_POWER" | "IDLE"; + export class Scheduler { private tasks: Map = new Map(); private timer: NodeJS.Timeout | null = null; + private monitorTimer: NodeJS.Timeout | null = null; + private cpuUsage: number = 0; + constructor(private readonly minTickInterval: number = 500) { this.start(); } private start(): void { this.scheduleNextTick(); + this.monitorTimer = setInterval(() => this.monitor(), 1000); + } + + private monitor(): void { + osu.cpu.usage().then((cpuPercentage) => { + this.cpuUsage = cpuPercentage / 100; + }) } private scheduleNextTick(): void { @@ -66,7 +81,17 @@ export class Scheduler { return; } - const isTaskReadyForIntervalRun = task.interval && task.nextRun && now >= task.nextRun; + const taskRequiredLowPower = task.requiredSystemState === "LOW_POWER"; + const cpuUsage = this.cpuUsage; + const isSystemLowPower = cpuUsage < 0.75; + const isTaskReadyForLowPowerRun = taskRequiredLowPower ? isSystemLowPower : true; + const reachedTaskNextRun = task.interval && task.nextRun && now >= task.nextRun; + const isTaskReadyForIntervalRun = reachedTaskNextRun && isTaskReadyForLowPowerRun; + + if (!isTaskReadyForLowPowerRun) { + this.delayTask(task.id, 1000) + } + if (isTaskReadyForIntervalRun) { task.func(); task.lastRun = now; @@ -100,15 +125,17 @@ export class Scheduler { * @param id A unique string identifier for the task. * @param func The function to be executed by the task. * @param interval The interval (in milliseconds) between task executions. + * @param requiredSystemState The required system state for the task to run. */ - addTask(id: TaskId, func: TaskFunction, interval?: number): void { + addTask(id: TaskId, func: TaskFunction, interval?: number, requiredSystemState: SystemState = "ANY"): void { this.tasks.set(id, { id, func, interval, isPaused: false, lastRun: undefined, - nextRun: interval ? Date.now() + interval : undefined + nextRun: interval ? Date.now() + interval : undefined, + requiredSystemState: requiredSystemState, }); this.scheduleNextTick(); @@ -172,6 +199,9 @@ export class Scheduler { const task = this.tasks.get(id); if (task) { task.delayUntil = Date.now() + delayMs; + if (task.nextRun) { + task.nextRun += delayMs; + } } this.scheduleNextTick(); @@ -215,5 +245,9 @@ export class Scheduler { clearTimeout(this.timer); this.timer = null; } + if (this.monitorTimer) { + clearTimeout(this.monitorTimer); + this.monitorTimer = null; + } } } diff --git a/src/electron/index.ts b/src/electron/index.ts index cff1b44..1490d38 100644 --- a/src/electron/index.ts +++ b/src/electron/index.ts @@ -112,7 +112,7 @@ app.on("ready", () => { initDatabase().then((db) => { scheduler.addTask("screenshot", takeScreenshot, 2000); scheduler.addTask("check-encoding", checkFramesForEncoding, 5000); - scheduler.addTask("process-encoding", processEncodingTasks, 10000); + scheduler.addTask("process-encoding", processEncodingTasks, 10000, "LOW_POWER"); scheduler.addTask("delete-screenshots", deleteUnnecessaryScreenshots, 20000); dbConnection = db; cache.put("server:dbConnection", dbConnection);