Compare commits
2 Commits
renovate/c
...
perf-rende
1
.gitignore
vendored
1
.gitignore
vendored
@@ -11,4 +11,3 @@ scripts/_env.sh
|
||||
.idea
|
||||
.old
|
||||
.eslintcache
|
||||
target
|
||||
@@ -42,7 +42,6 @@
|
||||
- 优化首页当前节点对MATCH规则的支持
|
||||
- 允许在 `界面设置` 修改 `悬浮跳转导航延迟`
|
||||
- 添加热键绑定错误的提示信息
|
||||
- 在 macOS 10.15 及更高版本默认包含 Mihomo-go122,以解决 Intel 架构 Mac 无法运行内核的问题
|
||||
|
||||
### 🐞 修复问题
|
||||
|
||||
|
||||
@@ -94,10 +94,9 @@ export default defineConfig([
|
||||
"warn",
|
||||
{
|
||||
vars: "all",
|
||||
varsIgnorePattern: "^_",
|
||||
varsIgnorePattern: "^_+$",
|
||||
args: "after-used",
|
||||
argsIgnorePattern: "^_",
|
||||
caughtErrorsIgnorePattern: "^ignore",
|
||||
argsIgnorePattern: "^_+$",
|
||||
},
|
||||
],
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
"@tauri-apps/plugin-updater": "2.9.0",
|
||||
"@types/json-schema": "^7.0.15",
|
||||
"ahooks": "^3.9.6",
|
||||
"axios": "^1.13.1",
|
||||
"axios": "^1.13.0",
|
||||
"dayjs": "1.11.18",
|
||||
"foxact": "^0.2.49",
|
||||
"i18next": "^25.6.0",
|
||||
@@ -85,7 +85,7 @@
|
||||
"@tauri-apps/cli": "2.9.1",
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/node": "^24.9.2",
|
||||
"@types/node": "^24.9.1",
|
||||
"@types/react": "19.2.2",
|
||||
"@types/react-dom": "19.2.2",
|
||||
"@vitejs/plugin-legacy": "^7.2.1",
|
||||
|
||||
58
pnpm-lock.yaml
generated
58
pnpm-lock.yaml
generated
@@ -69,8 +69,8 @@ importers:
|
||||
specifier: ^3.9.6
|
||||
version: 3.9.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0)
|
||||
axios:
|
||||
specifier: ^1.13.1
|
||||
version: 1.13.1
|
||||
specifier: ^1.13.0
|
||||
version: 1.13.0
|
||||
dayjs:
|
||||
specifier: 1.11.18
|
||||
version: 1.11.18
|
||||
@@ -157,8 +157,8 @@ importers:
|
||||
specifier: ^4.17.12
|
||||
version: 4.17.12
|
||||
'@types/node':
|
||||
specifier: ^24.9.2
|
||||
version: 24.9.2
|
||||
specifier: ^24.9.1
|
||||
version: 24.9.1
|
||||
'@types/react':
|
||||
specifier: 19.2.2
|
||||
version: 19.2.2
|
||||
@@ -167,10 +167,10 @@ importers:
|
||||
version: 19.2.2(@types/react@19.2.2)
|
||||
'@vitejs/plugin-legacy':
|
||||
specifier: ^7.2.1
|
||||
version: 7.2.1(terser@5.44.0)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(sass@1.93.2)(terser@5.44.0)(yaml@2.8.1))
|
||||
version: 7.2.1(terser@5.44.0)(vite@7.1.12(@types/node@24.9.1)(jiti@2.6.1)(sass@1.93.2)(terser@5.44.0)(yaml@2.8.1))
|
||||
'@vitejs/plugin-react':
|
||||
specifier: 5.1.0
|
||||
version: 5.1.0(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(sass@1.93.2)(terser@5.44.0)(yaml@2.8.1))
|
||||
version: 5.1.0(vite@7.1.12(@types/node@24.9.1)(jiti@2.6.1)(sass@1.93.2)(terser@5.44.0)(yaml@2.8.1))
|
||||
adm-zip:
|
||||
specifier: ^0.5.16
|
||||
version: 0.5.16
|
||||
@@ -251,16 +251,16 @@ importers:
|
||||
version: 8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3)
|
||||
vite:
|
||||
specifier: ^7.1.12
|
||||
version: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(sass@1.93.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
version: 7.1.12(@types/node@24.9.1)(jiti@2.6.1)(sass@1.93.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
vite-plugin-monaco-editor:
|
||||
specifier: ^1.1.0
|
||||
version: 1.1.0(monaco-editor@0.54.0)
|
||||
vite-plugin-svgr:
|
||||
specifier: ^4.5.0
|
||||
version: 4.5.0(rollup@4.46.2)(typescript@5.9.3)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(sass@1.93.2)(terser@5.44.0)(yaml@2.8.1))
|
||||
version: 4.5.0(rollup@4.46.2)(typescript@5.9.3)(vite@7.1.12(@types/node@24.9.1)(jiti@2.6.1)(sass@1.93.2)(terser@5.44.0)(yaml@2.8.1))
|
||||
vitest:
|
||||
specifier: ^4.0.4
|
||||
version: 4.0.4(@types/debug@4.1.12)(@types/node@24.9.2)(jiti@2.6.1)(sass@1.93.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
version: 4.0.4(@types/debug@4.1.12)(@types/node@24.9.1)(jiti@2.6.1)(sass@1.93.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
|
||||
packages:
|
||||
|
||||
@@ -1773,8 +1773,8 @@ packages:
|
||||
'@types/ms@2.1.0':
|
||||
resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
|
||||
|
||||
'@types/node@24.9.2':
|
||||
resolution: {integrity: sha512-uWN8YqxXxqFMX2RqGOrumsKeti4LlmIMIyV0lgut4jx7KQBcBiW6vkDtIBvHnHIquwNfJhk8v2OtmO8zXWHfPA==}
|
||||
'@types/node@24.9.1':
|
||||
resolution: {integrity: sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==}
|
||||
|
||||
'@types/parse-json@4.0.2':
|
||||
resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==}
|
||||
@@ -2085,8 +2085,8 @@ packages:
|
||||
resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
axios@1.13.1:
|
||||
resolution: {integrity: sha512-hU4EGxxt+j7TQijx1oYdAjw4xuIp1wRQSsbMFwSthCWeBQur1eF+qJ5iQ5sN3Tw8YRzQNKb8jszgBdMDVqwJcw==}
|
||||
axios@1.13.0:
|
||||
resolution: {integrity: sha512-zt40Pz4zcRXra9CVV31KeyofwiNvAbJ5B6YPz9pMJ+yOSLikvPT4Yi5LjfgjRa9CawVYBaD1JQzIVcIvBejKeA==}
|
||||
|
||||
babel-plugin-macros@3.1.0:
|
||||
resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==}
|
||||
@@ -5935,7 +5935,7 @@ snapshots:
|
||||
|
||||
'@types/ms@2.1.0': {}
|
||||
|
||||
'@types/node@24.9.2':
|
||||
'@types/node@24.9.1':
|
||||
dependencies:
|
||||
undici-types: 7.16.0
|
||||
|
||||
@@ -6113,7 +6113,7 @@ snapshots:
|
||||
'@unrs/resolver-binding-win32-x64-msvc@1.11.1':
|
||||
optional: true
|
||||
|
||||
'@vitejs/plugin-legacy@7.2.1(terser@5.44.0)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(sass@1.93.2)(terser@5.44.0)(yaml@2.8.1))':
|
||||
'@vitejs/plugin-legacy@7.2.1(terser@5.44.0)(vite@7.1.12(@types/node@24.9.1)(jiti@2.6.1)(sass@1.93.2)(terser@5.44.0)(yaml@2.8.1))':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.4
|
||||
'@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.28.4)
|
||||
@@ -6128,11 +6128,11 @@ snapshots:
|
||||
regenerator-runtime: 0.14.1
|
||||
systemjs: 6.15.1
|
||||
terser: 5.44.0
|
||||
vite: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(sass@1.93.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
vite: 7.1.12(@types/node@24.9.1)(jiti@2.6.1)(sass@1.93.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@vitejs/plugin-react@5.1.0(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(sass@1.93.2)(terser@5.44.0)(yaml@2.8.1))':
|
||||
'@vitejs/plugin-react@5.1.0(vite@7.1.12(@types/node@24.9.1)(jiti@2.6.1)(sass@1.93.2)(terser@5.44.0)(yaml@2.8.1))':
|
||||
dependencies:
|
||||
'@babel/core': 7.28.4
|
||||
'@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.4)
|
||||
@@ -6140,7 +6140,7 @@ snapshots:
|
||||
'@rolldown/pluginutils': 1.0.0-beta.43
|
||||
'@types/babel__core': 7.20.5
|
||||
react-refresh: 0.18.0
|
||||
vite: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(sass@1.93.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
vite: 7.1.12(@types/node@24.9.1)(jiti@2.6.1)(sass@1.93.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -6153,13 +6153,13 @@ snapshots:
|
||||
chai: 6.2.0
|
||||
tinyrainbow: 3.0.3
|
||||
|
||||
'@vitest/mocker@4.0.4(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(sass@1.93.2)(terser@5.44.0)(yaml@2.8.1))':
|
||||
'@vitest/mocker@4.0.4(vite@7.1.12(@types/node@24.9.1)(jiti@2.6.1)(sass@1.93.2)(terser@5.44.0)(yaml@2.8.1))':
|
||||
dependencies:
|
||||
'@vitest/spy': 4.0.4
|
||||
estree-walker: 3.0.3
|
||||
magic-string: 0.30.19
|
||||
optionalDependencies:
|
||||
vite: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(sass@1.93.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
vite: 7.1.12(@types/node@24.9.1)(jiti@2.6.1)(sass@1.93.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
|
||||
'@vitest/pretty-format@4.0.4':
|
||||
dependencies:
|
||||
@@ -6297,7 +6297,7 @@ snapshots:
|
||||
possible-typed-array-names: 1.1.0
|
||||
optional: true
|
||||
|
||||
axios@1.13.1:
|
||||
axios@1.13.0:
|
||||
dependencies:
|
||||
follow-redirects: 1.15.9
|
||||
form-data: 4.0.4
|
||||
@@ -8803,18 +8803,18 @@ snapshots:
|
||||
dependencies:
|
||||
monaco-editor: 0.54.0
|
||||
|
||||
vite-plugin-svgr@4.5.0(rollup@4.46.2)(typescript@5.9.3)(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(sass@1.93.2)(terser@5.44.0)(yaml@2.8.1)):
|
||||
vite-plugin-svgr@4.5.0(rollup@4.46.2)(typescript@5.9.3)(vite@7.1.12(@types/node@24.9.1)(jiti@2.6.1)(sass@1.93.2)(terser@5.44.0)(yaml@2.8.1)):
|
||||
dependencies:
|
||||
'@rollup/pluginutils': 5.2.0(rollup@4.46.2)
|
||||
'@svgr/core': 8.1.0(typescript@5.9.3)
|
||||
'@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.9.3))
|
||||
vite: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(sass@1.93.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
vite: 7.1.12(@types/node@24.9.1)(jiti@2.6.1)(sass@1.93.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
transitivePeerDependencies:
|
||||
- rollup
|
||||
- supports-color
|
||||
- typescript
|
||||
|
||||
vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(sass@1.93.2)(terser@5.44.0)(yaml@2.8.1):
|
||||
vite@7.1.12(@types/node@24.9.1)(jiti@2.6.1)(sass@1.93.2)(terser@5.44.0)(yaml@2.8.1):
|
||||
dependencies:
|
||||
esbuild: 0.25.4
|
||||
fdir: 6.5.0(picomatch@4.0.3)
|
||||
@@ -8823,17 +8823,17 @@ snapshots:
|
||||
rollup: 4.46.2
|
||||
tinyglobby: 0.2.15
|
||||
optionalDependencies:
|
||||
'@types/node': 24.9.2
|
||||
'@types/node': 24.9.1
|
||||
fsevents: 2.3.3
|
||||
jiti: 2.6.1
|
||||
sass: 1.93.2
|
||||
terser: 5.44.0
|
||||
yaml: 2.8.1
|
||||
|
||||
vitest@4.0.4(@types/debug@4.1.12)(@types/node@24.9.2)(jiti@2.6.1)(sass@1.93.2)(terser@5.44.0)(yaml@2.8.1):
|
||||
vitest@4.0.4(@types/debug@4.1.12)(@types/node@24.9.1)(jiti@2.6.1)(sass@1.93.2)(terser@5.44.0)(yaml@2.8.1):
|
||||
dependencies:
|
||||
'@vitest/expect': 4.0.4
|
||||
'@vitest/mocker': 4.0.4(vite@7.1.12(@types/node@24.9.2)(jiti@2.6.1)(sass@1.93.2)(terser@5.44.0)(yaml@2.8.1))
|
||||
'@vitest/mocker': 4.0.4(vite@7.1.12(@types/node@24.9.1)(jiti@2.6.1)(sass@1.93.2)(terser@5.44.0)(yaml@2.8.1))
|
||||
'@vitest/pretty-format': 4.0.4
|
||||
'@vitest/runner': 4.0.4
|
||||
'@vitest/snapshot': 4.0.4
|
||||
@@ -8850,11 +8850,11 @@ snapshots:
|
||||
tinyexec: 0.3.2
|
||||
tinyglobby: 0.2.15
|
||||
tinyrainbow: 3.0.3
|
||||
vite: 7.1.12(@types/node@24.9.2)(jiti@2.6.1)(sass@1.93.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
vite: 7.1.12(@types/node@24.9.1)(jiti@2.6.1)(sass@1.93.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
why-is-node-running: 2.3.0
|
||||
optionalDependencies:
|
||||
'@types/debug': 4.1.12
|
||||
'@types/node': 24.9.2
|
||||
'@types/node': 24.9.1
|
||||
transitivePeerDependencies:
|
||||
- jiti
|
||||
- less
|
||||
|
||||
@@ -18,6 +18,7 @@ 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
|
||||
* 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();
|
||||
@@ -55,7 +56,8 @@ const ARCH_MAP = {
|
||||
|
||||
const arg1 = process.argv.slice(2)[0];
|
||||
const arg2 = process.argv.slice(2)[1];
|
||||
let target = arg1 === "--force" || arg1 === "-f" ? arg2 : arg1;
|
||||
let target;
|
||||
target = arg1 === "--force" || arg1 === "-f" ? arg2 : arg1;
|
||||
const { platform, arch } = target
|
||||
? { platform: PLATFORM_MAP[target], arch: ARCH_MAP[target] }
|
||||
: process;
|
||||
@@ -66,9 +68,7 @@ const SIDECAR_HOST = target
|
||||
.toString()
|
||||
.match(/(?<=host: ).+(?=\s*)/g)[0];
|
||||
|
||||
// =======================
|
||||
// Version Cache
|
||||
// =======================
|
||||
/* ======= Version Cache Functions ======= */
|
||||
async function loadVersionCache() {
|
||||
try {
|
||||
if (fs.existsSync(VERSION_CACHE_FILE)) {
|
||||
@@ -80,6 +80,7 @@ async function loadVersionCache() {
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
async function saveVersionCache(cache) {
|
||||
try {
|
||||
await fsp.mkdir(TEMP_DIR, { recursive: true });
|
||||
@@ -89,24 +90,28 @@ async function saveVersionCache(cache) {
|
||||
log_debug("Failed to save version cache:", err.message);
|
||||
}
|
||||
}
|
||||
|
||||
async function getCachedVersion(key) {
|
||||
const cache = await loadVersionCache();
|
||||
const cached = cache[key];
|
||||
if (cached && Date.now() - cached.timestamp < 3600000) {
|
||||
// 1小时内有效
|
||||
log_info(`Using cached version for ${key}: ${cached.version}`);
|
||||
return cached.version;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
async function setCachedVersion(key, version) {
|
||||
const cache = await loadVersionCache();
|
||||
cache[key] = { version, timestamp: Date.now() };
|
||||
cache[key] = {
|
||||
version,
|
||||
timestamp: Date.now(),
|
||||
};
|
||||
await saveVersionCache(cache);
|
||||
}
|
||||
|
||||
// =======================
|
||||
// Hash Cache & File Hash
|
||||
// =======================
|
||||
/* ======= File Hash Functions ======= */
|
||||
async function calculateFileHash(filePath) {
|
||||
try {
|
||||
const fileBuffer = await fsp.readFile(filePath);
|
||||
@@ -117,6 +122,7 @@ async function calculateFileHash(filePath) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function loadHashCache() {
|
||||
try {
|
||||
if (fs.existsSync(HASH_CACHE_FILE)) {
|
||||
@@ -128,6 +134,7 @@ async function loadHashCache() {
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
async function saveHashCache(cache) {
|
||||
try {
|
||||
await fsp.mkdir(TEMP_DIR, { recursive: true });
|
||||
@@ -137,20 +144,28 @@ async function saveHashCache(cache) {
|
||||
log_debug("Failed to save hash cache:", err.message);
|
||||
}
|
||||
}
|
||||
|
||||
async function hasFileChanged(filePath, targetPath) {
|
||||
if (FORCE) return true;
|
||||
if (!fs.existsSync(targetPath)) return true;
|
||||
|
||||
const hashCache = await loadHashCache();
|
||||
const sourceHash = await calculateFileHash(filePath);
|
||||
const targetHash = await calculateFileHash(targetPath);
|
||||
|
||||
if (!sourceHash || !targetHash) return true;
|
||||
|
||||
const cacheKey = targetPath;
|
||||
const cachedHash = hashCache[cacheKey];
|
||||
|
||||
if (cachedHash === sourceHash && sourceHash === targetHash) {
|
||||
// 文件未变化,不输出日志
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
async function updateHashCache(targetPath) {
|
||||
const hashCache = await loadHashCache();
|
||||
const hash = await calculateFileHash(targetPath);
|
||||
@@ -160,25 +175,18 @@ async function updateHashCache(targetPath) {
|
||||
}
|
||||
}
|
||||
|
||||
// =======================
|
||||
// Meta maps (stable & alpha)
|
||||
// =======================
|
||||
/* ======= clash meta alpha======= */
|
||||
const META_ALPHA_VERSION_URL =
|
||||
"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`;
|
||||
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 = {
|
||||
"win32-x64": "mihomo-windows-amd64-v2",
|
||||
"win32-ia32": "mihomo-windows-386",
|
||||
"win32-arm64": "mihomo-windows-arm64",
|
||||
"darwin-x64": "mihomo-darwin-amd64-v1-go122",
|
||||
"darwin-arm64": "mihomo-darwin-arm64-go122",
|
||||
"darwin-x64": "mihomo-darwin-amd64-v1",
|
||||
"darwin-arm64": "mihomo-darwin-arm64",
|
||||
"linux-x64": "mihomo-linux-amd64-v2",
|
||||
"linux-ia32": "mihomo-linux-386",
|
||||
"linux-arm64": "mihomo-linux-arm64",
|
||||
@@ -187,24 +195,9 @@ const META_ALPHA_MAP = {
|
||||
"linux-loong64": "mihomo-linux-loong64",
|
||||
};
|
||||
|
||||
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
|
||||
// =======================
|
||||
// Fetch the latest alpha release version from the version.txt file
|
||||
async function getLatestAlphaVersion() {
|
||||
// 如果不强制更新,先尝试从缓存获取
|
||||
if (!FORCE) {
|
||||
const cached = await getCachedVersion("META_ALPHA_VERSION");
|
||||
if (cached) {
|
||||
@@ -212,33 +205,58 @@ async function getLatestAlphaVersion() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (httpProxy) {
|
||||
options.agent = new HttpsProxyAgent(httpProxy);
|
||||
}
|
||||
try {
|
||||
const response = await fetch(META_ALPHA_VERSION_URL, {
|
||||
...options,
|
||||
method: "GET",
|
||||
});
|
||||
if (!response.ok)
|
||||
throw new Error(
|
||||
`Failed to fetch ${META_ALPHA_VERSION_URL}: ${response.status}`,
|
||||
);
|
||||
META_ALPHA_VERSION = (await response.text()).trim();
|
||||
let v = await response.text();
|
||||
META_ALPHA_VERSION = v.trim(); // Trim to remove extra whitespaces
|
||||
log_info(`Latest alpha version: ${META_ALPHA_VERSION}`);
|
||||
|
||||
// 保存到缓存
|
||||
await setCachedVersion("META_ALPHA_VERSION", META_ALPHA_VERSION);
|
||||
} catch (err) {
|
||||
log_error("Error fetching latest alpha version:", err.message);
|
||||
} catch (error) {
|
||||
log_error("Error fetching latest alpha version:", error.message);
|
||||
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() {
|
||||
// 如果不强制更新,先尝试从缓存获取
|
||||
if (!FORCE) {
|
||||
const cached = await getCachedVersion("META_VERSION");
|
||||
if (cached) {
|
||||
@@ -246,57 +264,67 @@ async function getLatestReleaseVersion() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (httpProxy) {
|
||||
options.agent = new HttpsProxyAgent(httpProxy);
|
||||
}
|
||||
try {
|
||||
const response = await fetch(META_VERSION_URL, {
|
||||
...options,
|
||||
method: "GET",
|
||||
});
|
||||
if (!response.ok)
|
||||
throw new Error(
|
||||
`Failed to fetch ${META_VERSION_URL}: ${response.status}`,
|
||||
);
|
||||
META_VERSION = (await response.text()).trim();
|
||||
let v = await response.text();
|
||||
META_VERSION = v.trim(); // Trim to remove extra whitespaces
|
||||
log_info(`Latest release version: ${META_VERSION}`);
|
||||
|
||||
// 保存到缓存
|
||||
await setCachedVersion("META_VERSION", META_VERSION);
|
||||
} catch (err) {
|
||||
log_error("Error fetching latest release version:", err.message);
|
||||
} catch (error) {
|
||||
log_error("Error fetching latest release version:", error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// =======================
|
||||
// Validate availability
|
||||
// =======================
|
||||
/*
|
||||
* check available
|
||||
*/
|
||||
if (!META_MAP[`${platform}-${arch}`]) {
|
||||
throw new Error(`clash meta unsupported platform "${platform}-${arch}"`);
|
||||
throw new Error(
|
||||
`clash meta alpha unsupported platform "${platform}-${arch}"`,
|
||||
);
|
||||
}
|
||||
|
||||
if (!META_ALPHA_MAP[`${platform}-${arch}`]) {
|
||||
throw new Error(
|
||||
`clash meta alpha unsupported platform "${platform}-${arch}"`,
|
||||
);
|
||||
}
|
||||
|
||||
// =======================
|
||||
// Build meta objects
|
||||
// =======================
|
||||
/**
|
||||
* core info
|
||||
*/
|
||||
function clashMetaAlpha() {
|
||||
const name = META_ALPHA_MAP[`${platform}-${arch}`];
|
||||
const isWin = platform === "win32";
|
||||
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 {
|
||||
name: "verge-mihomo-alpha",
|
||||
targetFile: `verge-mihomo-alpha-${SIDECAR_HOST}${isWin ? ".exe" : ""}`,
|
||||
exeFile: `${name}${isWin ? ".exe" : ""}`,
|
||||
zipFile: `${name}-${META_ALPHA_VERSION}.${urlExt}`,
|
||||
downloadURL: `${META_ALPHA_URL_PREFIX}/${name}-${META_ALPHA_VERSION}.${urlExt}`,
|
||||
exeFile,
|
||||
zipFile,
|
||||
downloadURL,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -304,83 +332,40 @@ function clashMeta() {
|
||||
const name = META_MAP[`${platform}-${arch}`];
|
||||
const isWin = platform === "win32";
|
||||
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 {
|
||||
name: "verge-mihomo",
|
||||
targetFile: `verge-mihomo-${SIDECAR_HOST}${isWin ? ".exe" : ""}`,
|
||||
exeFile: `${name}${isWin ? ".exe" : ""}`,
|
||||
zipFile: `${name}-${META_VERSION}.${urlExt}`,
|
||||
downloadURL: `${META_URL_PREFIX}/${META_VERSION}/${name}-${META_VERSION}.${urlExt}`,
|
||||
exeFile,
|
||||
zipFile,
|
||||
downloadURL,
|
||||
};
|
||||
}
|
||||
|
||||
// =======================
|
||||
// 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)
|
||||
// =======================
|
||||
/**
|
||||
* download sidecar and rename
|
||||
*/
|
||||
async function resolveSidecar(binInfo) {
|
||||
const { name, targetFile, zipFile, exeFile, downloadURL } = binInfo;
|
||||
|
||||
const sidecarDir = path.join(cwd, "src-tauri", "sidecar");
|
||||
const sidecarPath = path.join(sidecarDir, targetFile);
|
||||
|
||||
await fsp.mkdir(sidecarDir, { recursive: true });
|
||||
|
||||
// 检查文件是否已存在,如果存在则跳过重复下载
|
||||
if (!FORCE && fs.existsSync(sidecarPath)) {
|
||||
log_success(`"${name}" already exists, skipping download`);
|
||||
log_success(`"${name}" already exists, skipping download to save time`);
|
||||
return;
|
||||
}
|
||||
|
||||
const tempDir = path.join(TEMP_DIR, name);
|
||||
const tempZip = path.join(tempDir, zipFile);
|
||||
const tempExe = path.join(tempDir, exeFile);
|
||||
await fsp.mkdir(tempDir, { recursive: true });
|
||||
|
||||
await fsp.mkdir(tempDir, { recursive: true });
|
||||
try {
|
||||
if (!fs.existsSync(tempZip)) {
|
||||
await downloadFile(downloadURL, tempZip);
|
||||
@@ -389,76 +374,78 @@ async function resolveSidecar(binInfo) {
|
||||
if (zipFile.endsWith(".zip")) {
|
||||
const zip = new AdmZip(tempZip);
|
||||
zip.getEntries().forEach((entry) => {
|
||||
log_debug(`"${name}" entry: ${entry.entryName}`);
|
||||
log_debug(`"${name}" entry name`, entry.entryName);
|
||||
});
|
||||
zip.extractAllTo(tempDir, true);
|
||||
// 尝试按 exeFile 重命名,否则找第一个可执行文件
|
||||
if (fs.existsSync(tempExe)) {
|
||||
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}`);
|
||||
await fsp.rename(tempExe, sidecarPath);
|
||||
log_success(`unzip finished: "${name}"`);
|
||||
} else if (zipFile.endsWith(".tgz")) {
|
||||
await extract({ cwd: tempDir, file: tempZip });
|
||||
// tgz
|
||||
await fsp.mkdir(tempDir, { recursive: true });
|
||||
await extract({
|
||||
cwd: tempDir,
|
||||
file: tempZip,
|
||||
//strip: 1, // 可能需要根据实际的 .tgz 文件结构调整
|
||||
});
|
||||
const files = await fsp.readdir(tempDir);
|
||||
log_debug(`"${name}" extracted files:`, files);
|
||||
// 优先寻找给定 exeFile 或已知前缀
|
||||
let extracted = files.find(
|
||||
(f) =>
|
||||
f === path.basename(exeFile) ||
|
||||
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}`);
|
||||
log_success(`tgz processed: "${name}"`);
|
||||
log_debug(`"${name}" files in tempDir:`, files);
|
||||
const extractedFile = files.find((file) => file.startsWith("虚空终端-"));
|
||||
if (extractedFile) {
|
||||
const extractedFilePath = path.join(tempDir, extractedFile);
|
||||
await fsp.rename(extractedFilePath, sidecarPath);
|
||||
log_success(`"${name}" file renamed to "${sidecarPath}"`);
|
||||
execSync(`chmod 755 ${sidecarPath}`);
|
||||
log_success(`chmod binary finished: "${name}"`);
|
||||
} else {
|
||||
throw new Error(`Expected file not found in ${tempDir}`);
|
||||
}
|
||||
} else {
|
||||
// .gz
|
||||
// gz
|
||||
const readStream = fs.createReadStream(tempZip);
|
||||
const writeStream = fs.createWriteStream(sidecarPath);
|
||||
await new Promise((resolve, reject) => {
|
||||
const onError = (error) => {
|
||||
log_error(`"${name}" gz failed:`, error.message);
|
||||
reject(error);
|
||||
};
|
||||
readStream
|
||||
.pipe(zlib.createGunzip())
|
||||
.on("error", (e) => {
|
||||
log_error(`gunzip error for ${name}:`, e.message);
|
||||
reject(e);
|
||||
})
|
||||
.pipe(zlib.createGunzip().on("error", onError))
|
||||
.pipe(writeStream)
|
||||
.on("finish", () => {
|
||||
if (platform !== "win32") execSync(`chmod 755 ${sidecarPath}`);
|
||||
execSync(`chmod 755 ${sidecarPath}`);
|
||||
log_success(`chmod binary finished: "${name}"`);
|
||||
resolve();
|
||||
})
|
||||
.on("error", (e) => {
|
||||
log_error(`write stream error for ${name}:`, e.message);
|
||||
reject(e);
|
||||
});
|
||||
.on("error", onError);
|
||||
});
|
||||
log_success(`gz binary processed: "${name}"`);
|
||||
}
|
||||
} catch (err) {
|
||||
// 需要删除文件
|
||||
await fsp.rm(sidecarPath, { recursive: true, force: true });
|
||||
throw err;
|
||||
} finally {
|
||||
// delete temp dir
|
||||
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) {
|
||||
const { file, downloadURL, localPath } = binInfo;
|
||||
|
||||
const resDir = path.join(cwd, "src-tauri/resources");
|
||||
const targetPath = path.join(resDir, file);
|
||||
|
||||
@@ -478,9 +465,12 @@ async function resolveResource(binInfo) {
|
||||
}
|
||||
|
||||
if (localPath) {
|
||||
// 检查文件哈希是否变化
|
||||
if (!(await hasFileChanged(localPath, targetPath))) {
|
||||
// 文件未变化,静默跳过
|
||||
return;
|
||||
}
|
||||
|
||||
await fsp.mkdir(resDir, { recursive: true });
|
||||
await fsp.copyFile(localPath, targetPath);
|
||||
await updateHashCache(targetPath);
|
||||
@@ -490,17 +480,44 @@ async function resolveResource(binInfo) {
|
||||
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 url =
|
||||
"https://nsis.sourceforge.io/mediawiki/images/e/ef/NSIS_Simple_Service_Plugin_Unicode_1.30.zip";
|
||||
|
||||
const tempDir = path.join(TEMP_DIR, "SimpleSC");
|
||||
const tempZip = path.join(
|
||||
tempDir,
|
||||
"NSIS_Simple_Service_Plugin_Unicode_1.30.zip",
|
||||
);
|
||||
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");
|
||||
await fsp.mkdir(pluginDir, { recursive: true });
|
||||
await fsp.mkdir(tempDir, { recursive: true });
|
||||
@@ -510,33 +527,18 @@ const resolvePlugin = async () => {
|
||||
await downloadFile(url, tempZip);
|
||||
}
|
||||
const zip = new AdmZip(tempZip);
|
||||
zip
|
||||
.getEntries()
|
||||
.forEach((entry) => log_debug(`"SimpleSC" entry`, entry.entryName));
|
||||
zip.getEntries().forEach((entry) => {
|
||||
log_debug(`"SimpleSC" entry name`, entry.entryName);
|
||||
});
|
||||
zip.extractAllTo(tempDir, true);
|
||||
if (fs.existsSync(tempDll)) {
|
||||
await fsp.cp(tempDll, pluginPath, { recursive: true, force: true });
|
||||
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");
|
||||
}
|
||||
}
|
||||
await fsp.cp(tempDll, pluginPath, { recursive: true, force: true });
|
||||
log_success(`unzip finished: "SimpleSC"`);
|
||||
} finally {
|
||||
await fsp.rm(tempDir, { recursive: true, force: true });
|
||||
}
|
||||
};
|
||||
|
||||
// service chmod (保留并使用 glob)
|
||||
// service chmod
|
||||
const resolveServicePermission = async () => {
|
||||
const serviceExecutables = [
|
||||
"clash-verge-service*",
|
||||
@@ -548,20 +550,23 @@ const resolveServicePermission = async () => {
|
||||
let hasChanges = false;
|
||||
|
||||
for (let f of serviceExecutables) {
|
||||
// 使用glob模块来处理通配符
|
||||
const files = glob.sync(path.join(resDir, f));
|
||||
for (let filePath of files) {
|
||||
if (fs.existsSync(filePath)) {
|
||||
const currentHash = await calculateFileHash(filePath);
|
||||
const cacheKey = `${filePath}_chmod`;
|
||||
|
||||
// 检查文件哈希是否变化
|
||||
if (!FORCE && hashCache[cacheKey] === currentHash) {
|
||||
// 权限未变化,静默跳过
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
execSync(`chmod 755 ${filePath}`);
|
||||
log_success(`chmod finished: "${filePath}"`);
|
||||
} catch (e) {
|
||||
log_error(`chmod failed for ${filePath}:`, e.message);
|
||||
}
|
||||
|
||||
execSync(`chmod 755 ${filePath}`);
|
||||
log_success(`chmod finished: "${filePath}"`);
|
||||
|
||||
// 更新哈希缓存
|
||||
hashCache[cacheKey] = currentHash;
|
||||
hasChanges = true;
|
||||
}
|
||||
@@ -573,22 +578,34 @@ const resolveServicePermission = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
// resolve locales (从 src/locales 复制到 resources/locales,并使用 hash 检查)
|
||||
// 在 resolveResource 函数后添加新函数
|
||||
async function resolveLocales() {
|
||||
const srcLocalesDir = path.join(cwd, "src/locales");
|
||||
const targetLocalesDir = path.join(cwd, "src-tauri/resources/locales");
|
||||
|
||||
try {
|
||||
// 确保目标目录存在
|
||||
await fsp.mkdir(targetLocalesDir, { recursive: true });
|
||||
|
||||
// 读取所有语言文件
|
||||
const files = await fsp.readdir(srcLocalesDir);
|
||||
|
||||
// 复制每个文件,只有当哈希变化时才复制
|
||||
for (const file of files) {
|
||||
const srcPath = path.join(srcLocalesDir, 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 updateHashCache(targetPath);
|
||||
log_success(`Copied locale file: ${file}`);
|
||||
}
|
||||
|
||||
log_success("All locale files processed successfully");
|
||||
} catch (err) {
|
||||
log_error("Error copying locale files:", err.message);
|
||||
@@ -596,30 +613,34 @@ async function resolveLocales() {
|
||||
}
|
||||
}
|
||||
|
||||
// =======================
|
||||
// Other resource resolvers (service, mmdb, geosite, geoip, enableLoopback, sysproxy)
|
||||
// =======================
|
||||
/**
|
||||
* main
|
||||
*/
|
||||
const SERVICE_URL = `https://github.com/clash-verge-rev/clash-verge-service-ipc/releases/download/${SIDECAR_HOST}`;
|
||||
|
||||
const resolveService = () => {
|
||||
let ext = platform === "win32" ? ".exe" : "";
|
||||
let suffix = platform === "linux" ? "-" + SIDECAR_HOST : "";
|
||||
return resolveResource({
|
||||
resolveResource({
|
||||
file: "clash-verge-service" + suffix + ext,
|
||||
downloadURL: `${SERVICE_URL}/clash-verge-service${ext}`,
|
||||
});
|
||||
};
|
||||
|
||||
const resolveInstall = () => {
|
||||
let ext = platform === "win32" ? ".exe" : "";
|
||||
let suffix = platform === "linux" ? "-" + SIDECAR_HOST : "";
|
||||
return resolveResource({
|
||||
resolveResource({
|
||||
file: "clash-verge-service-install" + suffix + ext,
|
||||
downloadURL: `${SERVICE_URL}/clash-verge-service-install${ext}`,
|
||||
});
|
||||
};
|
||||
|
||||
const resolveUninstall = () => {
|
||||
let ext = platform === "win32" ? ".exe" : "";
|
||||
let suffix = platform === "linux" ? "-" + SIDECAR_HOST : "";
|
||||
return resolveResource({
|
||||
|
||||
resolveResource({
|
||||
file: "clash-verge-service-uninstall" + suffix + ext,
|
||||
downloadURL: `${SERVICE_URL}/clash-verge-service-uninstall${ext}`,
|
||||
});
|
||||
@@ -645,27 +666,15 @@ const resolveEnableLoopback = () =>
|
||||
file: "enableLoopback.exe",
|
||||
downloadURL: `https://github.com/Kuingsmile/uwp-tool/releases/download/latest/enableLoopback.exe`,
|
||||
});
|
||||
|
||||
const resolveWinSysproxy = () =>
|
||||
resolveResource({
|
||||
file: "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 = [
|
||||
// { name: "clash", func: resolveClash, retry: 5 },
|
||||
{
|
||||
name: "verge-mihomo-alpha",
|
||||
func: () =>
|
||||
@@ -715,7 +724,11 @@ const tasks = [
|
||||
retry: 5,
|
||||
macosOnly: true,
|
||||
},
|
||||
{ name: "locales", func: resolveLocales, retry: 2 },
|
||||
{
|
||||
name: "locales",
|
||||
func: resolveLocales,
|
||||
retry: 2,
|
||||
},
|
||||
];
|
||||
|
||||
async function runTask() {
|
||||
|
||||
159
src-tauri/Cargo.lock
generated
159
src-tauri/Cargo.lock
generated
@@ -147,17 +147,11 @@ dependencies = [
|
||||
"objc2-foundation 0.3.2",
|
||||
"parking_lot 0.12.5",
|
||||
"percent-encoding",
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.59.0",
|
||||
"wl-clipboard-rs",
|
||||
"x11rb",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arraydeque"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.6"
|
||||
@@ -1170,21 +1164,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clash_verge_logger"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/clash-verge-rev/clash-verge-logger#9bb189b5b5c4c2eee35168ff4997e8fb10901c81"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/clash-verge-rev/clash-verge-logger#256dc7441f3d0a0c1faa89e345379b32308bc815"
|
||||
dependencies = [
|
||||
"arraydeque",
|
||||
"compact_str",
|
||||
"flexi_logger",
|
||||
"log",
|
||||
"nu-ansi-term",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clash_verge_service_ipc"
|
||||
version = "2.0.20"
|
||||
source = "git+https://github.com/clash-verge-rev/clash-verge-service-ipc#c0b6e99da27e7956047d42aee104f5c33083c970"
|
||||
version = "2.0.18"
|
||||
source = "git+https://github.com/clash-verge-rev/clash-verge-service-ipc#381fee14ce5c69274c547b6b18819452d97fb2b2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"compact_str",
|
||||
@@ -1265,11 +1256,9 @@ dependencies = [
|
||||
"castaway 0.2.4",
|
||||
"cfg-if",
|
||||
"itoa",
|
||||
"rkyv",
|
||||
"rustversion",
|
||||
"ryu",
|
||||
"serde",
|
||||
"smallvec",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
@@ -1935,7 +1924,7 @@ dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users 0.5.2",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2191,7 +2180,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3356,7 +3345,7 @@ dependencies = [
|
||||
"libc",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"socket2 0.6.1",
|
||||
"socket2 0.5.10",
|
||||
"system-configuration",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
@@ -3376,7 +3365,7 @@ dependencies = [
|
||||
"js-sys",
|
||||
"log",
|
||||
"wasm-bindgen",
|
||||
"windows-core 0.61.2",
|
||||
"windows-core 0.62.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4255,26 +4244,6 @@ dependencies = [
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "munge"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e17401f259eba956ca16491461b6e8f72913a0a114e39736ce404410f915a0c"
|
||||
dependencies = [
|
||||
"munge_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "munge_macro"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4568f25ccbd45ab5d5603dc34318c1ec56b117531781260002151b8530a9f931"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.108",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nanoid"
|
||||
version = "0.4.0"
|
||||
@@ -4456,7 +4425,7 @@ version = "0.50.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4950,7 +4919,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5675,26 +5644,6 @@ version = "2.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac"
|
||||
|
||||
[[package]]
|
||||
name = "ptr_meta"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b9a0cf95a1196af61d4f1cbdab967179516d9a4a4312af1f31948f8f6224a79"
|
||||
dependencies = [
|
||||
"ptr_meta_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ptr_meta_derive"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7347867d0a7e1208d93b46767be83e2b8f978c3dad35f775ac8d8847551d6fe1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.108",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "publicsuffix"
|
||||
version = "2.3.0"
|
||||
@@ -5751,7 +5700,7 @@ dependencies = [
|
||||
"quinn-udp",
|
||||
"rustc-hash",
|
||||
"rustls",
|
||||
"socket2 0.6.1",
|
||||
"socket2 0.5.10",
|
||||
"thiserror 2.0.17",
|
||||
"tokio",
|
||||
"tracing",
|
||||
@@ -5788,9 +5737,9 @@ dependencies = [
|
||||
"cfg_aliases",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"socket2 0.6.1",
|
||||
"socket2 0.5.10",
|
||||
"tracing",
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5808,15 +5757,6 @@ version = "5.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||
|
||||
[[package]]
|
||||
name = "rancor"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a063ea72381527c2a0561da9c80000ef822bdd7c3241b1cc1b12100e3df081ee"
|
||||
dependencies = [
|
||||
"ptr_meta",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.7.3"
|
||||
@@ -6058,12 +5998,6 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rend"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cadadef317c2f20755a64d7fdc48f9e7178ee6b0e1f7fce33fa60f1d68a276e6"
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.12.24"
|
||||
@@ -6183,30 +6117,6 @@ dependencies = [
|
||||
"portable-atomic-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rkyv"
|
||||
version = "0.8.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "35a640b26f007713818e9a9b65d34da1cf58538207b052916a83d80e43f3ffa4"
|
||||
dependencies = [
|
||||
"munge",
|
||||
"ptr_meta",
|
||||
"rancor",
|
||||
"rend",
|
||||
"rkyv_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rkyv_derive"
|
||||
version = "0.8.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd83f5f173ff41e00337d97f6572e416d022ef8a19f371817259ae960324c482"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.108",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rs-snowflake"
|
||||
version = "0.6.0"
|
||||
@@ -6296,7 +6206,7 @@ dependencies = [
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.11.0",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -7266,9 +7176,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
|
||||
|
||||
[[package]]
|
||||
name = "tauri"
|
||||
version = "2.9.2"
|
||||
version = "2.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8bceb52453e507c505b330afe3398510e87f428ea42b6e76ecb6bd63b15965b5"
|
||||
checksum = "c9871670c6711f50fddd4e20350be6b9dd6e6c2b5d77d8ee8900eb0d58cd837a"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@@ -7799,7 +7709,7 @@ dependencies = [
|
||||
"getrandom 0.3.4",
|
||||
"once_cell",
|
||||
"rustix 1.1.2",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -9165,7 +9075,7 @@ version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -9247,6 +9157,19 @@ dependencies = [
|
||||
"windows-strings 0.4.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.62.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
|
||||
dependencies = [
|
||||
"windows-implement 0.60.2",
|
||||
"windows-interface 0.59.3",
|
||||
"windows-link 0.2.1",
|
||||
"windows-result 0.4.1",
|
||||
"windows-strings 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-future"
|
||||
version = "0.2.1"
|
||||
@@ -9353,6 +9276,15 @@ dependencies = [
|
||||
"windows-link 0.1.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
|
||||
dependencies = [
|
||||
"windows-link 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.1.0"
|
||||
@@ -9372,6 +9304,15 @@ dependencies = [
|
||||
"windows-link 0.1.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
|
||||
dependencies = [
|
||||
"windows-link 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.45.0"
|
||||
|
||||
@@ -43,7 +43,7 @@ serde = { version = "1.0.228", features = ["derive"] }
|
||||
reqwest = { version = "0.12.24", features = ["json", "cookies"] }
|
||||
regex = "1.12.2"
|
||||
sysproxy = { git = "https://github.com/clash-verge-rev/sysproxy-rs" }
|
||||
tauri = { version = "2.9.2", features = [
|
||||
tauri = { version = "2.9.1", features = [
|
||||
"protocol-asset",
|
||||
"devtools",
|
||||
"tray-icon",
|
||||
@@ -88,7 +88,7 @@ tauri-plugin-mihomo = { git = "https://github.com/clash-verge-rev/tauri-plugin-m
|
||||
clash_verge_logger = { git = "https://github.com/clash-verge-rev/clash-verge-logger" }
|
||||
async-trait = "0.1.89"
|
||||
smartstring = { version = "1.0.1", features = ["serde"] }
|
||||
clash_verge_service_ipc = { version = "2.0.20", features = [
|
||||
clash_verge_service_ipc = { version = "2.0.18", features = [
|
||||
"client",
|
||||
], git = "https://github.com/clash-verge-rev/clash-verge-service-ipc" }
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use super::CmdResult;
|
||||
use crate::{
|
||||
cmd::StringifyErr,
|
||||
@@ -273,7 +275,7 @@ pub async fn validate_dns_config() -> CmdResult<(bool, String)> {
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_clash_logs() -> CmdResult<Vec<CompactString>> {
|
||||
pub async fn get_clash_logs() -> CmdResult<VecDeque<CompactString>> {
|
||||
let logs = CoreManager::global()
|
||||
.get_clash_logs()
|
||||
.await
|
||||
|
||||
@@ -1,6 +1,38 @@
|
||||
use std::sync::Arc;
|
||||
use std::{collections::VecDeque, sync::Arc};
|
||||
|
||||
use clash_verge_logger::AsyncLogger;
|
||||
use once_cell::sync::Lazy;
|
||||
use compact_str::CompactString;
|
||||
use once_cell::sync::OnceCell;
|
||||
use parking_lot::{RwLock, RwLockReadGuard};
|
||||
|
||||
pub static CLASH_LOGGER: Lazy<Arc<AsyncLogger>> = Lazy::new(|| Arc::new(AsyncLogger::new()));
|
||||
const LOGS_QUEUE_LEN: usize = 100;
|
||||
|
||||
pub struct ClashLogger {
|
||||
logs: Arc<RwLock<VecDeque<CompactString>>>,
|
||||
}
|
||||
|
||||
impl ClashLogger {
|
||||
pub fn global() -> &'static ClashLogger {
|
||||
static LOGGER: OnceCell<ClashLogger> = OnceCell::new();
|
||||
|
||||
LOGGER.get_or_init(|| ClashLogger {
|
||||
logs: Arc::new(RwLock::new(VecDeque::with_capacity(LOGS_QUEUE_LEN + 10))),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_logs(&self) -> RwLockReadGuard<'_, VecDeque<CompactString>> {
|
||||
self.logs.read()
|
||||
}
|
||||
|
||||
pub fn append_log(&self, text: CompactString) {
|
||||
let mut logs = self.logs.write();
|
||||
if logs.len() > LOGS_QUEUE_LEN {
|
||||
logs.pop_front();
|
||||
}
|
||||
logs.push_back(text);
|
||||
}
|
||||
|
||||
pub fn clear_logs(&self) {
|
||||
let mut logs = self.logs.write();
|
||||
logs.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::{CoreManager, RunningMode};
|
||||
use crate::{
|
||||
core::{
|
||||
logger::CLASH_LOGGER,
|
||||
logger::ClashLogger,
|
||||
service::{SERVICE_MANAGER, ServiceStatus},
|
||||
},
|
||||
logging,
|
||||
@@ -21,7 +21,7 @@ impl CoreManager {
|
||||
}
|
||||
|
||||
pub async fn stop_core(&self) -> Result<()> {
|
||||
CLASH_LOGGER.clear_logs().await;
|
||||
ClashLogger::global().clear_logs();
|
||||
|
||||
match *self.get_running_mode() {
|
||||
RunningMode::Service => self.stop_core_by_service().await,
|
||||
|
||||
@@ -2,7 +2,7 @@ use super::{CoreManager, RunningMode};
|
||||
use crate::{
|
||||
AsyncHandler,
|
||||
config::Config,
|
||||
core::{handle, logger::CLASH_LOGGER, service},
|
||||
core::{handle, logger::ClashLogger, service},
|
||||
logging,
|
||||
process::CommandChildGuard,
|
||||
utils::{
|
||||
@@ -16,14 +16,15 @@ use compact_str::CompactString;
|
||||
use flexi_logger::DeferredNow;
|
||||
use log::Level;
|
||||
use scopeguard::defer;
|
||||
use std::collections::VecDeque;
|
||||
use tauri_plugin_shell::ShellExt;
|
||||
|
||||
impl CoreManager {
|
||||
pub async fn get_clash_logs(&self) -> Result<Vec<CompactString>> {
|
||||
pub async fn get_clash_logs(&self) -> Result<VecDeque<CompactString>> {
|
||||
match *self.get_running_mode() {
|
||||
RunningMode::Service => service::get_clash_logs_by_service().await,
|
||||
RunningMode::Sidecar => Ok(CLASH_LOGGER.get_logs().await),
|
||||
RunningMode::NotRunning => Ok(Vec::new()),
|
||||
RunningMode::Sidecar => Ok(ClashLogger::global().get_logs().clone()),
|
||||
RunningMode::NotRunning => Ok(VecDeque::new()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +65,7 @@ impl CoreManager {
|
||||
let message = CompactString::from(String::from_utf8_lossy(&line).as_ref());
|
||||
let w = shared_writer.lock().await;
|
||||
write_sidecar_log(w, &mut now, Level::Error, &message);
|
||||
CLASH_LOGGER.append_log(message).await;
|
||||
ClashLogger::global().append_log(message);
|
||||
}
|
||||
tauri_plugin_shell::process::CommandEvent::Terminated(term) => {
|
||||
let mut now = DeferredNow::default();
|
||||
@@ -77,7 +78,7 @@ impl CoreManager {
|
||||
};
|
||||
let w = shared_writer.lock().await;
|
||||
write_sidecar_log(w, &mut now, Level::Info, &message);
|
||||
CLASH_LOGGER.clear_logs().await;
|
||||
ClashLogger::global().clear_logs();
|
||||
break;
|
||||
}
|
||||
_ => {}
|
||||
|
||||
@@ -96,17 +96,10 @@ impl NotificationSystem {
|
||||
let handle = Handle::global();
|
||||
|
||||
while !handle.is_exiting() {
|
||||
match rx.recv() {
|
||||
match rx.recv_timeout(std::time::Duration::from_millis(100)) {
|
||||
Ok(event) => Self::process_event(handle, event),
|
||||
Err(e) => {
|
||||
logging!(
|
||||
error,
|
||||
Type::System,
|
||||
"receive event error, stop notification worker: {}",
|
||||
e
|
||||
);
|
||||
break;
|
||||
}
|
||||
Err(mpsc::RecvTimeoutError::Disconnected) => break,
|
||||
Err(mpsc::RecvTimeoutError::Timeout) => break,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ use clash_verge_service_ipc::CoreConfig;
|
||||
use compact_str::CompactString;
|
||||
use once_cell::sync::Lazy;
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
env::current_exe,
|
||||
path::{Path, PathBuf},
|
||||
process::Command as StdCommand,
|
||||
@@ -393,7 +394,7 @@ pub(super) async fn run_core_by_service(config_file: &PathBuf) -> Result<()> {
|
||||
start_with_existing_service(config_file).await
|
||||
}
|
||||
|
||||
pub(super) async fn get_clash_logs_by_service() -> Result<Vec<CompactString>> {
|
||||
pub(super) async fn get_clash_logs_by_service() -> Result<VecDeque<CompactString>> {
|
||||
logging!(info, Type::Service, "正在获取服务模式下的 Clash 日志");
|
||||
|
||||
let response = clash_verge_service_ipc::get_clash_logs()
|
||||
|
||||
21
src/main.tsx
21
src/main.tsx
@@ -4,7 +4,6 @@ import "./assets/styles/index.scss";
|
||||
|
||||
import { ResizeObserver } from "@juggle/resize-observer";
|
||||
import { ComposeContextProvider } from "foxact/compose-context-provider";
|
||||
import React from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import { RouterProvider } from "react-router";
|
||||
import { MihomoWebSocket } from "tauri-plugin-mihomo-api";
|
||||
@@ -56,17 +55,15 @@ const initializeApp = () => {
|
||||
|
||||
const root = createRoot(container);
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<ComposeContextProvider contexts={contexts}>
|
||||
<BaseErrorBoundary>
|
||||
<WindowProvider>
|
||||
<AppDataProvider>
|
||||
<RouterProvider router={router} />
|
||||
</AppDataProvider>
|
||||
</WindowProvider>
|
||||
</BaseErrorBoundary>
|
||||
</ComposeContextProvider>
|
||||
</React.StrictMode>,
|
||||
<ComposeContextProvider contexts={contexts}>
|
||||
<BaseErrorBoundary>
|
||||
<WindowProvider>
|
||||
<AppDataProvider>
|
||||
<RouterProvider router={router} />
|
||||
</AppDataProvider>
|
||||
</WindowProvider>
|
||||
</BaseErrorBoundary>
|
||||
</ComposeContextProvider>,
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import {
|
||||
} from "@mui/material";
|
||||
import dayjs from "dayjs";
|
||||
import relativeTime from "dayjs/plugin/relativeTime";
|
||||
import type { CSSProperties } from "react";
|
||||
import {
|
||||
useCallback,
|
||||
useEffect,
|
||||
@@ -33,7 +34,6 @@ import {
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import type { CSSProperties } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Outlet, useNavigate } from "react-router";
|
||||
import { SWRConfig } from "swr";
|
||||
|
||||
Reference in New Issue
Block a user