Track bundled vendor runtime sources
This commit is contained in:
272
vendor/aigcpanel/electron/main/index.ts
vendored
Normal file
272
vendor/aigcpanel/electron/main/index.ts
vendored
Normal file
@@ -0,0 +1,272 @@
|
||||
import { app, BrowserWindow, desktopCapturer, session, shell } from "electron";
|
||||
import { optimizer } from "@electron-toolkit/utils";
|
||||
import path from "node:path";
|
||||
import fs from "node:fs";
|
||||
|
||||
/** process.js 必须位于非依赖项的顶部 */
|
||||
import { isDummy } from "../lib/process";
|
||||
import { AppEnv, AppRuntime } from "../mapi/env";
|
||||
import { MAPI } from "../mapi/main";
|
||||
|
||||
import { WindowConfig } from "../config/window";
|
||||
import { AppConfig } from "../../src/config";
|
||||
import Log from "../mapi/log/main";
|
||||
import { ConfigMenu } from "../config/menu";
|
||||
import { ConfigLang, t } from "../config/lang";
|
||||
import { ConfigContextMenu } from "../config/contextMenu";
|
||||
import { preloadDefault, rendererLoadPath } from "../lib/env-main";
|
||||
import { Page } from "../page";
|
||||
import { ConfigTray } from "../config/tray";
|
||||
import { icnsLogoPath, icoLogoPath, logoPath } from "../config/icon";
|
||||
import { isDev, isMac, isPackaged } from "../lib/env";
|
||||
import { executeHooks } from "../lib/hooks";
|
||||
import { DevToolsManager } from "../lib/devtools";
|
||||
import { AppsMain } from "../mapi/app/main";
|
||||
import { ServerMain } from "../mapi/server/main";
|
||||
import { HttpServerMain } from "../mapi/httpserver/main";
|
||||
import ConfigMain from "../mapi/config/main";
|
||||
import { reportError } from "../mapi/log/beacon";
|
||||
|
||||
const isDummyNew = isDummy;
|
||||
|
||||
if (process.env["ELECTRON_ENV_PROD"]) {
|
||||
DevToolsManager.setEnable(false);
|
||||
}
|
||||
|
||||
process.on("uncaughtException", (reason) => {
|
||||
let error: any = reason;
|
||||
if (error instanceof Error) {
|
||||
error = [error.message, error.stack].join("\n");
|
||||
}
|
||||
Log.error("UncaughtException", error);
|
||||
reportError(
|
||||
reason instanceof Error ? reason.message : String(reason),
|
||||
reason instanceof Error ? reason.stack : undefined,
|
||||
);
|
||||
});
|
||||
|
||||
process.on("unhandledRejection", (reason) => {
|
||||
Log.error("UnhandledRejection", reason);
|
||||
let error: any = reason;
|
||||
if (error instanceof Error) {
|
||||
error = [error.message, error.stack].join("\n");
|
||||
}
|
||||
Log.error("UnhandledRejection", error);
|
||||
reportError(
|
||||
reason instanceof Error ? (reason as Error).message : String(reason),
|
||||
reason instanceof Error ? (reason as Error).stack : undefined,
|
||||
);
|
||||
});
|
||||
|
||||
// Ensure consistent app name (macOS uses Info.plist CFBundleName from the dev binary,
|
||||
// which would be "Electron" instead of "aigcpanel" without this explicit override)
|
||||
if (app.getName() !== "aigcpanel") {
|
||||
app.setName("aigcpanel");
|
||||
}
|
||||
|
||||
app.disableHardwareAcceleration();
|
||||
|
||||
// Set application name for Windows 10+ notifications
|
||||
if (process.platform === "win32") app.setAppUserModelId(app.getName());
|
||||
|
||||
if (!app.requestSingleInstanceLock()) {
|
||||
app.quit();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const hasSplashWindow = true;
|
||||
|
||||
AppEnv.appRoot = process.env.APP_ROOT;
|
||||
AppEnv.appData = app.getPath("appData");
|
||||
AppEnv.userData = app.getPath("userData");
|
||||
AppEnv.dataRoot = path.join(AppEnv.userData, "data");
|
||||
|
||||
if (!fs.existsSync(AppEnv.dataRoot)) {
|
||||
fs.mkdirSync(AppEnv.dataRoot, { recursive: true });
|
||||
}
|
||||
for (const dir of ["logs", "storage"]) {
|
||||
if (!fs.existsSync(path.join(AppEnv.dataRoot, dir))) {
|
||||
fs.mkdirSync(path.join(AppEnv.dataRoot, dir), { recursive: true });
|
||||
}
|
||||
}
|
||||
|
||||
AppEnv.isInit = true;
|
||||
|
||||
MAPI.init();
|
||||
ConfigContextMenu.init();
|
||||
|
||||
Log.info("Starting");
|
||||
Log.info("LaunchInfo", {
|
||||
isPackaged,
|
||||
userData: AppEnv.userData,
|
||||
dataRoot: AppEnv.dataRoot,
|
||||
});
|
||||
|
||||
async function createWindow() {
|
||||
let icon = logoPath;
|
||||
if (process.platform === "win32") {
|
||||
icon = icoLogoPath;
|
||||
} else if (process.platform === "darwin") {
|
||||
icon = icnsLogoPath;
|
||||
}
|
||||
if (hasSplashWindow) {
|
||||
AppRuntime.splashWindow = new BrowserWindow({
|
||||
title: AppConfig.title,
|
||||
width: 600,
|
||||
height: 350,
|
||||
transparent: true,
|
||||
frame: false,
|
||||
alwaysOnTop: true,
|
||||
hasShadow: true,
|
||||
skipTaskbar: true,
|
||||
});
|
||||
rendererLoadPath(AppRuntime.splashWindow, "splash.html");
|
||||
}
|
||||
AppRuntime.mainWindow = new BrowserWindow({
|
||||
show: !hasSplashWindow,
|
||||
title: AppConfig.title,
|
||||
...(!isPackaged ? { icon } : {}),
|
||||
frame: false,
|
||||
transparent: false,
|
||||
hasShadow: true,
|
||||
center: true,
|
||||
minWidth: WindowConfig.initWidth,
|
||||
minHeight: WindowConfig.initHeight,
|
||||
width: WindowConfig.initWidth,
|
||||
height: WindowConfig.initHeight,
|
||||
backgroundColor: await AppsMain.defaultDarkModeBackgroundColor(),
|
||||
titleBarStyle: "hidden",
|
||||
trafficLightPosition: { x: 10, y: 11 },
|
||||
webPreferences: {
|
||||
preload: preloadDefault,
|
||||
// Warning: Enable nodeIntegration and disable contextIsolation is not secure in production
|
||||
nodeIntegration: true,
|
||||
webSecurity: false,
|
||||
webviewTag: true,
|
||||
// Consider using contextBridge.exposeInMainWorld
|
||||
// Read more on https://www.electronjs.org/docs/latest/tutorial/context-isolation
|
||||
contextIsolation: false,
|
||||
// sandbox: false,
|
||||
},
|
||||
});
|
||||
|
||||
AppRuntime.mainWindow.on("closed", () => {
|
||||
AppRuntime.mainWindow = null;
|
||||
});
|
||||
AppRuntime.mainWindow.on("show", async () => {
|
||||
await executeHooks(AppRuntime.mainWindow, "Show");
|
||||
});
|
||||
AppRuntime.mainWindow.on("hide", async () => {
|
||||
await executeHooks(AppRuntime.mainWindow, "Hide");
|
||||
});
|
||||
|
||||
if (isMac) {
|
||||
AppRuntime.mainWindow.on("close", (event) => {
|
||||
// @ts-ignore
|
||||
if (!app.quitForce && !isDev) {
|
||||
executeHooks(AppRuntime.mainWindow, "ShowQuitConfirmDialog");
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
}
|
||||
AppRuntime.mainWindow.on("enter-full-screen", () => {
|
||||
executeHooks(AppRuntime.mainWindow, "EnterFullScreen");
|
||||
});
|
||||
AppRuntime.mainWindow.on("leave-full-screen", () => {
|
||||
executeHooks(AppRuntime.mainWindow, "LeaveFullScreen");
|
||||
});
|
||||
|
||||
rendererLoadPath(AppRuntime.mainWindow, "index.html");
|
||||
DevToolsManager.register("Main", AppRuntime.mainWindow);
|
||||
|
||||
AppRuntime.mainWindow.webContents.on("did-finish-load", () => {
|
||||
if (hasSplashWindow) {
|
||||
AppRuntime.mainWindow?.show();
|
||||
setTimeout(() => {
|
||||
try {
|
||||
AppRuntime.splashWindow?.close();
|
||||
AppRuntime.splashWindow = null;
|
||||
// AppRuntime.mainWindow.webContents.openDevTools({
|
||||
// mode: 'detach',
|
||||
// })
|
||||
} catch (e) {}
|
||||
}, 1000);
|
||||
}
|
||||
Page.ready("main");
|
||||
DevToolsManager.autoShow(AppRuntime.mainWindow);
|
||||
});
|
||||
AppRuntime.mainWindow.webContents.setWindowOpenHandler(({ url }) => {
|
||||
if (url.startsWith("https:")) shell.openExternal(url);
|
||||
return { action: "deny" };
|
||||
});
|
||||
}
|
||||
|
||||
app.whenReady()
|
||||
.then(() => {
|
||||
session.defaultSession.setDisplayMediaRequestHandler(
|
||||
(request, callback) => {
|
||||
desktopCapturer
|
||||
.getSources({ types: ["screen"] })
|
||||
.then((sources) => {
|
||||
// Grant access to the first screen found.
|
||||
callback({ video: sources[0], audio: "loopback" });
|
||||
});
|
||||
},
|
||||
);
|
||||
})
|
||||
.then(ConfigLang.readyAsync)
|
||||
.then(() => {
|
||||
MAPI.ready();
|
||||
ConfigMenu.ready();
|
||||
ConfigTray.ready();
|
||||
HttpServerMain.start().catch((err: any) => {
|
||||
Log.error("HttpServer auto-start failed", err);
|
||||
});
|
||||
app.on("browser-window-created", (_, window) => {
|
||||
optimizer.watchWindowShortcuts(window);
|
||||
});
|
||||
createWindow().then();
|
||||
});
|
||||
|
||||
app.on("before-quit", (event) => {
|
||||
const localServerRunningCount = ServerMain.getRunningServerCount();
|
||||
if (localServerRunningCount > 0) {
|
||||
// && isPackaged
|
||||
event.preventDefault();
|
||||
AppsMain.toast(
|
||||
t("有 {count} 个本地模型服务正在运行,请停止后再关闭应用", {
|
||||
count: localServerRunningCount,
|
||||
}),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
app.on("will-quit", () => {
|
||||
MAPI.destroy();
|
||||
});
|
||||
|
||||
app.on("window-all-closed", () => {
|
||||
if (process.platform !== "darwin") app.quit();
|
||||
});
|
||||
|
||||
app.on("second-instance", () => {
|
||||
if (AppRuntime.mainWindow) {
|
||||
if (AppRuntime.mainWindow.isMinimized()) {
|
||||
AppRuntime.mainWindow.restore();
|
||||
}
|
||||
AppRuntime.mainWindow.show();
|
||||
AppRuntime.mainWindow.focus();
|
||||
}
|
||||
});
|
||||
|
||||
app.on("activate", () => {
|
||||
const allWindows = BrowserWindow.getAllWindows();
|
||||
if (allWindows.length) {
|
||||
if (!AppRuntime.mainWindow.isVisible()) {
|
||||
AppRuntime.mainWindow.show();
|
||||
}
|
||||
AppRuntime.mainWindow.focus();
|
||||
} else {
|
||||
createWindow().then();
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user