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

use browser fetch on renderer

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
Jari Kolehmainen 2021-09-22 17:37:34 +03:00
parent 070fc1bb44
commit 7e20856641
4 changed files with 57 additions and 35 deletions

View File

@ -48,25 +48,17 @@ if (typeof window === "undefined") {
});
} else {
apiBase = new JsonApi({
serverAddress: `http://127.0.0.1:${window.location.port}`,
serverAddress: `http://localhost:${window.location.port}`,
apiBase: apiPrefix,
debug: isDevelopment || isDebugging,
}, {
headers: {
"Host": window.location.host
}
});
}
if (isClusterPageContext()) {
apiKube = new KubeJsonApi({
serverAddress: `http://127.0.0.1:${window.location.port}`,
serverAddress: `http://${window.location.host}:${window.location.port}`,
apiBase: apiKubePrefix,
debug: isDevelopment
}, {
headers: {
"Host": window.location.host
}
});
}

View File

@ -21,8 +21,9 @@
// Base http-service / json-api class
import { randomBytes } from "crypto";
import { merge } from "lodash";
import fetch, { Response, RequestInit } from "node-fetch";
import nodeFetch, { Response as NodeResponse, RequestInit as NodeRequestInit } from "node-fetch";
import { stringify } from "querystring";
import { EventEmitter } from "../../common/event-emitter";
import logger from "../../common/logger";
@ -44,11 +45,14 @@ export interface JsonApiParams<D = any> {
export interface JsonApiLog {
method: string;
reqUrl: string;
reqInit: RequestInit;
reqInit: RequestInit | NodeRequestInit;
data?: any;
error?: any;
}
export type JsonRequestInit = RequestInit | NodeRequestInit;
export type JsonResponse = Response | NodeResponse;
export interface JsonApiConfig {
apiBase: string;
serverAddress: string;
@ -65,22 +69,22 @@ export class JsonApi<D = JsonApiData, P extends JsonApiParams = JsonApiParams> {
debug: false
};
constructor(public readonly config: JsonApiConfig, protected reqInit?: RequestInit) {
constructor(public readonly config: JsonApiConfig, protected reqInit?: JsonRequestInit) {
this.config = Object.assign({}, JsonApi.configDefault, config);
this.reqInit = merge({}, JsonApi.reqInitDefault, reqInit);
this.parseResponse = this.parseResponse.bind(this);
}
public onData = new EventEmitter<[D, Response]>();
public onError = new EventEmitter<[JsonApiErrorParsed, Response]>();
public onData = new EventEmitter<[D, JsonResponse]>();
public onError = new EventEmitter<[JsonApiErrorParsed, JsonResponse]>();
get<T = D>(path: string, params?: P, reqInit: RequestInit = {}) {
get<T = D>(path: string, params?: P, reqInit: RequestInit | NodeRequestInit = {}) {
return this.request<T>(path, params, { ...reqInit, method: "get" });
}
getResponse(path: string, params?: P, init: RequestInit = {}): Promise<Response> {
let reqUrl = `${this.config.serverAddress}${this.config.apiBase}${path}`;
const reqInit: RequestInit = merge({}, this.reqInit, init);
getResponse(path: string, params?: P, init: JsonRequestInit = {}): Promise<JsonResponse> {
let reqUrl = this.buildRequestUrl(path, true);
const reqInit = merge({}, this.reqInit, init);
const { query } = params || {} as P;
if (!reqInit.method) {
@ -93,28 +97,42 @@ export class JsonApi<D = JsonApiData, P extends JsonApiParams = JsonApiParams> {
reqUrl += (reqUrl.includes("?") ? "&" : "?") + queryString;
}
return fetch(reqUrl, reqInit);
if (window) {
return fetch(reqUrl, reqInit as RequestInit);
} else {
return nodeFetch(reqUrl, reqInit as NodeRequestInit);
}
}
post<T = D>(path: string, params?: P, reqInit: RequestInit = {}) {
post<T = D>(path: string, params?: P, reqInit: JsonRequestInit = {}) {
return this.request<T>(path, params, { ...reqInit, method: "post" });
}
put<T = D>(path: string, params?: P, reqInit: RequestInit = {}) {
put<T = D>(path: string, params?: P, reqInit: JsonRequestInit = {}) {
return this.request<T>(path, params, { ...reqInit, method: "put" });
}
patch<T = D>(path: string, params?: P, reqInit: RequestInit = {}) {
patch<T = D>(path: string, params?: P, reqInit: JsonRequestInit = {}) {
return this.request<T>(path, params, { ...reqInit, method: "PATCH" });
}
del<T = D>(path: string, params?: P, reqInit: RequestInit = {}) {
del<T = D>(path: string, params?: P, reqInit: JsonRequestInit = {}) {
return this.request<T>(path, params, { ...reqInit, method: "delete" });
}
protected async request<D>(path: string, params?: P, init: RequestInit = {}) {
let reqUrl = `${this.config.serverAddress}${this.config.apiBase}${path}`;
const reqInit: RequestInit = merge({}, this.reqInit, init);
protected buildRequestUrl(path: string, useSubdomain = false) {
if (window) {
const subdomain = useSubdomain ? `${randomBytes(2).toString("hex")}.` : "";
return `http://${subdomain}${window.location.host}${this.config.apiBase}${path}`;
} else {
return `${this.config.serverAddress}${this.config.apiBase}${path}`;
}
}
protected async request<D>(path: string, params?: P, init: JsonRequestInit = {}) {
let reqUrl = this.buildRequestUrl(path);
const reqInit = merge({}, this.reqInit, init);
const { data, query } = params || {} as P;
if (data && !reqInit.body) {
@ -132,12 +150,20 @@ export class JsonApi<D = JsonApiData, P extends JsonApiParams = JsonApiParams> {
reqInit,
};
const res = await fetch(reqUrl, reqInit);
const res = await this.fetch(reqUrl, reqInit);
return this.parseResponse<D>(res, infoLog);
}
protected async parseResponse<D>(res: Response, log: JsonApiLog): Promise<D> {
protected fetch(reqUrl: string, reqInit: JsonRequestInit) {
if (window) {
return fetch(reqUrl, reqInit as RequestInit);
} else {
return nodeFetch(reqUrl, reqInit as NodeRequestInit);
}
}
protected async parseResponse<D>(res: JsonResponse, log: JsonApiLog): Promise<D> {
const { status } = res;
const text = await res.text();
@ -169,7 +195,7 @@ export class JsonApi<D = JsonApiData, P extends JsonApiParams = JsonApiParams> {
throw error;
}
protected parseError(error: JsonApiError | string, res: Response): string[] {
protected parseError(error: JsonApiError | string, res: JsonResponse): string[] {
if (typeof error === "string") {
return [error];
}

View File

@ -36,6 +36,7 @@ import { noop } from "../utils";
import type { RequestInit } from "node-fetch";
import AbortController from "abort-controller";
import { Agent, AgentOptions } from "https";
import { ReadableWebToNodeStream } from "readable-web-to-node-stream";
export interface IKubeApiOptions<T extends KubeObject> {
/**
@ -117,7 +118,7 @@ export interface IRemoteKubeApiConfig {
export function forCluster<T extends KubeObject>(cluster: ILocalKubeApiConfig, kubeClass: KubeObjectConstructor<T>): KubeApi<T> {
const url = new URL(apiBase.config.serverAddress);
const request = new KubeJsonApi({
serverAddress: apiBase.config.serverAddress,
serverAddress: window ? `${cluster.metadata.uid}.localhost:${url.port}` : apiBase.config.serverAddress,
apiBase: apiKubePrefix,
debug: isDevelopment,
}, {
@ -507,21 +508,24 @@ export class KubeApi<T extends KubeObject> {
return callback(null, response);
}
const body = window ? new ReadableWebToNodeStream(response.body as ReadableStream): response.body as NodeJS.ReadableStream;
["end", "close", "error"].forEach((eventName) => {
response.body.on(eventName, () => {
body.on(eventName, () => {
clearTimeout(timedRetry);
if (errorReceived) return; // kubernetes errors should be handled in a callback
if (signal.aborted) return;
logger.info(`[KUBE-API] watch (${watchId}) ${eventName} ${watchUrl}`);
clearTimeout(timedRetry);
timedRetry = setTimeout(() => { // we did not get any kubernetes errors so let's retry
this.watch({ ...opts, namespace, callback, watchId, retry: true });
}, 1000);
});
});
byline(response.body).on("data", (line) => {
byline(body).on("data", (line) => {
try {
const event: IKubeWatchEvent<KubeJsonApiData> = JSON.parse(line);

View File

@ -348,7 +348,7 @@ export abstract class KubeObjectStore<T extends KubeObject> extends ItemStore<T>
const { signal } = abortController;
const callback = (data: IKubeWatchEvent<T>, error: any) => {
if (!this.isLoaded || error?.type === "aborted") return;
if (!this.isLoaded || error instanceof DOMException || error?.type === "aborted") return;
if (error instanceof Response) {
if (error.status === 404 || error.status === 401) {