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:
parent
070fc1bb44
commit
7e20856641
@ -48,25 +48,17 @@ if (typeof window === "undefined") {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
apiBase = new JsonApi({
|
apiBase = new JsonApi({
|
||||||
serverAddress: `http://127.0.0.1:${window.location.port}`,
|
serverAddress: `http://localhost:${window.location.port}`,
|
||||||
apiBase: apiPrefix,
|
apiBase: apiPrefix,
|
||||||
debug: isDevelopment || isDebugging,
|
debug: isDevelopment || isDebugging,
|
||||||
}, {
|
|
||||||
headers: {
|
|
||||||
"Host": window.location.host
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isClusterPageContext()) {
|
if (isClusterPageContext()) {
|
||||||
apiKube = new KubeJsonApi({
|
apiKube = new KubeJsonApi({
|
||||||
serverAddress: `http://127.0.0.1:${window.location.port}`,
|
serverAddress: `http://${window.location.host}:${window.location.port}`,
|
||||||
apiBase: apiKubePrefix,
|
apiBase: apiKubePrefix,
|
||||||
debug: isDevelopment
|
debug: isDevelopment
|
||||||
}, {
|
|
||||||
headers: {
|
|
||||||
"Host": window.location.host
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -21,8 +21,9 @@
|
|||||||
|
|
||||||
// Base http-service / json-api class
|
// Base http-service / json-api class
|
||||||
|
|
||||||
|
import { randomBytes } from "crypto";
|
||||||
import { merge } from "lodash";
|
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 { stringify } from "querystring";
|
||||||
import { EventEmitter } from "../../common/event-emitter";
|
import { EventEmitter } from "../../common/event-emitter";
|
||||||
import logger from "../../common/logger";
|
import logger from "../../common/logger";
|
||||||
@ -44,11 +45,14 @@ export interface JsonApiParams<D = any> {
|
|||||||
export interface JsonApiLog {
|
export interface JsonApiLog {
|
||||||
method: string;
|
method: string;
|
||||||
reqUrl: string;
|
reqUrl: string;
|
||||||
reqInit: RequestInit;
|
reqInit: RequestInit | NodeRequestInit;
|
||||||
data?: any;
|
data?: any;
|
||||||
error?: any;
|
error?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type JsonRequestInit = RequestInit | NodeRequestInit;
|
||||||
|
export type JsonResponse = Response | NodeResponse;
|
||||||
|
|
||||||
export interface JsonApiConfig {
|
export interface JsonApiConfig {
|
||||||
apiBase: string;
|
apiBase: string;
|
||||||
serverAddress: string;
|
serverAddress: string;
|
||||||
@ -65,22 +69,22 @@ export class JsonApi<D = JsonApiData, P extends JsonApiParams = JsonApiParams> {
|
|||||||
debug: false
|
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.config = Object.assign({}, JsonApi.configDefault, config);
|
||||||
this.reqInit = merge({}, JsonApi.reqInitDefault, reqInit);
|
this.reqInit = merge({}, JsonApi.reqInitDefault, reqInit);
|
||||||
this.parseResponse = this.parseResponse.bind(this);
|
this.parseResponse = this.parseResponse.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public onData = new EventEmitter<[D, Response]>();
|
public onData = new EventEmitter<[D, JsonResponse]>();
|
||||||
public onError = new EventEmitter<[JsonApiErrorParsed, Response]>();
|
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" });
|
return this.request<T>(path, params, { ...reqInit, method: "get" });
|
||||||
}
|
}
|
||||||
|
|
||||||
getResponse(path: string, params?: P, init: RequestInit = {}): Promise<Response> {
|
getResponse(path: string, params?: P, init: JsonRequestInit = {}): Promise<JsonResponse> {
|
||||||
let reqUrl = `${this.config.serverAddress}${this.config.apiBase}${path}`;
|
let reqUrl = this.buildRequestUrl(path, true);
|
||||||
const reqInit: RequestInit = merge({}, this.reqInit, init);
|
const reqInit = merge({}, this.reqInit, init);
|
||||||
const { query } = params || {} as P;
|
const { query } = params || {} as P;
|
||||||
|
|
||||||
if (!reqInit.method) {
|
if (!reqInit.method) {
|
||||||
@ -93,28 +97,42 @@ export class JsonApi<D = JsonApiData, P extends JsonApiParams = JsonApiParams> {
|
|||||||
reqUrl += (reqUrl.includes("?") ? "&" : "?") + queryString;
|
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" });
|
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" });
|
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" });
|
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" });
|
return this.request<T>(path, params, { ...reqInit, method: "delete" });
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async request<D>(path: string, params?: P, init: RequestInit = {}) {
|
protected buildRequestUrl(path: string, useSubdomain = false) {
|
||||||
let reqUrl = `${this.config.serverAddress}${this.config.apiBase}${path}`;
|
if (window) {
|
||||||
const reqInit: RequestInit = merge({}, this.reqInit, init);
|
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;
|
const { data, query } = params || {} as P;
|
||||||
|
|
||||||
if (data && !reqInit.body) {
|
if (data && !reqInit.body) {
|
||||||
@ -132,12 +150,20 @@ export class JsonApi<D = JsonApiData, P extends JsonApiParams = JsonApiParams> {
|
|||||||
reqInit,
|
reqInit,
|
||||||
};
|
};
|
||||||
|
|
||||||
const res = await fetch(reqUrl, reqInit);
|
const res = await this.fetch(reqUrl, reqInit);
|
||||||
|
|
||||||
return this.parseResponse<D>(res, infoLog);
|
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 { status } = res;
|
||||||
|
|
||||||
const text = await res.text();
|
const text = await res.text();
|
||||||
@ -169,7 +195,7 @@ export class JsonApi<D = JsonApiData, P extends JsonApiParams = JsonApiParams> {
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected parseError(error: JsonApiError | string, res: Response): string[] {
|
protected parseError(error: JsonApiError | string, res: JsonResponse): string[] {
|
||||||
if (typeof error === "string") {
|
if (typeof error === "string") {
|
||||||
return [error];
|
return [error];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,6 +36,7 @@ import { noop } from "../utils";
|
|||||||
import type { RequestInit } from "node-fetch";
|
import type { RequestInit } from "node-fetch";
|
||||||
import AbortController from "abort-controller";
|
import AbortController from "abort-controller";
|
||||||
import { Agent, AgentOptions } from "https";
|
import { Agent, AgentOptions } from "https";
|
||||||
|
import { ReadableWebToNodeStream } from "readable-web-to-node-stream";
|
||||||
|
|
||||||
export interface IKubeApiOptions<T extends KubeObject> {
|
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> {
|
export function forCluster<T extends KubeObject>(cluster: ILocalKubeApiConfig, kubeClass: KubeObjectConstructor<T>): KubeApi<T> {
|
||||||
const url = new URL(apiBase.config.serverAddress);
|
const url = new URL(apiBase.config.serverAddress);
|
||||||
const request = new KubeJsonApi({
|
const request = new KubeJsonApi({
|
||||||
serverAddress: apiBase.config.serverAddress,
|
serverAddress: window ? `${cluster.metadata.uid}.localhost:${url.port}` : apiBase.config.serverAddress,
|
||||||
apiBase: apiKubePrefix,
|
apiBase: apiKubePrefix,
|
||||||
debug: isDevelopment,
|
debug: isDevelopment,
|
||||||
}, {
|
}, {
|
||||||
@ -507,21 +508,24 @@ export class KubeApi<T extends KubeObject> {
|
|||||||
return callback(null, response);
|
return callback(null, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const body = window ? new ReadableWebToNodeStream(response.body as ReadableStream): response.body as NodeJS.ReadableStream;
|
||||||
|
|
||||||
["end", "close", "error"].forEach((eventName) => {
|
["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 (errorReceived) return; // kubernetes errors should be handled in a callback
|
||||||
if (signal.aborted) return;
|
if (signal.aborted) return;
|
||||||
|
|
||||||
logger.info(`[KUBE-API] watch (${watchId}) ${eventName} ${watchUrl}`);
|
logger.info(`[KUBE-API] watch (${watchId}) ${eventName} ${watchUrl}`);
|
||||||
|
|
||||||
clearTimeout(timedRetry);
|
|
||||||
timedRetry = setTimeout(() => { // we did not get any kubernetes errors so let's retry
|
timedRetry = setTimeout(() => { // we did not get any kubernetes errors so let's retry
|
||||||
this.watch({ ...opts, namespace, callback, watchId, retry: true });
|
this.watch({ ...opts, namespace, callback, watchId, retry: true });
|
||||||
}, 1000);
|
}, 1000);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
byline(response.body).on("data", (line) => {
|
byline(body).on("data", (line) => {
|
||||||
try {
|
try {
|
||||||
const event: IKubeWatchEvent<KubeJsonApiData> = JSON.parse(line);
|
const event: IKubeWatchEvent<KubeJsonApiData> = JSON.parse(line);
|
||||||
|
|
||||||
|
|||||||
@ -348,7 +348,7 @@ export abstract class KubeObjectStore<T extends KubeObject> extends ItemStore<T>
|
|||||||
const { signal } = abortController;
|
const { signal } = abortController;
|
||||||
|
|
||||||
const callback = (data: IKubeWatchEvent<T>, error: any) => {
|
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 instanceof Response) {
|
||||||
if (error.status === 404 || error.status === 401) {
|
if (error.status === 404 || error.status === 401) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user