Fixing Singleton typing to correctly return child class (#1914)

- Add distinction between `getInstance` and `getInstanceOrCreate` since
  it is not always possible to create an instance (since you might not
  know the correct arguments)

- Remove all the `export const *Store = *Store.getInstance<*Store>();`
  calls as it defeats the purpose of `Singleton`. Plus with the typing
  changes the appropriate `*Store.getInstance()` is "short enough".

- Special case the two extension export facades to not need to use
  `getInstanceOrCreate`. Plus since they are just facades it is always
  possible to create them.

- Move some other types to be also `Singleton`'s: ExtensionLoader,
  ExtensionDiscovery, ThemeStore, LocalizationStore, ...

- Fixed dev-run always using the same port with electron inspect

- Update Store documentation with new recommendations about creating
  instances of singletons

- Fix all unit tests to create their dependent singletons

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton authored and GitHub committed 2021-04-21 09:59:59 -04:00
1 parent b2a570ce28
commit 9563ead2e6
114 files changed
+924 -736

No files matched your search

+40 -34
View File
@@ -15,15 +15,15 @@ import { getFreePort } from "./port";
import { mangleProxyEnv } from "./proxy-env";
import { registerFileProtocol } from "../common/register-protocol";
import logger from "./logger";
import { clusterStore } from "../common/cluster-store";
import { userStore } from "../common/user-store";
import { ClusterStore } from "../common/cluster-store";
import { UserStore } from "../common/user-store";
import { appEventBus } from "../common/event-bus";
import { extensionLoader } from "../extensions/extension-loader";
import { extensionsStore } from "../extensions/extensions-store";
import { InstalledExtension, extensionDiscovery } from "../extensions/extension-discovery";
import { ExtensionLoader } from "../extensions/extension-loader";
import { ExtensionsStore } from "../extensions/extensions-store";
import { InstalledExtension, ExtensionDiscovery } from "../extensions/extension-discovery";
import type { LensExtensionId } from "../extensions/lens-extension";
import { FilesystemProvisionerStore } from "./extension-filesystem";
import { installDeveloperTools } from "./developer-tools";
import { filesystemProvisionerStore } from "./extension-filesystem";
import { LensProtocolRouterMain } from "./protocol-handler";
import { getAppVersion, getAppVersionFromProxyServer } from "../common/utils";
import { bindBroadcastHandlers } from "../common/ipc";
@@ -31,13 +31,9 @@ import { startUpdateChecking } from "./app-updater";
import { IpcRendererNavigationEvents } from "../renderer/navigation/events";
import { CatalogPusher } from "./catalog-pusher";
import { catalogEntityRegistry } from "../common/catalog-entity-registry";
import { hotbarStore } from "../common/hotbar-store";
import { HotbarStore } from "../common/hotbar-store";
const workingDir = path.join(app.getPath("appData"), appName);
let proxyPort: number;
let proxyServer: LensProxy;
let clusterManager: ClusterManager;
let windowManager: WindowManager;
app.setName(appName);
@@ -66,7 +62,7 @@ if (app.commandLine.getSwitchValue("proxy-server") !== "") {
if (!app.requestSingleInstanceLock()) {
app.exit();
} else {
const lprm = LensProtocolRouterMain.getInstance<LensProtocolRouterMain>();
const lprm = LensProtocolRouterMain.getInstanceOrCreate();
for (const arg of process.argv) {
if (arg.toLowerCase().startsWith("lens://")) {
@@ -77,7 +73,7 @@ if (!app.requestSingleInstanceLock()) {
}
app.on("second-instance", (event, argv) => {
const lprm = LensProtocolRouterMain.getInstance<LensProtocolRouterMain>();
const lprm = LensProtocolRouterMain.getInstanceOrCreate();
for (const arg of argv) {
if (arg.toLowerCase().startsWith("lens://")) {
@@ -86,7 +82,7 @@ app.on("second-instance", (event, argv) => {
}
}
windowManager?.ensureMainWindow();
WindowManager.getInstance(false)?.ensureMainWindow();
});
app.on("ready", async () => {
@@ -102,7 +98,11 @@ app.on("ready", async () => {
registerFileProtocol("static", __static);
await installDeveloperTools();
const userStore = UserStore.getInstanceOrCreate();
const clusterStore = ClusterStore.getInstanceOrCreate();
const hotbarStore = HotbarStore.getInstanceOrCreate();
const extensionsStore = ExtensionsStore.getInstanceOrCreate();
const filesystemStore = FilesystemProvisionerStore.getInstanceOrCreate();
logger.info("💾 Loading stores");
// preload
@@ -111,10 +111,12 @@ app.on("ready", async () => {
clusterStore.load(),
hotbarStore.load(),
extensionsStore.load(),
filesystemProvisionerStore.load(),
filesystemStore.load(),
]);
// find free port
let proxyPort;
try {
logger.info("🔑 Getting free port for LensProxy server");
proxyPort = await getFreePort();
@@ -125,13 +127,13 @@ app.on("ready", async () => {
}
// create cluster manager
clusterManager = ClusterManager.getInstance<ClusterManager>(proxyPort);
ClusterManager.getInstanceOrCreate(proxyPort);
// run proxy
try {
logger.info("🔌 Starting LensProxy");
// eslint-disable-next-line unused-imports/no-unused-vars-ts
proxyServer = LensProxy.create(proxyPort, clusterManager);
LensProxy.getInstanceOrCreate(proxyPort).listen();
} catch (error) {
logger.error(`Could not start proxy (127.0.0:${proxyPort}): ${error?.message}`);
dialog.showErrorBox("Lens Error", `Could not start proxy (127.0.0:${proxyPort}): ${error?.message || "unknown error"}`);
@@ -151,7 +153,9 @@ app.on("ready", async () => {
logger.error("Checking proxy server connection failed", error);
}
extensionLoader.init();
const extensionDiscovery = ExtensionDiscovery.getInstanceOrCreate();
ExtensionLoader.getInstanceOrCreate().init();
extensionDiscovery.init();
// Start the app without showing the main window when auto starting on login
@@ -159,7 +163,9 @@ app.on("ready", async () => {
const startHidden = process.argv.includes("--hidden") || (isMac && app.getLoginItemSettings().wasOpenedAsHidden);
logger.info("🖥️ Starting WindowManager");
windowManager = WindowManager.getInstance<WindowManager>(proxyPort);
const windowManager = WindowManager.getInstanceOrCreate(proxyPort);
installDeveloperTools();
if (!startHidden) {
windowManager.initMainWindow();
@@ -169,13 +175,13 @@ app.on("ready", async () => {
CatalogPusher.init(catalogEntityRegistry);
startUpdateChecking();
LensProtocolRouterMain
.getInstance<LensProtocolRouterMain>()
.getInstance()
.rendererLoaded = true;
});
extensionLoader.whenLoaded.then(() => {
ExtensionLoader.getInstance().whenLoaded.then(() => {
LensProtocolRouterMain
.getInstance<LensProtocolRouterMain>()
.getInstance()
.extensionsLoaded = true;
});
@@ -189,14 +195,15 @@ app.on("ready", async () => {
extensionDiscovery.watchExtensions();
// Subscribe to extensions that are copied or deleted to/from the extensions folder
extensionDiscovery.events.on("add", (extension: InstalledExtension) => {
extensionLoader.addExtension(extension);
});
extensionDiscovery.events.on("remove", (lensExtensionId: LensExtensionId) => {
extensionLoader.removeExtension(lensExtensionId);
});
extensionDiscovery.events
.on("add", (extension: InstalledExtension) => {
ExtensionLoader.getInstance().addExtension(extension);
})
.on("remove", (lensExtensionId: LensExtensionId) => {
ExtensionLoader.getInstance().removeExtension(lensExtensionId);
});
extensionLoader.initExtensions(extensions);
ExtensionLoader.getInstance().initExtensions(extensions);
} catch (error) {
dialog.showErrorBox("Lens Error", `Could not load extensions${error?.message ? `: ${error.message}` : ""}`);
console.error(error);
@@ -212,7 +219,7 @@ app.on("activate", (event, hasVisibleWindows) => {
logger.info("APP:ACTIVATE", { hasVisibleWindows });
if (!hasVisibleWindows) {
windowManager?.initMainWindow(false);
WindowManager.getInstance(false)?.initMainWindow(false);
}
});
@@ -227,8 +234,7 @@ app.on("will-quit", (event) => {
// Quit app on Cmd+Q (MacOS)
logger.info("APP:QUIT");
appEventBus.emit({name: "app", action: "close"});
clusterManager?.stop(); // close cluster connections
ClusterManager.getInstance(false)?.stop(); // close cluster connections
if (blockQuit) {
event.preventDefault(); // prevent app's default shutdown (e.g. required for telemetry, etc.)
@@ -242,7 +248,7 @@ app.on("open-url", (event, rawUrl) => {
event.preventDefault();
LensProtocolRouterMain
.getInstance<LensProtocolRouterMain>()
.getInstance()
.route(rawUrl)
.catch(error => logger.error(`${LensProtocolRouterMain.LoggingPrefix}: an error occured`, { error, rawUrl }));
});