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

Simplify handleLensRequest by factoring out sub functions

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2023-01-20 09:21:33 -05:00
parent 2d8ecbff43
commit bd6f204828
2 changed files with 140 additions and 73 deletions

14
src/common/utils/box.ts Normal file
View File

@ -0,0 +1,14 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
export class Box<T> {
constructor(private value: T) {}
get = () => this.value;
set = (newValue: T) => {
this.value = newValue;
};
}

View File

@ -5,14 +5,19 @@
import { getInjectable } from "@ogre-tools/injectable";
import assert from "assert";
import type { IncomingMessage, ServerResponse } from "http";
import type { ErrorCallback, ProxyResCallback } from "http-proxy";
import HttpProxyServer from "http-proxy";
import { Socket } from "net";
import type { Logger } from "../../common/logger";
import loggerInjectable from "../../common/logger.injectable";
import { Box } from "../../common/utils/box";
import { apiKubePrefix } from "../../common/vars";
import contentSecurityPolicyInjectable from "../../common/vars/content-security-policy.injectable";
import type { ClusterContextHandler } from "../context-handler/context-handler";
import type { RouteRequest } from "../router/route-request.injectable";
import routeRequestInjectable from "../router/route-request.injectable";
import { getBoolean } from "../utils/parse-query";
import type { GetClusterForRequest } from "./get-cluster-for-request.injectable";
import getClusterForRequestInjectable from "./get-cluster-for-request.injectable";
const getRequestId = (req: IncomingMessage) => {
@ -37,18 +42,7 @@ export interface HandleLensRequest {
stopHandling: () => void;
}
const handleLensRequestInjectable = getInjectable({
id: "handle-lens-request",
instantiate: (di): HandleLensRequest => {
const logger = di.inject(loggerInjectable);
const getClusterForRequest = di.inject(getClusterForRequestInjectable);
const contentSecurityPolicy = di.inject(contentSecurityPolicyInjectable);
const routeRequest = di.inject(routeRequestInjectable);
const retryCounters = new Map<string, number>();
let closed = false;
const getProxyTarget = async (req: IncomingMessage, contextHandler: ClusterContextHandler) => {
const getProxyTarget = async (req: IncomingMessage, contextHandler: ClusterContextHandler) => {
if (req.url?.startsWith(apiKubePrefix)) {
delete req.headers.authorization;
req.url = req.url.replace(apiKubePrefix, "");
@ -57,18 +51,33 @@ const handleLensRequestInjectable = getInjectable({
}
return undefined;
};
};
const proxy = HttpProxyServer.createProxy()
.on("proxyRes", (proxyRes, req, res) => {
const onProxyResWith = (retryCounters: Map<string, number>): ProxyResCallback => (proxyRes, req, res) => {
retryCounters.delete(getRequestId(req));
proxyRes.on("aborted", () => { // happens when proxy target aborts connection
res.end();
});
})
.on("error", (error, req, res, target) => {
if (closed || res instanceof Socket) {
};
interface OnErrorWithDeps {
closed: Box<boolean>;
logger: Logger;
retryCounters: Map<string, number>;
handleRequest: HandleRequest;
}
const onErrorWith = (deps: OnErrorWithDeps): ErrorCallback => {
const {
closed,
logger,
retryCounters,
handleRequest,
} = deps;
return (error, req, res, target) => {
if (closed.get() || res instanceof Socket) {
return;
}
@ -104,9 +113,25 @@ const handleLensRequestInjectable = getInjectable({
} catch (e) {
logger.error(`[LENS-PROXY]: Failed to write headers: `, e);
}
});
};
};
const handleRequest: HandleRequest = async (req, res) => {
interface HandleRequestWithDeps {
getClusterForRequest: GetClusterForRequest;
proxy: HttpProxyServer;
contentSecurityPolicy: string;
routeRequest: RouteRequest;
}
const handleRequestWith = (deps: HandleRequestWithDeps): HandleRequest => {
const {
getClusterForRequest,
proxy,
contentSecurityPolicy,
routeRequest,
} = deps;
return async (req, res) => {
const cluster = getClusterForRequest(req);
if (cluster) {
@ -120,10 +145,38 @@ const handleLensRequestInjectable = getInjectable({
res.setHeader("Content-Security-Policy", contentSecurityPolicy);
await routeRequest(cluster, req, res);
};
};
const handleLensRequestInjectable = getInjectable({
id: "handle-lens-request",
instantiate: (di): HandleLensRequest => {
const logger = di.inject(loggerInjectable);
const getClusterForRequest = di.inject(getClusterForRequestInjectable);
const contentSecurityPolicy = di.inject(contentSecurityPolicyInjectable);
const routeRequest = di.inject(routeRequestInjectable);
const retryCounters = new Map<string, number>();
const closed = new Box(false);
const proxy = HttpProxyServer.createProxy();
const handleRequest = handleRequestWith({
contentSecurityPolicy,
getClusterForRequest,
proxy,
routeRequest,
});
proxy.on("proxyRes", onProxyResWith(retryCounters));
proxy.on("error", onErrorWith({
closed,
handleRequest,
logger,
retryCounters,
}));
return {
handle: handleRequest,
stopHandling: () => closed = true,
stopHandling: () => closed.set(true),
};
},
});