mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Remove global version of appEventBus (#6096)
* Remove global version of appEventBus Signed-off-by: Sebastian Malton <sebastian@malton.name> * Introduce a temporary but better shape of ExecFileInjectable error Signed-off-by: Sebastian Malton <sebastian@malton.name> Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
1 parent
ba349e8b8d
commit
900f02fd8c
53 files changed
+330
-283
No files matched your search
+6
@@ -12,6 +12,8 @@ import operatingSystemThemeInjectable from "../../../theme/operating-system-them
|
||||
import catalogEntityRegistryInjectable from "../../../catalog/entity-registry.injectable";
|
||||
import askUserForFilePathsInjectable from "../../../ipc/ask-user-for-file-paths.injectable";
|
||||
import applicationMenuItemCompositeInjectable from "../../../../features/application-menu/main/application-menu-item-composite.injectable";
|
||||
import emitAppEventInjectable from "../../../../common/app-event-bus/emit-event.injectable";
|
||||
import createResourceApplierInjectable from "../../../resource-applier/create-resource-applier.injectable";
|
||||
|
||||
const setupIpcMainHandlersInjectable = getInjectable({
|
||||
id: "setup-ipc-main-handlers",
|
||||
@@ -24,6 +26,8 @@ const setupIpcMainHandlersInjectable = getInjectable({
|
||||
const clusterStore = di.inject(clusterStoreInjectable);
|
||||
const operatingSystemTheme = di.inject(operatingSystemThemeInjectable);
|
||||
const askUserForFilePaths = di.inject(askUserForFilePathsInjectable);
|
||||
const emitAppEvent = di.inject(emitAppEventInjectable);
|
||||
const createResourceApplier = di.inject(createResourceApplierInjectable);
|
||||
|
||||
return {
|
||||
id: "setup-ipc-main-handlers",
|
||||
@@ -37,6 +41,8 @@ const setupIpcMainHandlersInjectable = getInjectable({
|
||||
clusterStore,
|
||||
operatingSystemTheme,
|
||||
askUserForFilePaths,
|
||||
emitAppEvent,
|
||||
createResourceApplier,
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
@@ -8,12 +8,10 @@ import { clusterFrameMap } from "../../../../common/cluster-frames";
|
||||
import { clusterActivateHandler, clusterSetFrameIdHandler, clusterVisibilityHandler, clusterRefreshHandler, clusterDisconnectHandler, clusterKubectlApplyAllHandler, clusterKubectlDeleteAllHandler } from "../../../../common/ipc/cluster";
|
||||
import type { ClusterId } from "../../../../common/cluster-types";
|
||||
import { ClusterStore } from "../../../../common/cluster-store/cluster-store";
|
||||
import { appEventBus } from "../../../../common/app-event-bus/event-bus";
|
||||
import { broadcastMainChannel, broadcastMessage, ipcMainHandle, ipcMainOn } from "../../../../common/ipc";
|
||||
import type { CatalogEntityRegistry } from "../../../catalog";
|
||||
import { pushCatalogToRenderer } from "../../../catalog-pusher";
|
||||
import type { ClusterManager } from "../../../cluster/manager";
|
||||
import { ResourceApplier } from "../../../resource-applier";
|
||||
import type { IComputedValue } from "mobx";
|
||||
import { windowActionHandleChannel, windowLocationChangedChannel, windowOpenAppMenuAsContextMenuChannel } from "../../../../common/ipc/window";
|
||||
import { handleWindowAction, onLocationChange } from "../../../ipc/window";
|
||||
@@ -25,6 +23,8 @@ import type { ApplicationMenuItemTypes } from "../../../../features/application-
|
||||
import type { Composite } from "../../../../common/utils/composite/get-composite/get-composite";
|
||||
import { getApplicationMenuTemplate } from "../../../../features/application-menu/main/populate-application-menu.injectable";
|
||||
import type { MenuItemRoot } from "../../../../features/application-menu/main/application-menu-item-composite.injectable";
|
||||
import type { EmitAppEvent } from "../../../../common/app-event-bus/emit-event.injectable";
|
||||
import type { CreateResourceApplier } from "../../../resource-applier/create-resource-applier.injectable";
|
||||
|
||||
interface Dependencies {
|
||||
applicationMenuItemComposite: IComputedValue<Composite<ApplicationMenuItemTypes | MenuItemRoot>>;
|
||||
@@ -33,6 +33,8 @@ interface Dependencies {
|
||||
clusterStore: ClusterStore;
|
||||
operatingSystemTheme: IComputedValue<Theme>;
|
||||
askUserForFilePaths: AskUserForFilePaths;
|
||||
emitAppEvent: EmitAppEvent;
|
||||
createResourceApplier: CreateResourceApplier;
|
||||
}
|
||||
|
||||
export const setupIpcMainHandlers = ({
|
||||
@@ -42,6 +44,8 @@ export const setupIpcMainHandlers = ({
|
||||
clusterStore,
|
||||
operatingSystemTheme,
|
||||
askUserForFilePaths,
|
||||
emitAppEvent,
|
||||
createResourceApplier,
|
||||
}: Dependencies) => {
|
||||
ipcMainHandle(clusterActivateHandler, (event, clusterId: ClusterId, force = false) => {
|
||||
return ClusterStore.getInstance()
|
||||
@@ -71,7 +75,7 @@ export const setupIpcMainHandlers = ({
|
||||
});
|
||||
|
||||
ipcMainHandle(clusterDisconnectHandler, (event, clusterId: ClusterId) => {
|
||||
appEventBus.emit({ name: "cluster", action: "stop" });
|
||||
emitAppEvent({ name: "cluster", action: "stop" });
|
||||
const cluster = ClusterStore.getInstance().getById(clusterId);
|
||||
|
||||
if (cluster) {
|
||||
@@ -81,11 +85,11 @@ export const setupIpcMainHandlers = ({
|
||||
});
|
||||
|
||||
ipcMainHandle(clusterKubectlApplyAllHandler, async (event, clusterId: ClusterId, resources: string[], extraArgs: string[]) => {
|
||||
appEventBus.emit({ name: "cluster", action: "kubectl-apply-all" });
|
||||
emitAppEvent({ name: "cluster", action: "kubectl-apply-all" });
|
||||
const cluster = ClusterStore.getInstance().getById(clusterId);
|
||||
|
||||
if (cluster) {
|
||||
const applier = new ResourceApplier(cluster);
|
||||
const applier = createResourceApplier(cluster);
|
||||
|
||||
try {
|
||||
const stdout = await applier.kubectlApplyAll(resources, extraArgs);
|
||||
@@ -100,11 +104,11 @@ export const setupIpcMainHandlers = ({
|
||||
});
|
||||
|
||||
ipcMainHandle(clusterKubectlDeleteAllHandler, async (event, clusterId: ClusterId, resources: string[], extraArgs: string[]) => {
|
||||
appEventBus.emit({ name: "cluster", action: "kubectl-delete-all" });
|
||||
emitAppEvent({ name: "cluster", action: "kubectl-delete-all" });
|
||||
const cluster = ClusterStore.getInstance().getById(clusterId);
|
||||
|
||||
if (cluster) {
|
||||
const applier = new ResourceApplier(cluster);
|
||||
const applier = createResourceApplier(cluster);
|
||||
|
||||
try {
|
||||
const stdout = await applier.kubectlDeleteAll(resources, extraArgs);
|
||||
|
||||
@@ -19,9 +19,6 @@ import type { FileSystemProvisionerStore } from "../extensions/extension-loader/
|
||||
import userStoreInjectable from "../common/user-store/user-store.injectable";
|
||||
import type { UserStore } from "../common/user-store";
|
||||
import hotbarStoreInjectable from "../common/hotbars/store.injectable";
|
||||
import appEventBusInjectable from "../common/app-event-bus/app-event-bus.injectable";
|
||||
import { EventEmitter } from "../common/event-emitter";
|
||||
import type { AppEvent } from "../common/app-event-bus/event-bus";
|
||||
import commandLineArgumentsInjectable from "./utils/command-line-arguments.injectable";
|
||||
import initializeExtensionsInjectable from "./start-main-application/runnables/initialize-extensions.injectable";
|
||||
import lensResourcesDirInjectable from "../common/vars/lens-resources-dir.injectable";
|
||||
@@ -167,9 +164,6 @@ export function getDiForUnitTesting(opts: { doGeneralOverrides?: boolean } = {})
|
||||
execFileInjectable,
|
||||
]);
|
||||
|
||||
// TODO: Remove usages of globally exported appEventBus to get rid of this
|
||||
di.override(appEventBusInjectable, () => new EventEmitter<[AppEvent]>());
|
||||
|
||||
di.override(broadcastMessageInjectable, () => (channel) => {
|
||||
throw new Error(`Tried to broadcast message to channel "${channel}" over IPC without explicit override.`);
|
||||
});
|
||||
|
||||
@@ -3,11 +3,12 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { ExecFileException } from "child_process";
|
||||
import execFileInjectable from "../../../common/fs/exec-file.injectable";
|
||||
import helmBinaryPathInjectable from "../helm-binary-path.injectable";
|
||||
import type { AsyncResult } from "../../../common/utils/async-result";
|
||||
import helmBinaryPathInjectable from "../helm-binary-path.injectable";
|
||||
|
||||
export type ExecHelm = (args: string[]) => Promise<AsyncResult<string, string>>;
|
||||
export type ExecHelm = (args: string[]) => Promise<AsyncResult<string, ExecFileException & { stderr: string }>>;
|
||||
|
||||
const execHelmInjectable = getInjectable({
|
||||
id: "exec-helm",
|
||||
@@ -16,20 +17,9 @@ const execHelmInjectable = getInjectable({
|
||||
const execFile = di.inject(execFileInjectable);
|
||||
const helmBinaryPath = di.inject(helmBinaryPathInjectable);
|
||||
|
||||
return async (args) => {
|
||||
const response = await execFile(helmBinaryPath, args, {
|
||||
maxBuffer: 32 * 1024 * 1024 * 1024, // 32 MiB
|
||||
});
|
||||
|
||||
if (response.callWasSuccessful) {
|
||||
return response;
|
||||
}
|
||||
|
||||
return {
|
||||
callWasSuccessful: false,
|
||||
error: response.error.stderr || response.error.error.message,
|
||||
};
|
||||
};
|
||||
return async (args) => execFile(helmBinaryPath, args, {
|
||||
maxBuffer: 32 * 1024 * 1024 * 1024, // 32 MiB
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ const getHelmEnvInjectable = getInjectable({
|
||||
const result = await execHelm(["env"]);
|
||||
|
||||
if (!result.callWasSuccessful) {
|
||||
return { callWasSuccessful: false, error: result.error };
|
||||
return { callWasSuccessful: false, error: result.error.stderr };
|
||||
}
|
||||
|
||||
const lines = result.response.split(/\r?\n/); // split by new line feed
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ const callForHelmManifestInjectable = getInjectable({
|
||||
]);
|
||||
|
||||
if (!result.callWasSuccessful) {
|
||||
return { callWasSuccessful: false, error: result.error };
|
||||
return { callWasSuccessful: false, error: result.error.message };
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -4,17 +4,18 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import execHelmInjectable from "../../exec-helm/exec-helm.injectable";
|
||||
import type { HelmRepo } from "../../../../common/helm/helm-repo";
|
||||
import loggerInjectable from "../../../../common/logger.injectable";
|
||||
import type { AddHelmRepositoryChannel } from "../../../../common/helm/add-helm-repository-channel";
|
||||
import type { RequestChannelHandler } from "../../../utils/channel/channel-listeners/listener-tokens";
|
||||
|
||||
const addHelmRepositoryInjectable = getInjectable({
|
||||
id: "add-helm-repository",
|
||||
|
||||
instantiate: (di) => {
|
||||
instantiate: (di): RequestChannelHandler<AddHelmRepositoryChannel> => {
|
||||
const execHelm = di.inject(execHelmInjectable);
|
||||
const logger = di.inject(loggerInjectable);
|
||||
|
||||
return async (repo: HelmRepo) => {
|
||||
return async (repo) => {
|
||||
const {
|
||||
name,
|
||||
url,
|
||||
@@ -54,7 +55,18 @@ const addHelmRepositoryInjectable = getInjectable({
|
||||
args.push("--cert-file", certFile);
|
||||
}
|
||||
|
||||
return await execHelm(args);
|
||||
const result = await execHelm(args);
|
||||
|
||||
if (result.callWasSuccessful) {
|
||||
return {
|
||||
callWasSuccessful: true,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
callWasSuccessful: false,
|
||||
error: result.error.stderr || result.error.message,
|
||||
};
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
+3
-3
@@ -78,10 +78,10 @@ const getActiveHelmRepositoriesInjectable = getInjectable({
|
||||
const updateResult = await execHelm(["repo", "update"]);
|
||||
|
||||
if (!updateResult.callWasSuccessful) {
|
||||
if (!updateResult.error.includes(internalHelmErrorForNoRepositoriesFound)) {
|
||||
if (!updateResult.error.stderr.includes(internalHelmErrorForNoRepositoriesFound)) {
|
||||
return {
|
||||
callWasSuccessful: false,
|
||||
error: `Error updating Helm repositories: ${updateResult.error}`,
|
||||
error: `Error updating Helm repositories: ${updateResult.error.stderr}`,
|
||||
};
|
||||
}
|
||||
const resultOfAddingDefaultRepository = await execHelm(["repo", "add", "bitnami", "https://charts.bitnami.com/bitnami"]);
|
||||
@@ -89,7 +89,7 @@ const getActiveHelmRepositoriesInjectable = getInjectable({
|
||||
if (!resultOfAddingDefaultRepository.callWasSuccessful) {
|
||||
return {
|
||||
callWasSuccessful: false,
|
||||
error: `Error when adding default Helm repository: ${resultOfAddingDefaultRepository.error}`,
|
||||
error: `Error when adding default Helm repository: ${resultOfAddingDefaultRepository.error.stderr}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+14
-2
@@ -6,6 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
||||
import execHelmInjectable from "../../exec-helm/exec-helm.injectable";
|
||||
import type { HelmRepo } from "../../../../common/helm/helm-repo";
|
||||
import loggerInjectable from "../../../../common/logger.injectable";
|
||||
import type { AsyncResult } from "../../../../common/utils/async-result";
|
||||
|
||||
const removeHelmRepositoryInjectable = getInjectable({
|
||||
id: "remove-helm-repository",
|
||||
@@ -14,14 +15,25 @@ const removeHelmRepositoryInjectable = getInjectable({
|
||||
const execHelm = di.inject(execHelmInjectable);
|
||||
const logger = di.inject(loggerInjectable);
|
||||
|
||||
return async (repo: HelmRepo) => {
|
||||
return async (repo: HelmRepo): Promise<AsyncResult<void, string>> => {
|
||||
logger.info(`[HELM]: removing repo ${repo.name} (${repo.url})`);
|
||||
|
||||
return execHelm([
|
||||
const result = await execHelm([
|
||||
"repo",
|
||||
"remove",
|
||||
repo.name,
|
||||
]);
|
||||
|
||||
if (result.callWasSuccessful) {
|
||||
return {
|
||||
callWasSuccessful: true,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
callWasSuccessful: false,
|
||||
error: result.error.stderr,
|
||||
};
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
@@ -11,6 +11,8 @@ import clusterManagerInjectable from "../cluster/manager.injectable";
|
||||
import shellApiRequestInjectable from "./proxy-functions/shell-api-request/shell-api-request.injectable";
|
||||
import lensProxyPortInjectable from "./lens-proxy-port.injectable";
|
||||
import contentSecurityPolicyInjectable from "../../common/vars/content-security-policy.injectable";
|
||||
import emitAppEventInjectable from "../../common/app-event-bus/emit-event.injectable";
|
||||
import loggerInjectable from "../../common/logger.injectable";
|
||||
|
||||
const lensProxyInjectable = getInjectable({
|
||||
id: "lens-proxy",
|
||||
@@ -23,6 +25,8 @@ const lensProxyInjectable = getInjectable({
|
||||
getClusterForRequest: di.inject(clusterManagerInjectable).getClusterForRequest,
|
||||
lensProxyPort: di.inject(lensProxyPortInjectable),
|
||||
contentSecurityPolicy: di.inject(contentSecurityPolicyInjectable),
|
||||
emitAppEvent: di.inject(emitAppEventInjectable),
|
||||
logger: di.inject(loggerInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
@@ -10,13 +10,13 @@ import type httpProxy from "http-proxy";
|
||||
import { apiPrefix, apiKubePrefix } from "../../common/vars";
|
||||
import type { Router } from "../router/router";
|
||||
import type { ClusterContextHandler } from "../context-handler/context-handler";
|
||||
import logger from "../logger";
|
||||
import type { Cluster } from "../../common/cluster/cluster";
|
||||
import type { ProxyApiRequestArgs } from "./proxy-functions";
|
||||
import { appEventBus } from "../../common/app-event-bus/event-bus";
|
||||
import { getBoolean } from "../utils/parse-query";
|
||||
import assert from "assert";
|
||||
import type { SetRequired } from "type-fest";
|
||||
import type { EmitAppEvent } from "../../common/app-event-bus/emit-event.injectable";
|
||||
import type { Logger } from "../../common/logger";
|
||||
|
||||
type GetClusterForRequest = (req: http.IncomingMessage) => Cluster | undefined;
|
||||
|
||||
@@ -26,10 +26,12 @@ interface Dependencies {
|
||||
getClusterForRequest: GetClusterForRequest;
|
||||
shellApiRequest: (args: ProxyApiRequestArgs) => void | Promise<void>;
|
||||
kubeApiUpgradeRequest: (args: ProxyApiRequestArgs) => void | Promise<void>;
|
||||
emitAppEvent: EmitAppEvent;
|
||||
readonly router: Router;
|
||||
readonly proxy: httpProxy;
|
||||
readonly lensProxyPort: { set: (portNumber: number) => void };
|
||||
readonly contentSecurityPolicy: string;
|
||||
readonly logger: Logger;
|
||||
}
|
||||
|
||||
const watchParam = "watch";
|
||||
@@ -81,14 +83,14 @@ export class LensProxy {
|
||||
const cluster = dependencies.getClusterForRequest(req);
|
||||
|
||||
if (!cluster) {
|
||||
logger.error(`[LENS-PROXY]: Could not find cluster for upgrade request from url=${req.url}`);
|
||||
this.dependencies.logger.error(`[LENS-PROXY]: Could not find cluster for upgrade request from url=${req.url}`);
|
||||
socket.destroy();
|
||||
} else {
|
||||
const isInternal = req.url.startsWith(`${apiPrefix}?`);
|
||||
const reqHandler = isInternal ? dependencies.shellApiRequest : dependencies.kubeApiUpgradeRequest;
|
||||
|
||||
(async () => reqHandler({ req, socket, head, cluster }))()
|
||||
.catch(error => logger.error("[LENS-PROXY]: failed to handle proxy upgrade", error));
|
||||
.catch(error => this.dependencies.logger.error("[LENS-PROXY]: failed to handle proxy upgrade", error));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -111,17 +113,17 @@ export class LensProxy {
|
||||
|
||||
this.dependencies.lensProxyPort.set(port);
|
||||
|
||||
logger.info(`[LENS-PROXY]: Proxy server has started at ${address}:${port}`);
|
||||
this.dependencies.logger.info(`[LENS-PROXY]: Proxy server has started at ${address}:${port}`);
|
||||
|
||||
this.proxyServer.on("error", (error) => {
|
||||
logger.info(`[LENS-PROXY]: Subsequent error: ${error}`);
|
||||
this.dependencies.logger.info(`[LENS-PROXY]: Subsequent error: ${error}`);
|
||||
});
|
||||
|
||||
appEventBus.emit({ name: "lens-proxy", action: "listen", params: { port }});
|
||||
this.dependencies.emitAppEvent({ name: "lens-proxy", action: "listen", params: { port }});
|
||||
resolve(port);
|
||||
})
|
||||
.once("error", (error) => {
|
||||
logger.info(`[LENS-PROXY]: Proxy server failed to start: ${error}`);
|
||||
this.dependencies.logger.info(`[LENS-PROXY]: Proxy server failed to start: ${error}`);
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
@@ -144,7 +146,7 @@ export class LensProxy {
|
||||
return;
|
||||
}
|
||||
|
||||
logger.warn(`[LENS-PROXY]: Proxy server has with port known to be considered unsafe to connect to by chrome, restarting...`);
|
||||
this.dependencies.logger.warn(`[LENS-PROXY]: Proxy server has with port known to be considered unsafe to connect to by chrome, restarting...`);
|
||||
|
||||
if (seenPorts.has(port)) {
|
||||
/**
|
||||
@@ -160,7 +162,7 @@ export class LensProxy {
|
||||
}
|
||||
|
||||
close() {
|
||||
logger.info("[LENS-PROXY]: Closing server");
|
||||
this.dependencies.logger.info("[LENS-PROXY]: Closing server");
|
||||
this.proxyServer.close();
|
||||
this.closed = true;
|
||||
}
|
||||
@@ -183,10 +185,10 @@ export class LensProxy {
|
||||
return;
|
||||
}
|
||||
|
||||
logger.error(`[LENS-PROXY]: http proxy errored for cluster: ${error}`, { url: req.url });
|
||||
this.dependencies.logger.error(`[LENS-PROXY]: http proxy errored for cluster: ${error}`, { url: req.url });
|
||||
|
||||
if (target) {
|
||||
logger.debug(`Failed proxy to target: ${JSON.stringify(target, null, 2)}`);
|
||||
this.dependencies.logger.debug(`Failed proxy to target: ${JSON.stringify(target, null, 2)}`);
|
||||
|
||||
if (req.method === "GET" && (!res.statusCode || res.statusCode >= 500)) {
|
||||
const reqId = this.getRequestId(req);
|
||||
@@ -194,11 +196,11 @@ export class LensProxy {
|
||||
const timeoutMs = retryCount * 250;
|
||||
|
||||
if (retryCount < 20) {
|
||||
logger.debug(`Retrying proxy request to url: ${reqId}`);
|
||||
this.dependencies.logger.debug(`Retrying proxy request to url: ${reqId}`);
|
||||
setTimeout(() => {
|
||||
this.retryCounters.set(reqId, retryCount + 1);
|
||||
this.handleRequest(req as ServerIncomingMessage, res)
|
||||
.catch(error => logger.error(`[LENS-PROXY]: failed to handle request on proxy error: ${error}`));
|
||||
.catch(error => this.dependencies.logger.error(`[LENS-PROXY]: failed to handle request on proxy error: ${error}`));
|
||||
}, timeoutMs);
|
||||
}
|
||||
}
|
||||
@@ -207,7 +209,7 @@ export class LensProxy {
|
||||
try {
|
||||
res.writeHead(500).end(`Oops, something went wrong.\n${error}`);
|
||||
} catch (e) {
|
||||
logger.error(`[LENS-PROXY]: Failed to write headers: `, e);
|
||||
this.dependencies.logger.error(`[LENS-PROXY]: Failed to write headers: `, e);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import emitAppEventInjectable from "../../common/app-event-bus/emit-event.injectable";
|
||||
import type { Cluster } from "../../common/cluster/cluster";
|
||||
import deleteFileInjectable from "../../common/fs/delete-file.injectable";
|
||||
import execFileInjectable from "../../common/fs/exec-file.injectable";
|
||||
import writeFileInjectable from "../../common/fs/write-file.injectable";
|
||||
import loggerInjectable from "../../common/logger.injectable";
|
||||
import joinPathsInjectable from "../../common/path/join-paths.injectable";
|
||||
import type { ResourceApplierDependencies } from "./resource-applier";
|
||||
import { ResourceApplier } from "./resource-applier";
|
||||
|
||||
export type CreateResourceApplier = (cluster: Cluster) => ResourceApplier;
|
||||
|
||||
const createResourceApplierInjectable = getInjectable({
|
||||
id: "create-resource-applier",
|
||||
instantiate: (di): CreateResourceApplier => {
|
||||
const deps: ResourceApplierDependencies = {
|
||||
deleteFile: di.inject(deleteFileInjectable),
|
||||
emitAppEvent: di.inject(emitAppEventInjectable),
|
||||
execFile: di.inject(execFileInjectable),
|
||||
joinPaths: di.inject(joinPathsInjectable),
|
||||
logger: di.inject(loggerInjectable),
|
||||
writeFile: di.inject(writeFileInjectable),
|
||||
};
|
||||
|
||||
return (cluster) => new ResourceApplier(deps, cluster);
|
||||
},
|
||||
});
|
||||
|
||||
export default createResourceApplierInjectable;
|
||||
@@ -3,21 +3,29 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { Cluster } from "../common/cluster/cluster";
|
||||
import { exec } from "child_process";
|
||||
import fs from "fs-extra";
|
||||
import type { Cluster } from "../../common/cluster/cluster";
|
||||
import * as yaml from "js-yaml";
|
||||
import path from "path";
|
||||
import tempy from "tempy";
|
||||
import logger from "./logger";
|
||||
import { appEventBus } from "../common/app-event-bus/event-bus";
|
||||
import { isChildProcessError } from "../common/utils";
|
||||
import type { Patch } from "rfc6902";
|
||||
import { promiseExecFile } from "../common/utils/promise-exec";
|
||||
import type { KubernetesObject } from "@kubernetes/client-node";
|
||||
import type { EmitAppEvent } from "../../common/app-event-bus/emit-event.injectable";
|
||||
import type { Logger } from "../../common/logger";
|
||||
import type { WriteFile } from "../../common/fs/write-file.injectable";
|
||||
import type { DeleteFile } from "../../common/fs/delete-file.injectable";
|
||||
import type { ExecFile } from "../../common/fs/exec-file.injectable";
|
||||
import type { JoinPaths } from "../../common/path/join-paths.injectable";
|
||||
|
||||
export interface ResourceApplierDependencies {
|
||||
emitAppEvent: EmitAppEvent;
|
||||
writeFile: WriteFile;
|
||||
deleteFile: DeleteFile;
|
||||
execFile: ExecFile;
|
||||
joinPaths: JoinPaths;
|
||||
readonly logger: Logger;
|
||||
}
|
||||
|
||||
export class ResourceApplier {
|
||||
constructor(protected cluster: Cluster) {}
|
||||
constructor(protected readonly dependencies: ResourceApplierDependencies, protected readonly cluster: Cluster) {}
|
||||
|
||||
/**
|
||||
* Patch a kube resource's manifest, throwing any error that occurs.
|
||||
@@ -27,7 +35,7 @@ export class ResourceApplier {
|
||||
* @param ns The optional namespace of the kube resource
|
||||
*/
|
||||
async patch(name: string, kind: string, patch: Patch, ns?: string): Promise<string> {
|
||||
appEventBus.emit({ name: "resource", action: "patch" });
|
||||
this.dependencies.emitAppEvent({ name: "resource", action: "patch" });
|
||||
|
||||
const kubectl = await this.cluster.ensureKubectl();
|
||||
const kubectlPath = await kubectl.getPath();
|
||||
@@ -49,23 +57,17 @@ export class ResourceApplier {
|
||||
"-o", "json",
|
||||
);
|
||||
|
||||
try {
|
||||
const { stdout } = await promiseExecFile(kubectlPath, args);
|
||||
const result = await this.dependencies.execFile(kubectlPath, args);
|
||||
|
||||
return stdout;
|
||||
} catch (error) {
|
||||
if (isChildProcessError(error)) {
|
||||
throw error.stderr ?? error;
|
||||
}
|
||||
|
||||
throw error;
|
||||
if (result.callWasSuccessful) {
|
||||
return result.response;
|
||||
}
|
||||
|
||||
throw result.error.stderr || result.error.message;
|
||||
}
|
||||
|
||||
async create(resource: string): Promise<string> {
|
||||
appEventBus.emit({ name: "resource", action: "apply" });
|
||||
|
||||
console.log({ resource });
|
||||
this.dependencies.emitAppEvent({ name: "resource", action: "apply" });
|
||||
|
||||
return this.kubectlApply(this.sanitizeObject(resource));
|
||||
}
|
||||
@@ -82,7 +84,7 @@ export class ResourceApplier {
|
||||
"-f", fileName,
|
||||
];
|
||||
|
||||
logger.debug(`shooting manifests with ${kubectlPath}`, { args });
|
||||
this.dependencies.logger.debug(`shooting manifests with ${kubectlPath}`, { args });
|
||||
|
||||
const execEnv = { ...process.env };
|
||||
const httpsProxy = this.cluster.preferences?.httpsProxy;
|
||||
@@ -92,18 +94,17 @@ export class ResourceApplier {
|
||||
}
|
||||
|
||||
try {
|
||||
await fs.writeFile(fileName, content);
|
||||
const { stdout } = await promiseExecFile(kubectlPath, args);
|
||||
await this.dependencies.writeFile(fileName, content);
|
||||
|
||||
return stdout;
|
||||
} catch (error) {
|
||||
if (isChildProcessError(error)) {
|
||||
throw error.stderr ?? error;
|
||||
const result = await this.dependencies.execFile(kubectlPath, args);
|
||||
|
||||
if (result.callWasSuccessful) {
|
||||
return result.response;
|
||||
}
|
||||
|
||||
throw error;
|
||||
throw result.error.stderr || result.error.message;
|
||||
} finally {
|
||||
await fs.unlink(fileName);
|
||||
await this.dependencies.deleteFile(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,39 +116,36 @@ export class ResourceApplier {
|
||||
return this.kubectlCmdAll("delete", resources, extraArgs);
|
||||
}
|
||||
|
||||
protected async kubectlCmdAll(subCmd: string, resources: string[], args: string[] = []): Promise<string> {
|
||||
protected async kubectlCmdAll(subCmd: string, resources: string[], parentArgs: string[] = []): Promise<string> {
|
||||
const kubectl = await this.cluster.ensureKubectl();
|
||||
const kubectlPath = await kubectl.getPath();
|
||||
const proxyKubeconfigPath = await this.cluster.getProxyKubeconfigPath();
|
||||
const tmpDir = tempy.directory();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const tmpDir = tempy.directory();
|
||||
await Promise.all(resources.map((resource, index) => this.dependencies.writeFile(
|
||||
this.dependencies.joinPaths(tmpDir, `${index}.yaml`),
|
||||
resource,
|
||||
)));
|
||||
|
||||
// Dump each resource into tmpDir
|
||||
resources.forEach((resource, index) => {
|
||||
fs.writeFileSync(path.join(tmpDir, `${index}.yaml`), resource);
|
||||
});
|
||||
args.push("-f", `"${tmpDir}"`);
|
||||
const cmd = `"${kubectlPath}" ${subCmd} --kubeconfig "${proxyKubeconfigPath}" ${args.join(" ")}`;
|
||||
const args = [
|
||||
subCmd,
|
||||
"--kubeconfig", `"${proxyKubeconfigPath}"`,
|
||||
...parentArgs,
|
||||
"-f", `"${tmpDir}"`,
|
||||
];
|
||||
|
||||
logger.info(`[RESOURCE-APPLIER] running cmd ${cmd}`);
|
||||
exec(cmd, (error, stdout) => {
|
||||
if (error) {
|
||||
logger.error(`[RESOURCE-APPLIER] cmd errored: ${error}`);
|
||||
const splitError = error.toString().split(`.yaml": `);
|
||||
this.dependencies.logger.info(`[RESOURCE-APPLIER] running kubectl`, { args });
|
||||
const result = await this.dependencies.execFile(kubectlPath, args);
|
||||
|
||||
if (splitError[1]) {
|
||||
reject(splitError[1]);
|
||||
} else {
|
||||
reject(error);
|
||||
}
|
||||
if (result.callWasSuccessful) {
|
||||
return result.response;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
this.dependencies.logger.error(`[RESOURCE-APPLIER] kubectl errored: ${result.error.message}`);
|
||||
|
||||
resolve(stdout);
|
||||
});
|
||||
});
|
||||
const splitError = result.error.stderr.split(`.yaml": `);
|
||||
|
||||
throw splitError[1] || result.error.message;
|
||||
}
|
||||
|
||||
protected sanitizeObject(resource: string) {
|
||||
@@ -20,6 +20,7 @@ import type { SetRequired } from "type-fest";
|
||||
import normalizedPlatformInjectable from "../../common/vars/normalized-platform.injectable";
|
||||
import kubectlBinaryNameInjectable from "../kubectl/binary-name.injectable";
|
||||
import kubectlDownloadingNormalizedArchInjectable from "../kubectl/normalized-arch.injectable";
|
||||
import fsInjectable from "../../common/fs/fs.injectable";
|
||||
import { runInAction } from "mobx";
|
||||
|
||||
describe("router", () => {
|
||||
@@ -32,6 +33,7 @@ describe("router", () => {
|
||||
const di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
|
||||
mockFs();
|
||||
di.permitSideEffects(fsInjectable);
|
||||
|
||||
di.override(parseRequestInjectable, () => () => Promise.resolve({
|
||||
payload: "some-payload",
|
||||
|
||||
@@ -4,20 +4,24 @@
|
||||
*/
|
||||
import { getRouteInjectable } from "../../router/router.injectable";
|
||||
import { apiPrefix } from "../../../common/vars";
|
||||
import { ResourceApplier } from "../../resource-applier";
|
||||
import { payloadValidatedClusterRoute } from "../../router/route";
|
||||
import Joi from "joi";
|
||||
import createResourceApplierInjectable from "../../resource-applier/create-resource-applier.injectable";
|
||||
|
||||
const createResourceRouteInjectable = getRouteInjectable({
|
||||
id: "create-resource-route",
|
||||
|
||||
instantiate: () => payloadValidatedClusterRoute({
|
||||
method: "post",
|
||||
path: `${apiPrefix}/stack`,
|
||||
payloadValidator: Joi.string(),
|
||||
})(async ({ cluster, payload }) => ({
|
||||
response: await new ResourceApplier(cluster).create(payload),
|
||||
})),
|
||||
instantiate: (di) => {
|
||||
const createResourceApplier = di.inject(createResourceApplierInjectable);
|
||||
|
||||
return payloadValidatedClusterRoute({
|
||||
method: "post",
|
||||
path: `${apiPrefix}/stack`,
|
||||
payloadValidator: Joi.string(),
|
||||
})(async ({ cluster, payload }) => ({
|
||||
response: await createResourceApplier(cluster).create(payload),
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
||||
export default createResourceRouteInjectable;
|
||||
@@ -4,10 +4,10 @@
|
||||
*/
|
||||
import { getRouteInjectable } from "../../router/router.injectable";
|
||||
import { apiPrefix } from "../../../common/vars";
|
||||
import { ResourceApplier } from "../../resource-applier";
|
||||
import { payloadValidatedClusterRoute } from "../../router/route";
|
||||
import Joi from "joi";
|
||||
import type { Patch } from "rfc6902";
|
||||
import createResourceApplierInjectable from "../../resource-applier/create-resource-applier.injectable";
|
||||
|
||||
interface PatchResourcePayload {
|
||||
name: string;
|
||||
@@ -40,18 +40,22 @@ const patchResourcePayloadValidator = Joi.object<PatchResourcePayload, true, Pat
|
||||
const patchResourceRouteInjectable = getRouteInjectable({
|
||||
id: "patch-resource-route",
|
||||
|
||||
instantiate: () => payloadValidatedClusterRoute({
|
||||
method: "patch",
|
||||
path: `${apiPrefix}/stack`,
|
||||
payloadValidator: patchResourcePayloadValidator,
|
||||
})(async ({ cluster, payload }) => ({
|
||||
response: await new ResourceApplier(cluster).patch(
|
||||
payload.name,
|
||||
payload.kind,
|
||||
payload.patch,
|
||||
payload.ns,
|
||||
),
|
||||
})),
|
||||
instantiate: (di) => {
|
||||
const createResourceApplier = di.inject(createResourceApplierInjectable);
|
||||
|
||||
return payloadValidatedClusterRoute({
|
||||
method: "patch",
|
||||
path: `${apiPrefix}/stack`,
|
||||
payloadValidator: patchResourcePayloadValidator,
|
||||
})(async ({ cluster, payload }) => ({
|
||||
response: await createResourceApplier(cluster).patch(
|
||||
payload.name,
|
||||
payload.kind,
|
||||
payload.patch,
|
||||
payload.ns,
|
||||
),
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
||||
export default patchResourceRouteInjectable;
|
||||
@@ -22,6 +22,8 @@ import spawnPtyInjectable from "../spawn-pty.injectable";
|
||||
import resolvedShellInjectable from "../../../common/user-store/resolved-shell.injectable";
|
||||
import appNameInjectable from "../../../common/vars/app-name.injectable";
|
||||
import buildVersionInjectable from "../../vars/build-version/build-version.injectable";
|
||||
import emitAppEventInjectable from "../../../common/app-event-bus/emit-event.injectable";
|
||||
import statInjectable from "../../../common/fs/stat/stat.injectable";
|
||||
|
||||
export interface OpenLocalShellSessionArgs {
|
||||
websocket: WebSocket;
|
||||
@@ -46,11 +48,13 @@ const openLocalShellSessionInjectable = getInjectable({
|
||||
appName: di.inject(appNameInjectable),
|
||||
buildVersion: di.inject(buildVersionInjectable),
|
||||
modifyTerminalShellEnv: di.inject(modifyTerminalShellEnvInjectable),
|
||||
emitAppEvent: di.inject(emitAppEventInjectable),
|
||||
getDirnameOfPath: di.inject(getDirnameOfPathInjectable),
|
||||
joinPaths: di.inject(joinPathsInjectable),
|
||||
getBasenameOfPath: di.inject(getBasenameOfPathInjectable),
|
||||
computeShellEnvironment: di.inject(computeShellEnvironmentInjectable),
|
||||
spawnPty: di.inject(spawnPtyInjectable),
|
||||
stat: di.inject(statInjectable),
|
||||
};
|
||||
|
||||
return (args) => {
|
||||
|
||||
@@ -17,6 +17,8 @@ import spawnPtyInjectable from "../spawn-pty.injectable";
|
||||
import resolvedShellInjectable from "../../../common/user-store/resolved-shell.injectable";
|
||||
import appNameInjectable from "../../../common/vars/app-name.injectable";
|
||||
import buildVersionInjectable from "../../vars/build-version/build-version.injectable";
|
||||
import emitAppEventInjectable from "../../../common/app-event-bus/emit-event.injectable";
|
||||
import statInjectable from "../../../common/fs/stat/stat.injectable";
|
||||
|
||||
export interface NodeShellSessionArgs {
|
||||
websocket: WebSocket;
|
||||
@@ -39,6 +41,8 @@ const openNodeShellSessionInjectable = getInjectable({
|
||||
createKubeJsonApiForCluster: di.inject(createKubeJsonApiForClusterInjectable),
|
||||
computeShellEnvironment: di.inject(computeShellEnvironmentInjectable),
|
||||
spawnPty: di.inject(spawnPtyInjectable),
|
||||
emitAppEvent: di.inject(emitAppEventInjectable),
|
||||
stat: di.inject(statInjectable),
|
||||
};
|
||||
const kubectl = createKubectl(params.cluster.version);
|
||||
const session = new NodeShellSession(dependencies, { kubectl, ...params });
|
||||
|
||||
@@ -10,14 +10,14 @@ import { clearKubeconfigEnvVars } from "../utils/clear-kube-env-vars";
|
||||
import path from "path";
|
||||
import os, { userInfo } from "os";
|
||||
import type * as pty from "node-pty";
|
||||
import { appEventBus } from "../../common/app-event-bus/event-bus";
|
||||
import { stat } from "fs/promises";
|
||||
import { getOrInsertWith } from "../../common/utils";
|
||||
import { type TerminalMessage, TerminalChannels } from "../../common/terminal/channels";
|
||||
import type { Logger } from "../../common/logger";
|
||||
import type { ComputeShellEnvironment } from "../utils/shell-env/compute-shell-environment.injectable";
|
||||
import type { SpawnPty } from "./spawn-pty.injectable";
|
||||
import type { InitializableState } from "../../common/initializable-state/create";
|
||||
import type { EmitAppEvent } from "../../common/app-event-bus/emit-event.injectable";
|
||||
import type { Stat } from "../../common/fs/stat/stat.injectable";
|
||||
|
||||
export class ShellOpenError extends Error {
|
||||
constructor(message: string, options?: ErrorOptions) {
|
||||
@@ -112,6 +112,8 @@ export interface ShellSessionDependencies {
|
||||
readonly buildVersion: InitializableState<string>;
|
||||
computeShellEnvironment: ComputeShellEnvironment;
|
||||
spawnPty: SpawnPty;
|
||||
emitAppEvent: EmitAppEvent;
|
||||
stat: Stat;
|
||||
}
|
||||
|
||||
export interface ShellSessionArgs {
|
||||
@@ -213,7 +215,7 @@ export abstract class ShellSession {
|
||||
}
|
||||
|
||||
try {
|
||||
const stats = await stat(potentialCwd);
|
||||
const stats = await this.dependencies.stat(potentialCwd);
|
||||
|
||||
if (stats.isDirectory()) {
|
||||
return potentialCwd;
|
||||
@@ -310,7 +312,7 @@ export abstract class ShellSession {
|
||||
}
|
||||
});
|
||||
|
||||
appEventBus.emit({ name: this.ShellType, action: "open" });
|
||||
this.dependencies.emitAppEvent({ name: this.ShellType, action: "open" });
|
||||
}
|
||||
|
||||
protected getPathEntries(): string[] {
|
||||
|
||||
+5
-5
@@ -6,9 +6,9 @@ import { getInjectable } from "@ogre-tools/injectable";
|
||||
import createLensWindowInjectable from "./create-lens-window.injectable";
|
||||
import lensProxyPortInjectable from "../../../lens-proxy/lens-proxy-port.injectable";
|
||||
import isMacInjectable from "../../../../common/vars/is-mac.injectable";
|
||||
import appEventBusInjectable from "../../../../common/app-event-bus/app-event-bus.injectable";
|
||||
import waitUntilBundledExtensionsAreLoadedInjectable from "./wait-until-bundled-extensions-are-loaded.injectable";
|
||||
import { applicationWindowInjectionToken } from "./application-window-injection-token";
|
||||
import emitAppEventInjectable from "../../../../common/app-event-bus/emit-event.injectable";
|
||||
import { runInAction } from "mobx";
|
||||
import appNameInjectable from "../../../../common/vars/app-name.injectable";
|
||||
|
||||
@@ -23,9 +23,9 @@ const createApplicationWindowInjectable = getInjectable({
|
||||
const createLensWindow = di.inject(createLensWindowInjectable);
|
||||
const isMac = di.inject(isMacInjectable);
|
||||
const applicationName = di.inject(appNameInjectable);
|
||||
const appEventBus = di.inject(appEventBusInjectable);
|
||||
const waitUntilBundledExtensionsAreLoaded = di.inject(waitUntilBundledExtensionsAreLoadedInjectable);
|
||||
const lensProxyPort = di.inject(lensProxyPortInjectable);
|
||||
const emitAppEvent = di.inject(emitAppEventInjectable);
|
||||
|
||||
return createLensWindow({
|
||||
id,
|
||||
@@ -40,13 +40,13 @@ const createApplicationWindowInjectable = getInjectable({
|
||||
titleBarStyle: isMac ? "hiddenInset" : "hidden",
|
||||
centered: false,
|
||||
onFocus: () => {
|
||||
appEventBus.emit({ name: "app", action: "focus" });
|
||||
emitAppEvent({ name: "app", action: "focus" });
|
||||
},
|
||||
onBlur: () => {
|
||||
appEventBus.emit({ name: "app", action: "blur" });
|
||||
emitAppEvent({ name: "app", action: "blur" });
|
||||
},
|
||||
onDomReady: () => {
|
||||
appEventBus.emit({ name: "app", action: "dom-ready" });
|
||||
emitAppEvent({ name: "app", action: "dom-ready" });
|
||||
},
|
||||
|
||||
onClose: () => {
|
||||
|
||||
@@ -3,19 +3,19 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import appEventBusInjectable from "../../../common/app-event-bus/app-event-bus.injectable";
|
||||
import emitAppEventInjectable from "../../../common/app-event-bus/emit-event.injectable";
|
||||
import { beforeQuitOfFrontEndInjectionToken } from "../runnable-tokens/before-quit-of-front-end-injection-token";
|
||||
|
||||
const emitCloseToEventBusInjectable = getInjectable({
|
||||
id: "emit-close-to-event-bus",
|
||||
|
||||
instantiate: (di) => {
|
||||
const appEventBus = di.inject(appEventBusInjectable);
|
||||
const emitAppEvent = di.inject(emitAppEventInjectable);
|
||||
|
||||
return {
|
||||
id: "emit-close-to-event-bus",
|
||||
run: () => {
|
||||
appEventBus.emit({ name: "app", action: "close" });
|
||||
emitAppEvent({ name: "app", action: "close" });
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
+3
-3
@@ -3,19 +3,19 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import appEventBusInjectable from "../../../common/app-event-bus/app-event-bus.injectable";
|
||||
import emitAppEventInjectable from "../../../common/app-event-bus/emit-event.injectable";
|
||||
import { afterApplicationIsLoadedInjectionToken } from "../runnable-tokens/after-application-is-loaded-injection-token";
|
||||
|
||||
const emitServiceStartToEventBusInjectable = getInjectable({
|
||||
id: "emit-service-start-to-event-bus",
|
||||
|
||||
instantiate: (di) => {
|
||||
const appEventBus = di.inject(appEventBusInjectable);
|
||||
const emitAppEvent = di.inject(emitAppEventInjectable);
|
||||
|
||||
return {
|
||||
id: "emit-service-start-to-event-bus",
|
||||
run: () => {
|
||||
appEventBus.emit({ name: "service", action: "start" });
|
||||
emitAppEvent({ name: "service", action: "start" });
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import exitAppInjectable from "./electron-app/features/exit-app.injectable";
|
||||
import clusterManagerInjectable from "./cluster/manager.injectable";
|
||||
import appEventBusInjectable from "../common/app-event-bus/app-event-bus.injectable";
|
||||
import loggerInjectable from "../common/logger.injectable";
|
||||
import closeAllWindowsInjectable from "./start-main-application/lens-window/hide-all-windows/close-all-windows.injectable";
|
||||
import emitAppEventInjectable from "../common/app-event-bus/emit-event.injectable";
|
||||
|
||||
const stopServicesAndExitAppInjectable = getInjectable({
|
||||
id: "stop-services-and-exit-app",
|
||||
@@ -15,12 +15,12 @@ const stopServicesAndExitAppInjectable = getInjectable({
|
||||
instantiate: (di) => {
|
||||
const exitApp = di.inject(exitAppInjectable);
|
||||
const clusterManager = di.inject(clusterManagerInjectable);
|
||||
const appEventBus = di.inject(appEventBusInjectable);
|
||||
const logger = di.inject(loggerInjectable);
|
||||
const closeAllWindows = di.inject(closeAllWindowsInjectable);
|
||||
const emitAppEvent = di.inject(emitAppEventInjectable);
|
||||
|
||||
return () => {
|
||||
appEventBus.emit({ name: "service", action: "close" });
|
||||
emitAppEvent({ name: "service", action: "close" });
|
||||
closeAllWindows();
|
||||
clusterManager.stop();
|
||||
logger.info("SERVICE:QUIT");
|
||||
|
||||
Reference in new issue
Block a user