diff --git a/packages/core/src/main/lens-proxy/attempt-to-listen.injectable.ts b/packages/core/src/main/lens-proxy/attempt-to-listen.injectable.ts new file mode 100644 index 0000000000..04a044252c --- /dev/null +++ b/packages/core/src/main/lens-proxy/attempt-to-listen.injectable.ts @@ -0,0 +1,56 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import type { AddressInfo } from "net"; +import emitAppEventInjectable from "../../common/app-event-bus/emit-event.injectable"; +import loggerInjectable from "../../common/logger.injectable"; +import lensProxyHttpsServerInjectable from "./https-proxy/server.injectable"; +import lensProxyPortInjectable from "./lens-proxy-port.injectable"; + +/** + * Starts to listen on an OS provided port. Will reject if the server throws + * an error. + * + * Resolves with the port number that was picked + */ +export type AttemptToListen = () => Promise; + +const attemptToListenInjectable = getInjectable({ + id: "attempt-to-listen", + instantiate: (di) => { + const proxyServer = di.inject(lensProxyHttpsServerInjectable); + const lensProxyPort = di.inject(lensProxyPortInjectable); + const logger = di.inject(loggerInjectable); + const emitAppEvent = di.inject(emitAppEventInjectable); + + return () => new Promise((resolve, reject) => { + proxyServer + .once("listening", () => { + proxyServer.removeAllListeners("error"); // don't reject the promise + + const { address, port } = proxyServer.address() as AddressInfo; + + lensProxyPort.set(port); + + logger.info(`[LENS-PROXY]: Proxy server has started at ${address}:${port}`); + + proxyServer.on("error", (error) => { + logger.info(`[LENS-PROXY]: Subsequent error: ${error}`); + }); + + emitAppEvent({ name: "lens-proxy", action: "listen", params: { port }}); + resolve(port); + }) + .once("error", (error) => { + logger.info(`[LENS-PROXY]: Proxy server failed to start: ${error}`); + reject(error); + }); + + proxyServer.listen(0, "127.0.0.1"); + }); + }, +}); + +export default attemptToListenInjectable; diff --git a/packages/core/src/main/lens-proxy/lens-proxy.injectable.ts b/packages/core/src/main/lens-proxy/lens-proxy.injectable.ts index 265e9dbe4b..b182d24723 100644 --- a/packages/core/src/main/lens-proxy/lens-proxy.injectable.ts +++ b/packages/core/src/main/lens-proxy/lens-proxy.injectable.ts @@ -4,21 +4,19 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { LensProxy } from "./lens-proxy"; -import lensProxyPortInjectable from "./lens-proxy-port.injectable"; -import emitAppEventInjectable from "../../common/app-event-bus/emit-event.injectable"; import loggerInjectable from "../../common/logger.injectable"; import lensProxyHttpsServerInjectable from "./https-proxy/server.injectable"; import proxyRetryInjectable from "./proxy/retry.injectable"; +import attemptToListenInjectable from "./attempt-to-listen.injectable"; const lensProxyInjectable = getInjectable({ id: "lens-proxy", instantiate: (di) => new LensProxy({ proxyServer: di.inject(lensProxyHttpsServerInjectable), - lensProxyPort: di.inject(lensProxyPortInjectable), - emitAppEvent: di.inject(emitAppEventInjectable), logger: di.inject(loggerInjectable), proxyRetry: di.inject(proxyRetryInjectable), + attemptToListen: di.inject(attemptToListenInjectable), }), }); diff --git a/packages/core/src/main/lens-proxy/lens-proxy.ts b/packages/core/src/main/lens-proxy/lens-proxy.ts index a509d0c230..57435fc26f 100644 --- a/packages/core/src/main/lens-proxy/lens-proxy.ts +++ b/packages/core/src/main/lens-proxy/lens-proxy.ts @@ -3,24 +3,22 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import type net from "net"; import type https from "https"; import type http from "http"; import type { Cluster } from "../../common/cluster/cluster"; import type { ProxyApiRequestArgs } from "./proxy-functions"; import type { SetRequired } from "type-fest"; -import type { EmitAppEvent } from "../../common/app-event-bus/emit-event.injectable"; import type { Logger } from "../../common/logger"; import { disallowedPorts } from "./disallowed-ports"; import type { ProxyRetry } from "./proxy/retry.injectable"; +import type { AttemptToListen } from "./attempt-to-listen.injectable"; export type GetClusterForRequest = (req: http.IncomingMessage) => Cluster | undefined; export type ServerIncomingMessage = SetRequired; export type LensProxyApiRequest = (args: ProxyApiRequestArgs) => void | Promise; interface Dependencies { - emitAppEvent: EmitAppEvent; - readonly lensProxyPort: { set: (portNumber: number) => void }; + attemptToListen: AttemptToListen; readonly logger: Logger; readonly proxyServer: https.Server; readonly proxyRetry: ProxyRetry; @@ -29,40 +27,6 @@ interface Dependencies { export class LensProxy { constructor(private readonly dependencies: Dependencies) {} - /** - * Starts to listen on an OS provided port. Will reject if the server throws - * an error. - * - * Resolves with the port number that was picked - */ - private attemptToListen(): Promise { - return new Promise((resolve, reject) => { - this.dependencies.proxyServer.listen(0, "127.0.0.1"); - - this.dependencies.proxyServer - .once("listening", () => { - this.dependencies.proxyServer.removeAllListeners("error"); // don't reject the promise - - const { address, port } = this.dependencies.proxyServer.address() as net.AddressInfo; - - this.dependencies.lensProxyPort.set(port); - - this.dependencies.logger.info(`[LENS-PROXY]: Proxy server has started at ${address}:${port}`); - - this.dependencies.proxyServer.on("error", (error) => { - this.dependencies.logger.info(`[LENS-PROXY]: Subsequent error: ${error}`); - }); - - this.dependencies.emitAppEvent({ name: "lens-proxy", action: "listen", params: { port }}); - resolve(port); - }) - .once("error", (error) => { - this.dependencies.logger.info(`[LENS-PROXY]: Proxy server failed to start: ${error}`); - reject(error); - }); - }); - } - /** * Starts the lens proxy. * @resolves After the server is listening on a good port @@ -73,7 +37,7 @@ export class LensProxy { while(true) { this.dependencies.proxyServer?.close(); - const port = await this.attemptToListen(); + const port = await this.dependencies.attemptToListen(); if (!disallowedPorts.has(port)) { // We didn't get a port that would result in an ERR_UNSAFE_PORT error, use it