feature/IO-3205-Paint-Scale-Integrations: Pre Protocol Handler Keep ALive.
This commit is contained in:
@@ -26,7 +26,7 @@ nsis:
|
|||||||
shortcutName: ${productName}
|
shortcutName: ${productName}
|
||||||
uninstallDisplayName: ${productName}
|
uninstallDisplayName: ${productName}
|
||||||
createDesktopShortcut: always
|
createDesktopShortcut: always
|
||||||
requestExecutionLevel: admin # Ensure elevated privileges
|
perMachine: true # Ensure elevated privileges
|
||||||
include: "scripts/installer.nsh" # Reference NSIS script from scripts directory
|
include: "scripts/installer.nsh" # Reference NSIS script from scripts directory
|
||||||
mac:
|
mac:
|
||||||
entitlementsInherit: build/entitlements.mac.plist
|
entitlementsInherit: build/entitlements.mac.plist
|
||||||
@@ -59,10 +59,6 @@ linux:
|
|||||||
category: Utility
|
category: Utility
|
||||||
desktop:
|
desktop:
|
||||||
MimeType: x-scheme-handler/imexmedia;
|
MimeType: x-scheme-handler/imexmedia;
|
||||||
afterInstall: |
|
|
||||||
# Install .desktop file for protocol handling
|
|
||||||
cp scripts/imex-shop-partner.desktop $HOME/.local/share/applications/
|
|
||||||
update-desktop-database $HOME/.local/share/applications/
|
|
||||||
appImage:
|
appImage:
|
||||||
artifactName: ${name}-${version}.${ext}
|
artifactName: ${name}-${version}.${ext}
|
||||||
npmRebuild: false
|
npmRebuild: false
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ nsis:
|
|||||||
shortcutName: ${productName}
|
shortcutName: ${productName}
|
||||||
uninstallDisplayName: ${productName}
|
uninstallDisplayName: ${productName}
|
||||||
createDesktopShortcut: always
|
createDesktopShortcut: always
|
||||||
requestExecutionLevel: admin # Ensure elevated privileges
|
perMachine: true # Ensure elevated privileges
|
||||||
include: "scripts/installer.nsh" # Reference NSIS script from scripts directory
|
include: "scripts/installer.nsh" # Reference NSIS script from scripts directory
|
||||||
mac:
|
mac:
|
||||||
entitlementsInherit: build/entitlements.mac.plist
|
entitlementsInherit: build/entitlements.mac.plist
|
||||||
@@ -59,10 +59,6 @@ linux:
|
|||||||
category: Utility
|
category: Utility
|
||||||
desktop:
|
desktop:
|
||||||
MimeType: x-scheme-handler/imexmedia;
|
MimeType: x-scheme-handler/imexmedia;
|
||||||
afterInstall: |
|
|
||||||
# Install .desktop file for protocol handling
|
|
||||||
cp scripts/rome-shop-partner.desktop $HOME/.local/share/applications/
|
|
||||||
update-desktop-database $HOME/.local/share/applications/
|
|
||||||
appImage:
|
appImage:
|
||||||
artifactName: ${name}-${version}.${ext}
|
artifactName: ${name}-${version}.${ext}
|
||||||
npmRebuild: false
|
npmRebuild: false
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ function createWindow(): void {
|
|||||||
// { role: 'appMenu' }
|
// { role: 'appMenu' }
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
...(isMac
|
...(isMac
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
label: app.name,
|
label: app.name,
|
||||||
submenu: [
|
submenu: [
|
||||||
@@ -94,7 +94,7 @@ function createWindow(): void {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
// { role: 'fileMenu' }
|
// { role: 'fileMenu' }
|
||||||
{
|
{
|
||||||
label: "File",
|
label: "File",
|
||||||
@@ -117,7 +117,7 @@ function createWindow(): void {
|
|||||||
{ role: "paste" },
|
{ role: "paste" },
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
...(isMac
|
...(isMac
|
||||||
? [
|
? [
|
||||||
{ role: "pasteAndMatchStyle" },
|
{ role: "pasteAndMatchStyle" },
|
||||||
{ role: "delete" },
|
{ role: "delete" },
|
||||||
{ role: "selectAll" },
|
{ role: "selectAll" },
|
||||||
@@ -127,7 +127,7 @@ function createWindow(): void {
|
|||||||
submenu: [{ role: "startSpeaking" }, { role: "stopSpeaking" }],
|
submenu: [{ role: "startSpeaking" }, { role: "stopSpeaking" }],
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: [{ role: "delete" }, { type: "separator" }, { role: "selectAll" }]),
|
: [{ role: "delete" }, { type: "separator" }, { role: "selectAll" }]),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
// { role: 'viewMenu' }
|
// { role: 'viewMenu' }
|
||||||
@@ -202,13 +202,13 @@ function createWindow(): void {
|
|||||||
click: (): void => {
|
click: (): void => {
|
||||||
/* action for item 1 */
|
/* action for item 1 */
|
||||||
shell
|
shell
|
||||||
.openPath(log.transports.file.getFile().path)
|
.openPath(log.transports.file.getFile().path)
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
log.error(
|
log.error(
|
||||||
"Failed to open log file:",
|
"Failed to open log file:",
|
||||||
errorTypeCheck(error),
|
errorTypeCheck(error),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -222,8 +222,8 @@ function createWindow(): void {
|
|||||||
click: (): void => {
|
click: (): void => {
|
||||||
shell.openPath(path.dirname(store.path)).catch((error) => {
|
shell.openPath(path.dirname(store.path)).catch((error) => {
|
||||||
log.error(
|
log.error(
|
||||||
"Failed to open config folder:",
|
"Failed to open config folder:",
|
||||||
errorTypeCheck(error),
|
errorTypeCheck(error),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -232,7 +232,7 @@ function createWindow(): void {
|
|||||||
label: "Log the Store",
|
label: "Log the Store",
|
||||||
click: (): void => {
|
click: (): void => {
|
||||||
log.debug(
|
log.debug(
|
||||||
"Store Contents" + JSON.stringify(store.store, null, 4),
|
"Store Contents" + JSON.stringify(store.store, null, 4),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -251,17 +251,21 @@ function createWindow(): void {
|
|||||||
click: async (): Promise<void> => {
|
click: async (): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
if (platform.isWindows) {
|
if (platform.isWindows) {
|
||||||
|
log.debug("Creating Windows keep-alive task");
|
||||||
await setupKeepAliveTask();
|
await setupKeepAliveTask();
|
||||||
log.info("Successfully installed Windows keep-alive task");
|
log.info("Successfully installed Windows keep-alive task");
|
||||||
} else if (platform.isMacOS) {
|
} else if (platform.isMacOS) {
|
||||||
|
log.debug("Creating macOS keep-alive agent");
|
||||||
await setupKeepAliveAgent();
|
await setupKeepAliveAgent();
|
||||||
log.info("Successfully installed macOS keep-alive agent");
|
log.info("Successfully installed macOS keep-alive agent");
|
||||||
}
|
}
|
||||||
|
// Wait to ensure task/agent is registered
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 1500));
|
||||||
// Rebuild menu and update enabled state
|
// Rebuild menu and update enabled state
|
||||||
await updateKeepAliveMenuItem();
|
await updateKeepAliveMenuItem();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.error(
|
log.error(
|
||||||
`Failed to install keep-alive: ${error instanceof Error ? error.message : String(error)}`,
|
`Failed to install keep-alive: ${error instanceof Error ? error.message : String(error)}`,
|
||||||
);
|
);
|
||||||
// Optionally notify user (e.g., via dialog or log)
|
// Optionally notify user (e.g., via dialog or log)
|
||||||
}
|
}
|
||||||
@@ -285,13 +289,13 @@ function createWindow(): void {
|
|||||||
{ role: "zoom" },
|
{ role: "zoom" },
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
...(isMac
|
...(isMac
|
||||||
? [
|
? [
|
||||||
{ type: "separator" },
|
{ type: "separator" },
|
||||||
{ role: "front" },
|
{ role: "front" },
|
||||||
{ type: "separator" },
|
{ type: "separator" },
|
||||||
{ role: "window" },
|
{ role: "window" },
|
||||||
]
|
]
|
||||||
: [{ role: "close" }]),
|
: [{ role: "close" }]),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@@ -300,29 +304,29 @@ function createWindow(): void {
|
|||||||
const updateKeepAliveMenuItem = async (): Promise<void> => {
|
const updateKeepAliveMenuItem = async (): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
const isInstalled = platform.isWindows
|
const isInstalled = platform.isWindows
|
||||||
? await isKeepAliveTaskInstalled()
|
? await isKeepAliveTaskInstalled()
|
||||||
: platform.isMacOS
|
: platform.isMacOS
|
||||||
? await isKeepAliveAgentInstalled()
|
? await isKeepAliveAgentInstalled()
|
||||||
: false;
|
: false;
|
||||||
const developmentMenu = template
|
const developmentMenu = template
|
||||||
.find((item) => item.label === "Application")
|
.find((item) => item.label === "Application")
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
?.submenu?.find((item: { id: string }) => item.id === "development")
|
?.submenu?.find((item: { id: string }) => item.id === "development")
|
||||||
?.submenu as Electron.MenuItemConstructorOptions[];
|
?.submenu as Electron.MenuItemConstructorOptions[];
|
||||||
const keepAliveItem = developmentMenu?.find(
|
const keepAliveItem = developmentMenu?.find(
|
||||||
(item) => item.label === "Install Keep Alive",
|
(item) => item.label === "Install Keep Alive",
|
||||||
);
|
);
|
||||||
if (keepAliveItem) {
|
if (keepAliveItem) {
|
||||||
keepAliveItem.enabled = !isInstalled; // Enable if not installed, disable if installed
|
keepAliveItem.enabled = !isInstalled; // Enable if not installed, disable if installed
|
||||||
const menu = Menu.buildFromTemplate(template);
|
const menu = Menu.buildFromTemplate(template);
|
||||||
Menu.setApplicationMenu(menu);
|
Menu.setApplicationMenu(menu);
|
||||||
log.debug(
|
log.debug(
|
||||||
`Updated Install Keep Alive menu item: enabled=${keepAliveItem.enabled}`,
|
`Updated Install Keep Alive menu item: enabled=${keepAliveItem.enabled}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.error(
|
log.error(
|
||||||
`Error updating Keep Alive menu item: ${error instanceof Error ? error.message : String(error)}`,
|
`Error updating Keep Alive menu item: ${error instanceof Error ? error.message : String(error)}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -332,7 +336,7 @@ function createWindow(): void {
|
|||||||
// Update menu item enabled state on app start
|
// Update menu item enabled state on app start
|
||||||
updateKeepAliveMenuItem().catch((error) => {
|
updateKeepAliveMenuItem().catch((error) => {
|
||||||
log.error(
|
log.error(
|
||||||
`Error updating Keep Alive menu item: ${error instanceof Error ? error.message : String(error)}`,
|
`Error updating Keep Alive menu item: ${error instanceof Error ? error.message : String(error)}`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -345,7 +349,7 @@ function createWindow(): void {
|
|||||||
const fileMenu = template.find((item) => item.label === "Application");
|
const fileMenu = template.find((item) => item.label === "Application");
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const hiddenItem = fileMenu?.submenu?.find(
|
const hiddenItem = fileMenu?.submenu?.find(
|
||||||
(item: { id: string }) => item.id === "development",
|
(item: { id: string }) => item.id === "development",
|
||||||
);
|
);
|
||||||
//Adjust the development menu as well.
|
//Adjust the development menu as well.
|
||||||
|
|
||||||
@@ -397,13 +401,15 @@ function createWindow(): void {
|
|||||||
// HMR for renderer base on electron-vite cli.
|
// HMR for renderer base on electron-vite cli.
|
||||||
// Load the remote URL for development or the local html file for production.
|
// Load the remote URL for development or the local html file for production.
|
||||||
if (is.dev && process.env["ELECTRON_RENDERER_URL"]) {
|
if (is.dev && process.env["ELECTRON_RENDERER_URL"]) {
|
||||||
mainWindow.loadURL(process.env["ELECTRON_RENDERER_URL"]).catch(error => {
|
mainWindow.loadURL(process.env["ELECTRON_RENDERER_URL"]).catch((error) => {
|
||||||
log.error("Failed to load URL:", errorTypeCheck(error));
|
log.error("Failed to load URL:", errorTypeCheck(error));
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
mainWindow.loadFile(join(__dirname, "../renderer/index.html")).catch(error => {
|
mainWindow
|
||||||
log.error("Failed to load file:", errorTypeCheck(error));
|
.loadFile(join(__dirname, "../renderer/index.html"))
|
||||||
});
|
.catch((error) => {
|
||||||
|
log.error("Failed to load file:", errorTypeCheck(error));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (import.meta.env.DEV) {
|
if (import.meta.env.DEV) {
|
||||||
mainWindow.webContents.openDevTools();
|
mainWindow.webContents.openDevTools();
|
||||||
@@ -438,9 +444,9 @@ app.whenReady().then(async () => {
|
|||||||
// Set the path of electron.exe and your app.
|
// Set the path of electron.exe and your app.
|
||||||
// These two additional parameters are only available on windows.
|
// These two additional parameters are only available on windows.
|
||||||
isDefaultProtocolClient = app.setAsDefaultProtocolClient(
|
isDefaultProtocolClient = app.setAsDefaultProtocolClient(
|
||||||
protocol,
|
protocol,
|
||||||
process.execPath,
|
process.execPath,
|
||||||
[path.resolve(process.argv[1])],
|
[path.resolve(process.argv[1])],
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
isDefaultProtocolClient = app.setAsDefaultProtocolClient(protocol);
|
isDefaultProtocolClient = app.setAsDefaultProtocolClient(protocol);
|
||||||
@@ -453,16 +459,18 @@ app.whenReady().then(async () => {
|
|||||||
|
|
||||||
// Add this event handler for second instance
|
// Add this event handler for second instance
|
||||||
app.on("second-instance", (_event: Electron.Event, argv: string[]) => {
|
app.on("second-instance", (_event: Electron.Event, argv: string[]) => {
|
||||||
// Someone tried to run a second instance, we should focus our window
|
|
||||||
openMainWindow();
|
|
||||||
const url = argv.find((arg) => arg.startsWith(`${protocol}://`));
|
const url = argv.find((arg) => arg.startsWith(`${protocol}://`));
|
||||||
if (url) {
|
if (url) {
|
||||||
if (url.startsWith(`${protocol}://keep-alive`)) {
|
if (url.startsWith(`${protocol}://keep-alive`)) {
|
||||||
log.info("Keep-alive protocol received, app is already running.");
|
log.info("Keep-alive protocol received, app is already running.");
|
||||||
// Do nothing if already running
|
// Do nothing if already running
|
||||||
|
return; // Skip openMainWindow to avoid focusing the window
|
||||||
} else {
|
} else {
|
||||||
openInExplorer(url);
|
openInExplorer(url);
|
||||||
|
openMainWindow(); // Focus window for non-keep-alive URLs
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
openMainWindow(); // Focus window if no URL
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -535,8 +543,8 @@ app.whenReady().then(async () => {
|
|||||||
log.info(`Total downloaded ${progress.transferred}/${progress.total}`);
|
log.info(`Total downloaded ${progress.transferred}/${progress.total}`);
|
||||||
const mainWindow = BrowserWindow.getAllWindows()[0];
|
const mainWindow = BrowserWindow.getAllWindows()[0];
|
||||||
mainWindow?.webContents.send(
|
mainWindow?.webContents.send(
|
||||||
ipcTypes.toRenderer.updates.downloading,
|
ipcTypes.toRenderer.updates.downloading,
|
||||||
progress,
|
progress,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
autoUpdater.on("update-downloaded", (info) => {
|
autoUpdater.on("update-downloaded", (info) => {
|
||||||
@@ -564,10 +572,15 @@ app.on("open-url", (event: Electron.Event, url: string) => {
|
|||||||
//Don't do anything for now. We just want to open the app.
|
//Don't do anything for now. We just want to open the app.
|
||||||
if (url.startsWith(`${protocol}://keep-alive`)) {
|
if (url.startsWith(`${protocol}://keep-alive`)) {
|
||||||
log.info("Keep-alive protocol received.");
|
log.info("Keep-alive protocol received.");
|
||||||
isKeepAliveLaunch = true;
|
if (BrowserWindow.getAllWindows().length === 0) {
|
||||||
openMainWindow();
|
isKeepAliveLaunch = true;
|
||||||
|
openMainWindow(); // Launch app if not running
|
||||||
|
}
|
||||||
|
// Do nothing if already running
|
||||||
|
return; // Skip openMainWindow to avoid focusing the window
|
||||||
} else {
|
} else {
|
||||||
openInExplorer(url);
|
openInExplorer(url);
|
||||||
|
openMainWindow(); // Focus window for non-keep-alive URLs
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -625,4 +638,4 @@ function openInExplorer(url: string): void {
|
|||||||
shell.openPath(folderPath).catch((error) => {
|
shell.openPath(folderPath).catch((error) => {
|
||||||
log.error("Failed to open folder in explorer:", errorTypeCheck(error));
|
log.error("Failed to open folder in explorer:", errorTypeCheck(error));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -7,8 +7,8 @@ const execPromise = promisify(exec);
|
|||||||
export async function setupKeepAliveTask(): Promise<void> {
|
export async function setupKeepAliveTask(): Promise<void> {
|
||||||
const taskName = "ImEXShopPartnerKeepAlive";
|
const taskName = "ImEXShopPartnerKeepAlive";
|
||||||
const protocolUrl = "imexmedia://keep-alive";
|
const protocolUrl = "imexmedia://keep-alive";
|
||||||
// Use PowerShell with -ExecutionPolicy Bypass to open the URL
|
// Use rundll32.exe to silently open the URL as a protocol
|
||||||
const command = `powershell.exe -ExecutionPolicy Bypass -Command "Start-Process '${protocolUrl}'"`;
|
const command = `rundll32.exe url.dll,OpenURL "${protocolUrl}"`;
|
||||||
// Escape quotes for schtasks /tr parameter
|
// Escape quotes for schtasks /tr parameter
|
||||||
const escapedCommand = command.replace(/"/g, '\\"');
|
const escapedCommand = command.replace(/"/g, '\\"');
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user