mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
cluster-ipc refactoring
Signed-off-by: Roman <ixrock@gmail.com>
This commit is contained in:
parent
c0c1c227ca
commit
70bbb9fa62
32
src/common/cluster-ipc.ts
Normal file
32
src/common/cluster-ipc.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { createIpcChannel } from "./ipc";
|
||||||
|
import { ClusterId, clusterStore } from "./cluster-store";
|
||||||
|
import { tracker } from "./tracker";
|
||||||
|
|
||||||
|
export const clusterIpc = {
|
||||||
|
refresh: createIpcChannel({
|
||||||
|
channel: "cluster:refresh",
|
||||||
|
handle: async (clusterId: ClusterId = clusterStore.activeClusterId) => {
|
||||||
|
const cluster = clusterStore.getById(clusterId);
|
||||||
|
if (cluster) {
|
||||||
|
await cluster.refreshStatus();
|
||||||
|
cluster.pushState();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
|
||||||
|
disconnect: createIpcChannel({
|
||||||
|
channel: "cluster:disconnect",
|
||||||
|
handle: (clusterId: ClusterId) => {
|
||||||
|
tracker.event("cluster", "stop");
|
||||||
|
clusterStore.getById(clusterId)?.disconnect();
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
|
||||||
|
reconnect: createIpcChannel({
|
||||||
|
channel: "cluster:reconnect",
|
||||||
|
handle: (clusterId: ClusterId) => {
|
||||||
|
tracker.event("cluster", "reconnect");
|
||||||
|
clusterStore.getById(clusterId)?.reconnect();
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}
|
||||||
@ -43,9 +43,9 @@ export async function invokeIpc<R = any>(channel: IpcChannel, ...args: any[]): P
|
|||||||
}
|
}
|
||||||
|
|
||||||
// todo: make isomorphic api
|
// todo: make isomorphic api
|
||||||
export function handleIpc<T extends any[]>(channel: IpcChannel, handler: IpcMessageHandler<T>, options: IpcHandleOpts = {}) {
|
export function handleIpc(channel: IpcChannel, handler: IpcMessageHandler, options: IpcHandleOpts = {}) {
|
||||||
const { timeout = 0 } = options;
|
const { timeout = 0 } = options;
|
||||||
ipcMain.handle(channel, async (event, ...args: T) => {
|
ipcMain.handle(channel, async (event, ...args) => {
|
||||||
logger.info(`[IPC]: handle "${channel}"`, { args });
|
logger.info(`[IPC]: handle "${channel}"`, { args });
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
let timerId;
|
let timerId;
|
||||||
@ -65,3 +65,21 @@ export function handleIpc<T extends any[]>(channel: IpcChannel, handler: IpcMess
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IpcPairOptions {
|
||||||
|
channel: IpcChannel
|
||||||
|
handle?: IpcMessageHandler
|
||||||
|
options?: IpcHandleOpts
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createIpcChannel({ channel, ...initOpts }: IpcPairOptions) {
|
||||||
|
return {
|
||||||
|
handleInMain: (opts: Partial<Omit<IpcPairOptions, "channel">> = {}) => {
|
||||||
|
const { handle = initOpts.handle, options = initOpts.options } = opts;
|
||||||
|
return handleIpc(channel, handle, options);
|
||||||
|
},
|
||||||
|
invokeFromRenderer: (...args: any[]) => {
|
||||||
|
return invokeIpc(channel, ...args);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -2,10 +2,9 @@ import type http from "http"
|
|||||||
import { autorun, reaction } from "mobx";
|
import { autorun, reaction } from "mobx";
|
||||||
import { apiKubePrefix } from "../common/vars";
|
import { apiKubePrefix } from "../common/vars";
|
||||||
import { ClusterId, clusterStore } from "../common/cluster-store"
|
import { ClusterId, clusterStore } from "../common/cluster-store"
|
||||||
import { handleIpc } from "../common/ipc";
|
import { Cluster } from "./cluster"
|
||||||
import { Cluster, ClusterIpcChannel } from "./cluster"
|
import { clusterIpc } from "../common/cluster-ipc";
|
||||||
import logger from "./logger";
|
import logger from "./logger";
|
||||||
import { tracker } from "../common/tracker";
|
|
||||||
|
|
||||||
export class ClusterManager {
|
export class ClusterManager {
|
||||||
protected activeClusterId: ClusterId;
|
protected activeClusterId: ClusterId;
|
||||||
@ -53,9 +52,9 @@ export class ClusterManager {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// listen for ipc-events that must/can be handled *only* in main-process (nodeIntegration=true)
|
// listen for ipc-events that must/can be handled *only* in main-process (nodeIntegration=true)
|
||||||
handleIpc(ClusterIpcChannel.INIT, this.onClusterInit);
|
clusterIpc.refresh.handleInMain();
|
||||||
handleIpc(ClusterIpcChannel.DISCONNECT, this.onClusterDisconnect);
|
clusterIpc.disconnect.handleInMain();
|
||||||
handleIpc(ClusterIpcChannel.RECONNECT, this.onClusterReconnect);
|
clusterIpc.reconnect.handleInMain();
|
||||||
}
|
}
|
||||||
|
|
||||||
stop() {
|
stop() {
|
||||||
@ -64,26 +63,6 @@ export class ClusterManager {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
protected onClusterInit = async (id = clusterStore.activeClusterId) => {
|
|
||||||
const cluster = this.getCluster(id);
|
|
||||||
if (cluster) {
|
|
||||||
logger.info(`[CLUSTER-MANAGER]: init cluster`, cluster.getMeta());
|
|
||||||
tracker.event("cluster", "activate");
|
|
||||||
await cluster.refreshStatus();
|
|
||||||
cluster.pushState();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected onClusterDisconnect = (id: ClusterId) => {
|
|
||||||
tracker.event("cluster", "stop");
|
|
||||||
this.getCluster(id)?.disconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected onClusterReconnect = (id: ClusterId) => {
|
|
||||||
tracker.event("cluster", "reconnect");
|
|
||||||
this.getCluster(id)?.reconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected getCluster(id: ClusterId) {
|
protected getCluster(id: ClusterId) {
|
||||||
return clusterStore.getById(id);
|
return clusterStore.getById(id);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,12 +13,6 @@ import { getFeatures, installFeature, uninstallFeature, upgradeFeature } from ".
|
|||||||
import request, { RequestPromiseOptions } from "request-promise-native"
|
import request, { RequestPromiseOptions } from "request-promise-native"
|
||||||
import logger from "./logger"
|
import logger from "./logger"
|
||||||
|
|
||||||
export enum ClusterIpcChannel {
|
|
||||||
INIT = "cluster:init",
|
|
||||||
DISCONNECT = "cluster:disconnect",
|
|
||||||
RECONNECT = "cluster:reconnect",
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum ClusterStatus {
|
export enum ClusterStatus {
|
||||||
AccessGranted = 2,
|
AccessGranted = 2,
|
||||||
AccessDenied = 1,
|
AccessDenied = 1,
|
||||||
@ -341,7 +335,7 @@ export class Cluster implements ClusterModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pushState = (clusterState = this.getState()) => {
|
pushState = (clusterState = this.getState()) => {
|
||||||
logger.info(`[CLUSTER]: push-state`, clusterState);
|
logger.debug(`[CLUSTER]: push-state`, clusterState);
|
||||||
broadcastIpc({
|
broadcastIpc({
|
||||||
// webContentId: viewId, // todo: send to cluster-view only
|
// webContentId: viewId, // todo: send to cluster-view only
|
||||||
channel: "cluster:state",
|
channel: "cluster:state",
|
||||||
@ -354,6 +348,8 @@ export class Cluster implements ClusterModel {
|
|||||||
return {
|
return {
|
||||||
id: this.id,
|
id: this.id,
|
||||||
name: this.contextName,
|
name: this.contextName,
|
||||||
|
initialized: this.initialized,
|
||||||
|
accessible: this.accessible,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import "./cluster.scss"
|
import "./cluster.scss"
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { computed, reaction } from "mobx";
|
import { computed, reaction, when } from "mobx";
|
||||||
import { disposeOnUnmount, observer } from "mobx-react";
|
import { disposeOnUnmount, observer } from "mobx-react";
|
||||||
import { MainLayout } from "../layout/main-layout";
|
import { MainLayout } from "../layout/main-layout";
|
||||||
import { ClusterIssues } from "./cluster-issues";
|
import { ClusterIssues } from "./cluster-issues";
|
||||||
@ -13,6 +13,7 @@ import { nodesStore } from "../+nodes/nodes.store";
|
|||||||
import { podsStore } from "../+workloads-pods/pods.store";
|
import { podsStore } from "../+workloads-pods/pods.store";
|
||||||
import { clusterStore } from "./cluster.store";
|
import { clusterStore } from "./cluster.store";
|
||||||
import { eventStore } from "../+events/event.store";
|
import { eventStore } from "../+events/event.store";
|
||||||
|
import { configStore } from "../../config.store";
|
||||||
import { isAllowedResource } from "../../api/rbac";
|
import { isAllowedResource } from "../../api/rbac";
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
@ -24,7 +25,10 @@ export class Cluster extends React.Component {
|
|||||||
|
|
||||||
private dependentStores = [nodesStore, podsStore];
|
private dependentStores = [nodesStore, podsStore];
|
||||||
|
|
||||||
|
// todo: refactor
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
|
await when(() => configStore.isLoaded);
|
||||||
|
|
||||||
const { dependentStores } = this;
|
const { dependentStores } = this;
|
||||||
if (!isAllowedResource("nodes")) {
|
if (!isAllowedResource("nodes")) {
|
||||||
dependentStores.splice(dependentStores.indexOf(nodesStore), 1)
|
dependentStores.splice(dependentStores.indexOf(nodesStore), 1)
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import "./app.scss";
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { i18nStore } from "../i18n";
|
import { i18nStore } from "../i18n";
|
||||||
import { configStore } from "../config.store";
|
|
||||||
import { Terminal } from "./dock/terminal";
|
import { Terminal } from "./dock/terminal";
|
||||||
import { Redirect, Route, Switch } from "react-router";
|
import { Redirect, Route, Switch } from "react-router";
|
||||||
import { Notifications } from "./notifications";
|
import { Notifications } from "./notifications";
|
||||||
@ -35,6 +34,7 @@ import { clusterStore } from "../../common/cluster-store";
|
|||||||
import { ClusterSettings, clusterSettingsRoute } from "./+cluster-settings";
|
import { ClusterSettings, clusterSettingsRoute } from "./+cluster-settings";
|
||||||
import { Workspaces, workspacesRoute } from "./+workspaces";
|
import { Workspaces, workspacesRoute } from "./+workspaces";
|
||||||
import { ErrorBoundary } from "./error-boundary";
|
import { ErrorBoundary } from "./error-boundary";
|
||||||
|
import { configStore } from "../config.store";
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class App extends React.Component {
|
export class App extends React.Component {
|
||||||
|
|||||||
@ -1,15 +1,14 @@
|
|||||||
import "./cluster-manager.scss"
|
import "./cluster-manager.scss"
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { computed, observable } from "mobx";
|
import { observable } from "mobx";
|
||||||
import { App } from "../app";
|
import { App } from "../app";
|
||||||
import { ClusterStatus } from "./cluster-status";
|
import { ClusterStatus } from "./cluster-status";
|
||||||
import { ClustersMenu } from "./clusters-menu";
|
import { ClustersMenu } from "./clusters-menu";
|
||||||
import { BottomBar } from "./bottom-bar";
|
import { BottomBar } from "./bottom-bar";
|
||||||
import { cssNames, IClassName } from "../../utils";
|
import { cssNames, IClassName } from "../../utils";
|
||||||
import { invokeIpc } from "../../../common/ipc";
|
|
||||||
import { ClusterIpcChannel } from "../../../main/cluster";
|
|
||||||
import { clusterStore } from "../../../common/cluster-store";
|
import { clusterStore } from "../../../common/cluster-store";
|
||||||
|
import { clusterIpc } from "../../../common/cluster-ipc";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
className?: IClassName;
|
className?: IClassName;
|
||||||
@ -18,21 +17,17 @@ interface Props {
|
|||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class ClusterManager extends React.Component<Props> {
|
export class ClusterManager extends React.Component<Props> {
|
||||||
@observable appReady = false;
|
@observable isReady = false;
|
||||||
|
|
||||||
@computed get clusterReady() {
|
|
||||||
return clusterStore.activeCluster?.isReady
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
invokeIpc(ClusterIpcChannel.INIT);
|
clusterIpc.refresh.invokeFromRenderer();
|
||||||
await App.init();
|
await App.init();
|
||||||
this.appReady = true;
|
this.isReady = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { className, contentClass } = this.props;
|
const { className, contentClass } = this.props;
|
||||||
const isReady = this.appReady && this.clusterReady;
|
const isReady = this.isReady && clusterStore.activeCluster?.isReady;
|
||||||
return (
|
return (
|
||||||
<div className={cssNames("ClusterManager", className)}>
|
<div className={cssNames("ClusterManager", className)}>
|
||||||
<div id="draggable-top"/>
|
<div id="draggable-top"/>
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
import "./cluster-status.scss"
|
import "./cluster-status.scss"
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import type { KubeAuthProxyResponse } from "../../../main/kube-auth-proxy";
|
import type { KubeAuthProxyResponse } from "../../../main/kube-auth-proxy";
|
||||||
import { ClusterIpcChannel } from "../../../main/cluster";
|
|
||||||
import { invokeIpc } from "../../../common/ipc";
|
|
||||||
import { clusterStore } from "../../../common/cluster-store";
|
import { clusterStore } from "../../../common/cluster-store";
|
||||||
import { ipcRenderer } from "electron";
|
import { ipcRenderer } from "electron";
|
||||||
import { observable } from "mobx";
|
import { observable } from "mobx";
|
||||||
@ -10,6 +8,7 @@ import { observer } from "mobx-react";
|
|||||||
import { Icon } from "../icon";
|
import { Icon } from "../icon";
|
||||||
import { Button } from "../button";
|
import { Button } from "../button";
|
||||||
import { cssNames } from "../../utils";
|
import { cssNames } from "../../utils";
|
||||||
|
import { clusterIpc } from "../../../common/cluster-ipc";
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class ClusterStatus extends React.Component {
|
export class ClusterStatus extends React.Component {
|
||||||
@ -36,7 +35,7 @@ export class ClusterStatus extends React.Component {
|
|||||||
|
|
||||||
reconnect = () => {
|
reconnect = () => {
|
||||||
this.authOutput = ["Reconnecting ...\n"];
|
this.authOutput = ["Reconnecting ...\n"];
|
||||||
invokeIpc(ClusterIpcChannel.RECONNECT, this.clusterId);
|
clusterIpc.reconnect.invokeFromRenderer(this.clusterId);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { observable, when } from "mobx";
|
|||||||
import { autobind, interval } from "./utils";
|
import { autobind, interval } from "./utils";
|
||||||
import { apiBase } from "./api";
|
import { apiBase } from "./api";
|
||||||
|
|
||||||
// todo: use user-store.ts as isomorphic-store with config/settings for ui
|
// todo: remove, merge with common/user-store.ts
|
||||||
|
|
||||||
@autobind()
|
@autobind()
|
||||||
export class ConfigStore {
|
export class ConfigStore {
|
||||||
|
|||||||
@ -24,7 +24,7 @@ class LensApp extends React.Component {
|
|||||||
userStore.load(),
|
userStore.load(),
|
||||||
workspaceStore.load(),
|
workspaceStore.load(),
|
||||||
clusterStore.load(),
|
clusterStore.load(),
|
||||||
]);
|
])
|
||||||
render(<LensApp/>, rootElem);
|
render(<LensApp/>, rootElem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user