1
0
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:
Jari Kolehmainen 2020-09-24 15:24:39 +03:00 committed by GitHub
parent 386e7c63bb
commit 11ea9d2098
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 49 additions and 22 deletions

View File

@ -93,6 +93,10 @@ export class BaseStore<T = any> extends Singleton {
}
}
unregisterIpcListener() {
ipcRenderer.removeAllListeners(this.syncChannel)
}
disableSync() {
this.syncDisposers.forEach(dispose => dispose());
this.syncDisposers.length = 0;

View File

@ -9,7 +9,7 @@ export const clusterIpc = {
const cluster = clusterStore.getById(clusterId);
if (cluster) {
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)
}
}),
}
}

View File

@ -1,5 +1,5 @@
import path from "path";
import { app, ipcRenderer, remote } from "electron";
import { app, ipcRenderer, remote, webFrame, webContents } from "electron";
import { unlink } from "fs-extra";
import { action, computed, observable, toJS } from "mobx";
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
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 removedClusters = 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 {
return this.getById(this.activeClusterId);
}

View File

@ -56,10 +56,10 @@ export class Cluster implements ClusterModel {
@observable kubeConfigPath: string;
@observable apiUrl: string; // cluster server url
@observable kubeProxyUrl: string; // lens-proxy to kube-api url
@observable online: boolean;
@observable accessible: boolean;
@observable ready: boolean;
@observable disconnected: boolean;
@observable online = false;
@observable accessible = false;
@observable ready = false;
@observable disconnected = true;
@observable failureReason: string;
@observable nodes = 0;
@observable version: string;
@ -124,13 +124,14 @@ export class Cluster implements ClusterModel {
this.eventDisposers.length = 0;
}
async activate(init = false) {
@action
async activate() {
logger.info(`[CLUSTER]: activate`, this.getMeta());
await this.whenInitialized;
if (!this.eventDisposers.length) {
this.bindEvents();
}
if (this.disconnected || (!init && !this.accessible)) {
if (this.disconnected || !this.accessible) {
await this.reconnect();
}
await this.refreshConnectionStatus()
@ -143,6 +144,7 @@ export class Cluster implements ClusterModel {
return this.pushState();
}
@action
async reconnect() {
logger.info(`[CLUSTER]: reconnect`, this.getMeta());
this.contextHandler.stopServer();

View File

@ -134,7 +134,6 @@ export class LensProxy {
protected async handleRequest(proxy: httpProxy, req: http.IncomingMessage, res: http.ServerResponse) {
const cluster = this.clusterManager.getClusterForRequest(req)
if (cluster) {
await cluster.contextHandler.ensureServer();
const proxyTarget = await this.getProxyTarget(req, cluster.contextHandler)
if (proxyTarget) {
// allow to fetch apis in "clusterId.localhost:port" from "localhost:port"

View File

@ -1,6 +1,6 @@
import "./components/app.scss"
import React from "react";
import { render } from "react-dom";
import { render, unmountComponentAtNode } from "react-dom";
import { isMac } from "../common/vars";
import { userStore } from "../common/user-store";
import { workspaceStore } from "../common/workspace-store";
@ -27,10 +27,22 @@ export async function bootstrap(App: AppComponent) {
themeStore.init(),
]);
// Register additional store listeners
clusterStore.registerIpcListener();
// init app's dependencies if any
if (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(<>
{isMac && <div id="draggable-top" />}
<App />

View File

@ -19,8 +19,11 @@ export async function initView(clusterId: ClusterId) {
if (!clusterId || lensViews.has(clusterId)) {
return;
}
logger.info(`[LENS-VIEW]: init dashboard, clusterId=${clusterId}`)
const cluster = clusterStore.getById(clusterId);
if (!cluster) {
return;
}
logger.info(`[LENS-VIEW]: init dashboard, clusterId=${clusterId}`)
const parentElem = document.getElementById("lens-views");
const iframe = document.createElement("iframe");
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.
// In that case for some reasons `webFrame.routingId` returns some previous frameId (usage in app.tsx)
// Issue: https://github.com/lensapp/lens/issues/811
iframe.dataset.meta = `${iframe.name} was removed at ${new Date().toLocaleString()}`;
iframe.removeAttribute("src")
iframe.dataset.meta = `${iframe.name} was removed at ${new Date().toLocaleString()}`
iframe.removeAttribute("name")
iframe.contentWindow.postMessage("teardown", "*")
}
export function refreshViews() {