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

Split out use of httpsProxy preference (#6771)

* Split out use of httpsProxy preference

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Rename file

Signed-off-by: Sebastian Malton <sebastian@malton.name>

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2022-12-20 08:00:15 -08:00 committed by GitHub
parent 443081493b
commit 24240655c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 130 additions and 91 deletions

View File

@ -1,55 +0,0 @@
/**
* 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 { RequestInit, Response } from "node-fetch";
import type { AsyncResult } from "../utils/async-result";
import fetchInjectable from "./fetch.injectable";
export interface DownloadJsonOptions {
signal?: AbortSignal | null | undefined;
}
export type DownloadJson = (url: string, opts?: DownloadJsonOptions) => Promise<AsyncResult<unknown, string>>;
const downloadJsonInjectable = getInjectable({
id: "download-json",
instantiate: (di): DownloadJson => {
const fetch = di.inject(fetchInjectable);
return async (url, opts) => {
let result: Response;
try {
result = await fetch(url, opts as RequestInit);
} catch (error) {
return {
callWasSuccessful: false,
error: String(error),
};
}
if (result.status < 200 || 300 <= result.status) {
return {
callWasSuccessful: false,
error: result.statusText,
};
}
try {
return {
callWasSuccessful: true,
response: await result.json(),
};
} catch (error) {
return {
callWasSuccessful: false,
error: String(error),
};
}
};
},
});
export default downloadJsonInjectable;

View File

@ -0,0 +1,46 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { AsyncResult } from "../../utils/async-result";
import type { Fetch } from "../fetch.injectable";
import type { RequestInit, Response } from "node-fetch";
export interface DownloadJsonOptions {
signal?: AbortSignal | null | undefined;
}
export type DownloadJson = (url: string, opts?: DownloadJsonOptions) => Promise<AsyncResult<unknown, string>>;
export const downloadJsonWith = (fetch: Fetch): DownloadJson => async (url, opts) => {
let result: Response;
try {
result = await fetch(url, opts as RequestInit);
} catch (error) {
return {
callWasSuccessful: false,
error: String(error),
};
}
if (result.status < 200 || 300 <= result.status) {
return {
callWasSuccessful: false,
error: result.statusText,
};
}
try {
return {
callWasSuccessful: true,
response: await result.json(),
};
} catch (error) {
return {
callWasSuccessful: false,
error: String(error),
};
}
};

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.
*/
import { getInjectable } from "@ogre-tools/injectable";
import fetchInjectable from "../fetch.injectable";
import { downloadJsonWith } from "./impl";
const downloadJsonInjectable = getInjectable({
id: "download-json",
instantiate: (di) => downloadJsonWith(di.inject(fetchInjectable)),
});
export default downloadJsonInjectable;

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.
*/
import { getInjectable } from "@ogre-tools/injectable";
import proxyFetchInjectable from "../proxy-fetch.injectable";
import { downloadJsonWith } from "./impl";
const proxyDownloadJsonInjectable = getInjectable({
id: "proxy-download-json",
instantiate: (di) => downloadJsonWith(di.inject(proxyFetchInjectable)),
});
export default proxyDownloadJsonInjectable;

View File

@ -0,0 +1,19 @@
/**
* 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 * as FetchModule from "node-fetch";
const { NodeFetch } = require("../../../build/webpack/node-fetch.bundle") as { NodeFetch: typeof FetchModule };
/**
* NOTE: while using this module can cause side effects, this specific injectable is not marked as
* such since sometimes the request can be wholely within the perview of unit test
*/
const nodeFetchModuleInjectable = getInjectable({
id: "node-fetch-module",
instantiate: () => NodeFetch,
});
export default nodeFetchModuleInjectable;

View File

@ -3,32 +3,17 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { HttpsProxyAgent } from "hpagent";
import type * as FetchModule from "node-fetch";
import userStoreInjectable from "../user-store/user-store.injectable";
const { NodeFetch: { default: fetch }} = require("../../../build/webpack/node-fetch.bundle") as { NodeFetch: typeof FetchModule };
type Response = FetchModule.Response;
type RequestInit = FetchModule.RequestInit;
import type { RequestInit, Response } from "node-fetch";
import nodeFetchModuleInjectable from "./fetch-module.injectable";
export type Fetch = (url: string, init?: RequestInit) => Promise<Response>;
const fetchInjectable = getInjectable({
id: "fetch",
instantiate: (di): Fetch => {
const { httpsProxy, allowUntrustedCAs } = di.inject(userStoreInjectable);
const agent = httpsProxy
? new HttpsProxyAgent({
proxy: httpsProxy,
rejectUnauthorized: !allowUntrustedCAs,
})
: undefined;
const { default: fetch } = di.inject(nodeFetchModuleInjectable);
return (url, init = {}) => fetch(url, {
agent,
...init,
});
return (url, init) => fetch(url, init);
},
causesSideEffects: true,
});

View File

@ -0,0 +1,30 @@
/**
* 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 { HttpsProxyAgent } from "hpagent";
import userStoreInjectable from "../user-store/user-store.injectable";
import type { Fetch } from "./fetch.injectable";
import fetchInjectable from "./fetch.injectable";
const proxyFetchInjectable = getInjectable({
id: "proxy-fetch",
instantiate: (di): Fetch => {
const fetch = di.inject(fetchInjectable);
const { httpsProxy, allowUntrustedCAs } = di.inject(userStoreInjectable);
const agent = httpsProxy
? new HttpsProxyAgent({
proxy: httpsProxy,
rejectUnauthorized: !allowUntrustedCAs,
})
: undefined;
return (url, init = {}) => fetch(url, {
agent,
...init,
});
},
});
export default proxyFetchInjectable;

View File

@ -6,8 +6,6 @@
import type { RenderResult } from "@testing-library/react";
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import downloadBinaryInjectable, { type DownloadBinary } from "../../common/fetch/download-binary.injectable";
import downloadJsonInjectable, { type DownloadJson } from "../../common/fetch/download-json.injectable";
import focusWindowInjectable from "../../renderer/navigation/focus-window.injectable";
// TODO: Make components free of side effects by making them deterministic
@ -17,20 +15,14 @@ describe("extensions - navigation using application menu", () => {
let builder: ApplicationBuilder;
let rendered: RenderResult;
let focusWindowMock: jest.Mock;
let downloadJson: jest.MockedFunction<DownloadJson>;
let downloadBinary: jest.MockedFunction<DownloadBinary>;
beforeEach(async () => {
builder = getApplicationBuilder();
builder.beforeWindowStart((windowDi) => {
focusWindowMock = jest.fn();
downloadJson = jest.fn().mockImplementation((url) => { throw new Error(`Unexpected call to downloadJson for url=${url}`); });
downloadBinary = jest.fn().mockImplementation((url) => { throw new Error(`Unexpected call to downloadJson for url=${url}`); });
windowDi.override(focusWindowInjectable, () => focusWindowMock);
windowDi.override(downloadJsonInjectable, () => downloadJson);
windowDi.override(downloadBinaryInjectable, () => downloadBinary);
});
rendered = await builder.render();

View File

@ -4,7 +4,7 @@
*/
import { getInjectable } from "@ogre-tools/injectable";
import { sortBy } from "lodash/fp";
import downloadJsonInjectable from "../../../../../../../common/fetch/download-json.injectable";
import proxyDownloadJsonInjectable from "../../../../../../../common/fetch/download-json/proxy.injectable";
import { withTimeout } from "../../../../../../../common/fetch/timeout-controller";
import type { HelmRepo } from "../../../../../../../common/helm/helm-repo";
import loggerInjectable from "../../../../../../../common/logger.injectable";
@ -15,7 +15,7 @@ const requestPublicHelmRepositoriesInjectable = getInjectable({
id: "request-public-helm-repositories",
instantiate: (di) => {
const downloadJson = di.inject(downloadJsonInjectable);
const downloadJson = di.inject(proxyDownloadJsonInjectable);
const logger = di.inject(loggerInjectable);
return async (): Promise<HelmRepo[]> => {

View File

@ -25,9 +25,7 @@ import extensionInstallationStateStoreInjectable from "../../../../extensions/ex
import { observable, when } from "mobx";
import type { RemovePath } from "../../../../common/fs/remove.injectable";
import removePathInjectable from "../../../../common/fs/remove.injectable";
import type { DownloadJson } from "../../../../common/fetch/download-json.injectable";
import type { DownloadBinary } from "../../../../common/fetch/download-binary.injectable";
import downloadJsonInjectable from "../../../../common/fetch/download-json.injectable";
import downloadBinaryInjectable from "../../../../common/fetch/download-binary.injectable";
import currentlyInClusterFrameInjectable from "../../../routes/currently-in-cluster-frame.injectable";
@ -38,7 +36,6 @@ describe("Extensions", () => {
let extensionInstallationStateStore: ExtensionInstallationStateStore;
let render: DiRender;
let deleteFileMock: jest.MockedFunction<RemovePath>;
let downloadJson: jest.MockedFunction<DownloadJson>;
let downloadBinary: jest.MockedFunction<DownloadBinary>;
beforeEach(() => {
@ -56,9 +53,6 @@ describe("Extensions", () => {
deleteFileMock = jest.fn();
di.override(removePathInjectable, () => deleteFileMock);
downloadJson = jest.fn().mockImplementation((url) => { throw new Error(`Unexpected call to downloadJson for url=${url}`); });
di.override(downloadJsonInjectable, () => downloadJson);
downloadBinary = jest.fn().mockImplementation((url) => { throw new Error(`Unexpected call to downloadJson for url=${url}`); });
di.override(downloadBinaryInjectable, () => downloadBinary);

View File

@ -15,7 +15,7 @@ import { reduce } from "lodash";
import getBasenameOfPathInjectable from "../../../common/path/get-basename.injectable";
import { withTimeout } from "../../../common/fetch/timeout-controller";
import downloadBinaryInjectable from "../../../common/fetch/download-binary.injectable";
import downloadJsonInjectable from "../../../common/fetch/download-json.injectable";
import downloadJsonInjectable from "../../../common/fetch/download-json/normal.injectable";
import type { PackageJson } from "type-fest";
import showErrorNotificationInjectable from "../notifications/show-error-notification.injectable";
import loggerInjectable from "../../../common/logger.injectable";