mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Fix iframe ipc flakyness after cluster is removed (#954)
Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
parent
386e7c63bb
commit
11ea9d2098
@ -93,6 +93,10 @@ export class BaseStore<T = any> extends Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unregisterIpcListener() {
|
||||||
|
ipcRenderer.removeAllListeners(this.syncChannel)
|
||||||
|
}
|
||||||
|
|
||||||
disableSync() {
|
disableSync() {
|
||||||
this.syncDisposers.forEach(dispose => dispose());
|
this.syncDisposers.forEach(dispose => dispose());
|
||||||
this.syncDisposers.length = 0;
|
this.syncDisposers.length = 0;
|
||||||
|
|||||||
@ -9,7 +9,7 @@ export const clusterIpc = {
|
|||||||
const cluster = clusterStore.getById(clusterId);
|
const cluster = clusterStore.getById(clusterId);
|
||||||
if (cluster) {
|
if (cluster) {
|
||||||
if (frameId) cluster.frameId = frameId; // save cluster's webFrame.routingId to be able to send push-updates
|
if (frameId) cluster.frameId = frameId; // save cluster's webFrame.routingId to be able to send push-updates
|
||||||
return cluster.activate(true);
|
return cluster.activate();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@ -58,4 +58,4 @@ export const clusterIpc = {
|
|||||||
return clusterStore.getById(clusterId)?.upgradeFeature(feature, config)
|
return clusterStore.getById(clusterId)?.upgradeFeature(feature, config)
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import path from "path";
|
import path from "path";
|
||||||
import { app, ipcRenderer, remote } from "electron";
|
import { app, ipcRenderer, remote, webFrame, webContents } from "electron";
|
||||||
import { unlink } from "fs-extra";
|
import { unlink } from "fs-extra";
|
||||||
import { action, computed, observable, toJS } from "mobx";
|
import { action, computed, observable, toJS } from "mobx";
|
||||||
import { BaseStore } from "./base-store";
|
import { BaseStore } from "./base-store";
|
||||||
@ -73,20 +73,27 @@ export class ClusterStore extends BaseStore<ClusterStoreModel> {
|
|||||||
accessPropertiesByDotNotation: false, // To make dots safe in cluster context names
|
accessPropertiesByDotNotation: false, // To make dots safe in cluster context names
|
||||||
migrations: migrations,
|
migrations: migrations,
|
||||||
});
|
});
|
||||||
if (ipcRenderer) {
|
|
||||||
ipcRenderer.on("cluster:state", (event, model: ClusterState) => {
|
|
||||||
this.applyWithoutSync(() => {
|
|
||||||
logger.silly(`[CLUSTER-STORE]: received push-state at ${location.host}`, model);
|
|
||||||
this.getById(model.id)?.updateModel(model);
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@observable activeClusterId: ClusterId;
|
@observable activeClusterId: ClusterId;
|
||||||
@observable removedClusters = observable.map<ClusterId, Cluster>();
|
@observable removedClusters = observable.map<ClusterId, Cluster>();
|
||||||
@observable clusters = observable.map<ClusterId, Cluster>();
|
@observable clusters = observable.map<ClusterId, Cluster>();
|
||||||
|
|
||||||
|
registerIpcListener() {
|
||||||
|
logger.info(`[CLUSTER-STORE] start to listen (${webFrame.routingId})`)
|
||||||
|
ipcRenderer.on("cluster:state", (event, model: ClusterState) => {
|
||||||
|
this.applyWithoutSync(() => {
|
||||||
|
logger.silly(`[CLUSTER-STORE]: received push-state at ${location.host} (${webFrame.routingId})`, model);
|
||||||
|
this.getById(model.id)?.updateModel(model);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
unregisterIpcListener() {
|
||||||
|
super.unregisterIpcListener()
|
||||||
|
ipcRenderer.removeAllListeners("cluster:state")
|
||||||
|
}
|
||||||
|
|
||||||
@computed get activeCluster(): Cluster | null {
|
@computed get activeCluster(): Cluster | null {
|
||||||
return this.getById(this.activeClusterId);
|
return this.getById(this.activeClusterId);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -56,10 +56,10 @@ export class Cluster implements ClusterModel {
|
|||||||
@observable kubeConfigPath: string;
|
@observable kubeConfigPath: string;
|
||||||
@observable apiUrl: string; // cluster server url
|
@observable apiUrl: string; // cluster server url
|
||||||
@observable kubeProxyUrl: string; // lens-proxy to kube-api url
|
@observable kubeProxyUrl: string; // lens-proxy to kube-api url
|
||||||
@observable online: boolean;
|
@observable online = false;
|
||||||
@observable accessible: boolean;
|
@observable accessible = false;
|
||||||
@observable ready: boolean;
|
@observable ready = false;
|
||||||
@observable disconnected: boolean;
|
@observable disconnected = true;
|
||||||
@observable failureReason: string;
|
@observable failureReason: string;
|
||||||
@observable nodes = 0;
|
@observable nodes = 0;
|
||||||
@observable version: string;
|
@observable version: string;
|
||||||
@ -124,13 +124,14 @@ export class Cluster implements ClusterModel {
|
|||||||
this.eventDisposers.length = 0;
|
this.eventDisposers.length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
async activate(init = false) {
|
@action
|
||||||
|
async activate() {
|
||||||
logger.info(`[CLUSTER]: activate`, this.getMeta());
|
logger.info(`[CLUSTER]: activate`, this.getMeta());
|
||||||
await this.whenInitialized;
|
await this.whenInitialized;
|
||||||
if (!this.eventDisposers.length) {
|
if (!this.eventDisposers.length) {
|
||||||
this.bindEvents();
|
this.bindEvents();
|
||||||
}
|
}
|
||||||
if (this.disconnected || (!init && !this.accessible)) {
|
if (this.disconnected || !this.accessible) {
|
||||||
await this.reconnect();
|
await this.reconnect();
|
||||||
}
|
}
|
||||||
await this.refreshConnectionStatus()
|
await this.refreshConnectionStatus()
|
||||||
@ -143,6 +144,7 @@ export class Cluster implements ClusterModel {
|
|||||||
return this.pushState();
|
return this.pushState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
async reconnect() {
|
async reconnect() {
|
||||||
logger.info(`[CLUSTER]: reconnect`, this.getMeta());
|
logger.info(`[CLUSTER]: reconnect`, this.getMeta());
|
||||||
this.contextHandler.stopServer();
|
this.contextHandler.stopServer();
|
||||||
|
|||||||
@ -134,7 +134,6 @@ export class LensProxy {
|
|||||||
protected async handleRequest(proxy: httpProxy, req: http.IncomingMessage, res: http.ServerResponse) {
|
protected async handleRequest(proxy: httpProxy, req: http.IncomingMessage, res: http.ServerResponse) {
|
||||||
const cluster = this.clusterManager.getClusterForRequest(req)
|
const cluster = this.clusterManager.getClusterForRequest(req)
|
||||||
if (cluster) {
|
if (cluster) {
|
||||||
await cluster.contextHandler.ensureServer();
|
|
||||||
const proxyTarget = await this.getProxyTarget(req, cluster.contextHandler)
|
const proxyTarget = await this.getProxyTarget(req, cluster.contextHandler)
|
||||||
if (proxyTarget) {
|
if (proxyTarget) {
|
||||||
// allow to fetch apis in "clusterId.localhost:port" from "localhost:port"
|
// allow to fetch apis in "clusterId.localhost:port" from "localhost:port"
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import "./components/app.scss"
|
import "./components/app.scss"
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { render } from "react-dom";
|
import { render, unmountComponentAtNode } from "react-dom";
|
||||||
import { isMac } from "../common/vars";
|
import { isMac } from "../common/vars";
|
||||||
import { userStore } from "../common/user-store";
|
import { userStore } from "../common/user-store";
|
||||||
import { workspaceStore } from "../common/workspace-store";
|
import { workspaceStore } from "../common/workspace-store";
|
||||||
@ -27,10 +27,22 @@ export async function bootstrap(App: AppComponent) {
|
|||||||
themeStore.init(),
|
themeStore.init(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// Register additional store listeners
|
||||||
|
clusterStore.registerIpcListener();
|
||||||
|
|
||||||
// init app's dependencies if any
|
// init app's dependencies if any
|
||||||
if (App.init) {
|
if (App.init) {
|
||||||
await App.init();
|
await App.init();
|
||||||
}
|
}
|
||||||
|
window.addEventListener("message", (ev: MessageEvent) => {
|
||||||
|
if (ev.data === "teardown") {
|
||||||
|
userStore.unregisterIpcListener()
|
||||||
|
workspaceStore.unregisterIpcListener()
|
||||||
|
clusterStore.unregisterIpcListener()
|
||||||
|
unmountComponentAtNode(rootElem)
|
||||||
|
window.location.href = "about:blank"
|
||||||
|
}
|
||||||
|
})
|
||||||
render(<>
|
render(<>
|
||||||
{isMac && <div id="draggable-top" />}
|
{isMac && <div id="draggable-top" />}
|
||||||
<App />
|
<App />
|
||||||
|
|||||||
@ -19,8 +19,11 @@ export async function initView(clusterId: ClusterId) {
|
|||||||
if (!clusterId || lensViews.has(clusterId)) {
|
if (!clusterId || lensViews.has(clusterId)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
logger.info(`[LENS-VIEW]: init dashboard, clusterId=${clusterId}`)
|
|
||||||
const cluster = clusterStore.getById(clusterId);
|
const cluster = clusterStore.getById(clusterId);
|
||||||
|
if (!cluster) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
logger.info(`[LENS-VIEW]: init dashboard, clusterId=${clusterId}`)
|
||||||
const parentElem = document.getElementById("lens-views");
|
const parentElem = document.getElementById("lens-views");
|
||||||
const iframe = document.createElement("iframe");
|
const iframe = document.createElement("iframe");
|
||||||
iframe.name = cluster.contextName;
|
iframe.name = cluster.contextName;
|
||||||
@ -42,9 +45,9 @@ export async function autoCleanOnRemove(clusterId: ClusterId, iframe: HTMLIFrame
|
|||||||
// Keep frame in DOM to avoid possible bugs when same cluster re-created after being removed.
|
// Keep frame in DOM to avoid possible bugs when same cluster re-created after being removed.
|
||||||
// In that case for some reasons `webFrame.routingId` returns some previous frameId (usage in app.tsx)
|
// In that case for some reasons `webFrame.routingId` returns some previous frameId (usage in app.tsx)
|
||||||
// Issue: https://github.com/lensapp/lens/issues/811
|
// Issue: https://github.com/lensapp/lens/issues/811
|
||||||
iframe.dataset.meta = `${iframe.name} was removed at ${new Date().toLocaleString()}`;
|
iframe.dataset.meta = `${iframe.name} was removed at ${new Date().toLocaleString()}`
|
||||||
iframe.removeAttribute("src")
|
|
||||||
iframe.removeAttribute("name")
|
iframe.removeAttribute("name")
|
||||||
|
iframe.contentWindow.postMessage("teardown", "*")
|
||||||
}
|
}
|
||||||
|
|
||||||
export function refreshViews() {
|
export function refreshViews() {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user