1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Refactor runnables (#6528)

* Convert runManyFor to use composite

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Convert runManySyncFor to use composite and to enfore sync-ness

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Remove dead code

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Convert getStartableStoppable to be always sync as it is never used in an async fashion

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Convert all sync runnables to comply with new checks for sync-ness

Signed-off-by: Sebastian Malton <sebastian@malton.name>

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2022-11-07 09:04:56 -08:00 committed by GitHub
parent 82ab60d544
commit b498f12186
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 191 additions and 401 deletions

View File

@ -223,7 +223,7 @@ describe("runManyFor", () => {
); );
return expect(() => runMany()).rejects.toThrow( return expect(() => runMany()).rejects.toThrow(
'Tried to run runnable "some-runnable-1" after the runnable "some-runnable-2" which does not share the "some-injection-token" injection token.', /Tried to get a composite but encountered missing parent ids: "some-runnable-2".\n\nAvailable parent ids are:\n"[0-9a-z-]+",\n"some-runnable-1"/,
); );
}); });

View File

@ -2,13 +2,10 @@
* Copyright (c) OpenLens Authors. All rights reserved. * Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import { pipeline } from "@ogre-tools/fp"; import type { DiContainerForInjection, InjectionToken } from "@ogre-tools/injectable";
import type { import type { Composite } from "../utils/composite/get-composite/get-composite";
DiContainerForInjection, import { getCompositeFor } from "../utils/composite/get-composite/get-composite";
InjectionToken, import * as uuid from "uuid";
} from "@ogre-tools/injectable";
import { filter, forEach, map, tap } from "lodash/fp";
import { throwWithIncorrectHierarchyFor } from "./throw-with-incorrect-hierarchy-for";
export interface Runnable<TParameter = void> { export interface Runnable<TParameter = void> {
id: string; id: string;
@ -18,35 +15,34 @@ export interface Runnable<TParameter = void> {
type Run<Param> = (parameter: Param) => Promise<void> | void; type Run<Param> = (parameter: Param) => Promise<void> | void;
export type RunMany = <Param>( export type RunMany = <Param>(injectionToken: InjectionToken<Runnable<Param>, void>) => Run<Param>;
injectionToken: InjectionToken<Runnable<Param>, void>
) => Run<Param>; async function runCompositeRunnables<Param>(param: Param, composite: Composite<Runnable<Param>>) {
await composite.value.run(param);
await Promise.all(composite.children.map(composite => runCompositeRunnables(param, composite)));
}
export function runManyFor(di: DiContainerForInjection): RunMany { export function runManyFor(di: DiContainerForInjection): RunMany {
return (injectionToken) => async (parameter) => { return <Param>(injectionToken: InjectionToken<Runnable<Param>, void>) => async (param: Param) => {
const allRunnables = di.injectMany(injectionToken); const allRunnables = di.injectMany(injectionToken);
const rootId = uuid.v4();
const getCompositeRunnables = getCompositeFor<Runnable<Param>>({
getId: (runnable) => runnable.id,
getParentId: (runnable) => (
runnable.id === rootId
? undefined
: runnable.runAfter?.id ?? rootId
),
});
const composite = getCompositeRunnables([
// This is a dummy runnable to conform to the requirements of `getCompositeFor` to only have one root
{
id: rootId,
run: () => {},
},
...allRunnables,
]);
const throwWithIncorrectHierarchy = throwWithIncorrectHierarchyFor((injectionToken as any).id, allRunnables); await runCompositeRunnables(param, composite);
const recursedRun = async (
runAfterRunnable: Runnable<any> | undefined = undefined,
) =>
await pipeline(
allRunnables,
tap(runnables => forEach(throwWithIncorrectHierarchy, runnables)),
filter((runnable) => runnable.runAfter === runAfterRunnable),
map(async (runnable) => {
await runnable.run(parameter);
await recursedRun(runnable);
}),
(promises) => Promise.all(promises),
);
await recursedRun();
}; };
} }

View File

@ -69,7 +69,7 @@ describe("runManySyncFor", () => {
instantiate: (di) => ({ instantiate: (di) => ({
id: "some-injectable-1", id: "some-injectable-1",
run: () => runMock("third-level-run"), run: () => void runMock("third-level-run"),
runAfter: di.inject(someInjectable2), runAfter: di.inject(someInjectable2),
}), }),
@ -81,7 +81,7 @@ describe("runManySyncFor", () => {
instantiate: (di) => ({ instantiate: (di) => ({
id: "some-injectable-2", id: "some-injectable-2",
run: () => runMock("second-level-run"), run: () => void runMock("second-level-run"),
runAfter: di.inject(someInjectable3), runAfter: di.inject(someInjectable3),
}), }),
@ -92,7 +92,7 @@ describe("runManySyncFor", () => {
id: "some-injectable-3", id: "some-injectable-3",
instantiate: () => ({ instantiate: () => ({
id: "some-injectable-3", id: "some-injectable-3",
run: () => runMock("first-level-run"), run: () => void runMock("first-level-run"),
}), }),
injectionToken: someInjectionTokenForRunnables, injectionToken: someInjectionTokenForRunnables,
}); });
@ -151,13 +151,13 @@ describe("runManySyncFor", () => {
someInjectionToken, someInjectionToken,
); );
return expect(() => runMany()).rejects.toThrow( return expect(() => runMany()).toThrow(
'Tried to run runnable "some-runnable-1" after the runnable "some-runnable-2" which does not share the "some-injection-token" injection token.', /Tried to get a composite but encountered missing parent ids: "some-runnable-2".\n\nAvailable parent ids are:\n"[0-9a-z-]+",\n"some-runnable-1"/,
); );
}); });
describe("when running many with parameter", () => { describe("when running many with parameter", () => {
let runMock: jest.Mock<(arg: string, arg2: string) => void>; let runMock: jest.Mock<(arg: string, arg2: string) => undefined>;
beforeEach(() => { beforeEach(() => {
const rootDi = createContainer("irrelevant"); const rootDi = createContainer("irrelevant");
@ -175,7 +175,7 @@ describe("runManySyncFor", () => {
instantiate: () => ({ instantiate: () => ({
id: "some-runnable-1", id: "some-runnable-1",
run: (parameter) => runMock("run-of-some-runnable-1", parameter), run: (parameter) => void runMock("run-of-some-runnable-1", parameter),
}), }),
injectionToken: someInjectionTokenForRunnablesWithParameter, injectionToken: someInjectionTokenForRunnablesWithParameter,
@ -186,7 +186,7 @@ describe("runManySyncFor", () => {
instantiate: () => ({ instantiate: () => ({
id: "some-runnable-2", id: "some-runnable-2",
run: (parameter) => runMock("run-of-some-runnable-2", parameter), run: (parameter) => void runMock("run-of-some-runnable-2", parameter),
}), }),
injectionToken: someInjectionTokenForRunnablesWithParameter, injectionToken: someInjectionTokenForRunnablesWithParameter,

View File

@ -2,11 +2,10 @@
* Copyright (c) OpenLens Authors. All rights reserved. * Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import { pipeline } from "@ogre-tools/fp";
import type { DiContainerForInjection, InjectionToken } from "@ogre-tools/injectable"; import type { DiContainerForInjection, InjectionToken } from "@ogre-tools/injectable";
import { filter, forEach, map, tap } from "lodash/fp"; import type { Composite } from "../utils/composite/get-composite/get-composite";
import type { Runnable } from "./run-many-for"; import { getCompositeFor } from "../utils/composite/get-composite/get-composite";
import { throwWithIncorrectHierarchyFor } from "./throw-with-incorrect-hierarchy-for"; import * as uuid from "uuid";
export interface RunnableSync<TParameter = void> { export interface RunnableSync<TParameter = void> {
id: string; id: string;
@ -14,35 +13,43 @@ export interface RunnableSync<TParameter = void> {
runAfter?: RunnableSync<TParameter>; runAfter?: RunnableSync<TParameter>;
} }
type RunSync<Param> = (parameter: Param) => void; /**
* NOTE: this is the worse of two evils. This makes sure that `RunnableSync` always is sync.
* If the return type is `void` instead then async functions (those return `Promise<T>`) can
* coerce to it.
*/
type RunSync<Param> = (parameter: Param) => undefined;
export type RunManySync = <Param>( export type RunManySync = <Param>(injectionToken: InjectionToken<RunnableSync<Param>, void>) => RunSync<Param>;
injectionToken: InjectionToken<Runnable<Param>, void>
) => RunSync<Param>; function runCompositeRunnableSyncs<Param>(param: Param, composite: Composite<RunnableSync<Param>>): undefined {
composite.value.run(param);
composite.children.map(composite => runCompositeRunnableSyncs(param, composite));
return undefined;
}
export function runManySyncFor(di: DiContainerForInjection): RunManySync { export function runManySyncFor(di: DiContainerForInjection): RunManySync {
return (injectionToken) => async (parameter) => { return <Param>(injectionToken: InjectionToken<RunnableSync<Param>, void>) => (param: Param): undefined => {
const allRunnables = di.injectMany(injectionToken); const allRunnables = di.injectMany(injectionToken);
const rootId = uuid.v4();
const getCompositeRunnables = getCompositeFor<RunnableSync<Param>>({
getId: (runnable) => runnable.id,
getParentId: (runnable) => (
runnable.id === rootId
? undefined
: runnable.runAfter?.id ?? rootId
),
});
const composite = getCompositeRunnables([
// This is a dummy runnable to conform to the requirements of `getCompositeFor` to only have one root
{
id: rootId,
run: () => undefined,
},
...allRunnables,
]);
const throwWithIncorrectHierarchy = throwWithIncorrectHierarchyFor((injectionToken as any).id, allRunnables); return runCompositeRunnableSyncs(param, composite);
const recursedRun = (
runAfterRunnable: RunnableSync<any> | undefined = undefined,
) =>
pipeline(
allRunnables,
tap(runnables => forEach(throwWithIncorrectHierarchy, runnables)),
filter((runnable) => runnable.runAfter === runAfterRunnable),
map((runnable) => {
runnable.run(parameter);
recursedRun(runnable);
}),
);
recursedRun();
}; };
} }

View File

@ -1,14 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { Runnable } from "./run-many-for";
import type { RunnableSync } from "./run-many-sync-for";
export const throwWithIncorrectHierarchyFor = (injectionTokenId: string, allRunnables: Runnable<any>[] | RunnableSync<any>[]) => (
(runnable: Runnable<any> | RunnableSync<any>) => {
if (runnable.runAfter && !allRunnables.includes(runnable.runAfter)) {
throw new Error(`Tried to run runnable "${runnable.id}" after the runnable "${runnable.runAfter.id}" which does not share the "${injectionTokenId}" injection token.`);
}
}
);

View File

@ -2,21 +2,17 @@
* Copyright (c) OpenLens Authors. All rights reserved. * Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import type { AsyncFnMock } from "@async-fn/jest"; import type { StartableStoppable } from "./get-startable-stoppable";
import asyncFn from "@async-fn/jest";
import { getStartableStoppable } from "./get-startable-stoppable"; import { getStartableStoppable } from "./get-startable-stoppable";
import { getPromiseStatus } from "../test-utils/get-promise-status";
import { flushPromises } from "../test-utils/flush-promises";
describe("getStartableStoppable", () => { describe("getStartableStoppable", () => {
let stopMock: AsyncFnMock<() => Promise<void>>; let stopMock: jest.MockedFunction<() => void>;
let startMock: AsyncFnMock<() => Promise<() => Promise<void>>>; let startMock: jest.MockedFunction<() => () => void>;
let actual: { stop: () => Promise<void>; start: () => Promise<void>; started: boolean }; let actual: StartableStoppable;
beforeEach(() => { beforeEach(() => {
stopMock = asyncFn(); stopMock = jest.fn();
startMock = asyncFn(); startMock = jest.fn().mockImplementation(() => stopMock);
actual = getStartableStoppable("some-id", startMock); actual = getStartableStoppable("some-id", startMock);
}); });
@ -29,7 +25,7 @@ describe("getStartableStoppable", () => {
}); });
it("when stopping before ever starting, throws", () => { it("when stopping before ever starting, throws", () => {
expect(actual.stop).rejects.toThrow("Tried to stop \"some-id\", but it has not started yet."); expect(() => actual.stop()).toThrow("Tried to stop \"some-id\", but it is already stopped.");
}); });
it("is not started", () => { it("is not started", () => {
@ -37,199 +33,30 @@ describe("getStartableStoppable", () => {
}); });
describe("when started", () => { describe("when started", () => {
let startPromise: Promise<void>;
beforeEach(() => { beforeEach(() => {
startPromise = actual.start();
});
it("starts starting", () => {
expect(startMock).toHaveBeenCalled();
});
it("starting does not resolve yet", async () => {
const promiseStatus = await getPromiseStatus(startPromise);
expect(promiseStatus.fulfilled).toBe(false);
});
it("is not started yet", () => {
expect(actual.started).toBe(false);
});
describe("when started again before the start has finished", () => {
let error: Error;
beforeEach(() => {
startMock.mockClear();
actual.start().catch((e) => { error = e; });
});
it("does not start starting again", () => {
expect(startMock).not.toHaveBeenCalled();
});
it("throws", () => {
expect(error.message).toBe("Tried to start \"some-id\", but it is already being started.");
});
});
describe("when starting finishes", () => {
beforeEach(async () => {
await startMock.resolve(stopMock);
});
it("is started", () => {
expect(actual.started).toBe(true);
});
it("starting resolves", async () => {
const promiseStatus = await getPromiseStatus(startPromise);
expect(promiseStatus.fulfilled).toBe(true);
});
it("when started again, throws", () => {
expect(actual.start).rejects.toThrow("Tried to start \"some-id\", but it has already started.");
});
it("does not stop yet", () => {
expect(stopMock).not.toHaveBeenCalled();
});
describe("when stopped", () => {
let stopPromise: Promise<void>;
beforeEach(() => {
stopPromise = actual.stop();
});
it("starts stopping", () => {
expect(stopMock).toHaveBeenCalled();
});
it("stopping does not resolve yet", async () => {
const promiseStatus = await getPromiseStatus(stopPromise);
expect(promiseStatus.fulfilled).toBe(false);
});
it("is not stopped yet", () => {
expect(actual.started).toBe(true);
});
describe("when stopping finishes", () => {
beforeEach(async () => {
await stopMock.resolve();
});
it("is not started", () => {
expect(actual.started).toBe(false);
});
it("stopping resolves", async () => {
const promiseStatus = await getPromiseStatus(stopPromise);
expect(promiseStatus.fulfilled).toBe(true);
});
it("when stopped again, throws", () => {
expect(actual.stop).rejects.toThrow("Tried to stop \"some-id\", but it has already stopped.");
});
describe("when started again", () => {
beforeEach(
() => {
startMock.mockClear();
actual.start(); actual.start();
}); });
it("starts", () => { it("calls start function", () => {
expect(startMock).toHaveBeenCalled(); expect(startMock).toHaveBeenCalled();
}); });
it("is not started yet", () => {
expect(actual.started).toBe(false);
});
describe("when starting finishes", () => {
beforeEach(async () => {
await startMock.resolve(stopMock);
});
it("is started", () => { it("is started", () => {
expect(actual.started).toBe(true); expect(actual.started).toBe(true);
}); });
it("when stopped again, starts stopping again", async () => { describe("when stopped", () => {
stopMock.mockClear();
actual.stop();
await flushPromises();
expect(stopMock).toHaveBeenCalled();
});
});
});
});
});
});
describe("when stopped before starting finishes", () => {
let stopPromise: Promise<void>;
beforeEach(() => { beforeEach(() => {
stopPromise = actual.stop(); actual.stop();
}); });
it("does not resolve yet", async () => { it("calls stop function", () => {
const promiseStatus = await getPromiseStatus(stopPromise); expect(stopMock).toBeCalled();
expect(promiseStatus.fulfilled).toBe(false);
});
it("is not started yet", () => {
expect(actual.started).toBe(false);
});
describe("when starting finishes", () => {
beforeEach(async () => {
await startMock.resolve(stopMock);
});
it("starts stopping", () => {
expect(stopMock).toHaveBeenCalled();
});
it("is not stopped yet", () => {
expect(actual.started).toBe(true);
});
it("does not resolve yet", async () => {
const promiseStatus = await getPromiseStatus(stopPromise);
expect(promiseStatus.fulfilled).toBe(false);
});
describe("when stopping finishes", () => {
beforeEach(async () => {
await stopMock.resolve();
}); });
it("is stopped", () => { it("is stopped", () => {
expect(actual.started).toBe(false); expect(actual.started).toBe(false);
}); });
it("resolves", async () => {
const promiseStatus = await getPromiseStatus(stopPromise);
expect(promiseStatus.fulfilled).toBe(true);
});
});
});
}); });
}); });
}); });

View File

@ -3,58 +3,43 @@
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
type Stopper = () => Promise<void> | void; export type Stopper = () => void;
type Starter = () => Promise<Stopper> | Stopper; export type Starter = () => Stopper;
export const getStartableStoppable = ( export interface StartableStoppable {
id: string, readonly started: boolean;
startAndGetStopCallback: Starter, start: () => void;
) => { stop: () => void;
}
type StartableStoppableState = "stopped" | "started" | "starting";
export function getStartableStoppable(id: string, startAndGetStopper: Starter): StartableStoppable {
let stop: Stopper; let stop: Stopper;
let stopped = false; let state: StartableStoppableState = "stopped";
let started = false;
let starting = false;
let startingPromise: Promise<Stopper> | Stopper;
return { return {
get started() { get started() {
return started; return state === "started";
}, },
start: async () => { start: () => {
if (starting) { if (state !== "stopped") {
throw new Error(`Tried to start "${id}", but it is already being started.`); throw new Error(`Tried to start "${id}", but it is already ${state}.`);
} }
starting = true; state = "starting";
stop = startAndGetStopper();
if (started) { state = "started";
throw new Error(`Tried to start "${id}", but it has already started.`);
}
startingPromise = startAndGetStopCallback();
stop = await startingPromise;
stopped = false;
started = true;
starting = false;
}, },
stop: async () => { stop: () => {
await startingPromise; if (state !== "started") {
throw new Error(`Tried to stop "${id}", but it is already ${state}.`);
if (stopped) {
throw new Error(`Tried to stop "${id}", but it has already stopped.`);
} }
if (!started) { stop();
throw new Error(`Tried to stop "${id}", but it has not started yet.`); state = "stopped";
}
await stop();
started = false;
stopped = true;
}, },
}; };
}; }

View File

@ -15,8 +15,9 @@ const applicationMenuReactivityInjectable = getInjectable({
const applicationMenuItemComposite = di.inject(applicationMenuItemCompositeInjectable); const applicationMenuItemComposite = di.inject(applicationMenuItemCompositeInjectable);
const populateApplicationMenu = di.inject(populateApplicationMenuInjectable); const populateApplicationMenu = di.inject(populateApplicationMenuInjectable);
return getStartableStoppable("application-menu-reactivity", () => return getStartableStoppable(
autorun(() => populateApplicationMenu(applicationMenuItemComposite.get()), { "application-menu-reactivity",
() => autorun(() => populateApplicationMenu(applicationMenuItemComposite.get()), {
delay: 100, delay: 100,
}), }),
); );

View File

@ -10,15 +10,11 @@ const stopApplicationMenuInjectable = getInjectable({
id: "stop-application-menu", id: "stop-application-menu",
instantiate: (di) => { instantiate: (di) => {
const applicationMenu = di.inject( const applicationMenu = di.inject(applicationMenuReactivityInjectable);
applicationMenuReactivityInjectable,
);
return { return {
id: "stop-application-menu", id: "stop-application-menu",
run: async () => { run: () => void applicationMenu.stop(),
await applicationMenu.stop();
},
}; };
}, },

View File

@ -7,6 +7,8 @@ import { getStartableStoppable } from "../../../../../common/utils/get-startable
import processCheckingForUpdatesInjectable from "../../../main/process-checking-for-updates.injectable"; import processCheckingForUpdatesInjectable from "../../../main/process-checking-for-updates.injectable";
import withOrphanPromiseInjectable from "../../../../../common/utils/with-orphan-promise/with-orphan-promise.injectable"; import withOrphanPromiseInjectable from "../../../../../common/utils/with-orphan-promise/with-orphan-promise.injectable";
const TWO_HOURS = 1000 * 60 * 60 * 2;
const periodicalCheckForUpdatesInjectable = getInjectable({ const periodicalCheckForUpdatesInjectable = getInjectable({
id: "periodical-check-for-updates", id: "periodical-check-for-updates",
@ -15,12 +17,9 @@ const periodicalCheckForUpdatesInjectable = getInjectable({
const processCheckingForUpdates = withOrphanPromise(di.inject(processCheckingForUpdatesInjectable)); const processCheckingForUpdates = withOrphanPromise(di.inject(processCheckingForUpdatesInjectable));
return getStartableStoppable("periodical-check-for-updates", () => { return getStartableStoppable("periodical-check-for-updates", () => {
const TWO_HOURS = 1000 * 60 * 60 * 2;
processCheckingForUpdates("periodic"); processCheckingForUpdates("periodic");
const intervalId = setInterval(() => { const intervalId = setInterval(() => {
processCheckingForUpdates("periodic"); processCheckingForUpdates("periodic");
}, TWO_HOURS); }, TWO_HOURS);

View File

@ -14,10 +14,12 @@ const stopCheckingForUpdatesInjectable = getInjectable({
return { return {
id: "stop-checking-for-updates", id: "stop-checking-for-updates",
run: async () => { run: () => {
if (periodicalCheckForUpdates.started) { if (periodicalCheckForUpdates.started) {
await periodicalCheckForUpdates.stop(); periodicalCheckForUpdates.stop();
} }
return undefined;
}, },
}; };
}, },

View File

@ -14,9 +14,7 @@ const stopWatchingIfUpdateShouldHappenOnQuitInjectable = getInjectable({
return { return {
id: "stop-watching-if-update-should-happen-on-quit", id: "stop-watching-if-update-should-happen-on-quit",
run: () => { run: () => void watchIfUpdateShouldHappenOnQuit.stop(),
watchIfUpdateShouldHappenOnQuit.stop();
},
}; };
}, },

View File

@ -44,6 +44,9 @@ const setupAppPathsInjectable = getInjectable({
) as AppPaths; ) as AppPaths;
appPathsState.set(appPaths); appPathsState.set(appPaths);
// NOTE: this is the worse of two evils. This makes sure that `RunnableSync` always is sync
return undefined;
}, },
}; };
}, },

View File

@ -13,8 +13,9 @@ const catalogSyncToRendererInjectable = getInjectable({
instantiate: (di) => { instantiate: (di) => {
const catalogEntityRegistry = di.inject(catalogEntityRegistryInjectable); const catalogEntityRegistry = di.inject(catalogEntityRegistryInjectable);
return getStartableStoppable("catalog-sync", () => return getStartableStoppable(
startCatalogSyncToRenderer(catalogEntityRegistry), "catalog-sync",
() => startCatalogSyncToRenderer(catalogEntityRegistry),
); );
}, },

View File

@ -14,10 +14,12 @@ const stopCatalogSyncInjectable = getInjectable({
return { return {
id: "stop-catalog-sync", id: "stop-catalog-sync",
run: async () => { run: () => {
if (catalogSyncToRenderer.started) { if (catalogSyncToRenderer.started) {
await catalogSyncToRenderer.stop(); catalogSyncToRenderer.stop();
} }
return undefined;
}, },
}; };
}, },

View File

@ -18,9 +18,7 @@ const syncThemeFromOperatingSystemInjectable = getInjectable({
return getStartableStoppable("sync-theme-from-operating-system", () => { return getStartableStoppable("sync-theme-from-operating-system", () => {
const updateThemeState = () => { const updateThemeState = () => {
const newTheme = getElectronTheme(); currentThemeState.set(getElectronTheme());
currentThemeState.set(newTheme);
}; };
nativeTheme.on("updated", updateThemeState); nativeTheme.on("updated", updateThemeState);

View File

@ -14,9 +14,7 @@ const cleanUpDeepLinkingInjectable = getInjectable({
return { return {
id: "clean-up-deep-linking", id: "clean-up-deep-linking",
run: () => { run: () => void lensProtocolRouterMain.cleanup(),
lensProtocolRouterMain.cleanup();
},
}; };
}, },

View File

@ -23,6 +23,8 @@ const hideDockForLastClosedWindowInjectable = getInjectable({
if (isEmpty(visibleWindows)) { if (isEmpty(visibleWindows)) {
app.dock?.hide(); app.dock?.hide();
} }
return undefined;
}, },
}; };
}, },

View File

@ -20,6 +20,8 @@ const enforceSingleApplicationInstanceInjectable = getInjectable({
if (!requestSingleInstanceLock()) { if (!requestSingleInstanceLock()) {
exitApp(); exitApp();
} }
return undefined;
}, },
}; };
}, },

View File

@ -18,6 +18,8 @@ const setupApplicationNameInjectable = getInjectable({
id: "setup-application-name", id: "setup-application-name",
run: () => { run: () => {
app.setName(appName); app.setName(appName);
return undefined;
}, },
}; };
}, },

View File

@ -13,15 +13,14 @@ const setupRunnablesAfterWindowIsOpenedInjectable = getInjectable({
instantiate: (di) => { instantiate: (di) => {
const afterWindowIsOpened = runManyFor(di)(afterWindowIsOpenedInjectionToken); const afterWindowIsOpened = runManyFor(di)(afterWindowIsOpenedInjectionToken);
const app = di.inject(electronAppInjectable);
return { return {
id: "setup-runnables-after-window-is-opened", id: "setup-runnables-after-window-is-opened",
run: () => { run: () => {
const app = di.inject(electronAppInjectable); app.on("browser-window-created", () => afterWindowIsOpened);
app.on("browser-window-created", async () => { return undefined;
await afterWindowIsOpened();
});
}, },
}; };
}, },

View File

@ -15,24 +15,16 @@ const setupRunnablesBeforeClosingOfApplicationInjectable = getInjectable({
id: "setup-closing-of-application", id: "setup-closing-of-application",
instantiate: (di) => { instantiate: (di) => {
const runMany = runManySyncFor(di); const runManySync = runManySyncFor(di);
const runRunnablesBeforeQuitOfFrontEnd = runManySync(beforeQuitOfFrontEndInjectionToken);
const runRunnablesBeforeQuitOfFrontEnd = runMany( const runRunnablesBeforeQuitOfBackEnd = runManySync(beforeQuitOfBackEndInjectionToken);
beforeQuitOfFrontEndInjectionToken, const app = di.inject(electronAppInjectable);
); const isIntegrationTesting = di.inject(isIntegrationTestingInjectable);
const autoUpdater = di.inject(autoUpdaterInjectable);
const runRunnablesBeforeQuitOfBackEnd = runMany(
beforeQuitOfBackEndInjectionToken,
);
return { return {
id: "setup-closing-of-application", id: "setup-closing-of-application",
run: () => { run: () => {
const app = di.inject(electronAppInjectable);
const isIntegrationTesting = di.inject(isIntegrationTestingInjectable);
const autoUpdater = di.inject(autoUpdaterInjectable);
let isAutoUpdating = false; let isAutoUpdating = false;
autoUpdater.on("before-quit-for-update", () => { autoUpdater.on("before-quit-for-update", () => {
@ -51,6 +43,8 @@ const setupRunnablesBeforeClosingOfApplicationInjectable = getInjectable({
event.preventDefault(); event.preventDefault();
} }
}); });
return undefined;
}, },
}; };
}, },

View File

@ -5,7 +5,6 @@
import { getInjectionToken } from "@ogre-tools/injectable"; import { getInjectionToken } from "@ogre-tools/injectable";
import type { RunnableSync } from "../../../common/runnable/run-many-sync-for"; import type { RunnableSync } from "../../../common/runnable/run-many-sync-for";
export const beforeElectronIsReadyInjectionToken = export const beforeElectronIsReadyInjectionToken = getInjectionToken<RunnableSync>({
getInjectionToken<RunnableSync>({
id: "before-electron-is-ready", id: "before-electron-is-ready",
}); });

View File

@ -5,7 +5,6 @@
import { getInjectionToken } from "@ogre-tools/injectable"; import { getInjectionToken } from "@ogre-tools/injectable";
import type { RunnableSync } from "../../../common/runnable/run-many-sync-for"; import type { RunnableSync } from "../../../common/runnable/run-many-sync-for";
export const beforeQuitOfBackEndInjectionToken = export const beforeQuitOfBackEndInjectionToken = getInjectionToken<RunnableSync>({
getInjectionToken<RunnableSync>({
id: "before-quit-of-back-end", id: "before-quit-of-back-end",
}); });

View File

@ -5,7 +5,6 @@
import { getInjectionToken } from "@ogre-tools/injectable"; import { getInjectionToken } from "@ogre-tools/injectable";
import type { RunnableSync } from "../../../common/runnable/run-many-sync-for"; import type { RunnableSync } from "../../../common/runnable/run-many-sync-for";
export const beforeQuitOfFrontEndInjectionToken = export const beforeQuitOfFrontEndInjectionToken = getInjectionToken<RunnableSync>({
getInjectionToken<RunnableSync>({
id: "before-quit-of-front-end", id: "before-quit-of-front-end",
}); });

View File

@ -11,9 +11,7 @@ const cleanUpShellSessionsInjectable = getInjectable({
instantiate: () => ({ instantiate: () => ({
id: "clean-up-shell-sessions", id: "clean-up-shell-sessions",
run: () => { run: () => void ShellSession.cleanup(),
ShellSession.cleanup();
},
}), }),
injectionToken: beforeQuitOfBackEndInjectionToken, injectionToken: beforeQuitOfBackEndInjectionToken,

View File

@ -16,6 +16,8 @@ const emitCloseToEventBusInjectable = getInjectable({
id: "emit-close-to-event-bus", id: "emit-close-to-event-bus",
run: () => { run: () => {
emitAppEvent({ name: "app", action: "close" }); emitAppEvent({ name: "app", action: "close" });
return undefined;
}, },
}; };
}, },

View File

@ -20,6 +20,8 @@ const flagRendererAsNotLoadedInjectable = getInjectable({
// Todo: remove this kludge which enables out-of-place temporal dependency. // Todo: remove this kludge which enables out-of-place temporal dependency.
lensProtocolRouterMain.rendererLoaded = false; lensProtocolRouterMain.rendererLoaded = false;
}); });
return undefined;
}, },
}; };
}, },

View File

@ -14,9 +14,7 @@ const stopKubeConfigSyncInjectable = getInjectable({
return { return {
id: "stop-kube-config-sync", id: "stop-kube-config-sync",
run: () => { run: () => void kubeConfigSyncManager.stopSync(),
kubeConfigSyncManager.stopSync();
},
}; };
}, },

View File

@ -15,7 +15,7 @@ const setupSentryInjectable = getInjectable({
return { return {
id: "setup-sentry", id: "setup-sentry",
run: () => initializeSentryReportingWith(initializeSentryOnMain), run: () => void initializeSentryReportingWith(initializeSentryOnMain),
}; };
}, },
injectionToken: beforeElectronIsReadyInjectionToken, injectionToken: beforeElectronIsReadyInjectionToken,

View File

@ -20,6 +20,8 @@ const setupHardwareAccelerationInjectable = getInjectable({
if (hardwareAccelerationShouldBeDisabled) { if (hardwareAccelerationShouldBeDisabled) {
disableHardwareAcceleration(); disableHardwareAcceleration();
} }
return undefined;
}, },
}; };
}, },

View File

@ -16,6 +16,8 @@ const setupImmerInjectable = getInjectable({
// Required in `utils/storage-helper.ts` // Required in `utils/storage-helper.ts`
Immer.setAutoFreeze(false); // allow to merge mobx observables Immer.setAutoFreeze(false); // allow to merge mobx observables
Immer.enableMapSet(); // allow to merge maps and sets Immer.enableMapSet(); // allow to merge maps and sets
return undefined;
}, },
}), }),

View File

@ -21,6 +21,8 @@ const setupMobxInjectable = getInjectable({
// reactionRequiresObservable: true, // reactionRequiresObservable: true,
// observableRequiresReaction: true, // observableRequiresReaction: true,
}); });
return undefined;
}, },
}), }),

