From 80bbb29a439f1abbc5cebd0ab8412dfc01aa523c Mon Sep 17 00:00:00 2001 From: The1111mp Date: Wed, 28 Aug 2024 17:37:49 +0800 Subject: [PATCH] feat: support proxy configuration Signed-off-by: The1111mp --- @types/index.d.ts | 7 ++ package.json | 5 +- pnpm-lock.yaml | 122 ++++++++++++-------- src/main/deps/all-node-versions/options.ts | 13 ++- src/main/deps/fetch-node-website/index.ts | 33 ++++-- src/main/deps/get-node/index.ts | 10 +- src/main/deps/get-node/options.ts | 26 +++-- src/main/main.ts | 2 + src/main/utils/setting.ts | 46 ++++---- src/renderer/src/app-context.tsx | 8 +- src/renderer/src/components/ui/ip-input.tsx | 12 +- src/renderer/src/pages/home/setting.tsx | 28 ++--- src/renderer/src/util.ts | 12 ++ 13 files changed, 200 insertions(+), 124 deletions(-) diff --git a/@types/index.d.ts b/@types/index.d.ts index 8e1f481..6ddf305 100644 --- a/@types/index.d.ts +++ b/@types/index.d.ts @@ -20,12 +20,19 @@ declare global { total: number; } + interface Proxy { + enabled: boolean; + ip?: string; + port?: string; + } + interface Setting { locale: string; theme: Themes; closer: Closer; directory: string; mirror: string; + proxy: Proxy; } type UpdateInfo = ElectronUpdateInfo | "update-not-available"; diff --git a/package.json b/package.json index 1faed43..2195f54 100644 --- a/package.json +++ b/package.json @@ -74,6 +74,8 @@ "electron-updater": "^6.2.1", "framer-motion": "^11.3.19", "got": "^14.4.2", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.5", "intro.js": "^7.2.0", "intro.js-react": "^1.0.0", "is-plain-obj": "^4.1.0", @@ -215,5 +217,6 @@ }, "devEngines": { "node": ">=18.19" - } + }, + "packageManager": "pnpm@9.9.0+sha512.60c18acd138bff695d339be6ad13f7e936eea6745660d4cc4a776d5247c540d0edee1a563695c183a66eb917ef88f2b4feb1fc25f32a7adcadc7aaf3438e99c1" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 66ca7b6..2fdeef9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -95,6 +95,12 @@ importers: got: specifier: ^14.4.2 version: 14.4.2 + http-proxy-agent: + specifier: ^7.0.2 + version: 7.0.2 + https-proxy-agent: + specifier: ^7.0.5 + version: 7.0.5 intro.js: specifier: ^7.2.0 version: 7.2.0 @@ -1558,71 +1564,85 @@ packages: resolution: {integrity: sha512-MXg1xp+e5GhZ3Vit1gGEyoC+dyQUBy2JgVQ+3hUrD9wZMkUw/ywgkpK7oZgnB6kPpGrxJ41clkPPnsknuD6M2Q==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.19.1': resolution: {integrity: sha512-DZNLwIY4ftPSRVkJEaxYkq7u2zel7aah57HESuNkUnz+3bZHxwkCUkrfS2IWC1sxK6F2QNIR0Qr/YXw7nkF3Pw==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.13.0': resolution: {integrity: sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-gnu@4.19.1': resolution: {integrity: sha512-C7evongnjyxdngSDRRSQv5GvyfISizgtk9RM+z2biV5kY6S/NF/wta7K+DanmktC5DkuaJQgoKGf7KUDmA7RUw==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.13.0': resolution: {integrity: sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-musl@4.19.1': resolution: {integrity: sha512-89tFWqxfxLLHkAthAcrTs9etAoBFRduNfWdl2xUs/yLV+7XDrJ5yuXMHptNqf1Zw0UCA3cAutkAiAokYCkaPtw==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-powerpc64le-gnu@4.19.1': resolution: {integrity: sha512-PromGeV50sq+YfaisG8W3fd+Cl6mnOOiNv2qKKqKCpiiEke2KiKVyDqG/Mb9GWKbYMHj5a01fq/qlUR28PFhCQ==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.13.0': resolution: {integrity: sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.19.1': resolution: {integrity: sha512-/1BmHYh+iz0cNCP0oHCuF8CSiNj0JOGf0jRlSo3L/FAyZyG2rGBuKpkZVH9YF+x58r1jgWxvm1aRg3DHrLDt6A==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-s390x-gnu@4.19.1': resolution: {integrity: sha512-0cYP5rGkQWRZKy9/HtsWVStLXzCF3cCBTRI+qRL8Z+wkYlqN7zrSYm6FuY5Kd5ysS5aH0q5lVgb/WbG4jqXN1Q==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.13.0': resolution: {integrity: sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.19.1': resolution: {integrity: sha512-XUXeI9eM8rMP8aGvii/aOOiMvTs7xlCosq9xCjcqI9+5hBxtjDpD+7Abm1ZhVIFE1J2h2VIg0t2DX/gjespC2Q==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.13.0': resolution: {integrity: sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-linux-x64-musl@4.19.1': resolution: {integrity: sha512-V7cBw/cKXMfEVhpSvVZhC+iGifD6U1zJ4tbibjjN+Xi3blSXaj/rJynAkCFFQfoG6VZrAiP7uGVzL440Q6Me2Q==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-win32-arm64-msvc@4.13.0': resolution: {integrity: sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA==} @@ -1695,24 +1715,28 @@ packages: engines: {node: '>=10'} cpu: [arm64] os: [linux] + libc: [glibc] '@swc/core-linux-arm64-musl@1.7.3': resolution: {integrity: sha512-s6VzyaJwaRGTi2mz2h6Ywxfmgpkc69IxhuMzl+sl34plH0V0RgnZDm14HoCGIKIzRk4+a2EcBV1ZLAfWmPACQg==} engines: {node: '>=10'} cpu: [arm64] os: [linux] + libc: [musl] '@swc/core-linux-x64-gnu@1.7.3': resolution: {integrity: sha512-IrFY48C356Z2dU2pjYg080yvMXzmSV3Lmm/Wna4cfcB1nkVLjWsuYwwRAk9CY7E19c+q8N1sMNggubAUDYoX2g==} engines: {node: '>=10'} cpu: [x64] os: [linux] + libc: [glibc] '@swc/core-linux-x64-musl@1.7.3': resolution: {integrity: sha512-qoLgxBlBnnyUEDu5vmRQqX90h9jldU1JXI96e6eh2d1gJyKRA0oSK7xXmTzorv1fGHiHulv9qiJOUG+g6uzJWg==} engines: {node: '>=10'} cpu: [x64] os: [linux] + libc: [musl] '@swc/core-win32-arm64-msvc@1.7.3': resolution: {integrity: sha512-OAd7jVVJ7nb0Ev80VAa1aeK+FldPeC4eZ35H4Qn6EICzIz0iqJo2T33qLKkSZiZEBKSoF4KcwrqYfkjLOp5qWg==} @@ -3495,8 +3519,8 @@ packages: resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} engines: {node: '>= 6'} - http-proxy-agent@7.0.0: - resolution: {integrity: sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==} + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} engines: {node: '>= 14'} http2-wrapper@1.0.3: @@ -3511,8 +3535,8 @@ packages: resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} engines: {node: '>= 6'} - https-proxy-agent@7.0.2: - resolution: {integrity: sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==} + https-proxy-agent@7.0.5: + resolution: {integrity: sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==} engines: {node: '>= 14'} human-signals@2.1.0: @@ -5964,7 +5988,7 @@ snapshots: '@electron/get@2.0.3': dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6 env-paths: 2.2.1 fs-extra: 8.1.0 got: 11.8.6 @@ -5978,7 +6002,7 @@ snapshots: '@electron/get@3.1.0': dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6 env-paths: 2.2.1 fs-extra: 8.1.0 got: 11.8.6 @@ -5992,7 +6016,7 @@ snapshots: '@electron/notarize@2.2.1': dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6 fs-extra: 9.1.0 promise-retry: 2.0.1 transitivePeerDependencies: @@ -6009,7 +6033,7 @@ snapshots: '@electron/osx-sign@1.0.5': dependencies: compare-version: 0.1.2 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6 fs-extra: 10.1.0 isbinaryfile: 4.0.10 minimist: 1.2.8 @@ -6025,7 +6049,7 @@ snapshots: '@electron/osx-sign': 1.0.5 '@electron/universal': 2.0.1 '@electron/windows-sign': 1.1.3 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6 extract-zip: 2.0.1 filenamify: 4.3.0 fs-extra: 11.2.0 @@ -6045,7 +6069,7 @@ snapshots: dependencies: '@electron/asar': 3.2.8 '@malept/cross-spawn-promise': 1.1.1 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6 dir-compare: 3.3.0 fs-extra: 9.1.0 minimatch: 3.1.2 @@ -6057,7 +6081,7 @@ snapshots: dependencies: '@electron/asar': 3.2.8 '@malept/cross-spawn-promise': 2.0.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6 dir-compare: 4.2.0 fs-extra: 11.2.0 minimatch: 9.0.4 @@ -6068,7 +6092,7 @@ snapshots: '@electron/windows-sign@1.1.3': dependencies: cross-dirname: 0.1.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6 fs-extra: 11.2.0 minimist: 1.2.8 postject: 1.0.0-alpha.6 @@ -6228,7 +6252,7 @@ snapshots: '@eslint/config-array@0.17.1': dependencies: '@eslint/object-schema': 2.1.4 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6 minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -6236,7 +6260,7 @@ snapshots: '@eslint/eslintrc@3.1.0': dependencies: ajv: 6.12.6 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6 espree: 10.1.0 globals: 14.0.0 ignore: 5.3.1 @@ -6351,7 +6375,7 @@ snapshots: '@malept/flatpak-bundler@0.4.0': dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6 fs-extra: 9.1.0 lodash: 4.17.21 tmp-promise: 3.0.3 @@ -7346,7 +7370,7 @@ snapshots: '@typescript-eslint/type-utils': 7.8.0(eslint@9.8.0)(typescript@5.5.4) '@typescript-eslint/utils': 7.8.0(eslint@9.8.0)(typescript@5.5.4) '@typescript-eslint/visitor-keys': 7.8.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6 eslint: 9.8.0 graphemer: 1.4.0 ignore: 5.3.1 @@ -7364,7 +7388,7 @@ snapshots: '@typescript-eslint/types': 7.8.0 '@typescript-eslint/typescript-estree': 7.8.0(typescript@5.5.4) '@typescript-eslint/visitor-keys': 7.8.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6 eslint: 9.8.0 optionalDependencies: typescript: 5.5.4 @@ -7380,7 +7404,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 7.8.0(typescript@5.5.4) '@typescript-eslint/utils': 7.8.0(eslint@9.8.0)(typescript@5.5.4) - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6 eslint: 9.8.0 ts-api-utils: 1.3.0(typescript@5.5.4) optionalDependencies: @@ -7394,7 +7418,7 @@ snapshots: dependencies: '@typescript-eslint/types': 7.8.0 '@typescript-eslint/visitor-keys': 7.8.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6 globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.4 @@ -7627,13 +7651,13 @@ snapshots: agent-base@6.0.2: dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6 transitivePeerDependencies: - supports-color agent-base@7.1.0: dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6 transitivePeerDependencies: - supports-color @@ -7692,7 +7716,7 @@ snapshots: builder-util: 24.13.1 builder-util-runtime: 9.2.4 chromium-pickle-js: 0.2.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6 dmg-builder: 24.13.3(electron-builder-squirrel-windows@24.13.3) ejs: 3.1.9 electron-builder-squirrel-windows: 24.13.3(dmg-builder@24.13.3) @@ -8006,7 +8030,7 @@ snapshots: builder-util-runtime@9.2.4: dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6 sax: 1.3.0 transitivePeerDependencies: - supports-color @@ -8020,7 +8044,7 @@ snapshots: builder-util-runtime: 9.2.4 chalk: 4.1.2 cross-spawn: 7.0.3 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6 fs-extra: 10.1.0 http-proxy-agent: 5.0.0 https-proxy-agent: 5.0.1 @@ -8575,7 +8599,7 @@ snapshots: electron-localshortcut@3.2.1: dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6 electron-is-accelerator: 0.1.2 keyboardevent-from-electron-accelerator: 2.0.0 keyboardevents-areequal: 0.2.2 @@ -9055,7 +9079,7 @@ snapshots: extract-zip@2.0.1: dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6 get-stream: 5.2.0 yauzl: 2.10.0 optionalDependencies: @@ -9162,7 +9186,7 @@ snapshots: flora-colossus@2.0.0: dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6 fs-extra: 10.1.0 transitivePeerDependencies: - supports-color @@ -9259,7 +9283,7 @@ snapshots: galactus@1.0.0: dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6 flora-colossus: 2.0.0 fs-extra: 10.1.0 transitivePeerDependencies: @@ -9273,8 +9297,8 @@ snapshots: dependencies: '@wdio/logger': 8.38.0 decamelize: 6.0.0 - http-proxy-agent: 7.0.0 - https-proxy-agent: 7.0.2 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.5 node-fetch: 3.3.2 tar-fs: 3.0.6 unzipper: 0.10.14 @@ -9343,7 +9367,7 @@ snapshots: dependencies: basic-ftp: 5.0.4 data-uri-to-buffer: 6.0.1 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6 fs-extra: 8.1.0 transitivePeerDependencies: - supports-color @@ -9543,14 +9567,14 @@ snapshots: dependencies: '@tootallnate/once': 2.0.0 agent-base: 6.0.2 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6 transitivePeerDependencies: - supports-color - http-proxy-agent@7.0.0: + http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6 transitivePeerDependencies: - supports-color @@ -9567,14 +9591,14 @@ snapshots: https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6 transitivePeerDependencies: - supports-color - https-proxy-agent@7.0.2: + https-proxy-agent@7.0.5: dependencies: agent-base: 7.1.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6 transitivePeerDependencies: - supports-color @@ -10387,10 +10411,10 @@ snapshots: dependencies: '@tootallnate/quickjs-emscripten': 0.23.0 agent-base: 7.1.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6 get-uri: 6.0.2 - http-proxy-agent: 7.0.0 - https-proxy-agent: 7.0.2 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.5 pac-resolver: 7.0.0 socks-proxy-agent: 8.0.2 transitivePeerDependencies: @@ -10614,9 +10638,9 @@ snapshots: proxy-agent@6.3.0: dependencies: agent-base: 7.1.0 - debug: 4.3.4(supports-color@8.1.1) - http-proxy-agent: 7.0.0 - https-proxy-agent: 7.0.2 + debug: 4.3.6 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.5 lru-cache: 7.18.3 pac-proxy-agent: 7.0.1 proxy-from-env: 1.1.0 @@ -10627,9 +10651,9 @@ snapshots: proxy-agent@6.3.1: dependencies: agent-base: 7.1.0 - debug: 4.3.4(supports-color@8.1.1) - http-proxy-agent: 7.0.0 - https-proxy-agent: 7.0.2 + debug: 4.3.6 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.5 lru-cache: 7.18.3 pac-proxy-agent: 7.0.1 proxy-from-env: 1.1.0 @@ -11149,7 +11173,7 @@ snapshots: socks-proxy-agent@8.0.2: dependencies: agent-base: 7.1.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6 socks: 2.7.1 transitivePeerDependencies: - supports-color @@ -11316,7 +11340,7 @@ snapshots: sumchecker@3.0.1: dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6 transitivePeerDependencies: - supports-color @@ -11704,7 +11728,7 @@ snapshots: dependencies: chalk: 4.1.2 commander: 9.5.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6 transitivePeerDependencies: - supports-color diff --git a/src/main/deps/all-node-versions/options.ts b/src/main/deps/all-node-versions/options.ts index 25963d6..c3dbb5e 100644 --- a/src/main/deps/all-node-versions/options.ts +++ b/src/main/deps/all-node-versions/options.ts @@ -1,5 +1,5 @@ -import type { Delays } from 'got'; -import type { Options as FetchNodeWebsiteOptions } from '../fetch-node-website'; +import type { Delays } from "got"; +import type { Options as FetchNodeWebsiteOptions } from "../fetch-node-website"; export interface Options { /** @@ -11,12 +11,12 @@ export interface Options { * * @default 'https://nodejs.org/dist' */ - mirror?: FetchNodeWebsiteOptions['mirror']; + mirror?: FetchNodeWebsiteOptions["mirror"]; /** * Cancels the release download when the signal is aborted. */ - signal?: FetchNodeWebsiteOptions['signal']; + signal?: FetchNodeWebsiteOptions["signal"]; /** * The list of available Node.js versions is cached for one hour by default. @@ -33,6 +33,11 @@ export interface Options { */ timeout?: Delays; + /** + * Proxy server configuration + */ + proxy?: Nvmd.Proxy; + /** * Progress event callback. * diff --git a/src/main/deps/fetch-node-website/index.ts b/src/main/deps/fetch-node-website/index.ts index 67c9a76..fde1747 100644 --- a/src/main/deps/fetch-node-website/index.ts +++ b/src/main/deps/fetch-node-website/index.ts @@ -2,10 +2,12 @@ * https://github.com/ehmicky/fetch-node-website */ -import { got } from 'got'; -import { getDefaultMirror } from './mirror'; +import { got } from "got"; +import { HttpProxyAgent } from "http-proxy-agent"; +import { HttpsProxyAgent } from "https-proxy-agent"; +import { getDefaultMirror } from "./mirror"; -import type { Request, Delays } from 'got'; +import type { Request, Delays } from "got"; const LEADING_SLASH_REGEXP = /^\//u; @@ -30,6 +32,11 @@ export interface Options { * Milliseconds to wait for the server to end the response before aborting the request with `got.TimeoutError` error (a.k.a. `request` property). */ timeout?: Delays; + + /** + * Proxy server configuration + */ + proxy?: Nvmd.Proxy; } /** @@ -50,17 +57,25 @@ export interface Options { * ) * ``` */ -export const fetchNodeWebsite = async ( - path: string, - opts?: Options, -): Promise => { - const { mirror = getDefaultMirror(), signal, timeout = {} } = opts || {}; +export const fetchNodeWebsite = async (path: string, opts?: Options): Promise => { + const { mirror = getDefaultMirror(), signal, timeout = {}, proxy } = opts || {}; + + const pathA = path.replace(LEADING_SLASH_REGEXP, ""); + // Configure proxy if provided + let agent; + if (proxy?.enabled) { + const proxyOptions = `http://${proxy.ip}:${proxy.port}`; + agent = { + http: new HttpProxyAgent(proxyOptions), + https: new HttpsProxyAgent(proxyOptions) + }; + } - const pathA = path.replace(LEADING_SLASH_REGEXP, ''); const response = got.stream(pathA, { prefixUrl: mirror, signal, timeout, + agent }); return response; diff --git a/src/main/deps/get-node/index.ts b/src/main/deps/get-node/index.ts index abbd4e4..52b1a91 100644 --- a/src/main/deps/get-node/index.ts +++ b/src/main/deps/get-node/index.ts @@ -2,11 +2,11 @@ * https://github.com/ehmicky/get-node */ -import { download } from './download'; -import { getOpts } from './options'; -import { checkVersion } from './version'; +import { download } from "./download"; +import { getOpts } from "./options"; +import { checkVersion } from "./version"; -import type { Options } from './options'; +import type { Options } from "./options"; // Download the Node.js binary for a specific `versionRange` /** @@ -63,7 +63,7 @@ const getNode = async (version: string, opts: Options = {}) => { output, arch, fetchOpts, - onProgress, + onProgress }); return { version, path: nodePath }; }; diff --git a/src/main/deps/get-node/options.ts b/src/main/deps/get-node/options.ts index af743d1..6c509f7 100644 --- a/src/main/deps/get-node/options.ts +++ b/src/main/deps/get-node/options.ts @@ -1,11 +1,11 @@ -import { arch as processArch } from 'node:process'; +import { arch as processArch } from "node:process"; -import isPlainObj from 'is-plain-obj'; +import isPlainObj from "is-plain-obj"; -import { validateArch } from './arch'; -import { getDefaultOutput, validateOutput } from './output'; +import { validateArch } from "./arch"; +import { getDefaultOutput, validateOutput } from "./output"; -import type { Arch } from './archive/types'; +import type { Arch } from "./archive/types"; export interface NodeBinary { /** @@ -71,6 +71,11 @@ export type Options = Partial<{ * @default `process.arch` */ arch?: Arch; + + /** + * Proxy server configuration + */ + proxy?: Nvmd.Proxy; }>; // Validate input parameters and assign default values. @@ -82,22 +87,23 @@ export const getOpts = async (opts: Options = {}) => { const { output = await getDefaultOutput(), - arch = processArch, + arch = processArch as Arch, mirror = DEFAULT_MIRROR, + proxy = undefined, signal, - onProgress, + onProgress } = opts; validateOutput(output); validateArch(arch); - const fetchOpts = { mirror, signal }; + const fetchOpts = { mirror, signal, proxy }; return { output, arch, fetchOpts, - onProgress, + onProgress }; }; -const DEFAULT_MIRROR = 'https://nodejs.org/dist'; +const DEFAULT_MIRROR = "https://nodejs.org/dist"; diff --git a/src/main/main.ts b/src/main/main.ts index a7da6b4..23fa9e8 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -464,6 +464,7 @@ Promise.resolve().then(() => { try { result = await allNodeVersions({ mirror: setting.mirror, + proxy: setting.proxy, signal: abortController.signal, fetch, timeout: { @@ -515,6 +516,7 @@ Promise.resolve().then(() => { arch, output: setting.directory, mirror: setting.mirror, + proxy: setting.proxy, signal: abortController.signal, onProgress: (data) => { mainWindow?.webContents.send("get-node:progress", id, data); diff --git a/src/main/utils/setting.ts b/src/main/utils/setting.ts index 8951e91..0b09a56 100644 --- a/src/main/utils/setting.ts +++ b/src/main/utils/setting.ts @@ -1,30 +1,34 @@ -import { pathExists, readJson, writeJson } from 'fs-extra'; -import { app } from 'electron'; -import { INSTALL_DIR, SETTING_JSONFILE } from '../constants'; -import { Closer, Themes } from '@src/types'; +import { pathExists, readJson, writeJson } from "fs-extra"; +import { app } from "electron"; +import { INSTALL_DIR, SETTING_JSONFILE } from "../constants"; +import { Closer, Themes } from "@src/types"; export async function getSetting(): Promise { - if (!(await pathExists(SETTING_JSONFILE))) - return { - locale: app.getLocale().startsWith('en') ? 'en' : 'zh-CN', - theme: Themes.System, - closer: Closer.Minimize, - directory: INSTALL_DIR, - mirror: 'https://nodejs.org/dist', - }; + const defaultSetting = { + locale: app.getLocale().startsWith("en") ? "en" : "zh-CN", + theme: Themes.System, + closer: Closer.Minimize, + directory: INSTALL_DIR, + mirror: "https://nodejs.org/dist", + proxy: { + enabled: false, + ip: "127.0.0.1", + port: "8080" + } + }; + + if (!(await pathExists(SETTING_JSONFILE))) return defaultSetting; const setting = await readJson(SETTING_JSONFILE, { throws: false }); if (!setting.directory) setting.directory = INSTALL_DIR; if (!setting.closer) setting.closer = Closer.Minimize; - return ( - setting || { - locale: app.getLocale().startsWith('en') ? 'en' : 'zh-CN', - theme: Themes.System, - closer: Closer.Minimize, - directory: INSTALL_DIR, - mirror: 'https://nodejs.org/dist', - } - ); + if (!setting.proxy) + setting.proxy = { + enabled: false, + ip: "127.0.0.1", + port: "8080" + }; + return setting || defaultSetting; } export async function setSetting(setting: Nvmd.Setting): Promise { diff --git a/src/renderer/src/app-context.tsx b/src/renderer/src/app-context.tsx index 8dabb5f..5ecfa17 100644 --- a/src/renderer/src/app-context.tsx +++ b/src/renderer/src/app-context.tsx @@ -18,6 +18,7 @@ type AppContextType = { closer: Closer; directory: string; mirror: string; + proxy: Nvmd.Proxy; setColor: (color: string) => void; getMessage: I18nFn; onUpdateSetting: (setting: Nvmd.Setting) => Promise; @@ -30,6 +31,7 @@ type StateType = { directory: string; // node installation directory sysTheme: Themes; // system real theme mirror: string; + proxy: Nvmd.Proxy; messages: I18n.Message; }; @@ -55,7 +57,7 @@ export type I18nFn = ( export const AppProviderContext = createContext(null); export function AppProvider({ defaultColor = "orange", storageKey = "nvmd-ui-theme", children }) { - const { locale, theme, closer, directory, mirror, localeMessages } = + const { locale, theme, closer, directory, mirror, proxy, localeMessages } = window.Context.getSettingData(); const [color, setColor] = useState( @@ -82,6 +84,7 @@ export function AppProvider({ defaultColor = "orange", storageKey = "nvmd-ui-the directory, sysTheme: window.Context.getSystemTheme() as Themes, mirror, + proxy, messages: localeMessages } ); @@ -140,7 +143,7 @@ export function AppProvider({ defaultColor = "orange", storageKey = "nvmd-ui-the payload: { ...state, ...setting, messages } }); }, - [state.locale, state.theme, state.directory, state.mirror] + [state.locale, state.theme, state.directory, state.mirror, state.proxy] ); const setColorHandler = useMemo( @@ -213,6 +216,7 @@ export function AppProvider({ defaultColor = "orange", storageKey = "nvmd-ui-the closer: state.closer, directory: state.directory, mirror: state.mirror, + proxy: state.proxy, color, setColor: setColorHandler, getMessage, diff --git a/src/renderer/src/components/ui/ip-input.tsx b/src/renderer/src/components/ui/ip-input.tsx index ab5e97c..ea4ced9 100644 --- a/src/renderer/src/components/ui/ip-input.tsx +++ b/src/renderer/src/components/ui/ip-input.tsx @@ -24,21 +24,21 @@ const IpInput: React.FC = memo( }; const onchangeHandle = (evt: React.ChangeEvent, index: number) => { - let val = parseInt(evt.target.value); - if (evt.target.value !== "" && isNaN(val)) { + let val = evt.target.value; + if (evt.target.value !== "" && isNaN(parseInt(val))) { return evt.preventDefault(); } - if (evt.target.value !== "" && !isValidIPItemValue(val)) { - val = 255; + if (evt.target.value !== "" && !isValidIPItemValue(parseInt(val))) { + val = "255"; } let dValue = [...value]; - dValue[index] = evt.target.value; + dValue[index] = val; setValue(dValue); onValueChange(dValue); - if (!isNaN(val) && String(val).length === 3 && index < 3) { + if (!isNaN(parseInt(val)) && val.length === 3 && index < 3) { inputs.current[index + 1]?.focus(); } }; diff --git a/src/renderer/src/pages/home/setting.tsx b/src/renderer/src/pages/home/setting.tsx index bdf8a56..1a5c65a 100644 --- a/src/renderer/src/pages/home/setting.tsx +++ b/src/renderer/src/pages/home/setting.tsx @@ -43,6 +43,7 @@ import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { useAppContext, useI18n } from "@src/renderer/src/app-context"; import { Closer, Themes } from "@src/types"; +import { compareObject } from "../../util"; type Options = NonNullable; @@ -69,7 +70,7 @@ const formSchema = z.object({ }); } - if (val.enabled && (val.port === "" || val.port === void 0)) { + if (val.enabled && (val.port === "" || val.port === "0" || val.port === void 0)) { ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["port"], @@ -88,7 +89,7 @@ export const Setting: React.FC = memo(() => { return optStr ? optStr.split("__") : []; }); - const { locale, theme, closer, directory, mirror, onUpdateSetting } = useAppContext(); + const { locale, theme, closer, directory, mirror, proxy, onUpdateSetting } = useAppContext(); const form = useForm>({ resolver: zodResolver(formSchema), @@ -98,33 +99,29 @@ export const Setting: React.FC = memo(() => { closer, directory, mirror, - proxy: { - enabled: false, - ip: "127.0.0.1", - port: "8080" - } + proxy } }); const i18n = useI18n(); const onSubmit = async (values: z.infer) => { - console.log("values", values); - return; setLoading(true); const { locale: newLocale, theme: newTheme, closer: newCloser, directory: newDirectory, - mirror: newMirror + mirror: newMirror, + proxy: newProxy } = values; if ( locale === newLocale && theme === newTheme && closer === newCloser && directory === newDirectory && - mirror === newMirror + mirror === newMirror && + compareObject(proxy, newProxy) ) { setLoading(false); setOpen(false); @@ -151,7 +148,8 @@ export const Setting: React.FC = memo(() => { theme: newTheme, closer: newCloser, directory: newDirectory, - mirror: newMirror + mirror: newMirror, + proxy: newProxy }); } finally { setLoading(false); @@ -169,11 +167,7 @@ export const Setting: React.FC = memo(() => { closer, directory, mirror, - proxy: { - enabled: false, - ip: "127.0.0.1", - port: "8080" - } + proxy }); setOpen(open); }} diff --git a/src/renderer/src/util.ts b/src/renderer/src/util.ts index 31f91a1..aba2c61 100644 --- a/src/renderer/src/util.ts +++ b/src/renderer/src/util.ts @@ -28,3 +28,15 @@ export function compareVersion(version1: string, version2: string): number { return semver.gt(version2, version1) ? -1 : 1; } + +type Obj = Record; + +export function compareObject(obj1: Obj, obj2: Obj) { + let ret = true; + for (let key in obj1) { + if (obj1[key] !== obj2[key]) { + ret = false; + } + } + return ret; +}