mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
refactor BaseStore
Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
parent
b21d1aa4d6
commit
b905199d22
@ -2,12 +2,13 @@ import path from "path";
|
|||||||
import Config from "conf";
|
import Config from "conf";
|
||||||
import { Options as ConfOptions } from "conf/dist/source/types";
|
import { Options as ConfOptions } from "conf/dist/source/types";
|
||||||
import { app, ipcMain, IpcMainEvent, ipcRenderer, IpcRendererEvent, remote } from "electron";
|
import { app, ipcMain, IpcMainEvent, ipcRenderer, IpcRendererEvent, remote } from "electron";
|
||||||
import { IReactionOptions, observable, reaction, runInAction, when } from "mobx";
|
import { IReactionOptions, observable, reaction, when } from "mobx";
|
||||||
import Singleton from "./utils/singleton";
|
import Singleton from "./utils/singleton";
|
||||||
import { getAppVersion } from "./utils/app-version";
|
import { getAppVersion } from "./utils/app-version";
|
||||||
import logger from "../main/logger";
|
import logger from "../main/logger";
|
||||||
import { broadcastMessage, subscribeToBroadcast, unsubscribeFromBroadcast } from "./ipc";
|
import { createTypedSender } from "./ipc";
|
||||||
import isEqual from "lodash/isEqual";
|
import isEqual from "lodash/isEqual";
|
||||||
|
import { autobind } from "./utils";
|
||||||
|
|
||||||
export interface BaseStoreParams<T = any> extends ConfOptions<T> {
|
export interface BaseStoreParams<T = any> extends ConfOptions<T> {
|
||||||
autoLoad?: boolean;
|
autoLoad?: boolean;
|
||||||
@ -39,13 +40,15 @@ export abstract class BaseStore<T = any> extends Singleton {
|
|||||||
return path.basename(this.storeConfig.path);
|
return path.basename(this.storeConfig.path);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected get syncRendererChannel() {
|
protected readonly syncRenderer = createTypedSender({
|
||||||
return `store-sync-renderer:${this.path}`;
|
channel: `store-sync-renderer:${this.path}`,
|
||||||
}
|
verifier: (src: unknown): src is any => true,
|
||||||
|
});
|
||||||
|
|
||||||
protected get syncMainChannel() {
|
protected readonly syncMain = createTypedSender({
|
||||||
return `store-sync-main:${this.path}`;
|
channel: `store-sync-main:${this.path}`,
|
||||||
}
|
verifier: (src: unknown): src is any => true,
|
||||||
|
});
|
||||||
|
|
||||||
get path() {
|
get path() {
|
||||||
return this.storeConfig.path;
|
return this.storeConfig.path;
|
||||||
@ -90,39 +93,27 @@ export abstract class BaseStore<T = any> extends Singleton {
|
|||||||
|
|
||||||
enableSync() {
|
enableSync() {
|
||||||
this.syncDisposers.push(
|
this.syncDisposers.push(
|
||||||
reaction(() => this.toJSON(), model => this.onModelChange(model), this.params.syncOptions),
|
reaction(() => this.toJSON(), this.onModelChange, this.params.syncOptions),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (ipcMain) {
|
if (ipcMain) {
|
||||||
const callback = (event: IpcMainEvent, model: T) => {
|
this.syncDisposers.push(this.syncMain.on((event: IpcMainEvent, model: T) => {
|
||||||
logger.silly(`[STORE]: SYNC ${this.name} from renderer`, { model });
|
logger.silly(`[STORE]: SYNC ${this.name} from renderer`, { model });
|
||||||
this.onSync(model);
|
this.onSync(model);
|
||||||
};
|
}));
|
||||||
|
|
||||||
subscribeToBroadcast(this.syncMainChannel, callback);
|
|
||||||
this.syncDisposers.push(() => unsubscribeFromBroadcast(this.syncMainChannel, callback));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ipcRenderer) {
|
if (ipcRenderer) {
|
||||||
const callback = (event: IpcRendererEvent, model: T) => {
|
this.syncDisposers.push(this.syncRenderer.on((event: IpcRendererEvent, model: T) => {
|
||||||
logger.silly(`[STORE]: SYNC ${this.name} from main`, { model });
|
logger.silly(`[STORE]: SYNC ${this.name} from main`, { model });
|
||||||
this.onSyncFromMain(model);
|
this.disableSync();
|
||||||
};
|
|
||||||
|
|
||||||
subscribeToBroadcast(this.syncRendererChannel, callback);
|
|
||||||
this.syncDisposers.push(() => unsubscribeFromBroadcast(this.syncRendererChannel, callback));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected onSyncFromMain(model: T) {
|
|
||||||
this.applyWithoutSync(() => {
|
|
||||||
this.onSync(model);
|
this.onSync(model);
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
unregisterIpcListener() {
|
if (this.params.syncEnabled) {
|
||||||
ipcRenderer.removeAllListeners(this.syncMainChannel);
|
this.enableSync();
|
||||||
ipcRenderer.removeAllListeners(this.syncRendererChannel);
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
disableSync() {
|
disableSync() {
|
||||||
@ -130,15 +121,6 @@ export abstract class BaseStore<T = any> extends Singleton {
|
|||||||
this.syncDisposers.length = 0;
|
this.syncDisposers.length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected applyWithoutSync(callback: () => void) {
|
|
||||||
this.disableSync();
|
|
||||||
runInAction(callback);
|
|
||||||
|
|
||||||
if (this.params.syncEnabled) {
|
|
||||||
this.enableSync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected onSync(model: T) {
|
protected onSync(model: T) {
|
||||||
// todo: use "resourceVersion" if merge required (to avoid equality checks => better performance)
|
// todo: use "resourceVersion" if merge required (to avoid equality checks => better performance)
|
||||||
if (!isEqual(this.toJSON(), model)) {
|
if (!isEqual(this.toJSON(), model)) {
|
||||||
@ -146,12 +128,13 @@ export abstract class BaseStore<T = any> extends Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@autobind()
|
||||||
protected async onModelChange(model: T) {
|
protected async onModelChange(model: T) {
|
||||||
if (ipcMain) {
|
if (ipcMain) {
|
||||||
this.saveToFile(model); // save config file
|
this.saveToFile(model); // save config file
|
||||||
broadcastMessage(this.syncRendererChannel, model);
|
this.syncRenderer.broadcast(model);
|
||||||
} else {
|
} else {
|
||||||
broadcastMessage(this.syncMainChannel, model);
|
this.syncMain.broadcast(model);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -171,7 +171,6 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unregisterIpcListener() {
|
unregisterIpcListener() {
|
||||||
super.unregisterIpcListener();
|
|
||||||
unsubscribeAllFromBroadcast("cluster:state");
|
unsubscribeAllFromBroadcast("cluster:state");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -188,12 +188,14 @@ export function createTypedInvoker<
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Disposer = () => void;
|
||||||
|
|
||||||
export interface TypedSender<
|
export interface TypedSender<
|
||||||
Args extends any[]
|
Args extends any[]
|
||||||
> {
|
> {
|
||||||
broadcast: (...args: Args) => void,
|
broadcast: (...args: Args) => void,
|
||||||
on: (listener: IpcListener<Event, Args>) => void,
|
on: (listener: IpcListener<Event, Args>) => Disposer,
|
||||||
once: (listener: IpcListener<Event, Args>) => void,
|
once: (listener: IpcListener<Event, Args>) => Disposer,
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createTypedSender<
|
export function createTypedSender<
|
||||||
@ -205,25 +207,31 @@ export function createTypedSender<
|
|||||||
channel: string,
|
channel: string,
|
||||||
verifier: ListVerifier<Args>,
|
verifier: ListVerifier<Args>,
|
||||||
}): TypedSender<Args> {
|
}): TypedSender<Args> {
|
||||||
|
const source = ipcMain ?? ipcRenderer;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
broadcast(...args) {
|
broadcast(...args) {
|
||||||
broadcastMessage(channel, ...args);
|
broadcastMessage(channel, ...args);
|
||||||
},
|
},
|
||||||
on(listener) {
|
on(listener) {
|
||||||
onCorrect({
|
onCorrect({
|
||||||
source: ipcMain ?? ipcRenderer,
|
source,
|
||||||
channel,
|
channel,
|
||||||
listener,
|
listener,
|
||||||
verifier: verifier as ListVerifier<Rest<[e: Event, ...args: Args]>>,
|
verifier: verifier as ListVerifier<Rest<[e: Event, ...args: Args]>>,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return () => source.removeListener(channel, listener);
|
||||||
},
|
},
|
||||||
once(listener) {
|
once(listener) {
|
||||||
onceCorrect({
|
onceCorrect({
|
||||||
source: ipcMain ?? ipcRenderer,
|
source,
|
||||||
channel,
|
channel,
|
||||||
listener,
|
listener,
|
||||||
verifier: verifier as ListVerifier<Rest<[e: Event, ...args: Args]>>,
|
verifier: verifier as ListVerifier<Rest<[e: Event, ...args: Args]>>,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return () => source.removeListener(channel, listener);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
type TypeGuard<T> = (arg: unknown) => arg is T;
|
export type TypeGuard<T> = (arg: unknown) => arg is T;
|
||||||
type Rest<T extends any[]> = T extends [any, ...infer R] ? R : any;
|
type Rest<T extends any[]> = T extends [any, ...infer R] ? R : any;
|
||||||
type First<T extends any[]> = T extends [infer R, ...any[]] ? R : any;
|
type First<T extends any[]> = T extends [infer R, ...any[]] ? R : any;
|
||||||
type TypeGuardReturnType<T extends (src: unknown) => src is any> = T extends (src: unknown) => src is infer R ? R : any;
|
type TypeGuardReturnType<T extends (src: unknown) => src is any> = T extends (src: unknown) => src is infer R ? R : any;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user