View File

@ -34,6 +34,8 @@ const setupProxyEnvInjectable = getInjectable({
if (getCommandLineSwitch("proxy-server") !== "") { if (getCommandLineSwitch("proxy-server") !== "") {
process.env.HTTPS_PROXY = getCommandLineSwitch("proxy-server"); process.env.HTTPS_PROXY = getCommandLineSwitch("proxy-server");
} }
return undefined;
}, },
}; };
}, },

View File

@ -16,13 +16,13 @@ const stopClusterManagerInjectable = getInjectable({
id: "stop-cluster-manager", id: "stop-cluster-manager",
run: () => { run: () => {
clusterManager.stop(); clusterManager.stop();
return undefined;
}, },
}; };
}, },
injectionToken: beforeQuitOfFrontEndInjectionToken, injectionToken: beforeQuitOfFrontEndInjectionToken,
causesSideEffects: true,
}); });
export default stopClusterManagerInjectable; export default stopClusterManagerInjectable;

View File

@ -14,9 +14,7 @@ const stopBroadcastingThemeChangeInjectable = getInjectable({
return { return {
id: "stop-broadcasting-theme-change", id: "stop-broadcasting-theme-change",
run: async () => { run: () => void broadcastThemeChange.stop(),
await broadcastThemeChange.stop();
},
}; };
}, },

