mirror of
https://github.com/bolucat/Archive.git
synced 2025-09-27 04:30:12 +08:00
206 lines
5.3 KiB
TypeScript
206 lines
5.3 KiB
TypeScript
import crypto from "node:crypto";
|
|
import path from "path";
|
|
import AdmZip from "adm-zip";
|
|
import fs from "fs-extra";
|
|
import { BinInfo } from "../types";
|
|
import { downloadFile, resolveSidecar } from "./download";
|
|
import { TAURI_APP_DIR, TEMP_DIR } from "./env";
|
|
import { colorize, consola } from "./logger";
|
|
import { NodeArch } from "./manifest";
|
|
import {
|
|
getClashBackupInfo,
|
|
getClashMetaAlphaInfo,
|
|
getClashMetaInfo,
|
|
getClashRustAlphaInfo,
|
|
getClashRustInfo,
|
|
getNyanpasuServiceInfo,
|
|
} from "./resource";
|
|
|
|
/**
|
|
* download the file to the resources dir
|
|
*/
|
|
export const resolveResource = async (
|
|
binInfo: { file: string; downloadURL: string },
|
|
options?: { force?: boolean },
|
|
) => {
|
|
const { file, downloadURL } = binInfo;
|
|
|
|
const resDir = path.join(TAURI_APP_DIR, "resources");
|
|
|
|
const targetPath = path.join(resDir, file);
|
|
|
|
if (!options?.force && (await fs.pathExists(targetPath))) return;
|
|
|
|
await fs.mkdirp(resDir);
|
|
|
|
await downloadFile(downloadURL, targetPath);
|
|
|
|
consola.success(colorize`resolve {green ${file}} finished`);
|
|
};
|
|
|
|
export class Resolve {
|
|
private infoOption: {
|
|
platform: NodeJS.Platform;
|
|
arch: NodeArch;
|
|
sidecarHost: string;
|
|
};
|
|
|
|
constructor(
|
|
private readonly options: {
|
|
force?: boolean;
|
|
platform: NodeJS.Platform;
|
|
arch: NodeArch;
|
|
sidecarHost: string;
|
|
},
|
|
) {
|
|
this.infoOption = {
|
|
platform: this.options.platform,
|
|
arch: this.options.arch,
|
|
sidecarHost: this.options.sidecarHost,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* only Windows
|
|
* get the wintun.dll (not required)
|
|
*/
|
|
public async wintun() {
|
|
const { platform } = process;
|
|
let arch: string = this.options.arch || "x64";
|
|
if (platform !== "win32") return;
|
|
|
|
switch (arch) {
|
|
case "x64":
|
|
arch = "amd64";
|
|
break;
|
|
case "ia32":
|
|
arch = "x86";
|
|
break;
|
|
case "arm":
|
|
arch = "arm";
|
|
break;
|
|
case "arm64":
|
|
arch = "arm64";
|
|
break;
|
|
default:
|
|
throw new Error(`unsupported arch ${arch}`);
|
|
}
|
|
|
|
const url = "https://www.wintun.net/builds/wintun-0.14.1.zip";
|
|
const hash =
|
|
"07c256185d6ee3652e09fa55c0b673e2624b565e02c4b9091c79ca7d2f24ef51";
|
|
|
|
const tempDir = path.join(TEMP_DIR, "wintun");
|
|
|
|
const tempZip = path.join(tempDir, "wintun.zip");
|
|
|
|
// const wintunPath = path.join(tempDir, "wintun/bin/amd64/wintun.dll");
|
|
|
|
const targetPath = path.join(TAURI_APP_DIR, "resources", "wintun.dll");
|
|
|
|
if (!this.options?.force && (await fs.pathExists(targetPath))) return;
|
|
|
|
await fs.mkdirp(tempDir);
|
|
|
|
if (!(await fs.pathExists(tempZip))) {
|
|
await downloadFile(url, tempZip);
|
|
}
|
|
|
|
// check hash
|
|
const hashBuffer = await fs.readFile(tempZip);
|
|
const sha256 = crypto.createHash("sha256");
|
|
sha256.update(hashBuffer);
|
|
const hashValue = sha256.digest("hex");
|
|
if (hashValue !== hash) {
|
|
throw new Error(`wintun. hash not match ${hashValue}`);
|
|
}
|
|
|
|
// unzip
|
|
const zip = new AdmZip(tempZip);
|
|
|
|
zip.extractAllTo(tempDir, true);
|
|
|
|
// recursive list path for debug use
|
|
const files = (await fs.readdir(tempDir, { recursive: true })).filter(
|
|
(file) => file.includes("wintun.dll"),
|
|
);
|
|
consola.debug(colorize`{green wintun} founded dlls: ${files}`);
|
|
|
|
const file = files.find((file) => file.includes(arch));
|
|
if (!file) {
|
|
throw new Error(`wintun. not found arch ${arch}`);
|
|
}
|
|
|
|
const wintunPath = path.join(tempDir, file.toString());
|
|
|
|
if (!(await fs.pathExists(wintunPath))) {
|
|
throw new Error(`path not found "${wintunPath}"`);
|
|
}
|
|
// prepare resource dir
|
|
await fs.mkdirp(path.dirname(targetPath));
|
|
await fs.copyFile(wintunPath, targetPath);
|
|
|
|
await fs.remove(tempDir);
|
|
|
|
consola.success(colorize`resolve {green wintun.dll} finished`);
|
|
}
|
|
|
|
public async service() {
|
|
return await this.sidecar(getNyanpasuServiceInfo(this.infoOption));
|
|
}
|
|
|
|
public mmdb() {
|
|
return resolveResource({
|
|
file: "Country.mmdb",
|
|
downloadURL: `https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/country.mmdb`,
|
|
});
|
|
}
|
|
|
|
public geosite() {
|
|
return resolveResource({
|
|
file: "geosite.dat",
|
|
downloadURL: `https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat`,
|
|
});
|
|
}
|
|
|
|
public geoip() {
|
|
return resolveResource({
|
|
file: "geoip.dat",
|
|
downloadURL: `https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.dat`,
|
|
});
|
|
}
|
|
|
|
public enableLoopback() {
|
|
return resolveResource({
|
|
file: "enableLoopback.exe",
|
|
downloadURL: `https://github.com/Kuingsmile/uwp-tool/releases/download/latest/enableLoopback.exe`,
|
|
});
|
|
}
|
|
|
|
private sidecar(binInfo: BinInfo | PromiseLike<BinInfo>) {
|
|
return resolveSidecar(binInfo, this.options.platform, {
|
|
force: this.options.force,
|
|
});
|
|
}
|
|
|
|
public async clash() {
|
|
return await this.sidecar(getClashBackupInfo(this.infoOption));
|
|
}
|
|
|
|
public async clashMeta() {
|
|
return await this.sidecar(getClashMetaInfo(this.infoOption));
|
|
}
|
|
|
|
public async clashMetaAlpha() {
|
|
return await this.sidecar(getClashMetaAlphaInfo(this.infoOption));
|
|
}
|
|
|
|
public async clashRust() {
|
|
return await this.sidecar(getClashRustInfo(this.infoOption));
|
|
}
|
|
|
|
public async clashRustAlpha() {
|
|
return await this.sidecar(getClashRustAlphaInfo(this.infoOption));
|
|
}
|
|
}
|