1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

workaround for browser connection limits

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
Jari Kolehmainen 2021-02-08 22:46:31 +02:00
parent 73195c2f14
commit c134d322a9
5 changed files with 29 additions and 16 deletions

View File

@ -194,7 +194,8 @@ export class LensProxy {
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"
res.setHeader("Access-Control-Allow-Origin", this.origin); // this should be safe because we have already validated cluster uuid
res.setHeader("Access-Control-Allow-Origin", "*");
return proxy.web(req, res, proxyTarget); return proxy.web(req, res, proxyTarget);
} }

View File

@ -55,17 +55,28 @@ export class JsonApi<D = JsonApiData, P extends JsonApiParams = JsonApiParams> {
return this.request<T>(path, params, { ...reqInit, method: "get" }); return this.request<T>(path, params, { ...reqInit, method: "get" });
} }
getReadableStream(path: string, params?: P, init: RequestInit = {}): Promise<Response> { getResponse(reqUrl: string, params?: P, init: RequestInit = { }): Promise<Response> {
let reqUrl = this.config.apiBase + path;
const reqInit: RequestInit = { ...init }; const reqInit: RequestInit = { ...init };
const { query } = params || {} as P; const { query } = params || {} as P;
if (!reqInit.method) {
reqInit.method = "get";
}
if (query) { if (query) {
const queryString = stringify(query); const queryString = stringify(query);
reqUrl += (reqUrl.includes("?") ? "&" : "?") + queryString; reqUrl += (reqUrl.includes("?") ? "&" : "?") + queryString;
} }
const infoLog: JsonApiLog = {
method: `${reqInit.method.toUpperCase()} (stream)`,
reqUrl,
reqInit,
};
this.writeLog({ ...infoLog });
return fetch(reqUrl, reqInit); return fetch(reqUrl, reqInit);
} }

View File

@ -371,12 +371,15 @@ export class KubeApi<T extends KubeObject = any> {
opts.abortController = new AbortController(); opts.abortController = new AbortController();
} }
const { abortController, namespace, callback } = opts; const { abortController, namespace, callback } = opts;
const watchUrl = this.getWatchUrl(namespace);
const responsePromise = this.request.getReadableStream(watchUrl, null, { signal: abortController.signal }); // FIXME
let disposed = false; const watchUrl = `http://${this.kind}-watch.${window.location.host}${apiKubePrefix}${this.getWatchUrl(namespace)}`;
const responsePromise = this.request.getResponse(watchUrl, null, {
signal: abortController.signal
});
responsePromise.then((response) => { responsePromise.then((response) => {
if (!response.ok && !disposed) { if (!response.ok && !abortController.signal.aborted) {
if (response.status === 410) { // resourceVersion has gone if (response.status === 410) { // resourceVersion has gone
setTimeout(() => { setTimeout(() => {
this.refreshResourceVersion().then(() => { this.refreshResourceVersion().then(() => {
@ -399,8 +402,6 @@ export class KubeApi<T extends KubeObject = any> {
try { try {
const data: IKubeWatchEvent = JSON.parse(line); const data: IKubeWatchEvent = JSON.parse(line);
console.log("data", data);
if (callback) { if (callback) {
callback(data); callback(data);
} }
@ -411,7 +412,7 @@ export class KubeApi<T extends KubeObject = any> {
stream.on("close", () => { stream.on("close", () => {
setTimeout(() => { setTimeout(() => {
if (!disposed) this.watch({...opts, namespace, callback}); if (!abortController.signal.aborted) this.watch({...opts, namespace, callback});
}, 1000); }, 1000);
}); });
}, (error) => { }, (error) => {
@ -423,7 +424,6 @@ export class KubeApi<T extends KubeObject = any> {
}); });
const disposer = () => { const disposer = () => {
disposed = true;
abortController.abort(); abortController.abort();
}; };

View File

@ -22,6 +22,7 @@ import { MenuItem } from "../menu";
import { Checkbox } from "../checkbox"; import { Checkbox } from "../checkbox";
import { userStore } from "../../../common/user-store"; import { userStore } from "../../../common/user-store";
import { namespaceStore } from "../+namespaces/namespace.store"; import { namespaceStore } from "../+namespaces/namespace.store";
import { Icon } from "../icon";
// todo: refactor, split to small re-usable components // todo: refactor, split to small re-usable components
@ -341,16 +342,17 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
const allItemsCount = this.props.store.getTotalCount(); const allItemsCount = this.props.store.getTotalCount();
const itemsCount = items.length; const itemsCount = items.length;
const isFiltered = isReady && filters.length > 0; const isFiltered = isReady && filters.length > 0;
const RefreshIcon = <Icon material="update" small={true} onClick={() => this.loadStores()} />;
if (isFiltered) { if (isFiltered) {
const toggleFilters = () => userSettings.showAppliedFilters = !userSettings.showAppliedFilters; const toggleFilters = () => userSettings.showAppliedFilters = !userSettings.showAppliedFilters;
return ( return (
<><a onClick={toggleFilters}>Filtered</a>: {itemsCount} / {allItemsCount}</> <><a onClick={toggleFilters}>Filtered</a>: {itemsCount} / {allItemsCount} {RefreshIcon}</>
); );
} }
return allItemsCount <= 1 ? `${allItemsCount} item` : `${allItemsCount} items`; return allItemsCount <= 1 ? <>{allItemsCount} item {RefreshIcon}</> : <>{allItemsCount} items {RefreshIcon}</>;
} }
renderHeader() { renderHeader() {

View File

@ -267,16 +267,16 @@ export abstract class KubeObjectStore<T extends KubeObject = any> extends ItemSt
} }
subscribe(apis = this.getSubscribeApis()) { subscribe(apis = this.getSubscribeApis()) {
const abortController = new AbortController();
let disposers: {(): void}[] = []; let disposers: {(): void}[] = [];
const callback = (data: IKubeWatchEvent) => { const callback = (data: IKubeWatchEvent) => {
if (!this.isLoaded) return;
this.eventsBuffer.push(data); this.eventsBuffer.push(data);
}; };
if (this.context.cluster.isGlobalWatchEnabled) { if (this.context.cluster.isGlobalWatchEnabled) {
disposers = apis.map(api => api.watch({ disposers = apis.map(api => api.watch({
abortController,
namespace: "", namespace: "",
callback: (data) => callback(data), callback: (data) => callback(data),
})); }));
@ -284,7 +284,6 @@ export abstract class KubeObjectStore<T extends KubeObject = any> extends ItemSt
apis.map(api => { apis.map(api => {
this.loadedNamespaces.forEach((namespace) => { this.loadedNamespaces.forEach((namespace) => {
disposers.push(api.watch({ disposers.push(api.watch({
abortController,
namespace, namespace,
callback: (data) => callback(data) callback: (data) => callback(data)
})); }));