View File

@ -14,9 +14,7 @@ const stopSyncingThemeFromOperatingSystemInjectable = getInjectable({
return { return {
id: "stop-syncing-theme-from-operating-system", id: "stop-syncing-theme-from-operating-system",
run: async () => { run: () => void syncTheme.stop(),
await syncTheme.stop();
},
}; };
}, },

View File

@ -15,10 +15,7 @@ const stopTrayInjectable = getInjectable({
return { return {
id: "stop-tray", id: "stop-tray",
run: () => { run: () => void electronTray.stop(),
electronTray.stop();
},
runAfter: di.inject(stopReactiveTrayMenuItemsInjectable), runAfter: di.inject(stopReactiveTrayMenuItemsInjectable),
}; };
}, },

View File

@ -14,9 +14,7 @@ const stopReactiveTrayMenuIconInjectable = getInjectable({
return { return {
id: "stop-reactive-tray-menu-icon", id: "stop-reactive-tray-menu-icon",
run: async () => { run: () => void reactiveTrayMenuIcon.stop(),
await reactiveTrayMenuIcon.stop();
},
}; };
}, },

View File

@ -19,10 +19,8 @@ const reactiveTrayMenuItemsInjectable = getInjectable({
return getStartableStoppable("reactive-tray-menu-items", () => return getStartableStoppable("reactive-tray-menu-items", () =>
reaction( reaction(
(): MinimalTrayMenuItem[] => reactiveItems.get().map(toNonReactiveItem), () => reactiveItems.get().map(toNonReactiveItem),
(nonReactiveItems) => electronTray.setMenuItems(nonReactiveItems), (nonReactiveItems) => electronTray.setMenuItems(nonReactiveItems),
{ {
fireImmediately: true, fireImmediately: true,
}, },

View File

@ -14,9 +14,7 @@ const stopReactiveTrayMenuItemsInjectable = getInjectable({
return { return {
id: "stop-reactive-tray-menu-items", id: "stop-reactive-tray-menu-items",
run: async () => { run: () => void reactiveTrayMenuItems.stop(),
await reactiveTrayMenuItems.stop();
},
}; };
}, },

View File

@ -16,9 +16,9 @@ const startListeningOnChannelsInjectable = getInjectable({
return { return {
id: "start-listening-on-channels-main", id: "start-listening-on-channels-main",
run: async () => { run: () => {
await listeningOnMessageChannels.start(); listeningOnMessageChannels.start();
await listeningOnRequestChannels.start(); listeningOnRequestChannels.start();
}, },
}; };
}, },