diff --git a/.gitignore b/.gitignore index 0d0363c8..360a16b4 100644 --- a/.gitignore +++ b/.gitignore @@ -106,3 +106,6 @@ resources/dist/ # Sentry Config File .env.sentry-build-plugin + +# Fastlist binary +resources/fastlist.exe diff --git a/package.json b/package.json index 84853898..381dd285 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,8 @@ "make": "electron-forge make", "publish": "electron-forge publish", "lint": "eslint .", - "format": "prettier . --write" + "format": "prettier . --write", + "postinstall": "python3 ./postinstall.py" }, "devDependencies": { "@electron-forge/cli": "^7.3.0", diff --git a/postinstall.py b/postinstall.py new file mode 100644 index 00000000..3fb85d8d --- /dev/null +++ b/postinstall.py @@ -0,0 +1,5 @@ +import shutil +import platform + +if platform.system() == "Windows": + shutil.copy("node_modules/ps-list/vendor/fastlist-0.3.0-x64.exe", "resources/fastlist.exe") diff --git a/src/main/events/library/close-game.ts b/src/main/events/library/close-game.ts index 0d556925..586253b9 100644 --- a/src/main/events/library/close-game.ts +++ b/src/main/events/library/close-game.ts @@ -4,12 +4,13 @@ import { gameRepository } from "@main/repository"; import { registerEvent } from "../register-event"; import { getProcesses } from "@main/helpers"; +import { app } from "electron"; const closeGame = async ( _event: Electron.IpcMainInvokeEvent, gameId: number ) => { - const processes = await getProcesses(); + const processes = await getProcesses(app.isPackaged); const game = await gameRepository.findOne({ where: { id: gameId } }); const gameProcess = processes.find((runningProcess) => { diff --git a/src/main/helpers/ps.ts b/src/main/helpers/ps.ts index 5a30a9ed..449d103f 100644 --- a/src/main/helpers/ps.ts +++ b/src/main/helpers/ps.ts @@ -1,5 +1,32 @@ import psList from "ps-list"; +import path from "node:path"; +import childProcess from "node:child_process"; +import { promisify } from "node:util"; -export const getProcesses = async () => { - return psList(); +const TEN_MEGABYTES = 1000 * 1000 * 10; +const execFile = promisify(childProcess.execFile); + +export const getProcesses = async (isPackaged: boolean) => { + if (process.platform == "win32") { + const binaryPath = isPackaged + ? path.join(process.resourcesPath, "fastlist.exe") + : path.join(__dirname, "..", "..", "resources", "fastlist.exe"); + + const { stdout } = await execFile(binaryPath, { + maxBuffer: TEN_MEGABYTES, + windowsHide: true, + }); + + return stdout + .trim() + .split("\r\n") + .map((line) => line.split("\t")) + .map(([pid, ppid, name]) => ({ + pid: Number.parseInt(pid, 10), + ppid: Number.parseInt(ppid, 10), + name, + })); + } else { + return psList(); + } }; diff --git a/src/main/services/process-watcher.ts b/src/main/services/process-watcher.ts index c040373a..0668c1db 100644 --- a/src/main/services/process-watcher.ts +++ b/src/main/services/process-watcher.ts @@ -4,18 +4,18 @@ import { IsNull, Not } from "typeorm"; import { gameRepository } from "@main/repository"; import { getProcesses } from "@main/helpers"; import { WindowManager } from "./window-manager"; +import { app } from "electron"; const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); export const startProcessWatcher = async () => { - const sleepTime = 100; + const sleepTime = 300; const gamesPlaytime = new Map(); // eslint-disable-next-line no-constant-condition while (true) { await sleep(sleepTime); - console.time("loopTotalTime"); const games = await gameRepository.find({ where: { executablePath: Not(IsNull()), @@ -26,9 +26,7 @@ export const startProcessWatcher = async () => { continue; } - console.time("getProcesses"); - const processes = await getProcesses(); - console.timeEnd("getProcesses"); + const processes = await getProcesses(app.isPackaged); for (const game of games) { const basename = path.win32.basename(game.executablePath); @@ -73,6 +71,5 @@ export const startProcessWatcher = async () => { } } } - console.timeEnd("loopTotalTime"); } };