mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2024-11-16 11:42:21 +08:00
feat: clash meta core support (wip)
This commit is contained in:
parent
c382ad1cc8
commit
b3a72d55ae
|
@ -10,6 +10,7 @@ const cwd = process.cwd();
|
||||||
const TEMP_DIR = path.join(cwd, "node_modules/.verge");
|
const TEMP_DIR = path.join(cwd, "node_modules/.verge");
|
||||||
|
|
||||||
const FORCE = process.argv.includes("--force");
|
const FORCE = process.argv.includes("--force");
|
||||||
|
const META = process.argv.includes("--meta"); // use Clash.Meta
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get the correct clash release infomation
|
* get the correct clash release infomation
|
||||||
|
@ -44,14 +45,51 @@ function resolveClash() {
|
||||||
return { url, zip, exefile, zipfile };
|
return { url, zip, exefile, zipfile };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the correct Clash.Meta release infomation
|
||||||
|
*/
|
||||||
|
async function resolveClashMeta() {
|
||||||
|
const { platform, arch } = process;
|
||||||
|
|
||||||
|
const urlPrefix = `https://github.com/MetaCubeX/Clash.Meta/releases/download/`;
|
||||||
|
const latestVersion = "v1.11.0";
|
||||||
|
|
||||||
|
const map = {
|
||||||
|
"win32-x64": "Clash.Meta-windows-amd64v3",
|
||||||
|
"darwin-x64": "Clash.Meta-darwin-amd64v3",
|
||||||
|
"darwin-arm64": "Clash.Meta-darwin-arm64",
|
||||||
|
"linux-x64": "Clash.Meta-linux-amd64v3",
|
||||||
|
};
|
||||||
|
|
||||||
|
const name = map[`${platform}-${arch}`];
|
||||||
|
|
||||||
|
if (!name) {
|
||||||
|
throw new Error(`unsupport platform "${platform}-${arch}"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const isWin = platform === "win32";
|
||||||
|
const ext = isWin ? "zip" : "gz";
|
||||||
|
const url = `${urlPrefix}${latestVersion}/${name}-${latestVersion}.${ext}`;
|
||||||
|
const exefile = `${name}${isWin ? ".exe" : ""}`;
|
||||||
|
const zipfile = `${name}-${latestVersion}.${ext}`;
|
||||||
|
|
||||||
|
return { url, zip: ext, exefile, zipfile };
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get the sidecar bin
|
* get the sidecar bin
|
||||||
|
* clash and Clash Meta
|
||||||
*/
|
*/
|
||||||
async function resolveSidecar() {
|
async function resolveSidecar() {
|
||||||
const sidecarDir = path.join(cwd, "src-tauri", "sidecar");
|
const sidecarDir = path.join(cwd, "src-tauri", "sidecar");
|
||||||
|
|
||||||
const host = execSync("rustc -vV | grep host").toString().slice(6).trim();
|
const host = execSync("rustc -vV | grep host").toString().slice(6).trim();
|
||||||
const ext = process.platform === "win32" ? ".exe" : "";
|
const ext = process.platform === "win32" ? ".exe" : "";
|
||||||
|
|
||||||
|
await clash();
|
||||||
|
if (META) await clashMeta();
|
||||||
|
|
||||||
|
async function clash() {
|
||||||
const sidecarFile = `clash-${host}${ext}`;
|
const sidecarFile = `clash-${host}${ext}`;
|
||||||
const sidecarPath = path.join(sidecarDir, sidecarFile);
|
const sidecarPath = path.join(sidecarDir, sidecarFile);
|
||||||
|
|
||||||
|
@ -65,7 +103,8 @@ async function resolveSidecar() {
|
||||||
const tempExe = path.join(tempDir, binInfo.exefile);
|
const tempExe = path.join(tempDir, binInfo.exefile);
|
||||||
|
|
||||||
await fs.mkdirp(tempDir);
|
await fs.mkdirp(tempDir);
|
||||||
if (!(await fs.pathExists(tempZip))) await downloadFile(binInfo.url, tempZip);
|
if (!(await fs.pathExists(tempZip)))
|
||||||
|
await downloadFile(binInfo.url, tempZip);
|
||||||
|
|
||||||
if (binInfo.zip === "zip") {
|
if (binInfo.zip === "zip") {
|
||||||
const zip = new AdmZip(tempZip);
|
const zip = new AdmZip(tempZip);
|
||||||
|
@ -93,6 +132,52 @@ async function resolveSidecar() {
|
||||||
|
|
||||||
// delete temp dir
|
// delete temp dir
|
||||||
await fs.remove(tempDir);
|
await fs.remove(tempDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function clashMeta() {
|
||||||
|
const sidecarFile = `clash-meta-${host}${ext}`;
|
||||||
|
const sidecarPath = path.join(sidecarDir, sidecarFile);
|
||||||
|
|
||||||
|
await fs.mkdirp(sidecarDir);
|
||||||
|
if (!FORCE && (await fs.pathExists(sidecarPath))) return;
|
||||||
|
|
||||||
|
// download sidecar
|
||||||
|
const binInfo = await resolveClashMeta();
|
||||||
|
const tempDir = path.join(TEMP_DIR, "clash-meta");
|
||||||
|
const tempZip = path.join(tempDir, binInfo.zipfile);
|
||||||
|
const tempExe = path.join(tempDir, binInfo.exefile);
|
||||||
|
|
||||||
|
await fs.mkdirp(tempDir);
|
||||||
|
if (!(await fs.pathExists(tempZip)))
|
||||||
|
await downloadFile(binInfo.url, tempZip);
|
||||||
|
|
||||||
|
if (binInfo.zip === "zip") {
|
||||||
|
const zip = new AdmZip(tempZip);
|
||||||
|
zip.getEntries().forEach((entry) => {
|
||||||
|
console.log("[INFO]: entry name", entry.entryName);
|
||||||
|
});
|
||||||
|
zip.extractAllTo(tempDir, true);
|
||||||
|
// save as sidecar
|
||||||
|
await fs.rename(tempExe, sidecarPath);
|
||||||
|
console.log(`[INFO]: unzip finished`);
|
||||||
|
} else {
|
||||||
|
// gz
|
||||||
|
const readStream = fs.createReadStream(tempZip);
|
||||||
|
const writeStream = fs.createWriteStream(sidecarPath);
|
||||||
|
readStream
|
||||||
|
.pipe(zlib.createGunzip())
|
||||||
|
.pipe(writeStream)
|
||||||
|
.on("finish", () => {
|
||||||
|
console.log(`[INFO]: gunzip finished`);
|
||||||
|
execSync(`chmod 755 ${sidecarPath}`);
|
||||||
|
console.log(`[INFO]: chmod binary finished`);
|
||||||
|
})
|
||||||
|
.on("error", (error) => console.error(error));
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete temp dir
|
||||||
|
await fs.remove(tempDir);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -46,7 +46,9 @@ winreg = { version = "0.10", features = ["transactions"] }
|
||||||
[features]
|
[features]
|
||||||
default = ["custom-protocol", "tauri/ayatana-tray"]
|
default = ["custom-protocol", "tauri/ayatana-tray"]
|
||||||
custom-protocol = ["tauri/custom-protocol"]
|
custom-protocol = ["tauri/custom-protocol"]
|
||||||
|
meta-dev = ["clash-meta", "verge-dev"]
|
||||||
verge-dev = []
|
verge-dev = []
|
||||||
|
clash-meta = []
|
||||||
debug-yml = []
|
debug-yml = []
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
|
|
|
@ -9,6 +9,8 @@ use std::{collections::HashMap, time::Duration};
|
||||||
use tauri::api::process::{Command, CommandChild, CommandEvent};
|
use tauri::api::process::{Command, CommandChild, CommandEvent};
|
||||||
use tokio::time::sleep;
|
use tokio::time::sleep;
|
||||||
|
|
||||||
|
static mut CLASH_CORE: &str = "clash";
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Service {
|
pub struct Service {
|
||||||
sidecar: Option<CommandChild>,
|
sidecar: Option<CommandChild>,
|
||||||
|
@ -25,6 +27,12 @@ impl Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_core(&mut self, clash_core: Option<String>) {
|
||||||
|
unsafe {
|
||||||
|
CLASH_CORE = Box::leak(clash_core.unwrap_or("clash".into()).into_boxed_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub fn set_mode(&mut self, enable: bool) {
|
pub fn set_mode(&mut self, enable: bool) {
|
||||||
self.service_mode = enable;
|
self.service_mode = enable;
|
||||||
|
@ -92,7 +100,8 @@ impl Service {
|
||||||
let app_dir = dirs::app_home_dir();
|
let app_dir = dirs::app_home_dir();
|
||||||
let app_dir = app_dir.as_os_str().to_str().unwrap();
|
let app_dir = app_dir.as_os_str().to_str().unwrap();
|
||||||
|
|
||||||
let cmd = Command::new_sidecar("clash")?;
|
let clash_core = unsafe { CLASH_CORE };
|
||||||
|
let cmd = Command::new_sidecar(clash_core)?;
|
||||||
let (mut rx, cmd_child) = cmd.args(["-d", app_dir]).spawn()?;
|
let (mut rx, cmd_child) = cmd.args(["-d", app_dir]).spawn()?;
|
||||||
|
|
||||||
self.sidecar = Some(cmd_child);
|
self.sidecar = Some(cmd_child);
|
||||||
|
@ -342,7 +351,9 @@ pub mod win_service {
|
||||||
sleep(Duration::from_secs(1)).await;
|
sleep(Duration::from_secs(1)).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
let bin_path = current_exe().unwrap().with_file_name("clash.exe");
|
let clash_core = unsafe { CLASH_CORE };
|
||||||
|
let clash_bin = format!("{clash_core}.exe");
|
||||||
|
let bin_path = current_exe().unwrap().with_file_name(clash_bin);
|
||||||
let bin_path = bin_path.as_os_str().to_str().unwrap();
|
let bin_path = bin_path.as_os_str().to_str().unwrap();
|
||||||
|
|
||||||
let config_dir = dirs::app_home_dir();
|
let config_dir = dirs::app_home_dir();
|
||||||
|
|
|
@ -45,6 +45,10 @@ pub struct Verge {
|
||||||
|
|
||||||
/// theme setting
|
/// theme setting
|
||||||
pub theme_setting: Option<VergeTheme>,
|
pub theme_setting: Option<VergeTheme>,
|
||||||
|
|
||||||
|
/// clash core path
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub clash_core: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone, Deserialize, Serialize)]
|
#[derive(Default, Debug, Clone, Deserialize, Serialize)]
|
||||||
|
@ -96,6 +100,9 @@ impl Verge {
|
||||||
if patch.traffic_graph.is_some() {
|
if patch.traffic_graph.is_some() {
|
||||||
self.traffic_graph = patch.traffic_graph;
|
self.traffic_graph = patch.traffic_graph;
|
||||||
}
|
}
|
||||||
|
if patch.clash_core.is_some() {
|
||||||
|
self.clash_core = patch.clash_core;
|
||||||
|
}
|
||||||
|
|
||||||
// system setting
|
// system setting
|
||||||
if patch.enable_silent_start.is_some() {
|
if patch.enable_silent_start.is_some() {
|
||||||
|
|
7
src-tauri/tauri.meta.conf.json
Normal file
7
src-tauri/tauri.meta.conf.json
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"tauri": {
|
||||||
|
"bundle": {
|
||||||
|
"externalBin": ["sidecar/clash", "sidecar/clash-meta"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user