fix: include Mihomo-go122 by default for macOS 10.15+ to resolve Intel architecture compatibility issues
This commit is contained in:
@@ -42,6 +42,7 @@
|
|||||||
- 优化首页当前节点对MATCH规则的支持
|
- 优化首页当前节点对MATCH规则的支持
|
||||||
- 允许在 `界面设置` 修改 `悬浮跳转导航延迟`
|
- 允许在 `界面设置` 修改 `悬浮跳转导航延迟`
|
||||||
- 添加热键绑定错误的提示信息
|
- 添加热键绑定错误的提示信息
|
||||||
|
- 在 macOS 10.15 及更高版本默认包含 Mihomo-go122,以解决 Intel 架构 Mac 无法运行内核的问题
|
||||||
|
|
||||||
### 🐞 修复问题
|
### 🐞 修复问题
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import { log_debug, log_error, log_info, log_success } from "./utils.mjs";
|
|||||||
* 3. Use file hash to detect changes and skip unnecessary chmod/copy operations
|
* 3. Use file hash to detect changes and skip unnecessary chmod/copy operations
|
||||||
* 4. Use --force or -f flag to force re-download and update all resources
|
* 4. Use --force or -f flag to force re-download and update all resources
|
||||||
*
|
*
|
||||||
* This optimization significantly reduces build time for local development
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const cwd = process.cwd();
|
const cwd = process.cwd();
|
||||||
@@ -56,8 +55,7 @@ const ARCH_MAP = {
|
|||||||
|
|
||||||
const arg1 = process.argv.slice(2)[0];
|
const arg1 = process.argv.slice(2)[0];
|
||||||
const arg2 = process.argv.slice(2)[1];
|
const arg2 = process.argv.slice(2)[1];
|
||||||
let target;
|
let target = arg1 === "--force" || arg1 === "-f" ? arg2 : arg1;
|
||||||
target = arg1 === "--force" || arg1 === "-f" ? arg2 : arg1;
|
|
||||||
const { platform, arch } = target
|
const { platform, arch } = target
|
||||||
? { platform: PLATFORM_MAP[target], arch: ARCH_MAP[target] }
|
? { platform: PLATFORM_MAP[target], arch: ARCH_MAP[target] }
|
||||||
: process;
|
: process;
|
||||||
@@ -68,7 +66,9 @@ const SIDECAR_HOST = target
|
|||||||
.toString()
|
.toString()
|
||||||
.match(/(?<=host: ).+(?=\s*)/g)[0];
|
.match(/(?<=host: ).+(?=\s*)/g)[0];
|
||||||
|
|
||||||
/* ======= Version Cache Functions ======= */
|
// =======================
|
||||||
|
// Version Cache
|
||||||
|
// =======================
|
||||||
async function loadVersionCache() {
|
async function loadVersionCache() {
|
||||||
try {
|
try {
|
||||||
if (fs.existsSync(VERSION_CACHE_FILE)) {
|
if (fs.existsSync(VERSION_CACHE_FILE)) {
|
||||||
@@ -80,7 +80,6 @@ async function loadVersionCache() {
|
|||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function saveVersionCache(cache) {
|
async function saveVersionCache(cache) {
|
||||||
try {
|
try {
|
||||||
await fsp.mkdir(TEMP_DIR, { recursive: true });
|
await fsp.mkdir(TEMP_DIR, { recursive: true });
|
||||||
@@ -90,28 +89,24 @@ async function saveVersionCache(cache) {
|
|||||||
log_debug("Failed to save version cache:", err.message);
|
log_debug("Failed to save version cache:", err.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getCachedVersion(key) {
|
async function getCachedVersion(key) {
|
||||||
const cache = await loadVersionCache();
|
const cache = await loadVersionCache();
|
||||||
const cached = cache[key];
|
const cached = cache[key];
|
||||||
if (cached && Date.now() - cached.timestamp < 3600000) {
|
if (cached && Date.now() - cached.timestamp < 3600000) {
|
||||||
// 1小时内有效
|
|
||||||
log_info(`Using cached version for ${key}: ${cached.version}`);
|
log_info(`Using cached version for ${key}: ${cached.version}`);
|
||||||
return cached.version;
|
return cached.version;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setCachedVersion(key, version) {
|
async function setCachedVersion(key, version) {
|
||||||
const cache = await loadVersionCache();
|
const cache = await loadVersionCache();
|
||||||
cache[key] = {
|
cache[key] = { version, timestamp: Date.now() };
|
||||||
version,
|
|
||||||
timestamp: Date.now(),
|
|
||||||
};
|
|
||||||
await saveVersionCache(cache);
|
await saveVersionCache(cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ======= File Hash Functions ======= */
|
// =======================
|
||||||
|
// Hash Cache & File Hash
|
||||||
|
// =======================
|
||||||
async function calculateFileHash(filePath) {
|
async function calculateFileHash(filePath) {
|
||||||
try {
|
try {
|
||||||
const fileBuffer = await fsp.readFile(filePath);
|
const fileBuffer = await fsp.readFile(filePath);
|
||||||
@@ -122,7 +117,6 @@ async function calculateFileHash(filePath) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadHashCache() {
|
async function loadHashCache() {
|
||||||
try {
|
try {
|
||||||
if (fs.existsSync(HASH_CACHE_FILE)) {
|
if (fs.existsSync(HASH_CACHE_FILE)) {
|
||||||
@@ -134,7 +128,6 @@ async function loadHashCache() {
|
|||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function saveHashCache(cache) {
|
async function saveHashCache(cache) {
|
||||||
try {
|
try {
|
||||||
await fsp.mkdir(TEMP_DIR, { recursive: true });
|
await fsp.mkdir(TEMP_DIR, { recursive: true });
|
||||||
@@ -144,28 +137,20 @@ async function saveHashCache(cache) {
|
|||||||
log_debug("Failed to save hash cache:", err.message);
|
log_debug("Failed to save hash cache:", err.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function hasFileChanged(filePath, targetPath) {
|
async function hasFileChanged(filePath, targetPath) {
|
||||||
if (FORCE) return true;
|
if (FORCE) return true;
|
||||||
if (!fs.existsSync(targetPath)) return true;
|
if (!fs.existsSync(targetPath)) return true;
|
||||||
|
|
||||||
const hashCache = await loadHashCache();
|
const hashCache = await loadHashCache();
|
||||||
const sourceHash = await calculateFileHash(filePath);
|
const sourceHash = await calculateFileHash(filePath);
|
||||||
const targetHash = await calculateFileHash(targetPath);
|
const targetHash = await calculateFileHash(targetPath);
|
||||||
|
|
||||||
if (!sourceHash || !targetHash) return true;
|
if (!sourceHash || !targetHash) return true;
|
||||||
|
|
||||||
const cacheKey = targetPath;
|
const cacheKey = targetPath;
|
||||||
const cachedHash = hashCache[cacheKey];
|
const cachedHash = hashCache[cacheKey];
|
||||||
|
|
||||||
if (cachedHash === sourceHash && sourceHash === targetHash) {
|
if (cachedHash === sourceHash && sourceHash === targetHash) {
|
||||||
// 文件未变化,不输出日志
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updateHashCache(targetPath) {
|
async function updateHashCache(targetPath) {
|
||||||
const hashCache = await loadHashCache();
|
const hashCache = await loadHashCache();
|
||||||
const hash = await calculateFileHash(targetPath);
|
const hash = await calculateFileHash(targetPath);
|
||||||
@@ -175,18 +160,25 @@ async function updateHashCache(targetPath) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ======= clash meta alpha======= */
|
// =======================
|
||||||
|
// Meta maps (stable & alpha)
|
||||||
|
// =======================
|
||||||
const META_ALPHA_VERSION_URL =
|
const META_ALPHA_VERSION_URL =
|
||||||
"https://github.com/MetaCubeX/mihomo/releases/download/Prerelease-Alpha/version.txt";
|
"https://github.com/MetaCubeX/mihomo/releases/download/Prerelease-Alpha/version.txt";
|
||||||
const META_ALPHA_URL_PREFIX = `https://github.com/MetaCubeX/mihomo/releases/download/Prerelease-Alpha`;
|
const META_ALPHA_URL_PREFIX = `https://github.com/MetaCubeX/mihomo/releases/download/Prerelease-Alpha`;
|
||||||
let META_ALPHA_VERSION;
|
let META_ALPHA_VERSION;
|
||||||
|
|
||||||
|
const META_VERSION_URL =
|
||||||
|
"https://github.com/MetaCubeX/mihomo/releases/latest/download/version.txt";
|
||||||
|
const META_URL_PREFIX = `https://github.com/MetaCubeX/mihomo/releases/download`;
|
||||||
|
let META_VERSION;
|
||||||
|
|
||||||
const META_ALPHA_MAP = {
|
const META_ALPHA_MAP = {
|
||||||
"win32-x64": "mihomo-windows-amd64-v2",
|
"win32-x64": "mihomo-windows-amd64-v2",
|
||||||
"win32-ia32": "mihomo-windows-386",
|
"win32-ia32": "mihomo-windows-386",
|
||||||
"win32-arm64": "mihomo-windows-arm64",
|
"win32-arm64": "mihomo-windows-arm64",
|
||||||
"darwin-x64": "mihomo-darwin-amd64-v1",
|
"darwin-x64": "mihomo-darwin-amd64-v1-go122",
|
||||||
"darwin-arm64": "mihomo-darwin-arm64",
|
"darwin-arm64": "mihomo-darwin-arm64-go122",
|
||||||
"linux-x64": "mihomo-linux-amd64-v2",
|
"linux-x64": "mihomo-linux-amd64-v2",
|
||||||
"linux-ia32": "mihomo-linux-386",
|
"linux-ia32": "mihomo-linux-386",
|
||||||
"linux-arm64": "mihomo-linux-arm64",
|
"linux-arm64": "mihomo-linux-arm64",
|
||||||
@@ -195,9 +187,24 @@ const META_ALPHA_MAP = {
|
|||||||
"linux-loong64": "mihomo-linux-loong64",
|
"linux-loong64": "mihomo-linux-loong64",
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fetch the latest alpha release version from the version.txt file
|
const META_MAP = {
|
||||||
|
"win32-x64": "mihomo-windows-amd64-v2",
|
||||||
|
"win32-ia32": "mihomo-windows-386",
|
||||||
|
"win32-arm64": "mihomo-windows-arm64",
|
||||||
|
"darwin-x64": "mihomo-darwin-amd64-v2-go122",
|
||||||
|
"darwin-arm64": "mihomo-darwin-arm64-go122",
|
||||||
|
"linux-x64": "mihomo-linux-amd64-v2",
|
||||||
|
"linux-ia32": "mihomo-linux-386",
|
||||||
|
"linux-arm64": "mihomo-linux-arm64",
|
||||||
|
"linux-arm": "mihomo-linux-armv7",
|
||||||
|
"linux-riscv64": "mihomo-linux-riscv64",
|
||||||
|
"linux-loong64": "mihomo-linux-loong64",
|
||||||
|
};
|
||||||
|
|
||||||
|
// =======================
|
||||||
|
// Fetch latest versions
|
||||||
|
// =======================
|
||||||
async function getLatestAlphaVersion() {
|
async function getLatestAlphaVersion() {
|
||||||
// 如果不强制更新,先尝试从缓存获取
|
|
||||||
if (!FORCE) {
|
if (!FORCE) {
|
||||||
const cached = await getCachedVersion("META_ALPHA_VERSION");
|
const cached = await getCachedVersion("META_ALPHA_VERSION");
|
||||||
if (cached) {
|
if (cached) {
|
||||||
@@ -205,58 +212,33 @@ async function getLatestAlphaVersion() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const options = {};
|
const options = {};
|
||||||
|
|
||||||
const httpProxy =
|
const httpProxy =
|
||||||
process.env.HTTP_PROXY ||
|
process.env.HTTP_PROXY ||
|
||||||
process.env.http_proxy ||
|
process.env.http_proxy ||
|
||||||
process.env.HTTPS_PROXY ||
|
process.env.HTTPS_PROXY ||
|
||||||
process.env.https_proxy;
|
process.env.https_proxy;
|
||||||
|
if (httpProxy) options.agent = new HttpsProxyAgent(httpProxy);
|
||||||
|
|
||||||
if (httpProxy) {
|
|
||||||
options.agent = new HttpsProxyAgent(httpProxy);
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(META_ALPHA_VERSION_URL, {
|
const response = await fetch(META_ALPHA_VERSION_URL, {
|
||||||
...options,
|
...options,
|
||||||
method: "GET",
|
method: "GET",
|
||||||
});
|
});
|
||||||
let v = await response.text();
|
if (!response.ok)
|
||||||
META_ALPHA_VERSION = v.trim(); // Trim to remove extra whitespaces
|
throw new Error(
|
||||||
|
`Failed to fetch ${META_ALPHA_VERSION_URL}: ${response.status}`,
|
||||||
|
);
|
||||||
|
META_ALPHA_VERSION = (await response.text()).trim();
|
||||||
log_info(`Latest alpha version: ${META_ALPHA_VERSION}`);
|
log_info(`Latest alpha version: ${META_ALPHA_VERSION}`);
|
||||||
|
|
||||||
// 保存到缓存
|
|
||||||
await setCachedVersion("META_ALPHA_VERSION", META_ALPHA_VERSION);
|
await setCachedVersion("META_ALPHA_VERSION", META_ALPHA_VERSION);
|
||||||
} catch (error) {
|
} catch (err) {
|
||||||
log_error("Error fetching latest alpha version:", error.message);
|
log_error("Error fetching latest alpha version:", err.message);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ======= clash meta stable ======= */
|
|
||||||
const META_VERSION_URL =
|
|
||||||
"https://github.com/MetaCubeX/mihomo/releases/latest/download/version.txt";
|
|
||||||
const META_URL_PREFIX = `https://github.com/MetaCubeX/mihomo/releases/download`;
|
|
||||||
let META_VERSION;
|
|
||||||
|
|
||||||
const META_MAP = {
|
|
||||||
"win32-x64": "mihomo-windows-amd64-v2",
|
|
||||||
"win32-ia32": "mihomo-windows-386",
|
|
||||||
"win32-arm64": "mihomo-windows-arm64",
|
|
||||||
"darwin-x64": "mihomo-darwin-amd64-v2",
|
|
||||||
"darwin-arm64": "mihomo-darwin-arm64",
|
|
||||||
"linux-x64": "mihomo-linux-amd64-v2",
|
|
||||||
"linux-ia32": "mihomo-linux-386",
|
|
||||||
"linux-arm64": "mihomo-linux-arm64",
|
|
||||||
"linux-arm": "mihomo-linux-armv7",
|
|
||||||
"linux-riscv64": "mihomo-linux-riscv64",
|
|
||||||
"linux-loong64": "mihomo-linux-loong64",
|
|
||||||
};
|
|
||||||
|
|
||||||
// Fetch the latest release version from the version.txt file
|
|
||||||
async function getLatestReleaseVersion() {
|
async function getLatestReleaseVersion() {
|
||||||
// 如果不强制更新,先尝试从缓存获取
|
|
||||||
if (!FORCE) {
|
if (!FORCE) {
|
||||||
const cached = await getCachedVersion("META_VERSION");
|
const cached = await getCachedVersion("META_VERSION");
|
||||||
if (cached) {
|
if (cached) {
|
||||||
@@ -264,67 +246,57 @@ async function getLatestReleaseVersion() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const options = {};
|
const options = {};
|
||||||
|
|
||||||
const httpProxy =
|
const httpProxy =
|
||||||
process.env.HTTP_PROXY ||
|
process.env.HTTP_PROXY ||
|
||||||
process.env.http_proxy ||
|
process.env.http_proxy ||
|
||||||
process.env.HTTPS_PROXY ||
|
process.env.HTTPS_PROXY ||
|
||||||
process.env.https_proxy;
|
process.env.https_proxy;
|
||||||
|
if (httpProxy) options.agent = new HttpsProxyAgent(httpProxy);
|
||||||
|
|
||||||
if (httpProxy) {
|
|
||||||
options.agent = new HttpsProxyAgent(httpProxy);
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(META_VERSION_URL, {
|
const response = await fetch(META_VERSION_URL, {
|
||||||
...options,
|
...options,
|
||||||
method: "GET",
|
method: "GET",
|
||||||
});
|
});
|
||||||
let v = await response.text();
|
if (!response.ok)
|
||||||
META_VERSION = v.trim(); // Trim to remove extra whitespaces
|
throw new Error(
|
||||||
|
`Failed to fetch ${META_VERSION_URL}: ${response.status}`,
|
||||||
|
);
|
||||||
|
META_VERSION = (await response.text()).trim();
|
||||||
log_info(`Latest release version: ${META_VERSION}`);
|
log_info(`Latest release version: ${META_VERSION}`);
|
||||||
|
|
||||||
// 保存到缓存
|
|
||||||
await setCachedVersion("META_VERSION", META_VERSION);
|
await setCachedVersion("META_VERSION", META_VERSION);
|
||||||
} catch (error) {
|
} catch (err) {
|
||||||
log_error("Error fetching latest release version:", error.message);
|
log_error("Error fetching latest release version:", err.message);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// =======================
|
||||||
* check available
|
// Validate availability
|
||||||
*/
|
// =======================
|
||||||
if (!META_MAP[`${platform}-${arch}`]) {
|
if (!META_MAP[`${platform}-${arch}`]) {
|
||||||
throw new Error(
|
throw new Error(`clash meta unsupported platform "${platform}-${arch}"`);
|
||||||
`clash meta alpha unsupported platform "${platform}-${arch}"`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!META_ALPHA_MAP[`${platform}-${arch}`]) {
|
if (!META_ALPHA_MAP[`${platform}-${arch}`]) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`clash meta alpha unsupported platform "${platform}-${arch}"`,
|
`clash meta alpha unsupported platform "${platform}-${arch}"`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// =======================
|
||||||
* core info
|
// Build meta objects
|
||||||
*/
|
// =======================
|
||||||
function clashMetaAlpha() {
|
function clashMetaAlpha() {
|
||||||
const name = META_ALPHA_MAP[`${platform}-${arch}`];
|
const name = META_ALPHA_MAP[`${platform}-${arch}`];
|
||||||
const isWin = platform === "win32";
|
const isWin = platform === "win32";
|
||||||
const urlExt = isWin ? "zip" : "gz";
|
const urlExt = isWin ? "zip" : "gz";
|
||||||
const downloadURL = `${META_ALPHA_URL_PREFIX}/${name}-${META_ALPHA_VERSION}.${urlExt}`;
|
|
||||||
const exeFile = `${name}${isWin ? ".exe" : ""}`;
|
|
||||||
const zipFile = `${name}-${META_ALPHA_VERSION}.${urlExt}`;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: "verge-mihomo-alpha",
|
name: "verge-mihomo-alpha",
|
||||||
targetFile: `verge-mihomo-alpha-${SIDECAR_HOST}${isWin ? ".exe" : ""}`,
|
targetFile: `verge-mihomo-alpha-${SIDECAR_HOST}${isWin ? ".exe" : ""}`,
|
||||||
exeFile,
|
exeFile: `${name}${isWin ? ".exe" : ""}`,
|
||||||
zipFile,
|
zipFile: `${name}-${META_ALPHA_VERSION}.${urlExt}`,
|
||||||
downloadURL,
|
downloadURL: `${META_ALPHA_URL_PREFIX}/${name}-${META_ALPHA_VERSION}.${urlExt}`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,40 +304,83 @@ function clashMeta() {
|
|||||||
const name = META_MAP[`${platform}-${arch}`];
|
const name = META_MAP[`${platform}-${arch}`];
|
||||||
const isWin = platform === "win32";
|
const isWin = platform === "win32";
|
||||||
const urlExt = isWin ? "zip" : "gz";
|
const urlExt = isWin ? "zip" : "gz";
|
||||||
const downloadURL = `${META_URL_PREFIX}/${META_VERSION}/${name}-${META_VERSION}.${urlExt}`;
|
|
||||||
const exeFile = `${name}${isWin ? ".exe" : ""}`;
|
|
||||||
const zipFile = `${name}-${META_VERSION}.${urlExt}`;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: "verge-mihomo",
|
name: "verge-mihomo",
|
||||||
targetFile: `verge-mihomo-${SIDECAR_HOST}${isWin ? ".exe" : ""}`,
|
targetFile: `verge-mihomo-${SIDECAR_HOST}${isWin ? ".exe" : ""}`,
|
||||||
exeFile,
|
exeFile: `${name}${isWin ? ".exe" : ""}`,
|
||||||
zipFile,
|
zipFile: `${name}-${META_VERSION}.${urlExt}`,
|
||||||
downloadURL,
|
downloadURL: `${META_URL_PREFIX}/${META_VERSION}/${name}-${META_VERSION}.${urlExt}`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* download sidecar and rename
|
// =======================
|
||||||
*/
|
// download helper (增强:status + magic bytes)
|
||||||
|
// =======================
|
||||||
|
async function downloadFile(url, outPath) {
|
||||||
|
const options = {};
|
||||||
|
const httpProxy =
|
||||||
|
process.env.HTTP_PROXY ||
|
||||||
|
process.env.http_proxy ||
|
||||||
|
process.env.HTTPS_PROXY ||
|
||||||
|
process.env.https_proxy;
|
||||||
|
if (httpProxy) options.agent = new HttpsProxyAgent(httpProxy);
|
||||||
|
|
||||||
|
const response = await fetch(url, {
|
||||||
|
...options,
|
||||||
|
method: "GET",
|
||||||
|
headers: { "Content-Type": "application/octet-stream" },
|
||||||
|
});
|
||||||
|
if (!response.ok) {
|
||||||
|
const body = await response.text().catch(() => "");
|
||||||
|
// 将 body 写到文件以便排查(可通过临时目录查看)
|
||||||
|
await fsp.mkdir(path.dirname(outPath), { recursive: true });
|
||||||
|
await fsp.writeFile(outPath, body);
|
||||||
|
throw new Error(`Failed to download ${url}: status ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const buf = Buffer.from(await response.arrayBuffer());
|
||||||
|
await fsp.mkdir(path.dirname(outPath), { recursive: true });
|
||||||
|
|
||||||
|
// 简单 magic 字节检查
|
||||||
|
if (url.endsWith(".gz") || url.endsWith(".tgz")) {
|
||||||
|
if (!(buf[0] === 0x1f && buf[1] === 0x8b)) {
|
||||||
|
await fsp.writeFile(outPath, buf);
|
||||||
|
throw new Error(
|
||||||
|
`Downloaded file for ${url} is not a valid gzip (magic mismatch).`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (url.endsWith(".zip")) {
|
||||||
|
if (!(buf[0] === 0x50 && buf[1] === 0x4b)) {
|
||||||
|
await fsp.writeFile(outPath, buf);
|
||||||
|
throw new Error(
|
||||||
|
`Downloaded file for ${url} is not a valid zip (magic mismatch).`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await fsp.writeFile(outPath, buf);
|
||||||
|
log_success(`download finished: ${url}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// =======================
|
||||||
|
// resolveSidecar (支持 zip / tgz / gz)
|
||||||
|
// =======================
|
||||||
async function resolveSidecar(binInfo) {
|
async function resolveSidecar(binInfo) {
|
||||||
const { name, targetFile, zipFile, exeFile, downloadURL } = binInfo;
|
const { name, targetFile, zipFile, exeFile, downloadURL } = binInfo;
|
||||||
|
|
||||||
const sidecarDir = path.join(cwd, "src-tauri", "sidecar");
|
const sidecarDir = path.join(cwd, "src-tauri", "sidecar");
|
||||||
const sidecarPath = path.join(sidecarDir, targetFile);
|
const sidecarPath = path.join(sidecarDir, targetFile);
|
||||||
|
|
||||||
await fsp.mkdir(sidecarDir, { recursive: true });
|
await fsp.mkdir(sidecarDir, { recursive: true });
|
||||||
|
|
||||||
// 检查文件是否已存在,如果存在则跳过重复下载
|
|
||||||
if (!FORCE && fs.existsSync(sidecarPath)) {
|
if (!FORCE && fs.existsSync(sidecarPath)) {
|
||||||
log_success(`"${name}" already exists, skipping download to save time`);
|
log_success(`"${name}" already exists, skipping download`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tempDir = path.join(TEMP_DIR, name);
|
const tempDir = path.join(TEMP_DIR, name);
|
||||||
const tempZip = path.join(tempDir, zipFile);
|
const tempZip = path.join(tempDir, zipFile);
|
||||||
const tempExe = path.join(tempDir, exeFile);
|
const tempExe = path.join(tempDir, exeFile);
|
||||||
|
|
||||||
await fsp.mkdir(tempDir, { recursive: true });
|
await fsp.mkdir(tempDir, { recursive: true });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!fs.existsSync(tempZip)) {
|
if (!fs.existsSync(tempZip)) {
|
||||||
await downloadFile(downloadURL, tempZip);
|
await downloadFile(downloadURL, tempZip);
|
||||||
@@ -374,78 +389,76 @@ async function resolveSidecar(binInfo) {
|
|||||||
if (zipFile.endsWith(".zip")) {
|
if (zipFile.endsWith(".zip")) {
|
||||||
const zip = new AdmZip(tempZip);
|
const zip = new AdmZip(tempZip);
|
||||||
zip.getEntries().forEach((entry) => {
|
zip.getEntries().forEach((entry) => {
|
||||||
log_debug(`"${name}" entry name`, entry.entryName);
|
log_debug(`"${name}" entry: ${entry.entryName}`);
|
||||||
});
|
});
|
||||||
zip.extractAllTo(tempDir, true);
|
zip.extractAllTo(tempDir, true);
|
||||||
|
// 尝试按 exeFile 重命名,否则找第一个可执行文件
|
||||||
|
if (fs.existsSync(tempExe)) {
|
||||||
await fsp.rename(tempExe, sidecarPath);
|
await fsp.rename(tempExe, sidecarPath);
|
||||||
|
} else {
|
||||||
|
// 搜索候选
|
||||||
|
const files = await fsp.readdir(tempDir);
|
||||||
|
const candidate = files.find(
|
||||||
|
(f) =>
|
||||||
|
f === path.basename(exeFile) ||
|
||||||
|
f.endsWith(".exe") ||
|
||||||
|
!f.includes("."),
|
||||||
|
);
|
||||||
|
if (!candidate)
|
||||||
|
throw new Error(`Expected binary not found in ${tempDir}`);
|
||||||
|
await fsp.rename(path.join(tempDir, candidate), sidecarPath);
|
||||||
|
}
|
||||||
|
if (platform !== "win32") execSync(`chmod 755 ${sidecarPath}`);
|
||||||
log_success(`unzip finished: "${name}"`);
|
log_success(`unzip finished: "${name}"`);
|
||||||
} else if (zipFile.endsWith(".tgz")) {
|
} else if (zipFile.endsWith(".tgz")) {
|
||||||
// tgz
|
await extract({ cwd: tempDir, file: tempZip });
|
||||||
await fsp.mkdir(tempDir, { recursive: true });
|
|
||||||
await extract({
|
|
||||||
cwd: tempDir,
|
|
||||||
file: tempZip,
|
|
||||||
//strip: 1, // 可能需要根据实际的 .tgz 文件结构调整
|
|
||||||
});
|
|
||||||
const files = await fsp.readdir(tempDir);
|
const files = await fsp.readdir(tempDir);
|
||||||
log_debug(`"${name}" files in tempDir:`, files);
|
log_debug(`"${name}" extracted files:`, files);
|
||||||
const extractedFile = files.find((file) => file.startsWith("虚空终端-"));
|
// 优先寻找给定 exeFile 或已知前缀
|
||||||
if (extractedFile) {
|
let extracted = files.find(
|
||||||
const extractedFilePath = path.join(tempDir, extractedFile);
|
(f) =>
|
||||||
await fsp.rename(extractedFilePath, sidecarPath);
|
f === path.basename(exeFile) ||
|
||||||
log_success(`"${name}" file renamed to "${sidecarPath}"`);
|
f.startsWith("虚空终端-") ||
|
||||||
|
!f.includes("."),
|
||||||
|
);
|
||||||
|
if (!extracted) extracted = files[0];
|
||||||
|
if (!extracted) throw new Error(`Expected file not found in ${tempDir}`);
|
||||||
|
await fsp.rename(path.join(tempDir, extracted), sidecarPath);
|
||||||
execSync(`chmod 755 ${sidecarPath}`);
|
execSync(`chmod 755 ${sidecarPath}`);
|
||||||
log_success(`chmod binary finished: "${name}"`);
|
log_success(`tgz processed: "${name}"`);
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`Expected file not found in ${tempDir}`);
|
// .gz
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// gz
|
|
||||||
const readStream = fs.createReadStream(tempZip);
|
const readStream = fs.createReadStream(tempZip);
|
||||||
const writeStream = fs.createWriteStream(sidecarPath);
|
const writeStream = fs.createWriteStream(sidecarPath);
|
||||||
await new Promise((resolve, reject) => {
|
await new Promise((resolve, reject) => {
|
||||||
const onError = (error) => {
|
|
||||||
log_error(`"${name}" gz failed:`, error.message);
|
|
||||||
reject(error);
|
|
||||||
};
|
|
||||||
readStream
|
readStream
|
||||||
.pipe(zlib.createGunzip().on("error", onError))
|
.pipe(zlib.createGunzip())
|
||||||
|
.on("error", (e) => {
|
||||||
|
log_error(`gunzip error for ${name}:`, e.message);
|
||||||
|
reject(e);
|
||||||
|
})
|
||||||
.pipe(writeStream)
|
.pipe(writeStream)
|
||||||
.on("finish", () => {
|
.on("finish", () => {
|
||||||
execSync(`chmod 755 ${sidecarPath}`);
|
if (platform !== "win32") execSync(`chmod 755 ${sidecarPath}`);
|
||||||
log_success(`chmod binary finished: "${name}"`);
|
|
||||||
resolve();
|
resolve();
|
||||||
})
|
})
|
||||||
.on("error", onError);
|
.on("error", (e) => {
|
||||||
|
log_error(`write stream error for ${name}:`, e.message);
|
||||||
|
reject(e);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
log_success(`gz binary processed: "${name}"`);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// 需要删除文件
|
|
||||||
await fsp.rm(sidecarPath, { recursive: true, force: true });
|
await fsp.rm(sidecarPath, { recursive: true, force: true });
|
||||||
throw err;
|
throw err;
|
||||||
} finally {
|
} finally {
|
||||||
// delete temp dir
|
|
||||||
await fsp.rm(tempDir, { recursive: true, force: true });
|
await fsp.rm(tempDir, { recursive: true, force: true });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const resolveSetDnsScript = () =>
|
|
||||||
resolveResource({
|
|
||||||
file: "set_dns.sh",
|
|
||||||
localPath: path.join(cwd, "scripts/set_dns.sh"),
|
|
||||||
});
|
|
||||||
const resolveUnSetDnsScript = () =>
|
|
||||||
resolveResource({
|
|
||||||
file: "unset_dns.sh",
|
|
||||||
localPath: path.join(cwd, "scripts/unset_dns.sh"),
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* download the file to the resources dir
|
|
||||||
*/
|
|
||||||
async function resolveResource(binInfo) {
|
async function resolveResource(binInfo) {
|
||||||
const { file, downloadURL, localPath } = binInfo;
|
const { file, downloadURL, localPath } = binInfo;
|
||||||
|
|
||||||
const resDir = path.join(cwd, "src-tauri/resources");
|
const resDir = path.join(cwd, "src-tauri/resources");
|
||||||
const targetPath = path.join(resDir, file);
|
const targetPath = path.join(resDir, file);
|
||||||
|
|
||||||
@@ -465,12 +478,9 @@ async function resolveResource(binInfo) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (localPath) {
|
if (localPath) {
|
||||||
// 检查文件哈希是否变化
|
|
||||||
if (!(await hasFileChanged(localPath, targetPath))) {
|
if (!(await hasFileChanged(localPath, targetPath))) {
|
||||||
// 文件未变化,静默跳过
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await fsp.mkdir(resDir, { recursive: true });
|
await fsp.mkdir(resDir, { recursive: true });
|
||||||
await fsp.copyFile(localPath, targetPath);
|
await fsp.copyFile(localPath, targetPath);
|
||||||
await updateHashCache(targetPath);
|
await updateHashCache(targetPath);
|
||||||
@@ -480,44 +490,17 @@ async function resolveResource(binInfo) {
|
|||||||
log_success(`${file} finished`);
|
log_success(`${file} finished`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// SimpleSC.dll (win plugin)
|
||||||
* download file and save to `path`
|
|
||||||
*/ async function downloadFile(url, path) {
|
|
||||||
const options = {};
|
|
||||||
|
|
||||||
const httpProxy =
|
|
||||||
process.env.HTTP_PROXY ||
|
|
||||||
process.env.http_proxy ||
|
|
||||||
process.env.HTTPS_PROXY ||
|
|
||||||
process.env.https_proxy;
|
|
||||||
|
|
||||||
if (httpProxy) {
|
|
||||||
options.agent = new HttpsProxyAgent(httpProxy);
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await fetch(url, {
|
|
||||||
...options,
|
|
||||||
method: "GET",
|
|
||||||
headers: { "Content-Type": "application/octet-stream" },
|
|
||||||
});
|
|
||||||
const buffer = await response.arrayBuffer();
|
|
||||||
await fsp.writeFile(path, new Uint8Array(buffer));
|
|
||||||
|
|
||||||
log_success(`download finished: ${url}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// SimpleSC.dll
|
|
||||||
const resolvePlugin = async () => {
|
const resolvePlugin = async () => {
|
||||||
const url =
|
const url =
|
||||||
"https://nsis.sourceforge.io/mediawiki/images/e/ef/NSIS_Simple_Service_Plugin_Unicode_1.30.zip";
|
"https://nsis.sourceforge.io/mediawiki/images/e/ef/NSIS_Simple_Service_Plugin_Unicode_1.30.zip";
|
||||||
|
|
||||||
const tempDir = path.join(TEMP_DIR, "SimpleSC");
|
const tempDir = path.join(TEMP_DIR, "SimpleSC");
|
||||||
const tempZip = path.join(
|
const tempZip = path.join(
|
||||||
tempDir,
|
tempDir,
|
||||||
"NSIS_Simple_Service_Plugin_Unicode_1.30.zip",
|
"NSIS_Simple_Service_Plugin_Unicode_1.30.zip",
|
||||||
);
|
);
|
||||||
const tempDll = path.join(tempDir, "SimpleSC.dll");
|
const tempDll = path.join(tempDir, "SimpleSC.dll");
|
||||||
const pluginDir = path.join(process.env.APPDATA, "Local/NSIS");
|
const pluginDir = path.join(process.env.APPDATA || "", "Local/NSIS");
|
||||||
const pluginPath = path.join(pluginDir, "SimpleSC.dll");
|
const pluginPath = path.join(pluginDir, "SimpleSC.dll");
|
||||||
await fsp.mkdir(pluginDir, { recursive: true });
|
await fsp.mkdir(pluginDir, { recursive: true });
|
||||||
await fsp.mkdir(tempDir, { recursive: true });
|
await fsp.mkdir(tempDir, { recursive: true });
|
||||||
@@ -527,18 +510,33 @@ const resolvePlugin = async () => {
|
|||||||
await downloadFile(url, tempZip);
|
await downloadFile(url, tempZip);
|
||||||
}
|
}
|
||||||
const zip = new AdmZip(tempZip);
|
const zip = new AdmZip(tempZip);
|
||||||
zip.getEntries().forEach((entry) => {
|
zip
|
||||||
log_debug(`"SimpleSC" entry name`, entry.entryName);
|
.getEntries()
|
||||||
});
|
.forEach((entry) => log_debug(`"SimpleSC" entry`, entry.entryName));
|
||||||
zip.extractAllTo(tempDir, true);
|
zip.extractAllTo(tempDir, true);
|
||||||
|
if (fs.existsSync(tempDll)) {
|
||||||
await fsp.cp(tempDll, pluginPath, { recursive: true, force: true });
|
await fsp.cp(tempDll, pluginPath, { recursive: true, force: true });
|
||||||
log_success(`unzip finished: "SimpleSC"`);
|
log_success(`unzip finished: "SimpleSC"`);
|
||||||
|
} else {
|
||||||
|
// 如果 dll 名称不同,尝试找到 dll
|
||||||
|
const files = await fsp.readdir(tempDir);
|
||||||
|
const dll = files.find((f) => f.toLowerCase().endsWith(".dll"));
|
||||||
|
if (dll) {
|
||||||
|
await fsp.cp(path.join(tempDir, dll), pluginPath, {
|
||||||
|
recursive: true,
|
||||||
|
force: true,
|
||||||
|
});
|
||||||
|
log_success(`unzip finished: "SimpleSC" (found ${dll})`);
|
||||||
|
} else {
|
||||||
|
throw new Error("SimpleSC.dll not found in zip");
|
||||||
|
}
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
await fsp.rm(tempDir, { recursive: true, force: true });
|
await fsp.rm(tempDir, { recursive: true, force: true });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// service chmod
|
// service chmod (保留并使用 glob)
|
||||||
const resolveServicePermission = async () => {
|
const resolveServicePermission = async () => {
|
||||||
const serviceExecutables = [
|
const serviceExecutables = [
|
||||||
"clash-verge-service*",
|
"clash-verge-service*",
|
||||||
@@ -550,23 +548,20 @@ const resolveServicePermission = async () => {
|
|||||||
let hasChanges = false;
|
let hasChanges = false;
|
||||||
|
|
||||||
for (let f of serviceExecutables) {
|
for (let f of serviceExecutables) {
|
||||||
// 使用glob模块来处理通配符
|
|
||||||
const files = glob.sync(path.join(resDir, f));
|
const files = glob.sync(path.join(resDir, f));
|
||||||
for (let filePath of files) {
|
for (let filePath of files) {
|
||||||
if (fs.existsSync(filePath)) {
|
if (fs.existsSync(filePath)) {
|
||||||
const currentHash = await calculateFileHash(filePath);
|
const currentHash = await calculateFileHash(filePath);
|
||||||
const cacheKey = `${filePath}_chmod`;
|
const cacheKey = `${filePath}_chmod`;
|
||||||
|
|
||||||
// 检查文件哈希是否变化
|
|
||||||
if (!FORCE && hashCache[cacheKey] === currentHash) {
|
if (!FORCE && hashCache[cacheKey] === currentHash) {
|
||||||
// 权限未变化,静默跳过
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
execSync(`chmod 755 ${filePath}`);
|
execSync(`chmod 755 ${filePath}`);
|
||||||
log_success(`chmod finished: "${filePath}"`);
|
log_success(`chmod finished: "${filePath}"`);
|
||||||
|
} catch (e) {
|
||||||
// 更新哈希缓存
|
log_error(`chmod failed for ${filePath}:`, e.message);
|
||||||
|
}
|
||||||
hashCache[cacheKey] = currentHash;
|
hashCache[cacheKey] = currentHash;
|
||||||
hasChanges = true;
|
hasChanges = true;
|
||||||
}
|
}
|
||||||
@@ -578,34 +573,22 @@ const resolveServicePermission = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 在 resolveResource 函数后添加新函数
|
// resolve locales (从 src/locales 复制到 resources/locales,并使用 hash 检查)
|
||||||
async function resolveLocales() {
|
async function resolveLocales() {
|
||||||
const srcLocalesDir = path.join(cwd, "src/locales");
|
const srcLocalesDir = path.join(cwd, "src/locales");
|
||||||
const targetLocalesDir = path.join(cwd, "src-tauri/resources/locales");
|
const targetLocalesDir = path.join(cwd, "src-tauri/resources/locales");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 确保目标目录存在
|
|
||||||
await fsp.mkdir(targetLocalesDir, { recursive: true });
|
await fsp.mkdir(targetLocalesDir, { recursive: true });
|
||||||
|
|
||||||
// 读取所有语言文件
|
|
||||||
const files = await fsp.readdir(srcLocalesDir);
|
const files = await fsp.readdir(srcLocalesDir);
|
||||||
|
|
||||||
// 复制每个文件,只有当哈希变化时才复制
|
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
const srcPath = path.join(srcLocalesDir, file);
|
const srcPath = path.join(srcLocalesDir, file);
|
||||||
const targetPath = path.join(targetLocalesDir, file);
|
const targetPath = path.join(targetLocalesDir, file);
|
||||||
|
if (!(await hasFileChanged(srcPath, targetPath))) continue;
|
||||||
// 检查文件是否需要更新
|
|
||||||
if (!(await hasFileChanged(srcPath, targetPath))) {
|
|
||||||
// 文件未变化,静默跳过
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
await fsp.copyFile(srcPath, targetPath);
|
await fsp.copyFile(srcPath, targetPath);
|
||||||
await updateHashCache(targetPath);
|
await updateHashCache(targetPath);
|
||||||
log_success(`Copied locale file: ${file}`);
|
log_success(`Copied locale file: ${file}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
log_success("All locale files processed successfully");
|
log_success("All locale files processed successfully");
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log_error("Error copying locale files:", err.message);
|
log_error("Error copying locale files:", err.message);
|
||||||
@@ -613,34 +596,30 @@ async function resolveLocales() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// =======================
|
||||||
* main
|
// Other resource resolvers (service, mmdb, geosite, geoip, enableLoopback, sysproxy)
|
||||||
*/
|
// =======================
|
||||||
const SERVICE_URL = `https://github.com/clash-verge-rev/clash-verge-service-ipc/releases/download/${SIDECAR_HOST}`;
|
const SERVICE_URL = `https://github.com/clash-verge-rev/clash-verge-service-ipc/releases/download/${SIDECAR_HOST}`;
|
||||||
|
|
||||||
const resolveService = () => {
|
const resolveService = () => {
|
||||||
let ext = platform === "win32" ? ".exe" : "";
|
let ext = platform === "win32" ? ".exe" : "";
|
||||||
let suffix = platform === "linux" ? "-" + SIDECAR_HOST : "";
|
let suffix = platform === "linux" ? "-" + SIDECAR_HOST : "";
|
||||||
resolveResource({
|
return resolveResource({
|
||||||
file: "clash-verge-service" + suffix + ext,
|
file: "clash-verge-service" + suffix + ext,
|
||||||
downloadURL: `${SERVICE_URL}/clash-verge-service${ext}`,
|
downloadURL: `${SERVICE_URL}/clash-verge-service${ext}`,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const resolveInstall = () => {
|
const resolveInstall = () => {
|
||||||
let ext = platform === "win32" ? ".exe" : "";
|
let ext = platform === "win32" ? ".exe" : "";
|
||||||
let suffix = platform === "linux" ? "-" + SIDECAR_HOST : "";
|
let suffix = platform === "linux" ? "-" + SIDECAR_HOST : "";
|
||||||
resolveResource({
|
return resolveResource({
|
||||||
file: "clash-verge-service-install" + suffix + ext,
|
file: "clash-verge-service-install" + suffix + ext,
|
||||||
downloadURL: `${SERVICE_URL}/clash-verge-service-install${ext}`,
|
downloadURL: `${SERVICE_URL}/clash-verge-service-install${ext}`,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const resolveUninstall = () => {
|
const resolveUninstall = () => {
|
||||||
let ext = platform === "win32" ? ".exe" : "";
|
let ext = platform === "win32" ? ".exe" : "";
|
||||||
let suffix = platform === "linux" ? "-" + SIDECAR_HOST : "";
|
let suffix = platform === "linux" ? "-" + SIDECAR_HOST : "";
|
||||||
|
return resolveResource({
|
||||||
resolveResource({
|
|
||||||
file: "clash-verge-service-uninstall" + suffix + ext,
|
file: "clash-verge-service-uninstall" + suffix + ext,
|
||||||
downloadURL: `${SERVICE_URL}/clash-verge-service-uninstall${ext}`,
|
downloadURL: `${SERVICE_URL}/clash-verge-service-uninstall${ext}`,
|
||||||
});
|
});
|
||||||
@@ -666,15 +645,27 @@ const resolveEnableLoopback = () =>
|
|||||||
file: "enableLoopback.exe",
|
file: "enableLoopback.exe",
|
||||||
downloadURL: `https://github.com/Kuingsmile/uwp-tool/releases/download/latest/enableLoopback.exe`,
|
downloadURL: `https://github.com/Kuingsmile/uwp-tool/releases/download/latest/enableLoopback.exe`,
|
||||||
});
|
});
|
||||||
|
|
||||||
const resolveWinSysproxy = () =>
|
const resolveWinSysproxy = () =>
|
||||||
resolveResource({
|
resolveResource({
|
||||||
file: "sysproxy.exe",
|
file: "sysproxy.exe",
|
||||||
downloadURL: `https://github.com/clash-verge-rev/sysproxy/releases/download/${arch}/sysproxy.exe`,
|
downloadURL: `https://github.com/clash-verge-rev/sysproxy/releases/download/${arch}/sysproxy.exe`,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const resolveSetDnsScript = () =>
|
||||||
|
resolveResource({
|
||||||
|
file: "set_dns.sh",
|
||||||
|
localPath: path.join(cwd, "scripts/set_dns.sh"),
|
||||||
|
});
|
||||||
|
const resolveUnSetDnsScript = () =>
|
||||||
|
resolveResource({
|
||||||
|
file: "unset_dns.sh",
|
||||||
|
localPath: path.join(cwd, "scripts/unset_dns.sh"),
|
||||||
|
});
|
||||||
|
|
||||||
|
// =======================
|
||||||
|
// Tasks
|
||||||
|
// =======================
|
||||||
const tasks = [
|
const tasks = [
|
||||||
// { name: "clash", func: resolveClash, retry: 5 },
|
|
||||||
{
|
{
|
||||||
name: "verge-mihomo-alpha",
|
name: "verge-mihomo-alpha",
|
||||||
func: () =>
|
func: () =>
|
||||||
@@ -724,11 +715,7 @@ const tasks = [
|
|||||||
retry: 5,
|
retry: 5,
|
||||||
macosOnly: true,
|
macosOnly: true,
|
||||||
},
|
},
|
||||||
{
|
{ name: "locales", func: resolveLocales, retry: 2 },
|
||||||
name: "locales",
|
|
||||||
func: resolveLocales,
|
|
||||||
retry: 2,
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
async function runTask() {
|
async function runTask() {
|
||||||
|
|||||||
Reference in New Issue
Block a user