diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e0d86b8..cea0a66 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -29,7 +29,9 @@ jobs: with: version: 9 - name: Install Dependencies - run: pnpm install + run: | + pnpm install + pnpm prepare --${{ matrix.arch }} - name: Build run: pnpm build:win --${{ matrix.arch }} @@ -47,7 +49,6 @@ jobs: arch: - x64 - arm64 - - armv7l runs-on: ubuntu-latest steps: - name: Checkout @@ -63,7 +64,9 @@ jobs: with: version: 9 - name: Install Dependencies - run: pnpm install + run: | + pnpm install + pnpm prepare --${{ matrix.arch }} - name: Build run: pnpm build:linux --${{ matrix.arch }} @@ -98,7 +101,9 @@ jobs: with: version: 9 - name: Install Dependencies - run: pnpm install + run: | + pnpm install + pnpm prepare --${{ matrix.arch }} - name: Build run: pnpm build:mac --${{ matrix.arch }} diff --git a/.gitignore b/.gitignore index 42bd71b..a0da93e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ node_modules +resources/files +resources/sidecar dist out .DS_Store diff --git a/package.json b/package.json index a26f3ce..3d5fe51 100644 --- a/package.json +++ b/package.json @@ -11,12 +11,10 @@ "typecheck:node": "tsc --noEmit -p tsconfig.node.json --composite false", "typecheck:web": "tsc --noEmit -p tsconfig.web.json --composite false", "typecheck": "npm run typecheck:node && npm run typecheck:web", - "start": "electron-vite preview", + "prepare": "node scripts/prepare.mjs", "dev": "electron-vite dev", - "build": "npm run typecheck && electron-vite build", "postinstall": "electron-builder install-app-deps", - "build:unpack": "npm run build && electron-builder --dir", - "build:win": "npm run build && electron-builder --win", + "build:win": "electron-vite build && electron-builder --win", "build:mac": "electron-vite build && electron-builder --mac", "build:linux": "electron-vite build && electron-builder --linux" }, @@ -41,6 +39,7 @@ "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", "@vitejs/plugin-react": "^4.3.1", + "adm-zip": "^0.5.14", "autoprefixer": "^10.4.19", "electron": "^31.3.1", "electron-builder": "^25.0.2", @@ -52,6 +51,8 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "tailwindcss": "^3.4.7", + "tar": "^7.4.3", + "tsx": "^4.16.3", "typescript": "^5.5.4", "vite": "^5.3.5" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e0cc9fc..0683ae4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -63,6 +63,9 @@ importers: '@vitejs/plugin-react': specifier: ^4.3.1 version: 4.3.1(vite@5.3.5(@types/node@22.0.0)) + adm-zip: + specifier: ^0.5.14 + version: 0.5.14 autoprefixer: specifier: ^10.4.19 version: 10.4.19(postcss@8.4.40) @@ -96,6 +99,12 @@ importers: tailwindcss: specifier: ^3.4.7 version: 3.4.7 + tar: + specifier: ^7.4.3 + version: 7.4.3 + tsx: + specifier: ^4.16.3 + version: 4.16.3 typescript: specifier: ^5.5.4 version: 5.5.4 @@ -477,6 +486,10 @@ packages: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} + '@isaacs/fs-minipass@4.0.1': + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + engines: {node: '>=18.0.0'} + '@jridgewell/gen-mapping@0.3.5': resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} engines: {node: '>=6.0.0'} @@ -1820,6 +1833,10 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + adm-zip@0.5.14: + resolution: {integrity: sha512-DnyqqifT4Jrcvb8USYjp6FHtBpEIz1mnXu6pTRHZ0RL69LbQYiO+0lDFg5+OKA7U29oWSs3a/i8fhn8ZcceIWg==} + engines: {node: '>=12.0'} + agent-base@6.0.2: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} @@ -2075,6 +2092,10 @@ packages: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} + chownr@3.0.0: + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} + engines: {node: '>=18'} + chromium-pickle-js@0.2.0: resolution: {integrity: sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw==} @@ -2651,6 +2672,9 @@ packages: resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} engines: {node: '>= 0.4'} + get-tsconfig@4.7.6: + resolution: {integrity: sha512-ZAqrLlu18NbDdRaHq+AKXzAmqIUPswPWKUchfytdAjiRFnCe5ojG2bstg6mRiZabkKfCoL/e98pbBELIV/YCeA==} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -3211,11 +3235,20 @@ packages: resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} engines: {node: '>= 8'} + minizlib@3.0.1: + resolution: {integrity: sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg==} + engines: {node: '>= 18'} + mkdirp@1.0.4: resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} engines: {node: '>=10'} hasBin: true + mkdirp@3.0.1: + resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} + engines: {node: '>=10'} + hasBin: true + ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} @@ -3620,6 +3653,9 @@ packages: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + resolve@1.22.8: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true @@ -3648,6 +3684,11 @@ packages: deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true + rimraf@5.0.9: + resolution: {integrity: sha512-3i7b8OcswU6CpU8Ej89quJD4O98id7TtVM5U4Mybh84zQXdrFmDLouWBEEaD/QfO3gDDfH+AGFCGsR7kngzQnA==} + engines: {node: 14 >=14.20 || 16 >=16.20 || >=18} + hasBin: true + roarr@2.15.4: resolution: {integrity: sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==} engines: {node: '>=8.0'} @@ -3880,6 +3921,10 @@ packages: resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} engines: {node: '>=10'} + tar@7.4.3: + resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==} + engines: {node: '>=18'} + temp-file@3.4.0: resolution: {integrity: sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==} @@ -3926,6 +3971,11 @@ packages: tslib@2.6.3: resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} + tsx@4.16.3: + resolution: {integrity: sha512-MP8AEUxVnboD2rCC6kDLxnpDBNWN9k3BSVU/0/nNxgm70bPBnfn+yCKcnOsIVPQwdkbKYoFOlKjjWZWJ2XCXUg==} + engines: {node: '>=18.0.0'} + hasBin: true + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -4134,6 +4184,10 @@ packages: yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + yallist@5.0.0: + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} + engines: {node: '>=18'} + yaml@2.5.0: resolution: {integrity: sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==} engines: {node: '>= 14'} @@ -4565,6 +4619,10 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 + '@isaacs/fs-minipass@4.0.1': + dependencies: + minipass: 7.1.2 + '@jridgewell/gen-mapping@0.3.5': dependencies: '@jridgewell/set-array': 1.2.1 @@ -6791,6 +6849,8 @@ snapshots: acorn@8.12.1: {} + adm-zip@0.5.14: {} + agent-base@6.0.2: dependencies: debug: 4.3.6 @@ -7179,6 +7239,8 @@ snapshots: chownr@2.0.0: {} + chownr@3.0.0: {} + chromium-pickle-js@0.2.0: {} ci-info@3.9.0: {} @@ -7914,6 +7976,10 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.2.4 + get-tsconfig@4.7.6: + dependencies: + resolve-pkg-maps: 1.0.0 + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -8474,8 +8540,15 @@ snapshots: minipass: 3.3.6 yallist: 4.0.0 + minizlib@3.0.1: + dependencies: + minipass: 7.1.2 + rimraf: 5.0.9 + mkdirp@1.0.4: {} + mkdirp@3.0.1: {} + ms@2.1.2: {} ms@2.1.3: {} @@ -8876,6 +8949,8 @@ snapshots: resolve-from@4.0.0: {} + resolve-pkg-maps@1.0.0: {} + resolve@1.22.8: dependencies: is-core-module: 2.15.0 @@ -8905,6 +8980,10 @@ snapshots: dependencies: glob: 7.2.3 + rimraf@5.0.9: + dependencies: + glob: 10.4.5 + roarr@2.15.4: dependencies: boolean: 3.2.0 @@ -9227,6 +9306,15 @@ snapshots: mkdirp: 1.0.4 yallist: 4.0.0 + tar@7.4.3: + dependencies: + '@isaacs/fs-minipass': 4.0.1 + chownr: 3.0.0 + minipass: 7.1.2 + minizlib: 3.0.1 + mkdirp: 3.0.1 + yallist: 5.0.0 + temp-file@3.4.0: dependencies: async-exit-hook: 2.0.1 @@ -9268,6 +9356,13 @@ snapshots: tslib@2.6.3: {} + tsx@4.16.3: + dependencies: + esbuild: 0.21.5 + get-tsconfig: 4.7.6 + optionalDependencies: + fsevents: 2.3.3 + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 @@ -9474,6 +9569,8 @@ snapshots: yallist@4.0.0: {} + yallist@5.0.0: {} + yaml@2.5.0: {} yargs-parser@21.1.1: {} diff --git a/script/prepare.ts b/script/prepare.ts deleted file mode 100644 index e69de29..0000000 diff --git a/scripts/prepare.mjs b/scripts/prepare.mjs new file mode 100644 index 0000000..61c7691 --- /dev/null +++ b/scripts/prepare.mjs @@ -0,0 +1,302 @@ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ +import fs from 'fs' +import AdmZip from 'adm-zip' +import path from 'path' +import zlib from 'zlib' +import { extract } from 'tar' +import { execSync } from 'child_process' + +const cwd = process.cwd() +const TEMP_DIR = path.join(cwd, 'node_modules/.temp') +let arch = process.arch +const platform = process.platform +if (process.argv.slice(2).length !== 0) { + arch = process.argv.slice(2)[0].replace('--', '') +} + +/* ======= mihomo alpha======= */ +const MIHOMO_ALPHA_VERSION_URL = + 'https://github.com/MetaCubeX/mihomo/releases/download/Prerelease-Alpha/version.txt' +const MIHOMO_ALPHA_URL_PREFIX = `https://github.com/MetaCubeX/mihomo/releases/download/Prerelease-Alpha` +let MIHOMO_ALPHA_VERSION + +const MIHOMO_ALPHA_MAP = { + 'win32-x64': 'mihomo-windows-amd64-compatible', + 'win32-ia32': 'mihomo-windows-386', + 'win32-arm64': 'mihomo-windows-arm64', + 'darwin-x64': 'mihomo-darwin-amd64-compatible', + 'darwin-arm64': 'mihomo-darwin-arm64', + 'linux-x64': 'mihomo-linux-amd64-compatible', + 'linux-arm64': 'mihomo-linux-arm64' +} + +// Fetch the latest alpha release version from the version.txt file +async function getLatestAlphaVersion() { + try { + const response = await fetch(MIHOMO_ALPHA_VERSION_URL, { + method: 'GET' + }) + let v = await response.text() + MIHOMO_ALPHA_VERSION = v.trim() // Trim to remove extra whitespaces + console.log(`Latest alpha version: ${MIHOMO_ALPHA_VERSION}`) + } catch (error) { + console.error('Error fetching latest alpha version:', error.message) + process.exit(1) + } +} + +/* ======= mihomo release ======= */ +const MIHOMO_VERSION_URL = + 'https://github.com/MetaCubeX/mihomo/releases/latest/download/version.txt' +const MIHOMO_URL_PREFIX = `https://github.com/MetaCubeX/mihomo/releases/download` +let MIHOMO_VERSION + +const MIHOMO_MAP = { + 'win32-x64': 'mihomo-windows-amd64-compatible', + 'win32-ia32': 'mihomo-windows-386', + 'win32-arm64': 'mihomo-windows-arm64', + 'darwin-x64': 'mihomo-darwin-amd64-compatible', + 'darwin-arm64': 'mihomo-darwin-arm64', + 'linux-x64': 'mihomo-linux-amd64-compatible', + 'linux-arm64': 'mihomo-linux-arm64' +} + +// Fetch the latest release version from the version.txt file +async function getLatestReleaseVersion() { + try { + const response = await fetch(MIHOMO_VERSION_URL, { + method: 'GET' + }) + let v = await response.text() + MIHOMO_VERSION = v.trim() // Trim to remove extra whitespaces + console.log(`Latest release version: ${MIHOMO_VERSION}`) + } catch (error) { + console.error('Error fetching latest release version:', error.message) + process.exit(1) + } +} + +/* + * check available + */ +if (!MIHOMO_MAP[`${platform}-${arch}`]) { + throw new Error(`unsupported platform "${platform}-${arch}"`) +} + +if (!MIHOMO_ALPHA_MAP[`${platform}-${arch}`]) { + throw new Error(`unsupported platform "${platform}-${arch}"`) +} + +/** + * core info + */ +function MihomoAlpha() { + const name = MIHOMO_ALPHA_MAP[`${platform}-${arch}`] + const isWin = platform === 'win32' + const urlExt = isWin ? 'zip' : 'gz' + const downloadURL = `${MIHOMO_ALPHA_URL_PREFIX}/${name}-${MIHOMO_ALPHA_VERSION}.${urlExt}` + const exeFile = `${name}${isWin ? '.exe' : ''}` + const zipFile = `${name}-${MIHOMO_ALPHA_VERSION}.${urlExt}` + + return { + name: 'mihomo-alpha', + targetFile: `mihomo-alpha${isWin ? '.exe' : ''}`, + exeFile, + zipFile, + downloadURL + } +} + +function mihomo() { + const name = MIHOMO_MAP[`${platform}-${arch}`] + const isWin = platform === 'win32' + const urlExt = isWin ? 'zip' : 'gz' + const downloadURL = `${MIHOMO_URL_PREFIX}/${MIHOMO_VERSION}/${name}-${MIHOMO_VERSION}.${urlExt}` + const exeFile = `${name}${isWin ? '.exe' : ''}` + const zipFile = `${name}-${MIHOMO_VERSION}.${urlExt}` + + return { + name: 'mihomo', + targetFile: `mihomo${isWin ? '.exe' : ''}`, + exeFile, + zipFile, + downloadURL + } +} +/** + * download sidecar and rename + */ +async function resolveSidecar(binInfo) { + const { name, targetFile, zipFile, exeFile, downloadURL } = binInfo + + const sidecarDir = path.join(cwd, 'resources', 'sidecar') + const sidecarPath = path.join(sidecarDir, targetFile) + + fs.mkdirSync(sidecarDir, { recursive: true }) + if (fs.existsSync(sidecarPath)) { + fs.rmSync(sidecarPath) + } + const tempDir = path.join(TEMP_DIR, name) + const tempZip = path.join(tempDir, zipFile) + const tempExe = path.join(tempDir, exeFile) + + fs.mkdirSync(tempDir, { recursive: true }) + try { + if (!fs.existsSync(tempZip)) { + await downloadFile(downloadURL, tempZip) + } + + if (zipFile.endsWith('.zip')) { + const zip = new AdmZip(tempZip) + zip.getEntries().forEach((entry) => { + console.log(`[DEBUG]: "${name}" entry name`, entry.entryName) + }) + zip.extractAllTo(tempDir, true) + fs.renameSync(tempExe, sidecarPath) + console.log(`[INFO]: "${name}" unzip finished`) + } else if (zipFile.endsWith('.tgz')) { + // tgz + fs.mkdirSync(tempDir, { recursive: true }) + await extract({ + cwd: tempDir, + file: tempZip + }) + const files = fs.readdirSync(tempDir) + console.log(`[DEBUG]: "${name}" files in tempDir:`, files) + const extractedFile = files.find((file) => file.startsWith('虚空终端-')) + if (extractedFile) { + const extractedFilePath = path.join(tempDir, extractedFile) + fs.renameSync(extractedFilePath, sidecarPath) + console.log(`[INFO]: "${name}" file renamed to "${sidecarPath}"`) + execSync(`chmod 755 ${sidecarPath}`) + console.log(`[INFO]: "${name}" chmod binary finished`) + } else { + throw new Error(`Expected file not found in ${tempDir}`) + } + } else { + // gz + const readStream = fs.createReadStream(tempZip) + const writeStream = fs.createWriteStream(sidecarPath) + await new Promise((resolve, reject) => { + const onError = (error) => { + console.error(`[ERROR]: "${name}" gz failed:`, error.message) + reject(error) + } + readStream + .pipe(zlib.createGunzip().on('error', onError)) + .pipe(writeStream) + .on('finish', () => { + console.log(`[INFO]: "${name}" gunzip finished`) + execSync(`chmod 755 ${sidecarPath}`) + console.log(`[INFO]: "${name}" chmod binary finished`) + resolve() + }) + .on('error', onError) + }) + } + } catch (err) { + // 需要删除文件 + fs.rmSync(sidecarPath) + throw err + } finally { + fs.rmSync(tempDir, { recursive: true }) + } +} + +/** + * download the file to the resources dir + */ +async function resolveResource(binInfo) { + const { file, downloadURL } = binInfo + + const resDir = path.join(cwd, 'resources', 'files') + const targetPath = path.join(resDir, file) + + if (fs.existsSync(targetPath)) { + fs.rmSync(targetPath) + } + + fs.mkdirSync(resDir, { recursive: true }) + await downloadFile(downloadURL, targetPath) + + console.log(`[INFO]: ${file} finished`) +} + +/** + * download file and save to `path` + */ +async function downloadFile(url, path) { + const response = await fetch(url, { + method: 'GET', + headers: { 'Content-Type': 'application/octet-stream' } + }) + const buffer = await response.arrayBuffer() + fs.writeFileSync(path, new Uint8Array(buffer)) + + console.log(`[INFO]: download finished "${url}"`) +} + +const resolveMmdb = () => + resolveResource({ + file: 'Country.mmdb', + downloadURL: `https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/country.mmdb` + }) +const resolveGeosite = () => + resolveResource({ + file: 'geosite.dat', + downloadURL: `https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat` + }) +const resolveGeoIP = () => + resolveResource({ + file: 'geoip.dat', + downloadURL: `https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.dat` + }) +const resolveEnableLoopback = () => + resolveResource({ + file: 'enableLoopback.exe', + downloadURL: `https://github.com/Kuingsmile/uwp-tool/releases/download/latest/enableLoopback.exe` + }) + +const tasks = [ + { + name: 'verge-mihomo-alpha', + func: () => getLatestAlphaVersion().then(() => resolveSidecar(MihomoAlpha())), + retry: 5 + }, + { + name: 'verge-mihomo', + func: () => getLatestReleaseVersion().then(() => resolveSidecar(mihomo())), + retry: 5 + }, + { name: 'mmdb', func: resolveMmdb, retry: 5 }, + { name: 'geosite', func: resolveGeosite, retry: 5 }, + { name: 'geoip', func: resolveGeoIP, retry: 5 }, + { + name: 'enableLoopback', + func: resolveEnableLoopback, + retry: 5, + winOnly: true + } +] + +async function runTask() { + const task = tasks.shift() + if (!task) return + if (task.winOnly && platform !== 'win32') return runTask() + if (task.linuxOnly && platform !== 'linux') return runTask() + if (task.unixOnly && platform === 'win32') return runTask() + + for (let i = 0; i < task.retry; i++) { + try { + await task.func() + break + } catch (err) { + console.error(`[ERROR]: task::${task.name} try ${i} ==`, err.message) + if (i === task.retry - 1) throw err + } + } + return runTask() +} + +runTask() +runTask()