mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Clean up impl and rename to better describe intent
Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
parent
4074d5925d
commit
dbb9a0f5a8
@ -1,148 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import type Config from "conf";
|
|
||||||
import type { Migrations, Options as ConfOptions } from "conf/dist/source/types";
|
|
||||||
import type { IEqualsComparer } from "mobx";
|
|
||||||
import { reaction } from "mobx";
|
|
||||||
import { disposer, isPromiseLike } from "@k8slens/utilities";
|
|
||||||
import { broadcastMessage } from "../ipc";
|
|
||||||
import isEqual from "lodash/isEqual";
|
|
||||||
import { kebabCase } from "lodash";
|
|
||||||
import type { GetConfigurationFileModel } from "../get-configuration-file-model/get-configuration-file-model.injectable";
|
|
||||||
import type { Logger } from "../logger";
|
|
||||||
import type { PersistStateToConfig } from "./save-to-file";
|
|
||||||
import type { GetBasenameOfPath } from "../path/get-basename.injectable";
|
|
||||||
import type { EnlistMessageChannelListener } from "@k8slens/messaging";
|
|
||||||
import { toJS } from "../utils";
|
|
||||||
|
|
||||||
export interface BaseStoreParams<T> extends Omit<ConfOptions<T>, "migrations"> {
|
|
||||||
syncOptions?: {
|
|
||||||
fireImmediately?: boolean;
|
|
||||||
equals?: IEqualsComparer<T>;
|
|
||||||
};
|
|
||||||
readonly configName: string;
|
|
||||||
|
|
||||||
migrations?: Migrations<Record<string, unknown>>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fromStore is called internally when a child class syncs with the file
|
|
||||||
* system.
|
|
||||||
*
|
|
||||||
* Note: This function **must** be synchronous.
|
|
||||||
*
|
|
||||||
* @param data the parsed information read from the stored JSON file
|
|
||||||
*/
|
|
||||||
fromStore(data: Partial<T>): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* toJSON is called when syncing the store to the filesystem. It should
|
|
||||||
* produce a JSON serializable object representation of the current state.
|
|
||||||
*
|
|
||||||
* It is recommended that a round trip is valid. Namely, calling
|
|
||||||
* `this.fromStore(this.toJSON())` shouldn't change the state.
|
|
||||||
*/
|
|
||||||
toJSON(): T;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IpcChannelPrefixes {
|
|
||||||
local: string;
|
|
||||||
remote: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface BaseStoreDependencies {
|
|
||||||
readonly logger: Logger;
|
|
||||||
readonly directoryForUserData: string;
|
|
||||||
readonly ipcChannelPrefixes: IpcChannelPrefixes;
|
|
||||||
readonly shouldDisableSyncInListener: boolean;
|
|
||||||
getConfigurationFileModel: GetConfigurationFileModel;
|
|
||||||
persistStateToConfig: PersistStateToConfig;
|
|
||||||
getBasenameOfPath: GetBasenameOfPath;
|
|
||||||
enlistMessageChannelListener: EnlistMessageChannelListener;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Note: T should only contain base JSON serializable types.
|
|
||||||
*/
|
|
||||||
export class BaseStore<T extends object> {
|
|
||||||
private readonly syncDisposers = disposer();
|
|
||||||
|
|
||||||
readonly displayName = kebabCase(this.params.configName).toUpperCase();
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
protected readonly dependencies: BaseStoreDependencies,
|
|
||||||
protected readonly params: BaseStoreParams<T>,
|
|
||||||
) {
|
|
||||||
this.dependencies = dependencies;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This must be called after the last child's constructor is finished (or just before it finishes)
|
|
||||||
*/
|
|
||||||
load() {
|
|
||||||
this.dependencies.logger.info(`[${this.displayName}]: LOADING ...`);
|
|
||||||
|
|
||||||
const config = this.dependencies.getConfigurationFileModel({
|
|
||||||
projectName: "lens",
|
|
||||||
cwd: this.cwd(),
|
|
||||||
...this.params as ConfOptions<T>,
|
|
||||||
});
|
|
||||||
|
|
||||||
const res = this.params.fromStore(config.store);
|
|
||||||
|
|
||||||
if (isPromiseLike(res)) {
|
|
||||||
this.dependencies.logger.error(`${this.displayName} extends BaseStore<T>'s fromStore method returns a Promise or promise-like object. This is an error and must be fixed.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.startSyncing(config);
|
|
||||||
this.dependencies.logger.info(`[${this.displayName}]: LOADED from ${config.path}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected cwd() {
|
|
||||||
return this.dependencies.directoryForUserData;
|
|
||||||
}
|
|
||||||
|
|
||||||
private startSyncing(config: Config<T>) {
|
|
||||||
const name = this.dependencies.getBasenameOfPath(config.path);
|
|
||||||
|
|
||||||
const disableSync = () => this.syncDisposers();
|
|
||||||
const enableSync = () => {
|
|
||||||
this.syncDisposers.push(
|
|
||||||
reaction(
|
|
||||||
() => toJS(this.params.toJSON()), // unwrap possible observables and react to everything
|
|
||||||
model => {
|
|
||||||
this.dependencies.persistStateToConfig(config, model);
|
|
||||||
broadcastMessage(`${this.dependencies.ipcChannelPrefixes.remote}:${config.path}`, model);
|
|
||||||
},
|
|
||||||
this.params.syncOptions,
|
|
||||||
),
|
|
||||||
this.dependencies.enlistMessageChannelListener<T>({
|
|
||||||
id: this.displayName,
|
|
||||||
channel: {
|
|
||||||
id: `${this.dependencies.ipcChannelPrefixes.local}:${config.path}`,
|
|
||||||
},
|
|
||||||
handler: (model) => {
|
|
||||||
this.dependencies.logger.silly(`[${this.displayName}]: syncing ${name}`, { model });
|
|
||||||
|
|
||||||
if (this.dependencies.shouldDisableSyncInListener) {
|
|
||||||
disableSync();
|
|
||||||
}
|
|
||||||
|
|
||||||
// todo: use "resourceVersion" if merge required (to avoid equality checks => better performance)
|
|
||||||
if (!isEqual(this.params.toJSON(), model)) {
|
|
||||||
this.params.fromStore(model);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.dependencies.shouldDisableSyncInListener) {
|
|
||||||
enableSync();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
enableSync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { getInjectionToken } from "@ogre-tools/injectable";
|
|
||||||
import type { IpcChannelPrefixes } from "./base-store";
|
|
||||||
|
|
||||||
export const baseStoreIpcChannelPrefixesInjectionToken = getInjectionToken<IpcChannelPrefixes>({
|
|
||||||
id: "base-store-ipc-channel-prefix-token",
|
|
||||||
});
|
|
||||||
@ -1,37 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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 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 getBasenameOfPathInjectable from "../path/get-basename.injectable";
|
|
||||||
import { enlistMessageChannelListenerInjectionToken } from "@k8slens/messaging";
|
|
||||||
import type { BaseStoreDependencies, BaseStoreParams } from "./base-store";
|
|
||||||
import { BaseStore } from "./base-store";
|
|
||||||
import { baseStoreIpcChannelPrefixesInjectionToken } from "./channel-prefix";
|
|
||||||
import { shouldBaseStoreDisableSyncInIpcListenerInjectionToken } from "./disable-sync";
|
|
||||||
import { persistStateToConfigInjectionToken } from "./save-to-file";
|
|
||||||
|
|
||||||
export type CreateBaseStore = <T extends object>(params: BaseStoreParams<T>) => BaseStore<T>;
|
|
||||||
|
|
||||||
const createBaseStoreInjectable = getInjectable({
|
|
||||||
id: "create-base-store",
|
|
||||||
instantiate: (di): CreateBaseStore => {
|
|
||||||
const deps: BaseStoreDependencies = {
|
|
||||||
directoryForUserData: di.inject(directoryForUserDataInjectable),
|
|
||||||
getConfigurationFileModel: di.inject(getConfigurationFileModelInjectable),
|
|
||||||
logger: di.inject(loggerInjectable),
|
|
||||||
getBasenameOfPath: di.inject(getBasenameOfPathInjectable),
|
|
||||||
ipcChannelPrefixes: di.inject(baseStoreIpcChannelPrefixesInjectionToken),
|
|
||||||
persistStateToConfig: di.inject(persistStateToConfigInjectionToken),
|
|
||||||
enlistMessageChannelListener: di.inject(enlistMessageChannelListenerInjectionToken),
|
|
||||||
shouldDisableSyncInListener: di.inject(shouldBaseStoreDisableSyncInIpcListenerInjectionToken),
|
|
||||||
};
|
|
||||||
|
|
||||||
return (params) => new BaseStore(deps, params);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default createBaseStoreInjectable;
|
|
||||||
@ -8,9 +8,9 @@ import readClusterConfigSyncInjectable from "./read-cluster-config.injectable";
|
|||||||
import emitAppEventInjectable from "../app-event-bus/emit-event.injectable";
|
import emitAppEventInjectable from "../app-event-bus/emit-event.injectable";
|
||||||
import loggerInjectable from "../logger.injectable";
|
import loggerInjectable from "../logger.injectable";
|
||||||
import storeMigrationVersionInjectable from "../vars/store-migration-version.injectable";
|
import storeMigrationVersionInjectable from "../vars/store-migration-version.injectable";
|
||||||
import storeMigrationsInjectable from "../base-store/migrations.injectable";
|
import persistentStorageMigrationsInjectable from "../persistent-storage/migrations.injectable";
|
||||||
import { clusterStoreMigrationInjectionToken } from "./migration-token";
|
import { clusterStoreMigrationInjectionToken } from "./migration-token";
|
||||||
import createBaseStoreInjectable from "../base-store/create-base-store.injectable";
|
import createPersistentStorageInjectable from "../persistent-storage/create.injectable";
|
||||||
|
|
||||||
const clusterStoreInjectable = getInjectable({
|
const clusterStoreInjectable = getInjectable({
|
||||||
id: "cluster-store",
|
id: "cluster-store",
|
||||||
@ -20,8 +20,8 @@ const clusterStoreInjectable = getInjectable({
|
|||||||
emitAppEvent: di.inject(emitAppEventInjectable),
|
emitAppEvent: di.inject(emitAppEventInjectable),
|
||||||
logger: di.inject(loggerInjectable),
|
logger: di.inject(loggerInjectable),
|
||||||
storeMigrationVersion: di.inject(storeMigrationVersionInjectable),
|
storeMigrationVersion: di.inject(storeMigrationVersionInjectable),
|
||||||
migrations: di.inject(storeMigrationsInjectable, clusterStoreMigrationInjectionToken),
|
migrations: di.inject(persistentStorageMigrationsInjectable, clusterStoreMigrationInjectionToken),
|
||||||
createBaseStore: di.inject(createBaseStoreInjectable),
|
createPersistentStorage: di.inject(createPersistentStorageInjectable),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -5,13 +5,13 @@
|
|||||||
|
|
||||||
|
|
||||||
import { action, comparer, computed, observable } from "mobx";
|
import { action, comparer, computed, observable } from "mobx";
|
||||||
import type { BaseStore } from "../base-store/base-store";
|
import type { BaseStore } from "../persistent-storage/base-store";
|
||||||
import { Cluster } from "../cluster/cluster";
|
import { Cluster } from "../cluster/cluster";
|
||||||
import { toJS } from "../utils";
|
import { toJS } from "../utils";
|
||||||
import type { ClusterModel, ClusterId } from "../cluster-types";
|
import type { ClusterModel, ClusterId } from "../cluster-types";
|
||||||
import type { ReadClusterConfigSync } from "./read-cluster-config.injectable";
|
import type { ReadClusterConfigSync } from "./read-cluster-config.injectable";
|
||||||
import type { EmitAppEvent } from "../app-event-bus/emit-event.injectable";
|
import type { EmitAppEvent } from "../app-event-bus/emit-event.injectable";
|
||||||
import type { CreateBaseStore } from "../base-store/create-base-store.injectable";
|
import type { CreatePersistentStorage } from "../persistent-storage/create.injectable";
|
||||||
import type { Migrations } from "conf/dist/source/types";
|
import type { Migrations } from "conf/dist/source/types";
|
||||||
import type { Logger } from "../logger";
|
import type { Logger } from "../logger";
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ export interface ClusterStoreModel {
|
|||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
readClusterConfigSync: ReadClusterConfigSync;
|
readClusterConfigSync: ReadClusterConfigSync;
|
||||||
emitAppEvent: EmitAppEvent;
|
emitAppEvent: EmitAppEvent;
|
||||||
createBaseStore: CreateBaseStore;
|
createPersistentStorage: CreatePersistentStorage;
|
||||||
readonly storeMigrationVersion: string;
|
readonly storeMigrationVersion: string;
|
||||||
readonly migrations: Migrations<Record<string, unknown>>;
|
readonly migrations: Migrations<Record<string, unknown>>;
|
||||||
readonly logger: Logger;
|
readonly logger: Logger;
|
||||||
@ -33,7 +33,7 @@ export class ClusterStore {
|
|||||||
private readonly store: BaseStore<ClusterStoreModel>;
|
private readonly store: BaseStore<ClusterStoreModel>;
|
||||||
|
|
||||||
constructor(protected readonly dependencies: Dependencies) {
|
constructor(protected readonly dependencies: Dependencies) {
|
||||||
this.store = this.dependencies.createBaseStore({
|
this.store = this.dependencies.createPersistentStorage({
|
||||||
configName: "lens-cluster-store",
|
configName: "lens-cluster-store",
|
||||||
accessPropertiesByDotNotation: false, // To make dots safe in cluster context names
|
accessPropertiesByDotNotation: false, // To make dots safe in cluster context names
|
||||||
syncOptions: {
|
syncOptions: {
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { getInjectionToken } from "@ogre-tools/injectable";
|
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||||
import type { MigrationDeclaration } from "../base-store/migrations.injectable";
|
import type { MigrationDeclaration } from "../persistent-storage/migrations.injectable";
|
||||||
|
|
||||||
export const clusterStoreMigrationInjectionToken = getInjectionToken<MigrationDeclaration>({
|
export const clusterStoreMigrationInjectionToken = getInjectionToken<MigrationDeclaration>({
|
||||||
id: "cluster-store-migration",
|
id: "cluster-store-migration",
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { getInjectionToken } from "@ogre-tools/injectable";
|
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||||
import type { MigrationDeclaration } from "../base-store/migrations.injectable";
|
import type { MigrationDeclaration } from "../persistent-storage/migrations.injectable";
|
||||||
|
|
||||||
export const hotbarStoreMigrationInjectionToken = getInjectionToken<MigrationDeclaration>({
|
export const hotbarStoreMigrationInjectionToken = getInjectionToken<MigrationDeclaration>({
|
||||||
id: "hotbar-store-migration-token",
|
id: "hotbar-store-migration-token",
|
||||||
|
|||||||
@ -6,9 +6,9 @@ import { getInjectable } from "@ogre-tools/injectable";
|
|||||||
import catalogCatalogEntityInjectable from "../catalog-entities/general-catalog-entities/implementations/catalog-catalog-entity.injectable";
|
import catalogCatalogEntityInjectable from "../catalog-entities/general-catalog-entities/implementations/catalog-catalog-entity.injectable";
|
||||||
import { HotbarStore } from "./store";
|
import { HotbarStore } from "./store";
|
||||||
import loggerInjectable from "../logger.injectable";
|
import loggerInjectable from "../logger.injectable";
|
||||||
import storeMigrationsInjectable from "../base-store/migrations.injectable";
|
import persistentStorageMigrationsInjectable from "../persistent-storage/migrations.injectable";
|
||||||
import { hotbarStoreMigrationInjectionToken } from "./migrations-token";
|
import { hotbarStoreMigrationInjectionToken } from "./migrations-token";
|
||||||
import createBaseStoreInjectable from "../base-store/create-base-store.injectable";
|
import createPersistentStorageInjectable from "../persistent-storage/create.injectable";
|
||||||
import storeMigrationVersionInjectable from "../vars/store-migration-version.injectable";
|
import storeMigrationVersionInjectable from "../vars/store-migration-version.injectable";
|
||||||
|
|
||||||
const hotbarStoreInjectable = getInjectable({
|
const hotbarStoreInjectable = getInjectable({
|
||||||
@ -18,8 +18,8 @@ const hotbarStoreInjectable = getInjectable({
|
|||||||
catalogCatalogEntity: di.inject(catalogCatalogEntityInjectable),
|
catalogCatalogEntity: di.inject(catalogCatalogEntityInjectable),
|
||||||
logger: di.inject(loggerInjectable),
|
logger: di.inject(loggerInjectable),
|
||||||
storeMigrationVersion: di.inject(storeMigrationVersionInjectable),
|
storeMigrationVersion: di.inject(storeMigrationVersionInjectable),
|
||||||
migrations: di.inject(storeMigrationsInjectable, hotbarStoreMigrationInjectionToken),
|
migrations: di.inject(persistentStorageMigrationsInjectable, hotbarStoreMigrationInjectionToken),
|
||||||
createBaseStore: di.inject(createBaseStoreInjectable),
|
createPersistentStorage: di.inject(createPersistentStorageInjectable),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import type { IObservableValue } from "mobx";
|
import type { IObservableValue } from "mobx";
|
||||||
import { runInAction, action, comparer, observable } from "mobx";
|
import { runInAction, action, comparer, observable } from "mobx";
|
||||||
import type { BaseStore } from "../base-store/base-store";
|
import type { BaseStore } from "../persistent-storage/base-store";
|
||||||
import type { CatalogEntity } from "../catalog";
|
import type { CatalogEntity } from "../catalog";
|
||||||
import { broadcastMessage } from "../ipc";
|
import { broadcastMessage } from "../ipc";
|
||||||
import type { Hotbar, CreateHotbarData, CreateHotbarOptions } from "./types";
|
import type { Hotbar, CreateHotbarData, CreateHotbarOptions } from "./types";
|
||||||
@ -16,7 +16,7 @@ import type { Logger } from "../logger";
|
|||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import { getShortName } from "../catalog/helpers";
|
import { getShortName } from "../catalog/helpers";
|
||||||
import type { Migrations } from "conf/dist/source/types";
|
import type { Migrations } from "conf/dist/source/types";
|
||||||
import type { CreateBaseStore } from "../base-store/create-base-store.injectable";
|
import type { CreatePersistentStorage } from "../persistent-storage/create.injectable";
|
||||||
|
|
||||||
export interface HotbarStoreModel {
|
export interface HotbarStoreModel {
|
||||||
hotbars: Hotbar[];
|
hotbars: Hotbar[];
|
||||||
@ -28,7 +28,7 @@ interface Dependencies {
|
|||||||
readonly logger: Logger;
|
readonly logger: Logger;
|
||||||
readonly storeMigrationVersion: string;
|
readonly storeMigrationVersion: string;
|
||||||
readonly migrations: Migrations<Record<string, unknown>>;
|
readonly migrations: Migrations<Record<string, unknown>>;
|
||||||
createBaseStore: CreateBaseStore;
|
createPersistentStorage: CreatePersistentStorage;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class HotbarStore {
|
export class HotbarStore {
|
||||||
@ -39,7 +39,7 @@ export class HotbarStore {
|
|||||||
readonly activeHotbarId = observable.box() as IObservableValue<string>;
|
readonly activeHotbarId = observable.box() as IObservableValue<string>;
|
||||||
|
|
||||||
constructor(protected readonly dependencies: Dependencies) {
|
constructor(protected readonly dependencies: Dependencies) {
|
||||||
this.store = this.dependencies.createBaseStore({
|
this.store = this.dependencies.createPersistentStorage({
|
||||||
configName: "lens-hotbar-store",
|
configName: "lens-hotbar-store",
|
||||||
accessPropertiesByDotNotation: false, // To make dots safe in cluster context names
|
accessPropertiesByDotNotation: false, // To make dots safe in cluster context names
|
||||||
syncOptions: {
|
syncOptions: {
|
||||||
|
|||||||
@ -0,0 +1,15 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||||
|
|
||||||
|
export interface IpcChannelPrefixes {
|
||||||
|
readonly local: string;
|
||||||
|
readonly remote: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const persistentStorageIpcChannelPrefixesInjectionToken = getInjectionToken<IpcChannelPrefixes>({
|
||||||
|
id: "persistent-storage-ipc-channel-prefix-token",
|
||||||
|
});
|
||||||
158
packages/core/src/common/persistent-storage/create.injectable.ts
Normal file
158
packages/core/src/common/persistent-storage/create.injectable.ts
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { disposer, isPromiseLike } from "@k8slens/utilities";
|
||||||
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import type Conf from "conf/dist/source";
|
||||||
|
import type { Options } from "conf/dist/source";
|
||||||
|
import type { Migrations } from "conf/dist/source/types";
|
||||||
|
import { isEqual, kebabCase } from "lodash";
|
||||||
|
import type { IEqualsComparer } from "mobx";
|
||||||
|
import { reaction } from "mobx";
|
||||||
|
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 getBasenameOfPathInjectable from "../path/get-basename.injectable";
|
||||||
|
import { toJS } from "../utils";
|
||||||
|
import { enlistMessageChannelListenerInjectionToken, sendMessageToChannelInjectionToken } from "@k8slens/messaging";
|
||||||
|
import type { MessageChannel } from "@k8slens/messaging";
|
||||||
|
import { persistentStorageIpcChannelPrefixesInjectionToken } from "./channel-prefix";
|
||||||
|
import { shouldPersistentStorageDisableSyncInIpcListenerInjectionToken } from "./disable-sync";
|
||||||
|
import { persistStateToConfigInjectionToken } from "./save-to-file";
|
||||||
|
|
||||||
|
export interface PersistentStorage {
|
||||||
|
loadAndStartSyncing: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PersistentStorageParams<T extends object> extends Omit<Options<T>, "migrations"> {
|
||||||
|
syncOptions?: {
|
||||||
|
fireImmediately?: boolean;
|
||||||
|
equals?: IEqualsComparer<T>;
|
||||||
|
};
|
||||||
|
readonly configName: string;
|
||||||
|
readonly cwd: string;
|
||||||
|
|
||||||
|
migrations?: Migrations<Record<string, unknown>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fromStore is called internally when a child class syncs with the file
|
||||||
|
* system.
|
||||||
|
*
|
||||||
|
* Note: This function **must** be synchronous.
|
||||||
|
*
|
||||||
|
* @param data the parsed information read from the stored JSON file
|
||||||
|
*/
|
||||||
|
fromStore(data: Partial<T>): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* toJSON is called when syncing the store to the filesystem. It should
|
||||||
|
* produce a JSON serializable object representation of the current state.
|
||||||
|
*
|
||||||
|
* It is recommended that a round trip is valid. Namely, calling
|
||||||
|
* `this.fromStore(this.toJSON())` shouldn't change the state.
|
||||||
|
*/
|
||||||
|
toJSON(): T;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CreatePersistentStorage = <T extends object>(params: PersistentStorageParams<T>) => PersistentStorage;
|
||||||
|
|
||||||
|
const createPersistentStorageInjectable = getInjectable({
|
||||||
|
id: "create-persistent-storage",
|
||||||
|
instantiate: (di): CreatePersistentStorage => {
|
||||||
|
const directoryForUserData = di.inject(directoryForUserDataInjectable);
|
||||||
|
const getConfigurationFileModel = di.inject(getConfigurationFileModelInjectable);
|
||||||
|
const logger = di.inject(loggerInjectable);
|
||||||
|
const getBasenameOfPath = di.inject(getBasenameOfPathInjectable);
|
||||||
|
const ipcChannelPrefixes = di.inject(persistentStorageIpcChannelPrefixesInjectionToken);
|
||||||
|
const persistStateToConfig = di.inject(persistStateToConfigInjectionToken);
|
||||||
|
const enlistMessageChannelListener = di.inject(enlistMessageChannelListenerInjectionToken);
|
||||||
|
const shouldDisableSyncInListener = di.inject(shouldPersistentStorageDisableSyncInIpcListenerInjectionToken);
|
||||||
|
const sendMessageToChannel = di.inject(sendMessageToChannelInjectionToken);
|
||||||
|
|
||||||
|
return <T extends object>(rawParams: PersistentStorageParams<T>) => {
|
||||||
|
const {
|
||||||
|
fromStore,
|
||||||
|
toJSON,
|
||||||
|
syncOptions,
|
||||||
|
migrations,
|
||||||
|
cwd = directoryForUserData,
|
||||||
|
...params
|
||||||
|
} = rawParams;
|
||||||
|
const displayName = kebabCase(params.configName).toUpperCase();
|
||||||
|
const syncDisposers = disposer();
|
||||||
|
|
||||||
|
const loadAndStartSyncing = () => {
|
||||||
|
logger.info(`[${displayName}]: LOADING ...`);
|
||||||
|
|
||||||
|
const config = getConfigurationFileModel({
|
||||||
|
projectName: "lens",
|
||||||
|
cwd,
|
||||||
|
migrations: migrations as Migrations<T>,
|
||||||
|
...params,
|
||||||
|
});
|
||||||
|
|
||||||
|
const res = fromStore(config.store);
|
||||||
|
|
||||||
|
if (isPromiseLike(res)) {
|
||||||
|
logger.error(`${displayName} extends BaseStore<T>'s fromStore method returns a Promise or promise-like object. This is an error and must be fixed.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
startSyncing(config);
|
||||||
|
logger.info(`[${displayName}]: LOADED from ${config.path}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
const startSyncing = (config: Conf<T>) => {
|
||||||
|
const sendChannel: MessageChannel<T> = {
|
||||||
|
id: `${ipcChannelPrefixes.remote}:${config.path}`,
|
||||||
|
};
|
||||||
|
const receiveChannel: MessageChannel<T> = {
|
||||||
|
id: `${ipcChannelPrefixes.local}:${config.path}`,
|
||||||
|
};
|
||||||
|
const name = getBasenameOfPath(config.path);
|
||||||
|
|
||||||
|
const disableSync = () => syncDisposers();
|
||||||
|
const enableSync = () => {
|
||||||
|
syncDisposers.push(
|
||||||
|
reaction(
|
||||||
|
() => toJS(toJSON()), // unwrap possible observables and react to everything
|
||||||
|
model => {
|
||||||
|
persistStateToConfig(config, model);
|
||||||
|
sendMessageToChannel(sendChannel, model);
|
||||||
|
},
|
||||||
|
syncOptions,
|
||||||
|
),
|
||||||
|
enlistMessageChannelListener({
|
||||||
|
id: "persistent-storage-sync",
|
||||||
|
channel: receiveChannel,
|
||||||
|
handler: (model) => {
|
||||||
|
logger.silly(`[${displayName}]: syncing ${name}`, { model });
|
||||||
|
|
||||||
|
if (shouldDisableSyncInListener) {
|
||||||
|
disableSync();
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: use "resourceVersion" if merge required (to avoid equality checks => better performance)
|
||||||
|
if (!isEqual(toJSON(), model)) {
|
||||||
|
fromStore(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldDisableSyncInListener) {
|
||||||
|
enableSync();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
enableSync();
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
loadAndStartSyncing,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default createPersistentStorageInjectable;
|
||||||
@ -5,6 +5,6 @@
|
|||||||
|
|
||||||
import { getInjectionToken } from "@ogre-tools/injectable";
|
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||||
|
|
||||||
export const shouldBaseStoreDisableSyncInIpcListenerInjectionToken = getInjectionToken<boolean>({
|
export const shouldPersistentStorageDisableSyncInIpcListenerInjectionToken = getInjectionToken<boolean>({
|
||||||
id: "should-base-store-disable-sync-in-ipc-listener-token",
|
id: "should-persistent-storage-disable-sync-in-ipc-listener-token",
|
||||||
});
|
});
|
||||||
@ -14,8 +14,8 @@ export interface MigrationDeclaration {
|
|||||||
run(store: Conf<Partial<Record<string, unknown>>>): void;
|
run(store: Conf<Partial<Record<string, unknown>>>): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const storeMigrationsInjectable = getInjectable({
|
const persistentStorageMigrationsInjectable = getInjectable({
|
||||||
id: "store-migrations",
|
id: "persistent-storage-migrations",
|
||||||
instantiate: (di, token): Migrations<Record<string, unknown>> => {
|
instantiate: (di, token): Migrations<Record<string, unknown>> => {
|
||||||
const logger = di.inject(loggerInjectable);
|
const logger = di.inject(loggerInjectable);
|
||||||
const declarations = di.injectMany(token);
|
const declarations = di.injectMany(token);
|
||||||
@ -43,4 +43,4 @@ const storeMigrationsInjectable = getInjectable({
|
|||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default storeMigrationsInjectable;
|
export default persistentStorageMigrationsInjectable;
|
||||||
@ -4,7 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { getInjectionToken } from "@ogre-tools/injectable";
|
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||||
import type { MigrationDeclaration } from "../base-store/migrations.injectable";
|
import type { MigrationDeclaration } from "../persistent-storage/migrations.injectable";
|
||||||
|
|
||||||
export const userStoreMigrationInjectionToken = getInjectionToken<MigrationDeclaration>({
|
export const userStoreMigrationInjectionToken = getInjectionToken<MigrationDeclaration>({
|
||||||
id: "user-store-migration-token",
|
id: "user-store-migration-token",
|
||||||
|
|||||||
@ -8,10 +8,10 @@ import selectedUpdateChannelInjectable from "../../features/application-update/c
|
|||||||
import emitAppEventInjectable from "../app-event-bus/emit-event.injectable";
|
import emitAppEventInjectable from "../app-event-bus/emit-event.injectable";
|
||||||
import loggerInjectable from "../logger.injectable";
|
import loggerInjectable from "../logger.injectable";
|
||||||
import storeMigrationVersionInjectable from "../vars/store-migration-version.injectable";
|
import storeMigrationVersionInjectable from "../vars/store-migration-version.injectable";
|
||||||
import storeMigrationsInjectable from "../base-store/migrations.injectable";
|
import persistentStorageMigrationsInjectable from "../persistent-storage/migrations.injectable";
|
||||||
import { userStoreMigrationInjectionToken } from "./migrations-token";
|
import { userStoreMigrationInjectionToken } from "./migrations-token";
|
||||||
import userStorePreferenceDescriptorsInjectable from "./preference-descriptors.injectable";
|
import userStorePreferenceDescriptorsInjectable from "./preference-descriptors.injectable";
|
||||||
import createBaseStoreInjectable from "../base-store/create-base-store.injectable";
|
import createPersistentStorageInjectable from "../persistent-storage/create.injectable";
|
||||||
|
|
||||||
const userStoreInjectable = getInjectable({
|
const userStoreInjectable = getInjectable({
|
||||||
id: "user-store",
|
id: "user-store",
|
||||||
@ -21,9 +21,9 @@ const userStoreInjectable = getInjectable({
|
|||||||
emitAppEvent: di.inject(emitAppEventInjectable),
|
emitAppEvent: di.inject(emitAppEventInjectable),
|
||||||
logger: di.inject(loggerInjectable),
|
logger: di.inject(loggerInjectable),
|
||||||
storeMigrationVersion: di.inject(storeMigrationVersionInjectable),
|
storeMigrationVersion: di.inject(storeMigrationVersionInjectable),
|
||||||
migrations: di.inject(storeMigrationsInjectable, userStoreMigrationInjectionToken),
|
migrations: di.inject(persistentStorageMigrationsInjectable, userStoreMigrationInjectionToken),
|
||||||
preferenceDescriptors: di.inject(userStorePreferenceDescriptorsInjectable),
|
preferenceDescriptors: di.inject(userStorePreferenceDescriptorsInjectable),
|
||||||
createBaseStore: di.inject(createBaseStoreInjectable),
|
createPersistentStorage: di.inject(createPersistentStorageInjectable),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { action, observable, makeObservable, isObservableArray, isObservableSet, isObservableMap, runInAction } from "mobx";
|
import { action, observable, makeObservable, isObservableArray, isObservableSet, isObservableMap, runInAction } from "mobx";
|
||||||
import type { BaseStore } from "../base-store/base-store";
|
import type { BaseStore } from "../persistent-storage/base-store";
|
||||||
import { getOrInsertSet, toggle, object } from "@k8slens/utilities";
|
import { getOrInsertSet, toggle, object } from "@k8slens/utilities";
|
||||||
import type { UserPreferencesModel, StoreType } from "./preferences-helpers";
|
import type { UserPreferencesModel, StoreType } from "./preferences-helpers";
|
||||||
import type { EmitAppEvent } from "../app-event-bus/emit-event.injectable";
|
import type { EmitAppEvent } from "../app-event-bus/emit-event.injectable";
|
||||||
@ -13,7 +13,7 @@ import type { EmitAppEvent } from "../app-event-bus/emit-event.injectable";
|
|||||||
import type { SelectedUpdateChannel } from "../../features/application-update/common/selected-update-channel/selected-update-channel.injectable";
|
import type { SelectedUpdateChannel } from "../../features/application-update/common/selected-update-channel/selected-update-channel.injectable";
|
||||||
import type { ReleaseChannel } from "../../features/application-update/common/update-channels";
|
import type { ReleaseChannel } from "../../features/application-update/common/update-channels";
|
||||||
import type { PreferenceDescriptors } from "./preference-descriptors.injectable";
|
import type { PreferenceDescriptors } from "./preference-descriptors.injectable";
|
||||||
import type { CreateBaseStore } from "../base-store/create-base-store.injectable";
|
import type { CreatePersistentStorage } from "../persistent-storage/create.injectable";
|
||||||
import type { Logger } from "../logger";
|
import type { Logger } from "../logger";
|
||||||
import type { Migrations } from "conf/dist/source/types";
|
import type { Migrations } from "conf/dist/source/types";
|
||||||
import { toJS } from "../utils";
|
import { toJS } from "../utils";
|
||||||
@ -29,14 +29,14 @@ interface Dependencies {
|
|||||||
readonly storeMigrationVersion: string;
|
readonly storeMigrationVersion: string;
|
||||||
readonly migrations: Migrations<Record<string, unknown>>;
|
readonly migrations: Migrations<Record<string, unknown>>;
|
||||||
emitAppEvent: EmitAppEvent;
|
emitAppEvent: EmitAppEvent;
|
||||||
createBaseStore: CreateBaseStore;
|
createPersistentStorage: CreatePersistentStorage;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UserStore {
|
export class UserStore {
|
||||||
private readonly store: BaseStore<UserStoreModel>;
|
private readonly store: BaseStore<UserStoreModel>;
|
||||||
|
|
||||||
constructor(protected readonly dependencies: Dependencies) {
|
constructor(protected readonly dependencies: Dependencies) {
|
||||||
this.store = this.dependencies.createBaseStore({
|
this.store = this.dependencies.createPersistentStorage({
|
||||||
configName: "lens-user-store",
|
configName: "lens-user-store",
|
||||||
projectVersion: this.dependencies.storeMigrationVersion,
|
projectVersion: this.dependencies.storeMigrationVersion,
|
||||||
migrations: this.dependencies.migrations,
|
migrations: this.dependencies.migrations,
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { getInjectionToken } from "@ogre-tools/injectable";
|
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||||
import type { MigrationDeclaration } from "../base-store/migrations.injectable";
|
import type { MigrationDeclaration } from "../persistent-storage/migrations.injectable";
|
||||||
|
|
||||||
export const weblinkStoreMigrationInjectionToken = getInjectionToken<MigrationDeclaration>({
|
export const weblinkStoreMigrationInjectionToken = getInjectionToken<MigrationDeclaration>({
|
||||||
id: "weblink-store-migration-token",
|
id: "weblink-store-migration-token",
|
||||||
|
|||||||
@ -3,8 +3,8 @@
|
|||||||
* 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 { getInjectable } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
import createBaseStoreInjectable from "../base-store/create-base-store.injectable";
|
import createPersistentStorageInjectable from "../persistent-storage/create.injectable";
|
||||||
import storeMigrationsInjectable from "../base-store/migrations.injectable";
|
import persistentStorageMigrationsInjectable from "../persistent-storage/migrations.injectable";
|
||||||
import storeMigrationVersionInjectable from "../vars/store-migration-version.injectable";
|
import storeMigrationVersionInjectable from "../vars/store-migration-version.injectable";
|
||||||
import { weblinkStoreMigrationInjectionToken } from "./migration-token";
|
import { weblinkStoreMigrationInjectionToken } from "./migration-token";
|
||||||
import { WeblinkStore } from "./weblink-store";
|
import { WeblinkStore } from "./weblink-store";
|
||||||
@ -13,8 +13,8 @@ const weblinkStoreInjectable = getInjectable({
|
|||||||
id: "weblink-store",
|
id: "weblink-store",
|
||||||
instantiate: (di) => new WeblinkStore({
|
instantiate: (di) => new WeblinkStore({
|
||||||
storeMigrationVersion: di.inject(storeMigrationVersionInjectable),
|
storeMigrationVersion: di.inject(storeMigrationVersionInjectable),
|
||||||
migrations: di.inject(storeMigrationsInjectable, weblinkStoreMigrationInjectionToken),
|
migrations: di.inject(persistentStorageMigrationsInjectable, weblinkStoreMigrationInjectionToken),
|
||||||
createBaseStore: di.inject(createBaseStoreInjectable),
|
createPersistentStorage: di.inject(createPersistentStorageInjectable),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -4,9 +4,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { action, comparer, observable, runInAction } from "mobx";
|
import { action, comparer, observable, runInAction } from "mobx";
|
||||||
import type { BaseStore } from "../base-store/base-store";
|
import type { BaseStore } from "../persistent-storage/base-store";
|
||||||
import * as uuid from "uuid";
|
import * as uuid from "uuid";
|
||||||
import type { CreateBaseStore } from "../base-store/create-base-store.injectable";
|
import type { CreatePersistentStorage } from "../persistent-storage/create.injectable";
|
||||||
import type { Migrations } from "conf/dist/source/types";
|
import type { Migrations } from "conf/dist/source/types";
|
||||||
|
|
||||||
export interface WeblinkData {
|
export interface WeblinkData {
|
||||||
@ -29,7 +29,7 @@ export interface WeblinkStoreModel {
|
|||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
readonly storeMigrationVersion: string;
|
readonly storeMigrationVersion: string;
|
||||||
readonly migrations: Migrations<Record<string, unknown>>;
|
readonly migrations: Migrations<Record<string, unknown>>;
|
||||||
createBaseStore: CreateBaseStore;
|
createPersistentStorage: CreatePersistentStorage;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WeblinkStore {
|
export class WeblinkStore {
|
||||||
@ -38,7 +38,7 @@ export class WeblinkStore {
|
|||||||
readonly weblinks = observable.array<WeblinkData>();
|
readonly weblinks = observable.array<WeblinkData>();
|
||||||
|
|
||||||
constructor(private readonly dependencies: Dependencies) {
|
constructor(private readonly dependencies: Dependencies) {
|
||||||
this.store = this.dependencies.createBaseStore({
|
this.store = this.dependencies.createPersistentStorage({
|
||||||
configName: "lens-weblink-store",
|
configName: "lens-weblink-store",
|
||||||
accessPropertiesByDotNotation: false, // To make dots safe in cluster context names
|
accessPropertiesByDotNotation: false, // To make dots safe in cluster context names
|
||||||
syncOptions: {
|
syncOptions: {
|
||||||
|
|||||||
@ -3,30 +3,23 @@
|
|||||||
* 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 { BaseStoreParams } from "../common/base-store/base-store";
|
|
||||||
import { BaseStore } from "../common/base-store/base-store";
|
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
import type { LensExtension } from "./lens-extension";
|
import type { LensExtension } from "./lens-extension";
|
||||||
import assert from "assert";
|
|
||||||
import type { StaticThis } from "../common/utils/singleton";
|
import type { StaticThis } from "../common/utils/singleton";
|
||||||
import { getOrInsertWith } from "@k8slens/utilities";
|
import { getOrInsertWith } from "@k8slens/utilities";
|
||||||
import { getLegacyGlobalDiForExtensionApi } from "./as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
|
import { getLegacyGlobalDiForExtensionApi } from "./as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
|
||||||
import directoryForUserDataInjectable from "../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
|
||||||
import getConfigurationFileModelInjectable from "../common/get-configuration-file-model/get-configuration-file-model.injectable";
|
|
||||||
import loggerInjectable from "../common/logger.injectable";
|
|
||||||
import storeMigrationVersionInjectable from "../common/vars/store-migration-version.injectable";
|
|
||||||
import type { Migrations } from "conf/dist/source/types";
|
import type { Migrations } from "conf/dist/source/types";
|
||||||
import { baseStoreIpcChannelPrefixesInjectionToken } from "../common/base-store/channel-prefix";
|
import type { PersistentStorage, PersistentStorageParams } from "../common/persistent-storage/create.injectable";
|
||||||
import { shouldBaseStoreDisableSyncInIpcListenerInjectionToken } from "../common/base-store/disable-sync";
|
import createPersistentStorageInjectable from "../common/persistent-storage/create.injectable";
|
||||||
import { persistStateToConfigInjectionToken } from "../common/base-store/save-to-file";
|
import directoryForUserDataInjectable from "../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||||
import getBasenameOfPathInjectable from "../common/path/get-basename.injectable";
|
import assert from "assert";
|
||||||
import { enlistMessageChannelListenerInjectionToken } from "@k8slens/messaging";
|
|
||||||
|
|
||||||
export interface ExtensionStoreParams<T extends object> extends Omit<BaseStoreParams<T>, "migrations"> {
|
export interface ExtensionStoreParams<T extends object> extends Omit<PersistentStorageParams<T>, "migrations" | "cwd" | "fromStore" | "toJSON"> {
|
||||||
migrations?: Migrations<T>;
|
migrations?: Migrations<T>;
|
||||||
|
cwd?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class BaseExtensionStore<T extends object> extends BaseStore<T> {
|
export abstract class BaseExtensionStore<T extends object> {
|
||||||
private static readonly instances = new WeakMap<object, any>();
|
private static readonly instances = new WeakMap<object, any>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -49,22 +42,17 @@ export abstract class BaseExtensionStore<T extends object> extends BaseStore<T>
|
|||||||
return BaseExtensionStore.instances.get(this) as (T | undefined);
|
return BaseExtensionStore.instances.get(this) as (T | undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor({ migrations, ...params }: ExtensionStoreParams<T>) {
|
protected persistentStorage?: PersistentStorage;
|
||||||
|
private readonly dependencies = (() => {
|
||||||
const di = getLegacyGlobalDiForExtensionApi();
|
const di = getLegacyGlobalDiForExtensionApi();
|
||||||
|
|
||||||
super({
|
return {
|
||||||
|
createPersistentStorage: di.inject(createPersistentStorageInjectable),
|
||||||
directoryForUserData: di.inject(directoryForUserDataInjectable),
|
directoryForUserData: di.inject(directoryForUserDataInjectable),
|
||||||
getConfigurationFileModel: di.inject(getConfigurationFileModelInjectable),
|
} as const;
|
||||||
logger: di.inject(loggerInjectable),
|
})();
|
||||||
storeMigrationVersion: di.inject(storeMigrationVersionInjectable),
|
|
||||||
migrations: migrations as Migrations<Record<string, unknown>>,
|
constructor(protected readonly rawParams: ExtensionStoreParams<T>) { }
|
||||||
getBasenameOfPath: di.inject(getBasenameOfPathInjectable),
|
|
||||||
ipcChannelPrefixes: di.inject(baseStoreIpcChannelPrefixesInjectionToken),
|
|
||||||
persistStateToConfig: di.inject(persistStateToConfigInjectionToken),
|
|
||||||
enlistMessageChannelListener: di.inject(enlistMessageChannelListenerInjectionToken),
|
|
||||||
shouldDisableSyncInListener: di.inject(shouldBaseStoreDisableSyncInIpcListenerInjectionToken),
|
|
||||||
}, params);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated This is a form of global shared state. Just call `new Store(...)`
|
* @deprecated This is a form of global shared state. Just call `new Store(...)`
|
||||||
@ -77,21 +65,38 @@ export abstract class BaseExtensionStore<T extends object> extends BaseStore<T>
|
|||||||
|
|
||||||
loadExtension(extension: LensExtension) {
|
loadExtension(extension: LensExtension) {
|
||||||
this.extension = extension;
|
this.extension = extension;
|
||||||
|
const {
|
||||||
|
projectVersion = this.extension.version,
|
||||||
|
cwd: _cwd, // This is ignored to maintain backwards compatibility
|
||||||
|
migrations = {},
|
||||||
|
...params
|
||||||
|
} = this.rawParams;
|
||||||
|
|
||||||
this.params.projectVersion ??= this.extension.version;
|
this.persistentStorage = this.dependencies.createPersistentStorage({
|
||||||
|
...params,
|
||||||
|
cwd: this.cwd(),
|
||||||
|
projectVersion,
|
||||||
|
migrations: migrations as Migrations<Record<string, unknown>>,
|
||||||
|
fromStore: (data) => this.fromStore(data),
|
||||||
|
toJSON: () => this.toJSON(),
|
||||||
|
});
|
||||||
|
|
||||||
return super.load();
|
this.persistentStorage.loadAndStartSyncing();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Never use this method. Instead call {@link BaseExtensionStore.loadExtension}
|
||||||
|
*/
|
||||||
load() {
|
load() {
|
||||||
if (!this.extension) { return; }
|
this.persistentStorage?.loadAndStartSyncing();
|
||||||
|
|
||||||
return super.load();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected cwd() {
|
protected cwd() {
|
||||||
assert(this.extension, "must call this.load() first");
|
assert(this.extension, "cwd can only be called in loadExtension");
|
||||||
|
|
||||||
return path.join(super.cwd(), "extension-store", this.extension.storeName);
|
return this.rawParams.cwd ?? path.join(this.dependencies.directoryForUserData, "extension-store", this.extension.storeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract fromStore(data: Partial<T>): void;
|
||||||
|
abstract toJSON(): T;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
* 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 { BaseStoreParams } from "../../common/base-store/base-store";
|
import type { BaseStoreParams } from "../../common/persistent-storage/base-store";
|
||||||
import { BaseExtensionStore as ExtensionStore } from "../base-extension-store";
|
import { BaseExtensionStore as ExtensionStore } from "../base-extension-store";
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
* 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 { getInjectionToken } from "@ogre-tools/injectable";
|
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||||
import type { MigrationDeclaration } from "../../../common/base-store/migrations.injectable";
|
import type { MigrationDeclaration } from "../../../common/persistent-storage/migrations.injectable";
|
||||||
|
|
||||||
export const fileSystemProvisionerStoreMigrationDeclarationInjectionToken = getInjectionToken<MigrationDeclaration>({
|
export const fileSystemProvisionerStoreMigrationDeclarationInjectionToken = getInjectionToken<MigrationDeclaration>({
|
||||||
id: "file-system-provisioner-store-migration-declaration",
|
id: "file-system-provisioner-store-migration-declaration",
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
import { getInjectable } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
import { registeredExtensionsInjectable } from "./registered-extensions.injectable";
|
import { registeredExtensionsInjectable } from "./registered-extensions.injectable";
|
||||||
import createBaseStoreInjectable from "../../../common/base-store/create-base-store.injectable";
|
import createPersistentStorageInjectable from "../../../common/persistent-storage/create.injectable";
|
||||||
import { action } from "mobx";
|
import { action } from "mobx";
|
||||||
import { object } from "@k8slens/utilities";
|
import { object } from "@k8slens/utilities";
|
||||||
import storeMigrationVersionInjectable from "../../../common/vars/store-migration-version.injectable";
|
import storeMigrationVersionInjectable from "../../../common/vars/store-migration-version.injectable";
|
||||||
@ -14,10 +14,10 @@ const fileSystemProvisionerStoreInjectable = getInjectable({
|
|||||||
|
|
||||||
instantiate: (di) => {
|
instantiate: (di) => {
|
||||||
const registeredExtensions = di.inject(registeredExtensionsInjectable);
|
const registeredExtensions = di.inject(registeredExtensionsInjectable);
|
||||||
const createBaseStore = di.inject(createBaseStoreInjectable);
|
const createPersistentStorage = di.inject(createPersistentStorageInjectable);
|
||||||
const storeMigrationVersion = di.inject(storeMigrationVersionInjectable);
|
const storeMigrationVersion = di.inject(storeMigrationVersionInjectable);
|
||||||
|
|
||||||
const store = createBaseStore({
|
const store = createPersistentStorage({
|
||||||
configName: "lens-filesystem-provisioner-store",
|
configName: "lens-filesystem-provisioner-store",
|
||||||
accessPropertiesByDotNotation: false, // To make dots safe in cluster context names
|
accessPropertiesByDotNotation: false, // To make dots safe in cluster context names
|
||||||
projectVersion: storeMigrationVersion,
|
projectVersion: storeMigrationVersion,
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
* 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 { getInjectable } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
import createBaseStoreInjectable from "../../common/base-store/create-base-store.injectable";
|
import createPersistentStorageInjectable from "../../common/persistent-storage/create.injectable";
|
||||||
import storeMigrationVersionInjectable from "../../common/vars/store-migration-version.injectable";
|
import storeMigrationVersionInjectable from "../../common/vars/store-migration-version.injectable";
|
||||||
import { ExtensionsStore } from "./extensions-store";
|
import { ExtensionsStore } from "./extensions-store";
|
||||||
|
|
||||||
@ -11,7 +11,7 @@ const extensionsStoreInjectable = getInjectable({
|
|||||||
id: "extensions-store",
|
id: "extensions-store",
|
||||||
instantiate: (di) => new ExtensionsStore({
|
instantiate: (di) => new ExtensionsStore({
|
||||||
storeMigrationVersion: di.inject(storeMigrationVersionInjectable),
|
storeMigrationVersion: di.inject(storeMigrationVersionInjectable),
|
||||||
createBaseStore: di.inject(createBaseStoreInjectable),
|
createPersistentStorage: di.inject(createPersistentStorageInjectable),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -5,8 +5,8 @@
|
|||||||
|
|
||||||
import type { LensExtensionId } from "@k8slens/legacy-extensions";
|
import type { LensExtensionId } from "@k8slens/legacy-extensions";
|
||||||
import { action, computed, observable } from "mobx";
|
import { action, computed, observable } from "mobx";
|
||||||
import type { BaseStore } from "../../common/base-store/base-store";
|
import type { BaseStore } from "../../common/persistent-storage/base-store";
|
||||||
import type { CreateBaseStore } from "../../common/base-store/create-base-store.injectable";
|
import type { CreatePersistentStorage } from "../../common/persistent-storage/create.injectable";
|
||||||
|
|
||||||
export interface LensExtensionsStoreModel {
|
export interface LensExtensionsStoreModel {
|
||||||
extensions?: Record<LensExtensionId, LensExtensionState>;
|
extensions?: Record<LensExtensionId, LensExtensionState>;
|
||||||
@ -23,7 +23,7 @@ export interface IsEnabledExtensionDescriptor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ExtensionsStoreDependencies {
|
export interface ExtensionsStoreDependencies {
|
||||||
createBaseStore: CreateBaseStore;
|
createPersistentStorage: CreatePersistentStorage;
|
||||||
readonly storeMigrationVersion: string;
|
readonly storeMigrationVersion: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ export class ExtensionsStore {
|
|||||||
private readonly store: BaseStore<LensExtensionsStoreModel>;
|
private readonly store: BaseStore<LensExtensionsStoreModel>;
|
||||||
|
|
||||||
constructor(private readonly dependencies: ExtensionsStoreDependencies) {
|
constructor(private readonly dependencies: ExtensionsStoreDependencies) {
|
||||||
this.store = this.dependencies.createBaseStore({
|
this.store = this.dependencies.createPersistentStorage({
|
||||||
configName: "lens-extensions",
|
configName: "lens-extensions",
|
||||||
fromStore: action(({ extensions = {}}) => {
|
fromStore: action(({ extensions = {}}) => {
|
||||||
this.state.merge(extensions);
|
this.state.merge(extensions);
|
||||||
|
|||||||
@ -3,12 +3,12 @@
|
|||||||
* 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 { getInjectable } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
import { shouldBaseStoreDisableSyncInIpcListenerInjectionToken } from "../../common/base-store/disable-sync";
|
import { shouldPersistentStorageDisableSyncInIpcListenerInjectionToken } from "../../common/persistent-storage/disable-sync";
|
||||||
|
|
||||||
const shouldBaseStoreDisableSyncInIpcListenerInjectable = getInjectable({
|
const shouldBaseStoreDisableSyncInIpcListenerInjectable = getInjectable({
|
||||||
id: "should-base-store-disable-sync-in-ipc-listener",
|
id: "should-base-store-disable-sync-in-ipc-listener",
|
||||||
instantiate: () => false,
|
instantiate: () => false,
|
||||||
injectionToken: shouldBaseStoreDisableSyncInIpcListenerInjectionToken,
|
injectionToken: shouldPersistentStorageDisableSyncInIpcListenerInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default shouldBaseStoreDisableSyncInIpcListenerInjectable;
|
export default shouldBaseStoreDisableSyncInIpcListenerInjectable;
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
* 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 { getInjectable } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
import { baseStoreIpcChannelPrefixesInjectionToken } from "../../common/base-store/channel-prefix";
|
import { persistentStorageIpcChannelPrefixesInjectionToken } from "../../common/persistent-storage/channel-prefix";
|
||||||
|
|
||||||
const baseStoreIpcChannelPrefixInjectable = getInjectable({
|
const baseStoreIpcChannelPrefixInjectable = getInjectable({
|
||||||
id: "base-store-ipc-channel-prefix",
|
id: "base-store-ipc-channel-prefix",
|
||||||
@ -11,7 +11,7 @@ const baseStoreIpcChannelPrefixInjectable = getInjectable({
|
|||||||
local: "store-sync-main",
|
local: "store-sync-main",
|
||||||
remote: "store-sync-renderer",
|
remote: "store-sync-renderer",
|
||||||
}),
|
}),
|
||||||
injectionToken: baseStoreIpcChannelPrefixesInjectionToken,
|
injectionToken: persistentStorageIpcChannelPrefixesInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default baseStoreIpcChannelPrefixInjectable;
|
export default baseStoreIpcChannelPrefixInjectable;
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
* 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 { getInjectable } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
import { persistStateToConfigInjectionToken } from "../../common/base-store/save-to-file";
|
import { persistStateToConfigInjectionToken } from "../../common/persistent-storage/save-to-file";
|
||||||
import loggerInjectable from "../../common/logger.injectable";
|
import loggerInjectable from "../../common/logger.injectable";
|
||||||
|
|
||||||
const persistStateToConfigInjectable = getInjectable({
|
const persistStateToConfigInjectable = getInjectable({
|
||||||
|
|||||||
@ -3,12 +3,12 @@
|
|||||||
* 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 { getInjectable } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
import { shouldBaseStoreDisableSyncInIpcListenerInjectionToken } from "../../common/base-store/disable-sync";
|
import { shouldPersistentStorageDisableSyncInIpcListenerInjectionToken } from "../../common/persistent-storage/disable-sync";
|
||||||
|
|
||||||
const shouldBaseStoreDisableSyncInIpcListenerInjectable = getInjectable({
|
const shouldBaseStoreDisableSyncInIpcListenerInjectable = getInjectable({
|
||||||
id: "should-base-store-disable-sync-in-ipc-listener",
|
id: "should-base-store-disable-sync-in-ipc-listener",
|
||||||
instantiate: () => true,
|
instantiate: () => true,
|
||||||
injectionToken: shouldBaseStoreDisableSyncInIpcListenerInjectionToken,
|
injectionToken: shouldPersistentStorageDisableSyncInIpcListenerInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default shouldBaseStoreDisableSyncInIpcListenerInjectable;
|
export default shouldBaseStoreDisableSyncInIpcListenerInjectable;
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
* 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 { getInjectable } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
import { baseStoreIpcChannelPrefixesInjectionToken } from "../../common/base-store/channel-prefix";
|
import { persistentStorageIpcChannelPrefixesInjectionToken } from "../../common/persistent-storage/channel-prefix";
|
||||||
|
|
||||||
const baseStoreIpcChannelPrefixInjectable = getInjectable({
|
const baseStoreIpcChannelPrefixInjectable = getInjectable({
|
||||||
id: "base-store-ipc-channel-prefix",
|
id: "base-store-ipc-channel-prefix",
|
||||||
@ -11,7 +11,7 @@ const baseStoreIpcChannelPrefixInjectable = getInjectable({
|
|||||||
local: "store-sync-renderer",
|
local: "store-sync-renderer",
|
||||||
remote: "store-sync-main",
|
remote: "store-sync-main",
|
||||||
}),
|
}),
|
||||||
injectionToken: baseStoreIpcChannelPrefixesInjectionToken,
|
injectionToken: persistentStorageIpcChannelPrefixesInjectionToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default baseStoreIpcChannelPrefixInjectable;
|
export default baseStoreIpcChannelPrefixInjectable;
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
* 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 { getInjectable } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
import { persistStateToConfigInjectionToken } from "../../common/base-store/save-to-file";
|
import { persistStateToConfigInjectionToken } from "../../common/persistent-storage/save-to-file";
|
||||||
import { noop } from "@k8slens/utilities";
|
import { noop } from "@k8slens/utilities";
|
||||||
|
|
||||||
const persistStateToConfigInjectable = getInjectable({
|
const persistStateToConfigInjectable = getInjectable({
|
||||||
|
|||||||
@ -3,7 +3,6 @@
|
|||||||
* 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 { Writable } from "type-fest";
|
import type { Writable } from "type-fest";
|
||||||
import fileSystemProvisionerStoreInjectable from "../../../extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store.injectable";
|
|
||||||
import { lensExtensionDependencies } from "../../../extensions/lens-extension";
|
import { lensExtensionDependencies } from "../../../extensions/lens-extension";
|
||||||
import { LensMainExtension } from "../../../extensions/lens-main-extension";
|
import { LensMainExtension } from "../../../extensions/lens-main-extension";
|
||||||
import navigateForExtensionInjectable from "../../../main/start-main-application/lens-window/navigate-for-extension.injectable";
|
import navigateForExtensionInjectable from "../../../main/start-main-application/lens-window/navigate-for-extension.injectable";
|
||||||
@ -16,6 +15,7 @@ import catalogEntityRegistryForMainInjectable from "../../../main/catalog/entity
|
|||||||
import catalogEntityRegistryForRendererInjectable from "../../api/catalog/entity/registry.injectable";
|
import catalogEntityRegistryForRendererInjectable from "../../api/catalog/entity/registry.injectable";
|
||||||
import type { DiContainer } from "@ogre-tools/injectable";
|
import type { DiContainer } from "@ogre-tools/injectable";
|
||||||
import loggerInjectable from "../../../common/logger.injectable";
|
import loggerInjectable from "../../../common/logger.injectable";
|
||||||
|
import ensureHashedDirectoryForExtensionInjectable from "../../../extensions/extension-loader/file-system-provisioner-store/ensure-hashed-directory-for-extension.injectable";
|
||||||
|
|
||||||
export class TestExtensionMain extends LensMainExtension {}
|
export class TestExtensionMain extends LensMainExtension {}
|
||||||
export class TestExtensionRenderer extends LensRendererExtension {}
|
export class TestExtensionRenderer extends LensRendererExtension {}
|
||||||
@ -47,7 +47,7 @@ export const getMainExtensionFakeWith = (di: DiContainer) => ({ id, name, mainOp
|
|||||||
Object.assign(instance, mainOptions);
|
Object.assign(instance, mainOptions);
|
||||||
|
|
||||||
(instance as Writable<LensMainExtension>)[lensExtensionDependencies] = {
|
(instance as Writable<LensMainExtension>)[lensExtensionDependencies] = {
|
||||||
fileSystemProvisionerStore: di.inject(fileSystemProvisionerStoreInjectable),
|
ensureHashedDirectoryForExtension: di.inject(ensureHashedDirectoryForExtensionInjectable),
|
||||||
entityRegistry: di.inject(catalogEntityRegistryForMainInjectable),
|
entityRegistry: di.inject(catalogEntityRegistryForMainInjectable),
|
||||||
navigate: di.inject(navigateForExtensionInjectable),
|
navigate: di.inject(navigateForExtensionInjectable),
|
||||||
logger: di.inject(loggerInjectable),
|
logger: di.inject(loggerInjectable),
|
||||||
@ -78,7 +78,7 @@ export const getRendererExtensionFakeWith = (di: DiContainer) => ({ id, name, re
|
|||||||
(instance as Writable<LensRendererExtension>)[lensExtensionDependencies] = {
|
(instance as Writable<LensRendererExtension>)[lensExtensionDependencies] = {
|
||||||
categoryRegistry: di.inject(catalogCategoryRegistryInjectable),
|
categoryRegistry: di.inject(catalogCategoryRegistryInjectable),
|
||||||
entityRegistry: di.inject(catalogEntityRegistryForRendererInjectable),
|
entityRegistry: di.inject(catalogEntityRegistryForRendererInjectable),
|
||||||
fileSystemProvisionerStore: di.inject(fileSystemProvisionerStoreInjectable),
|
ensureHashedDirectoryForExtension: di.inject(ensureHashedDirectoryForExtensionInjectable),
|
||||||
getExtensionPageParameters: di.inject(getExtensionPageParametersInjectable),
|
getExtensionPageParameters: di.inject(getExtensionPageParametersInjectable),
|
||||||
navigateToRoute: di.inject(navigateToRouteInjectable),
|
navigateToRoute: di.inject(navigateToRouteInjectable),
|
||||||
routes: di.inject(routesInjectable),
|
routes: di.inject(routesInjectable),
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user