diff --git a/src/main/index.ts b/src/main/index.ts index 389078b4c4..e04746e1e2 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -251,19 +251,31 @@ let blockQuit = true; autoUpdater.on("before-quit-for-update", () => blockQuit = false); app.on("will-quit", (event) => { - // Quit app on Cmd+Q (MacOS) + // This is called when the close button of the main window is clicked + + const lprm = LensProtocolRouterMain.getInstance(false); + logger.info("APP:QUIT"); appEventBus.emit({ name: "app", action: "close" }); ClusterManager.getInstance(false)?.stop(); // close cluster connections KubeconfigSyncManager.getInstance(false)?.stopSync(); - LensProtocolRouterMain.getInstance(false)?.cleanup(); cleanup(); + + if (lprm) { + // This is set to false here so that LPRM can wait to send future lens:// + // requests until after it loads again + lprm.rendererLoaded = false; + } if (blockQuit) { + // Quit app on Cmd+Q (MacOS) + event.preventDefault(); // prevent app's default shutdown (e.g. required for telemetry, etc.) return; // skip exit to make tray work, to quit go to app's global menu or tray's menu } + + LensProtocolRouterMain.getInstance(false)?.cleanup(); }); app.on("open-url", (event, rawUrl) => { diff --git a/src/main/protocol-handler/router.ts b/src/main/protocol-handler/router.ts index 25c7bbefba..6a8090617b 100644 --- a/src/main/protocol-handler/router.ts +++ b/src/main/protocol-handler/router.ts @@ -21,17 +21,35 @@ import logger from "../logger"; import * as proto from "../../common/protocol-handler"; -import Url from "url-parse"; +import URLParse from "url-parse"; import type { LensExtension } from "../../extensions/lens-extension"; import { broadcastMessage } from "../../common/ipc"; import { observable, when, makeObservable } from "mobx"; import { ProtocolHandlerInvalid, RouteAttempt } from "../../common/protocol-handler"; -import { disposer } from "../../common/utils"; +import { disposer, noop } from "../../common/utils"; +import { WindowManager } from "../window-manager"; export interface FallbackHandler { (name: string): Promise; } +/** + * This function checks if the host part is valid + * @param host the URI host part + * @returns `true` if it should be routed internally to Lens, `false` if to an extension + * @throws if `host` is not valid + */ +function checkHost(url: URLParse): boolean { + switch (url.host) { + case "app": + return true; + case "extension": + return false; + default: + throw new proto.RoutingError(proto.RoutingErrorType.INVALID_HOST, url); + } +} + export class LensProtocolRouterMain extends proto.LensProtocolRouter { private missingExtensionHandlers: FallbackHandler[] = []; @@ -58,25 +76,22 @@ export class LensProtocolRouterMain extends proto.LensProtocolRouter { */ public route(rawUrl: string) { try { - const url = new Url(rawUrl, true); + const url = new URLParse(rawUrl, true); if (url.protocol.toLowerCase() !== "lens:") { throw new proto.RoutingError(proto.RoutingErrorType.INVALID_PROTOCOL, url); } + const routeInternally = checkHost(url); + logger.info(`${proto.LensProtocolRouter.LoggingPrefix}: routing ${url.toString()}`); + WindowManager.getInstance(false)?.ensureMainWindow().catch(noop); - switch (url.host) { - case "app": - this._routeToInternal(url); - break; - case "extension": - this.disposers.push(when(() => this.extensionsLoaded, () => this._routeToExtension(url))); - break; - default: - throw new proto.RoutingError(proto.RoutingErrorType.INVALID_HOST, url); + if (routeInternally) { + this._routeToInternal(url); + } else { + this.disposers.push(when(() => this.extensionsLoaded, () => this._routeToExtension(url))); } - } catch (error) { broadcastMessage(ProtocolHandlerInvalid, error.toString(), rawUrl); @@ -98,7 +113,7 @@ export class LensProtocolRouterMain extends proto.LensProtocolRouter { return false; } - protected async _findMatchingExtensionByName(url: Url): Promise { + protected async _findMatchingExtensionByName(url: URLParse): Promise { const firstAttempt = await super._findMatchingExtensionByName(url); if (typeof firstAttempt !== "string") { @@ -112,7 +127,7 @@ export class LensProtocolRouterMain extends proto.LensProtocolRouter { return ""; } - protected _routeToInternal(url: Url): RouteAttempt { + protected _routeToInternal(url: URLParse): RouteAttempt { const rawUrl = url.toString(); // for sending to renderer const attempt = super._routeToInternal(url); @@ -121,7 +136,7 @@ export class LensProtocolRouterMain extends proto.LensProtocolRouter { return attempt; } - protected async _routeToExtension(url: Url): Promise { + protected async _routeToExtension(url: URLParse): Promise { const rawUrl = url.toString(); // for sending to renderer /** @@ -131,7 +146,7 @@ export class LensProtocolRouterMain extends proto.LensProtocolRouter { * Note: this needs to clone the url because _routeToExtension modifies its * argument. */ - const attempt = await super._routeToExtension(new Url(url.toString(), true)); + const attempt = await super._routeToExtension(new URLParse(url.toString(), true)); this.disposers.push(when(() => this.rendererLoaded, () => broadcastMessage(proto.ProtocolHandlerExtension, rawUrl, attempt)));