feature/IO-3205-Paint-Scale-Integrations: Pre Protocol Handler Keep ALive.
This commit is contained in:
@@ -25,6 +25,14 @@ import store from "./store/store";
|
||||
import { checkForAppUpdates } from "./util/checkForAppUpdates";
|
||||
import { getMainWindow } from "./util/toRenderer";
|
||||
import { GetAllEnvFiles } from "./watcher/watcher";
|
||||
import {
|
||||
isKeepAliveAgentInstalled,
|
||||
setupKeepAliveAgent,
|
||||
} from "./setup-keep-alive-agent";
|
||||
import {
|
||||
isKeepAliveTaskInstalled,
|
||||
setupKeepAliveTask,
|
||||
} from "./setup-keep-alive-task";
|
||||
|
||||
Sentry.init({
|
||||
dsn: "https://ba41d22656999a8c1fd63bcb7df98650@o492140.ingest.us.sentry.io/4509074139447296",
|
||||
@@ -34,6 +42,7 @@ log.initialize();
|
||||
const isMac: boolean = process.platform === "darwin";
|
||||
const protocol: string = "imexmedia";
|
||||
let isAppQuitting = false; //Needed on Mac as an override to allow us to fully quit the app.
|
||||
let isKeepAliveLaunch = false; // Track if launched via keep-alive
|
||||
// Initialize the server
|
||||
const localServer = new LocalServer();
|
||||
const gotTheLock = app.requestSingleInstanceLock();
|
||||
@@ -52,7 +61,7 @@ function createWindow(): void {
|
||||
height,
|
||||
x,
|
||||
y,
|
||||
show: false,
|
||||
show: false, // Start hidden, show later if not keep-alive
|
||||
minWidth: 600,
|
||||
minHeight: 400,
|
||||
//autoHideMenuBar: true,
|
||||
@@ -192,7 +201,14 @@ function createWindow(): void {
|
||||
label: "Open Log File",
|
||||
click: (): void => {
|
||||
/* action for item 1 */
|
||||
shell.openPath(log.transports.file.getFile().path);
|
||||
shell
|
||||
.openPath(log.transports.file.getFile().path)
|
||||
.catch((error) => {
|
||||
log.error(
|
||||
"Failed to open log file:",
|
||||
errorTypeCheck(error),
|
||||
);
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -204,7 +220,12 @@ function createWindow(): void {
|
||||
{
|
||||
label: "Open Config Folder",
|
||||
click: (): void => {
|
||||
shell.openPath(path.dirname(store.path));
|
||||
shell.openPath(path.dirname(store.path)).catch((error) => {
|
||||
log.error(
|
||||
"Failed to open config folder:",
|
||||
errorTypeCheck(error),
|
||||
);
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -218,13 +239,34 @@ function createWindow(): void {
|
||||
{
|
||||
type: "separator",
|
||||
},
|
||||
|
||||
// {
|
||||
// label: "Decode Hardcoded Estimate",
|
||||
// click: (): void => {
|
||||
// ImportJob(`C:\\EMS\\CCC\\9ee762f4.ENV`);
|
||||
// },
|
||||
// },
|
||||
{
|
||||
label: "Install Keep Alive",
|
||||
enabled: true, // Default to enabled, update dynamically
|
||||
click: async (): Promise<void> => {
|
||||
try {
|
||||
if (platform.isWindows) {
|
||||
await setupKeepAliveTask();
|
||||
log.info("Successfully installed Windows keep-alive task");
|
||||
} else if (platform.isMacOS) {
|
||||
await setupKeepAliveAgent();
|
||||
log.info("Successfully installed macOS keep-alive agent");
|
||||
}
|
||||
// Rebuild menu and update enabled state
|
||||
await updateKeepAliveMenuItem();
|
||||
} catch (error) {
|
||||
log.error(
|
||||
`Failed to install keep-alive: ${error instanceof Error ? error.message : String(error)}`,
|
||||
);
|
||||
// Optionally notify user (e.g., via dialog or log)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Add All Estimates in watched directories",
|
||||
click: (): void => {
|
||||
@@ -254,8 +296,45 @@ function createWindow(): void {
|
||||
},
|
||||
];
|
||||
|
||||
// Dynamically update Install Keep Alive enabled state
|
||||
const updateKeepAliveMenuItem = async (): Promise<void> => {
|
||||
try {
|
||||
const isInstalled = platform.isWindows
|
||||
? await isKeepAliveTaskInstalled()
|
||||
: platform.isMacOS
|
||||
? await isKeepAliveAgentInstalled()
|
||||
: false;
|
||||
const developmentMenu = template
|
||||
.find((item) => item.label === "Application")
|
||||
// @ts-ignore
|
||||
?.submenu?.find((item: { id: string }) => item.id === "development")
|
||||
?.submenu as Electron.MenuItemConstructorOptions[];
|
||||
const keepAliveItem = developmentMenu?.find(
|
||||
(item) => item.label === "Install Keep Alive",
|
||||
);
|
||||
if (keepAliveItem) {
|
||||
keepAliveItem.enabled = !isInstalled; // Enable if not installed, disable if installed
|
||||
const menu = Menu.buildFromTemplate(template);
|
||||
Menu.setApplicationMenu(menu);
|
||||
log.debug(
|
||||
`Updated Install Keep Alive menu item: enabled=${keepAliveItem.enabled}`,
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
log.error(
|
||||
`Error updating Keep Alive menu item: ${error instanceof Error ? error.message : String(error)}`,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const menu: Electron.Menu = Menu.buildFromTemplate(template);
|
||||
Menu.setApplicationMenu(menu);
|
||||
// Update menu item enabled state on app start
|
||||
updateKeepAliveMenuItem().catch((error) => {
|
||||
log.error(
|
||||
`Error updating Keep Alive menu item: ${error instanceof Error ? error.message : String(error)}`,
|
||||
);
|
||||
});
|
||||
|
||||
// Register a global shortcut to show the hidden item
|
||||
globalShortcut.register("CommandOrControl+Shift+T", () => {
|
||||
@@ -266,7 +345,7 @@ function createWindow(): void {
|
||||
const fileMenu = template.find((item) => item.label === "Application");
|
||||
// @ts-ignore
|
||||
const hiddenItem = fileMenu?.submenu?.find(
|
||||
(item) => item.id === "development",
|
||||
(item: { id: string }) => item.id === "development",
|
||||
);
|
||||
//Adjust the development menu as well.
|
||||
|
||||
@@ -289,7 +368,9 @@ function createWindow(): void {
|
||||
mainWindow.on("moved", storeWindowState);
|
||||
|
||||
mainWindow.on("ready-to-show", () => {
|
||||
mainWindow.show();
|
||||
if (!isKeepAliveLaunch) {
|
||||
mainWindow.show(); // Show only if not a keep-alive launch
|
||||
}
|
||||
//Start the HTTP server.
|
||||
// Start the local HTTP server
|
||||
try {
|
||||
@@ -307,16 +388,22 @@ function createWindow(): void {
|
||||
});
|
||||
|
||||
mainWindow.webContents.setWindowOpenHandler((details) => {
|
||||
shell.openExternal(details.url);
|
||||
shell.openExternal(details.url).catch((error) => {
|
||||
log.error("Failed to open external URL:", errorTypeCheck(error));
|
||||
});
|
||||
return { action: "deny" };
|
||||
});
|
||||
|
||||
// HMR for renderer base on electron-vite cli.
|
||||
// Load the remote URL for development or the local html file for production.
|
||||
if (is.dev && process.env["ELECTRON_RENDERER_URL"]) {
|
||||
mainWindow.loadURL(process.env["ELECTRON_RENDERER_URL"]);
|
||||
mainWindow.loadURL(process.env["ELECTRON_RENDERER_URL"]).catch(error => {
|
||||
log.error("Failed to load URL:", errorTypeCheck(error));
|
||||
});
|
||||
} else {
|
||||
mainWindow.loadFile(join(__dirname, "../renderer/index.html"));
|
||||
mainWindow.loadFile(join(__dirname, "../renderer/index.html")).catch(error => {
|
||||
log.error("Failed to load file:", errorTypeCheck(error));
|
||||
});
|
||||
}
|
||||
if (import.meta.env.DEV) {
|
||||
mainWindow.webContents.openDevTools();
|
||||
@@ -341,7 +428,8 @@ app.whenReady().then(async () => {
|
||||
optimizer.watchWindowShortcuts(window);
|
||||
});
|
||||
|
||||
let isDefaultProtocolClient;
|
||||
let isDefaultProtocolClient: boolean;
|
||||
|
||||
// remove so we can register each time as we run the app.
|
||||
app.removeAsDefaultProtocolClient(protocol);
|
||||
|
||||
@@ -369,11 +457,15 @@ app.whenReady().then(async () => {
|
||||
openMainWindow();
|
||||
const url = argv.find((arg) => arg.startsWith(`${protocol}://`));
|
||||
if (url) {
|
||||
openInExplorer(url);
|
||||
if (url.startsWith(`${protocol}://keep-alive`)) {
|
||||
log.info("Keep-alive protocol received, app is already running.");
|
||||
// Do nothing if already running
|
||||
} else {
|
||||
openInExplorer(url);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
//Dynamically load ipcMain handlers once ready.
|
||||
try {
|
||||
const module = await import("./ipc/ipcMainConfig");
|
||||
@@ -453,6 +545,12 @@ app.whenReady().then(async () => {
|
||||
mainWindow?.webContents.send(ipcTypes.toRenderer.updates.downloaded, info);
|
||||
});
|
||||
|
||||
// Check if launched with keep-alive protocol (Windows)
|
||||
const args = process.argv.slice(1);
|
||||
if (args.some((arg) => arg.startsWith(`${protocol}://keep-alive`))) {
|
||||
isKeepAliveLaunch = true;
|
||||
}
|
||||
|
||||
//The update itself will run when the bodyshop record is queried to know what release channel to use.
|
||||
createWindow();
|
||||
|
||||
@@ -464,7 +562,13 @@ app.whenReady().then(async () => {
|
||||
app.on("open-url", (event: Electron.Event, url: string) => {
|
||||
event.preventDefault();
|
||||
//Don't do anything for now. We just want to open the app.
|
||||
openInExplorer(url);
|
||||
if (url.startsWith(`${protocol}://keep-alive`)) {
|
||||
log.info("Keep-alive protocol received.");
|
||||
isKeepAliveLaunch = true;
|
||||
openMainWindow();
|
||||
} else {
|
||||
openInExplorer(url);
|
||||
}
|
||||
});
|
||||
|
||||
// Quit when all windows are closed, except on macOS. There, it's common
|
||||
@@ -518,5 +622,7 @@ function openMainWindow(): void {
|
||||
function openInExplorer(url: string): void {
|
||||
const folderPath: string = decodeURIComponent(url.split(`${protocol}://`)[1]);
|
||||
log.info("Opening folder in explorer", folderPath);
|
||||
shell.openPath(folderPath);
|
||||
shell.openPath(folderPath).catch((error) => {
|
||||
log.error("Failed to open folder in explorer:", errorTypeCheck(error));
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user