From d2485d47b9c7a3942605c8c051f0f528bfbd69af Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Tue, 24 Jan 2023 10:04:03 -0500 Subject: [PATCH] Move ClusterStore to new format Signed-off-by: Sebastian Malton --- .../common/__tests__/cluster-store.test.ts | 8 +- .../cluster-store/cluster-store.injectable.ts | 16 +--- .../src/common/cluster-store/cluster-store.ts | 92 +++++++++---------- .../main/handle-initial.injectable.ts | 2 +- packages/core/src/main/cluster/manager.ts | 18 ++-- .../setup-ipc-main-handlers.ts | 2 +- 6 files changed, 65 insertions(+), 73 deletions(-) diff --git a/packages/core/src/common/__tests__/cluster-store.test.ts b/packages/core/src/common/__tests__/cluster-store.test.ts index 5b052548a5..dc82998272 100644 --- a/packages/core/src/common/__tests__/cluster-store.test.ts +++ b/packages/core/src/common/__tests__/cluster-store.test.ts @@ -212,7 +212,7 @@ describe("cluster-store", () => { }); it("allows getting all of the clusters", async () => { - const storedClusters = clusterStore.clustersList; + const storedClusters = clusterStore.clustersList.get(); expect(storedClusters.length).toBe(3); expect(storedClusters[0].id).toBe("cluster1"); @@ -258,7 +258,7 @@ describe("cluster-store", () => { }); it("does not enable clusters with invalid kubeconfig", () => { - const storedClusters = clusterStore.clustersList; + const storedClusters = clusterStore.clustersList.get(); expect(storedClusters.length).toBe(1); }); @@ -295,13 +295,13 @@ describe("cluster-store", () => { }); it("migrates to modern format with kubeconfig in a file", async () => { - const configPath = clusterStore.clustersList[0].kubeConfigPath.get(); + const configPath = clusterStore.clustersList.get()[0].kubeConfigPath.get(); expect(readFileSync(configPath)).toBe(minimalValidKubeConfig); }); it("migrates to modern format with icon not in file", async () => { - expect(clusterStore.clustersList[0].preferences.icon).toMatch(/data:;base64,/); + expect(clusterStore.clustersList.get()[0].preferences.icon).toMatch(/data:;base64,/); }); }); }); diff --git a/packages/core/src/common/cluster-store/cluster-store.injectable.ts b/packages/core/src/common/cluster-store/cluster-store.injectable.ts index 79eb02e36c..8d15f12725 100644 --- a/packages/core/src/common/cluster-store/cluster-store.injectable.ts +++ b/packages/core/src/common/cluster-store/cluster-store.injectable.ts @@ -6,17 +6,11 @@ import { getInjectable } from "@ogre-tools/injectable"; import { ClusterStore } from "./cluster-store"; import readClusterConfigSyncInjectable from "./read-cluster-config.injectable"; import emitAppEventInjectable from "../app-event-bus/emit-event.injectable"; -import directoryForUserDataInjectable from "../app-paths/directory-for-user-data/directory-for-user-data.injectable"; -import getConfigurationFileModelInjectable from "../get-configuration-file-model/get-configuration-file-model.injectable"; import loggerInjectable from "../logger.injectable"; import storeMigrationVersionInjectable from "../vars/store-migration-version.injectable"; import storeMigrationsInjectable from "../base-store/migrations.injectable"; import { clusterStoreMigrationInjectionToken } from "./migration-token"; -import { baseStoreIpcChannelPrefixesInjectionToken } from "../base-store/channel-prefix"; -import { shouldBaseStoreDisableSyncInIpcListenerInjectionToken } from "../base-store/disable-sync"; -import { persistStateToConfigInjectionToken } from "../base-store/save-to-file"; -import getBasenameOfPathInjectable from "../path/get-basename.injectable"; -import { enlistMessageChannelListenerInjectionToken } from "@k8slens/messaging"; +import createBaseStoreInjectable from "../base-store/create-base-store.injectable"; const clusterStoreInjectable = getInjectable({ id: "cluster-store", @@ -24,16 +18,10 @@ const clusterStoreInjectable = getInjectable({ instantiate: (di) => new ClusterStore({ readClusterConfigSync: di.inject(readClusterConfigSyncInjectable), emitAppEvent: di.inject(emitAppEventInjectable), - directoryForUserData: di.inject(directoryForUserDataInjectable), - getConfigurationFileModel: di.inject(getConfigurationFileModelInjectable), logger: di.inject(loggerInjectable), storeMigrationVersion: di.inject(storeMigrationVersionInjectable), migrations: di.inject(storeMigrationsInjectable, clusterStoreMigrationInjectionToken), - getBasenameOfPath: di.inject(getBasenameOfPathInjectable), - ipcChannelPrefixes: di.inject(baseStoreIpcChannelPrefixesInjectionToken), - persistStateToConfig: di.inject(persistStateToConfigInjectionToken), - enlistMessageChannelListener: di.inject(enlistMessageChannelListenerInjectionToken), - shouldDisableSyncInListener: di.inject(shouldBaseStoreDisableSyncInIpcListenerInjectionToken), + createBaseStore: di.inject(createBaseStoreInjectable), }), }); diff --git a/packages/core/src/common/cluster-store/cluster-store.ts b/packages/core/src/common/cluster-store/cluster-store.ts index 8d283411c9..9b58c73152 100644 --- a/packages/core/src/common/cluster-store/cluster-store.ts +++ b/packages/core/src/common/cluster-store/cluster-store.ts @@ -4,46 +4,75 @@ */ -import { action, comparer, computed, makeObservable, observable } from "mobx"; -import type { BaseStoreDependencies } from "../base-store/base-store"; -import { BaseStore } from "../base-store/base-store"; +import { action, comparer, computed, observable } from "mobx"; +import type { BaseStore } from "../base-store/base-store"; import { Cluster } from "../cluster/cluster"; import { toJS } from "../utils"; import type { ClusterModel, ClusterId } from "../cluster-types"; import type { ReadClusterConfigSync } from "./read-cluster-config.injectable"; import type { EmitAppEvent } from "../app-event-bus/emit-event.injectable"; +import type { CreateBaseStore } from "../base-store/create-base-store.injectable"; +import type { Migrations } from "conf/dist/source/types"; +import type { Logger } from "../logger"; export interface ClusterStoreModel { clusters?: ClusterModel[]; } -interface Dependencies extends BaseStoreDependencies { +interface Dependencies { readClusterConfigSync: ReadClusterConfigSync; emitAppEvent: EmitAppEvent; + createBaseStore: CreateBaseStore; + readonly storeMigrationVersion: string; + readonly migrations: Migrations>; + readonly logger: Logger; } -export class ClusterStore extends BaseStore { +export class ClusterStore { readonly clusters = observable.map(); + private readonly store: BaseStore; constructor(protected readonly dependencies: Dependencies) { - super(dependencies, { + this.store = this.dependencies.createBaseStore({ configName: "lens-cluster-store", accessPropertiesByDotNotation: false, // To make dots safe in cluster context names syncOptions: { equals: comparer.structural, }, + projectVersion: this.dependencies.storeMigrationVersion, + migrations: this.dependencies.migrations as unknown as Migrations, + fromStore: action(({ clusters = [] }) => { + const currentClusters = new Map(this.clusters); + const newClusters = new Map(); + + // update new clusters + for (const clusterModel of clusters) { + try { + let cluster = currentClusters.get(clusterModel.id); + + if (cluster) { + cluster.updateModel(clusterModel); + } else { + cluster = new Cluster( + clusterModel, + this.dependencies.readClusterConfigSync(clusterModel), + ); + } + newClusters.set(clusterModel.id, cluster); + } catch (error) { + this.dependencies.logger.warn(`[CLUSTER-STORE]: Failed to update/create a cluster: ${error}`); + } + } + + this.clusters.replace(newClusters); + }), + toJSON: () => toJS({ + clusters: this.clustersList.get().map(cluster => cluster.toJSON()), + }), }); - - makeObservable(this); } - @computed get clustersList(): Cluster[] { - return Array.from(this.clusters.values()); - } - - @computed get connectedClustersList(): Cluster[] { - return this.clustersList.filter((c) => !c.disconnected); - } + readonly clustersList = computed(() => [...this.clusters.values()]); hasClusters() { return this.clusters.size > 0; @@ -72,36 +101,7 @@ export class ClusterStore extends BaseStore { return cluster; } - @action - protected fromStore({ clusters = [] }: ClusterStoreModel = {}) { - const currentClusters = new Map(this.clusters); - const newClusters = new Map(); - - // update new clusters - for (const clusterModel of clusters) { - try { - let cluster = currentClusters.get(clusterModel.id); - - if (cluster) { - cluster.updateModel(clusterModel); - } else { - cluster = new Cluster( - clusterModel, - this.dependencies.readClusterConfigSync(clusterModel), - ); - } - newClusters.set(clusterModel.id, cluster); - } catch (error) { - this.dependencies.logger.warn(`[CLUSTER-STORE]: Failed to update/create a cluster: ${error}`); - } - } - - this.clusters.replace(newClusters); - } - - toJSON(): ClusterStoreModel { - return toJS({ - clusters: this.clustersList.map(cluster => cluster.toJSON()), - }); + load() { + this.store.load(); } } diff --git a/packages/core/src/features/cluster/state-sync/main/handle-initial.injectable.ts b/packages/core/src/features/cluster/state-sync/main/handle-initial.injectable.ts index db65024973..ddfc240f0f 100644 --- a/packages/core/src/features/cluster/state-sync/main/handle-initial.injectable.ts +++ b/packages/core/src/features/cluster/state-sync/main/handle-initial.injectable.ts @@ -12,7 +12,7 @@ const handleInitialClusterStateSyncInjectable = getRequestChannelListenerInjecta getHandler: (di) => { const clusterStore = di.inject(clusterStoreInjectable); - return () => clusterStore.clustersList.map(cluster => ({ + return () => clusterStore.clustersList.get().map(cluster => ({ clusterId: cluster.id, state: cluster.getState(), })); diff --git a/packages/core/src/main/cluster/manager.ts b/packages/core/src/main/cluster/manager.ts index bc270b79f1..2277d8fced 100644 --- a/packages/core/src/main/cluster/manager.ts +++ b/packages/core/src/main/cluster/manager.ts @@ -42,15 +42,15 @@ export class ClusterManager { init = once(() => { // reacting to every cluster's state change and total amount of items reaction( - () => this.dependencies.store.clustersList.map(c => c.getState()), - () => this.updateCatalog(this.dependencies.store.clustersList), + () => this.dependencies.store.clustersList.get().map(c => c.getState()), + () => this.updateCatalog(this.dependencies.store.clustersList.get()), { fireImmediately: false }, ); // reacting to every cluster's preferences change and total amount of items reaction( - () => this.dependencies.store.clustersList.map(c => toJS(c.preferences)), - () => this.updateCatalog(this.dependencies.store.clustersList), + () => this.dependencies.store.clustersList.get().map(c => toJS(c.preferences)), + () => this.updateCatalog(this.dependencies.store.clustersList.get()), { fireImmediately: false }, ); @@ -208,7 +208,9 @@ export class ClusterManager { this.dependencies.logger.info(`${logPrefix} network is offline`); await Promise.allSettled( - this.dependencies.store.clustersList + this.dependencies.store + .clustersList + .get() .filter(cluster => !cluster.disconnected.get()) .map(async (cluster) => { cluster.online.set(false); @@ -225,7 +227,9 @@ export class ClusterManager { this.dependencies.logger.info(`${logPrefix} network is online`); await Promise.allSettled( - this.dependencies.store.clustersList + this.dependencies.store + .clustersList + .get() .filter(cluster => !cluster.disconnected.get()) .map((cluster) => ( this.dependencies @@ -236,7 +240,7 @@ export class ClusterManager { }; stop() { - for (const cluster of this.dependencies.store.clustersList) { + for (const cluster of this.dependencies.store.clustersList.get()) { this.dependencies .getClusterConnection(cluster) .disconnect(); diff --git a/packages/core/src/main/electron-app/runnables/setup-ipc-main-handlers/setup-ipc-main-handlers.ts b/packages/core/src/main/electron-app/runnables/setup-ipc-main-handlers/setup-ipc-main-handlers.ts index d5b85c440a..874b14747a 100644 --- a/packages/core/src/main/electron-app/runnables/setup-ipc-main-handlers/setup-ipc-main-handlers.ts +++ b/packages/core/src/main/electron-app/runnables/setup-ipc-main-handlers/setup-ipc-main-handlers.ts @@ -60,7 +60,7 @@ export const setupIpcMainHandlers = ({ }); ipcMainHandle(clusterStates, () => ( - clusterStore.clustersList.map(cluster => ({ + clusterStore.clustersList.get().map(cluster => ({ id: cluster.id, state: cluster.getState(), }))