From 8120d293f7a588e9ac3229a29f0bc94fdeb5d0c1 Mon Sep 17 00:00:00 2001 From: Hiroshiba Date: Sat, 14 Sep 2024 01:16:47 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20=E3=82=A8=E3=83=B3=E3=82=B8?= =?UTF-8?q?=E3=83=B3=E6=83=85=E5=A0=B1=E3=83=9E=E3=83=8D=E3=83=BC=E3=82=B8?= =?UTF-8?q?=E3=83=A3=E3=83=BC=E3=81=A8=E3=82=A8=E3=83=B3=E3=82=B8=E3=83=B3?= =?UTF-8?q?=E3=83=97=E3=83=AD=E3=82=BB=E3=82=B9=E3=83=9E=E3=83=8D=E3=83=BC?= =?UTF-8?q?=E3=82=B8=E3=83=A3=E3=83=BC=E3=82=92=E5=88=86=E3=81=91=E3=82=8B?= =?UTF-8?q?=20(#2260)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * エンジン情報マネージャーとエンジンプロセスマネージャーを分ける * いろいろ使いやすく --- src/backend/electron/main.ts | 42 +-- .../electron/manager/engineInfoManager.ts | 229 +++++++++++++++++ ...gineManager.ts => engineProcessManager.ts} | 239 ++---------------- .../{manager/portManager.ts => portHelper.ts} | 0 4 files changed, 280 insertions(+), 230 deletions(-) create mode 100644 src/backend/electron/manager/engineInfoManager.ts rename src/backend/electron/manager/{engineManager.ts => engineProcessManager.ts} (62%) rename src/backend/electron/{manager/portManager.ts => portHelper.ts} (100%) diff --git a/src/backend/electron/main.ts b/src/backend/electron/main.ts index 7ba1609326..78114434a6 100644 --- a/src/backend/electron/main.ts +++ b/src/backend/electron/main.ts @@ -20,7 +20,8 @@ import log from "electron-log/main"; import dayjs from "dayjs"; import windowStateKeeper from "electron-window-state"; import { hasSupportedGpu } from "./device"; -import EngineManager from "./manager/engineManager"; +import EngineInfoManager from "./manager/engineInfoManager"; +import EngineProcessManager from "./manager/engineProcessManager"; import VvppManager, { isVvppFile } from "./manager/vvppManager"; import configMigration014 from "./configMigration014"; import { RuntimeInfoManager } from "./manager/RuntimeInfoManager"; @@ -184,17 +185,24 @@ const runtimeInfoManager = new RuntimeInfoManager( const configManager = getConfigManager(); -const engineManager = new EngineManager({ +const engineInfoManager = new EngineInfoManager({ configManager, defaultEngineDir: appDirPath, vvppEngineDir, +}); +const engineProcessManager = new EngineProcessManager({ + configManager, onEngineProcessError, + engineInfosFetcher: + engineInfoManager.fetchEngineInfos.bind(engineInfoManager), + engineAltPortUpdater: engineInfoManager.updateAltPort.bind(engineInfoManager), + engineSettingsGetter: () => configManager.get("engineSettings"), }); const vvppManager = new VvppManager({ vvppEngineDir }); // エンジンのフォルダを開く function openEngineDirectory(engineId: EngineId) { - const engineDirectory = engineManager.fetchEngineDirectory(engineId); + const engineDirectory = engineInfoManager.fetchEngineDirectory(engineId); // Windows環境だとスラッシュ区切りのパスが動かない。 // path.resolveはWindowsだけバックスラッシュ区切りにしてくれるため、path.resolveを挟む。 @@ -289,7 +297,7 @@ function checkMultiEngineEnabled(): boolean { async function uninstallVvppEngine(engineId: EngineId) { let engineInfo: EngineInfo | undefined = undefined; try { - engineInfo = engineManager.fetchEngineInfo(engineId); + engineInfo = engineInfoManager.fetchEngineInfo(engineId); if (!engineInfo) { throw new Error(`No such engineInfo registered: engineId == ${engineId}`); } @@ -521,11 +529,11 @@ async function start() { // エンジンの準備と起動 async function launchEngines() { - // エンジンの追加と削除を反映させるためEngineInfoとAltPortInfoを再生成する。 - engineManager.initializeEngineInfosAndAltPortInfo(); + // エンジンの追加と削除を反映させるためEngineInfoとAltPortInfosを再生成する。 + engineInfoManager.initializeEngineInfosAndAltPortInfo(); // TODO: デフォルトエンジンの処理をConfigManagerに移してブラウザ版と共通化する - const engineInfos = engineManager.fetchEngineInfos(); + const engineInfos = engineInfoManager.fetchEngineInfos(); const engineSettings = configManager.get("engineSettings"); for (const engineInfo of engineInfos) { if (!engineSettings[engineInfo.uuid]) { @@ -535,7 +543,7 @@ async function launchEngines() { } configManager.set("engineSettings", engineSettings); - await engineManager.runEngineAll(); + await engineProcessManager.runEngineAll(); runtimeInfoManager.setEngineInfos(engineInfos); await runtimeInfoManager.exportFile(); } @@ -546,7 +554,7 @@ async function launchEngines() { * そうでない場合は Promise を返す。 */ function cleanupEngines(): Promise | "alreadyCompleted" { - const killingProcessPromises = engineManager.killEngineAll(); + const killingProcessPromises = engineProcessManager.killEngineAll(); const numLivingEngineProcess = Object.entries(killingProcessPromises).length; // 前処理が完了している場合 @@ -719,7 +727,7 @@ registerIpcMainHandle({ }, GET_ALT_PORT_INFOS: () => { - return engineManager.altPortInfo; + return engineInfoManager.altPortInfos; }, SHOW_AUDIO_SAVE_DIALOG: async (_, { title, defaultPath }) => { @@ -903,8 +911,8 @@ registerIpcMainHandle({ }, ENGINE_INFOS: () => { - // エンジン情報を設定ファイルに保存しないためにstoreは使わない - return engineManager.fetchEngineInfos(); + // エンジン情報を設定ファイルに保存しないためにelectron-storeは使わない + return engineInfoManager.fetchEngineInfos(); }, /** @@ -912,9 +920,11 @@ registerIpcMainHandle({ * エンジンの起動が開始したらresolve、起動が失敗したらreject。 */ RESTART_ENGINE: async (_, { engineId }) => { - await engineManager.restartEngine(engineId); - // TODO: setEngineInfosからexportFileはロックしたほうがより良い - runtimeInfoManager.setEngineInfos(engineManager.fetchEngineInfos()); + await engineProcessManager.restartEngine(engineId); + + // ランタイム情報の更新 + // TODO: setからexportの処理は排他処理にしたほうがより良い + runtimeInfoManager.setEngineInfos(engineInfoManager.fetchEngineInfos()); await runtimeInfoManager.exportFile(); }, @@ -998,7 +1008,7 @@ registerIpcMainHandle({ }, VALIDATE_ENGINE_DIR: (_, { engineDir }) => { - return engineManager.validateEngineDir(engineDir); + return engineInfoManager.validateEngineDir(engineDir); }, RELOAD_APP: async (_, { isMultiEngineOffMode }) => { diff --git a/src/backend/electron/manager/engineInfoManager.ts b/src/backend/electron/manager/engineInfoManager.ts new file mode 100644 index 0000000000..e219797f12 --- /dev/null +++ b/src/backend/electron/manager/engineInfoManager.ts @@ -0,0 +1,229 @@ +import path from "path"; +import fs from "fs"; +import shlex from "shlex"; + +import { dialog } from "electron"; // FIXME: ここでelectronをimportするのは良くない + +import log from "electron-log/main"; + +import { + EngineInfo, + EngineDirValidationResult, + MinimumEngineManifestType, + EngineId, + minimumEngineManifestSchema, + envEngineInfoSchema, +} from "@/type/preload"; +import { AltPortInfos } from "@/store/type"; +import { BaseConfigManager } from "@/backend/common/ConfigManager"; + +/** + * デフォルトエンジンの情報を作成する + */ +function createDefaultEngineInfos(defaultEngineDir: string): EngineInfo[] { + // TODO: envから直接ではなく、envに書いたengine_manifest.jsonから情報を得るようにする + const defaultEngineInfosEnv = + import.meta.env.VITE_DEFAULT_ENGINE_INFOS ?? "[]"; + + const envSchema = envEngineInfoSchema.array(); + const engines = envSchema.parse(JSON.parse(defaultEngineInfosEnv)); + + return engines.map((engineInfo) => { + return { + ...engineInfo, + isDefault: true, + type: "path", + executionFilePath: path.resolve(engineInfo.executionFilePath), + path: + engineInfo.path == undefined + ? undefined + : path.resolve(defaultEngineDir, engineInfo.path), + } satisfies EngineInfo; + }); +} + +/** エンジンの情報を管理するクラス */ +export class EngineInfoManager { + configManager: BaseConfigManager; + defaultEngineDir: string; + vvppEngineDir: string; + + defaultEngineInfos: EngineInfo[] = []; + additionalEngineInfos: EngineInfo[] = []; + + /** 代替ポート情報 */ + public altPortInfos: AltPortInfos = {}; + + constructor(payload: { + configManager: BaseConfigManager; + defaultEngineDir: string; + vvppEngineDir: string; + }) { + this.configManager = payload.configManager; + this.defaultEngineDir = payload.defaultEngineDir; + this.vvppEngineDir = payload.vvppEngineDir; + } + + /** + * 追加エンジンの一覧を作成する。 + * FIXME: store.get("registeredEngineDirs")への副作用をEngineManager外に移動する + */ + private createAdditionalEngineInfos(): EngineInfo[] { + const engines: EngineInfo[] = []; + const addEngine = (engineDir: string, type: "vvpp" | "path") => { + const manifestPath = path.join(engineDir, "engine_manifest.json"); + if (!fs.existsSync(manifestPath)) { + return "manifestNotFound"; + } + let manifest: MinimumEngineManifestType; + try { + manifest = minimumEngineManifestSchema.parse( + JSON.parse(fs.readFileSync(manifestPath, { encoding: "utf8" })), + ); + } catch (e) { + return "manifestParseError"; + } + + const [command, ...args] = shlex.split(manifest.command); + + engines.push({ + uuid: manifest.uuid, + host: `http://127.0.0.1:${manifest.port}`, + name: manifest.name, + path: engineDir, + executionEnabled: true, + executionFilePath: path.join(engineDir, command), + executionArgs: args, + type, + isDefault: false, + } satisfies EngineInfo); + return "ok"; + }; + for (const dirName of fs.readdirSync(this.vvppEngineDir)) { + const engineDir = path.join(this.vvppEngineDir, dirName); + if (!fs.statSync(engineDir).isDirectory()) { + log.log(`${engineDir} is not directory`); + continue; + } + if (dirName === ".tmp") { + continue; + } + const result = addEngine(engineDir, "vvpp"); + if (result !== "ok") { + log.log(`Failed to load engine: ${result}, ${engineDir}`); + } + } + // FIXME: この関数の引数でregisteredEngineDirsを受け取り、動かないエンジンをreturnして、EngineManager外でconfig.setする + for (const engineDir of this.configManager.get("registeredEngineDirs")) { + const result = addEngine(engineDir, "path"); + if (result !== "ok") { + log.log(`Failed to load engine: ${result}, ${engineDir}`); + // 動かないエンジンは追加できないので削除 + // FIXME: エンジン管理UIで削除可能にする + dialog.showErrorBox( + "エンジンの読み込みに失敗しました。", + `${engineDir}を読み込めませんでした。このエンジンは削除されます。`, + ); + this.configManager.set( + "registeredEngineDirs", + this.configManager + .get("registeredEngineDirs") + .filter((p) => p !== engineDir), + ); + } + } + return engines; + } + + /** + * 全てのエンジンの一覧を取得する。デフォルトエンジン+追加エンジン。 + */ + fetchEngineInfos(): EngineInfo[] { + return [...this.defaultEngineInfos, ...this.additionalEngineInfos]; + } + + /** + * エンジンの情報を取得する。存在しない場合はエラーを返す。 + */ + fetchEngineInfo(engineId: EngineId): EngineInfo { + const engineInfos = this.fetchEngineInfos(); + const engineInfo = engineInfos.find( + (engineInfo) => engineInfo.uuid === engineId, + ); + if (!engineInfo) { + throw new Error(`No such engineInfo registered: engineId == ${engineId}`); + } + return engineInfo; + } + + /** + * エンジンのディレクトリを取得する。存在しない場合はエラーを返す。 + */ + fetchEngineDirectory(engineId: EngineId): string { + const engineInfo = this.fetchEngineInfo(engineId); + const engineDirectory = engineInfo.path; + if (engineDirectory == undefined) { + throw new Error(`engineDirectory is undefined: engineId == ${engineId}`); + } + + return engineDirectory; + } + + /** + * EngineInfosとAltPortInfoを初期化する。 + */ + initializeEngineInfosAndAltPortInfo() { + this.defaultEngineInfos = createDefaultEngineInfos(this.defaultEngineDir); + this.additionalEngineInfos = this.createAdditionalEngineInfos(); + this.altPortInfos = {}; + } + + /** + * 代替ポート情報を更新する。 + * エンジン起動時にポートが競合して代替ポートを使う場合に使用する。 + */ + updateAltPort(engineId: EngineId, port: number) { + const engineInfo = this.fetchEngineInfo(engineId); + const url = new URL(engineInfo.host); + this.altPortInfos[engineId] = { + from: Number(url.port), + to: port, + }; + + url.port = port.toString(); + engineInfo.host = url.toString(); + } + + /** + * ディレクトリがエンジンとして正しいかどうかを判定する + */ + validateEngineDir(engineDir: string): EngineDirValidationResult { + if (!fs.existsSync(engineDir)) { + return "directoryNotFound"; + } else if (!fs.statSync(engineDir).isDirectory()) { + return "notADirectory"; + } else if (!fs.existsSync(path.join(engineDir, "engine_manifest.json"))) { + return "manifestNotFound"; + } + const manifest = fs.readFileSync( + path.join(engineDir, "engine_manifest.json"), + "utf-8", + ); + let manifestContent: MinimumEngineManifestType; + try { + manifestContent = minimumEngineManifestSchema.parse(JSON.parse(manifest)); + } catch (e) { + return "invalidManifest"; + } + + const engineInfos = this.fetchEngineInfos(); + if ( + engineInfos.some((engineInfo) => engineInfo.uuid === manifestContent.uuid) + ) { + return "alreadyExists"; + } + return "ok"; + } +} + +export default EngineInfoManager; diff --git a/src/backend/electron/manager/engineManager.ts b/src/backend/electron/manager/engineProcessManager.ts similarity index 62% rename from src/backend/electron/manager/engineManager.ts rename to src/backend/electron/manager/engineProcessManager.ts index 6c32171316..539676f2b8 100644 --- a/src/backend/electron/manager/engineManager.ts +++ b/src/backend/electron/manager/engineProcessManager.ts @@ -1,8 +1,6 @@ import { spawn, ChildProcess } from "child_process"; import path from "path"; -import fs from "fs"; import treeKill from "tree-kill"; -import shlex from "shlex"; import { app, dialog } from "electron"; // FIXME: ここでelectronをimportするのは良くない @@ -13,17 +11,9 @@ import { getProcessNameFromPid, isAssignablePort, url2HostInfo, -} from "./portManager"; +} from "../portHelper"; -import { - EngineInfo, - EngineDirValidationResult, - MinimumEngineManifestType, - EngineId, - minimumEngineManifestSchema, - envEngineInfoSchema, -} from "@/type/preload"; -import { AltPortInfos } from "@/store/type"; +import { EngineInfo, EngineId, EngineSettings } from "@/type/preload"; import { BaseConfigManager } from "@/backend/common/ConfigManager"; type EngineProcessContainer = { @@ -31,180 +21,38 @@ type EngineProcessContainer = { engineProcess?: ChildProcess; }; -/** - * デフォルトエンジンの情報を作成する - */ -function createDefaultEngineInfos(defaultEngineDir: string): EngineInfo[] { - // TODO: envから直接ではなく、envに書いたengine_manifest.jsonから情報を得るようにする - const defaultEngineInfosEnv = - import.meta.env.VITE_DEFAULT_ENGINE_INFOS ?? "[]"; - - const envSchema = envEngineInfoSchema.array(); - const engines = envSchema.parse(JSON.parse(defaultEngineInfosEnv)); - - return engines.map((engineInfo) => { - return { - ...engineInfo, - isDefault: true, - type: "path", - executionFilePath: path.resolve(engineInfo.executionFilePath), - path: - engineInfo.path == undefined - ? undefined - : path.resolve(defaultEngineDir, engineInfo.path), - } satisfies EngineInfo; - }); -} - -export class EngineManager { - configManager: BaseConfigManager; - defaultEngineDir: string; - vvppEngineDir: string; +/** エンジンプロセスを管理するクラス */ +export class EngineProcessManager { onEngineProcessError: (engineInfo: EngineInfo, error: Error) => void; + engineInfosFetcher: () => Readonly[]; + engineAltPortUpdater: (engineId: EngineId, port: number) => void; + engineSettingsGetter: () => Partial; defaultEngineInfos: EngineInfo[] = []; additionalEngineInfos: EngineInfo[] = []; - engineProcessContainers: Record; - - public altPortInfo: AltPortInfos = {}; + engineProcessContainers: Record = {}; - constructor({ - configManager, - defaultEngineDir, - vvppEngineDir, - onEngineProcessError, - }: { + constructor(payload: { configManager: BaseConfigManager; - defaultEngineDir: string; - vvppEngineDir: string; onEngineProcessError: (engineInfo: EngineInfo, error: Error) => void; + /** エンジン情報を取得する関数 */ + engineInfosFetcher: () => Readonly[]; + /** エンジンの代替ポート情報を更新する関数 */ + engineAltPortUpdater: (engineId: EngineId, port: number) => void; + /** エンジン設定を取得する関数 */ + engineSettingsGetter: () => Partial; }) { - this.configManager = configManager; - this.defaultEngineDir = defaultEngineDir; - this.vvppEngineDir = vvppEngineDir; - this.onEngineProcessError = onEngineProcessError; - this.engineProcessContainers = {}; - } - - /** - * 追加エンジンの一覧を作成する。 - * FIXME: store.get("registeredEngineDirs")への副作用をEngineManager外に移動する - */ - private createAdditionalEngineInfos(): EngineInfo[] { - const engines: EngineInfo[] = []; - const addEngine = (engineDir: string, type: "vvpp" | "path") => { - const manifestPath = path.join(engineDir, "engine_manifest.json"); - if (!fs.existsSync(manifestPath)) { - return "manifestNotFound"; - } - let manifest: MinimumEngineManifestType; - try { - manifest = minimumEngineManifestSchema.parse( - JSON.parse(fs.readFileSync(manifestPath, { encoding: "utf8" })), - ); - } catch (e) { - return "manifestParseError"; - } - - const [command, ...args] = shlex.split(manifest.command); - - engines.push({ - uuid: manifest.uuid, - host: `http://127.0.0.1:${manifest.port}`, - name: manifest.name, - path: engineDir, - executionEnabled: true, - executionFilePath: path.join(engineDir, command), - executionArgs: args, - type, - isDefault: false, - } satisfies EngineInfo); - return "ok"; - }; - for (const dirName of fs.readdirSync(this.vvppEngineDir)) { - const engineDir = path.join(this.vvppEngineDir, dirName); - if (!fs.statSync(engineDir).isDirectory()) { - log.log(`${engineDir} is not directory`); - continue; - } - if (dirName === ".tmp") { - continue; - } - const result = addEngine(engineDir, "vvpp"); - if (result !== "ok") { - log.log(`Failed to load engine: ${result}, ${engineDir}`); - } - } - // FIXME: この関数の引数でregisteredEngineDirsを受け取り、動かないエンジンをreturnして、EngineManager外でconfig.setする - for (const engineDir of this.configManager.get("registeredEngineDirs")) { - const result = addEngine(engineDir, "path"); - if (result !== "ok") { - log.log(`Failed to load engine: ${result}, ${engineDir}`); - // 動かないエンジンは追加できないので削除 - // FIXME: エンジン管理UIで削除可能にする - dialog.showErrorBox( - "エンジンの読み込みに失敗しました。", - `${engineDir}を読み込めませんでした。このエンジンは削除されます。`, - ); - this.configManager.set( - "registeredEngineDirs", - this.configManager - .get("registeredEngineDirs") - .filter((p) => p !== engineDir), - ); - } - } - return engines; - } - - /** - * 全てのエンジンの一覧を取得する。デフォルトエンジン+追加エンジン。 - */ - fetchEngineInfos(): EngineInfo[] { - return [...this.defaultEngineInfos, ...this.additionalEngineInfos]; - } - - /** - * エンジンの情報を取得する。存在しない場合はエラーを返す。 - */ - fetchEngineInfo(engineId: EngineId): EngineInfo { - const engineInfos = this.fetchEngineInfos(); - const engineInfo = engineInfos.find( - (engineInfo) => engineInfo.uuid === engineId, - ); - if (!engineInfo) { - throw new Error(`No such engineInfo registered: engineId == ${engineId}`); - } - return engineInfo; - } - - /** - * エンジンのディレクトリを取得する。存在しない場合はエラーを返す。 - */ - fetchEngineDirectory(engineId: EngineId): string { - const engineInfo = this.fetchEngineInfo(engineId); - const engineDirectory = engineInfo.path; - if (engineDirectory == undefined) { - throw new Error(`engineDirectory is undefined: engineId == ${engineId}`); - } - - return engineDirectory; - } - - /** - * EngineInfosとAltPortInfoを初期化する。 - */ - initializeEngineInfosAndAltPortInfo() { - this.defaultEngineInfos = createDefaultEngineInfos(this.defaultEngineDir); - this.additionalEngineInfos = this.createAdditionalEngineInfos(); - this.altPortInfo = {}; + this.onEngineProcessError = payload.onEngineProcessError; + this.engineInfosFetcher = payload.engineInfosFetcher; + this.engineAltPortUpdater = payload.engineAltPortUpdater; + this.engineSettingsGetter = payload.engineSettingsGetter; } /** * 全てのエンジンを起動する。 */ async runEngineAll() { - const engineInfos = this.fetchEngineInfos(); + const engineInfos = this.engineInfosFetcher(); log.info(`Starting ${engineInfos.length} engine/s...`); for (const engineInfo of engineInfos) { @@ -217,7 +65,7 @@ export class EngineManager { * エンジンを起動する。 */ async runEngine(engineId: EngineId) { - const engineInfos = this.fetchEngineInfos(); + const engineInfos = this.engineInfosFetcher(); const engineInfo = engineInfos.find( (engineInfo) => engineInfo.uuid === engineId, ); @@ -278,14 +126,8 @@ export class EngineManager { throw new Error("No Alternative Port Found"); } - // 代替ポートの情報 - this.altPortInfo[engineId] = { - from: engineHostInfo.port, - to: altPort, - }; - - // 代替ポートを設定 - engineInfo.host = `${engineHostInfo.protocol}//${engineHostInfo.hostname}:${altPort}`; + // 代替ポート情報を更新 + this.engineAltPortUpdater(engineId, altPort); log.warn( `ENGINE ${engineId}: Applied Alternative Port: ${engineHostInfo.port} -> ${altPort}`, ); @@ -302,7 +144,7 @@ export class EngineManager { const engineProcessContainer = this.engineProcessContainers[engineId]; engineProcessContainer.willQuitEngine = false; - const engineSetting = this.configManager.get("engineSettings")[engineId]; + const engineSetting = this.engineSettingsGetter()[engineId]; if (engineSetting == undefined) throw new Error(`No such engineSetting: engineId == ${engineId}`); @@ -521,37 +363,6 @@ export class EngineManager { }); }); } - - /** - * ディレクトリがエンジンとして正しいかどうかを判定する - */ - validateEngineDir(engineDir: string): EngineDirValidationResult { - if (!fs.existsSync(engineDir)) { - return "directoryNotFound"; - } else if (!fs.statSync(engineDir).isDirectory()) { - return "notADirectory"; - } else if (!fs.existsSync(path.join(engineDir, "engine_manifest.json"))) { - return "manifestNotFound"; - } - const manifest = fs.readFileSync( - path.join(engineDir, "engine_manifest.json"), - "utf-8", - ); - let manifestContent: MinimumEngineManifestType; - try { - manifestContent = minimumEngineManifestSchema.parse(JSON.parse(manifest)); - } catch (e) { - return "invalidManifest"; - } - - const engineInfos = this.fetchEngineInfos(); - if ( - engineInfos.some((engineInfo) => engineInfo.uuid === manifestContent.uuid) - ) { - return "alreadyExists"; - } - return "ok"; - } } -export default EngineManager; +export default EngineProcessManager; diff --git a/src/backend/electron/manager/portManager.ts b/src/backend/electron/portHelper.ts similarity index 100% rename from src/backend/electron/manager/portManager.ts rename to src/backend/electron/portHelper.ts