Compare commits

..

5 Commits

9 changed files with 118 additions and 64 deletions

View File

@@ -1,4 +1,4 @@
name: CI
name: Release CI
on: [push]
@@ -53,7 +53,7 @@ jobs:
yarn run check
- name: Tauri build
uses: tauri-apps/tauri-action@v0
uses: tauri-apps/tauri-action@b9ce5d7dc68082d21d30a60103b0ab8c5ddae3a1
# enable cache even though failed
continue-on-error: true
env:
@@ -95,6 +95,5 @@ jobs:
- name: Release update.json
run: yarn run release
continue-on-error: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,10 +1,10 @@
{
"name": "clash-verge",
"version": "0.0.16",
"version": "0.0.17",
"license": "GPL-3.0",
"scripts": {
"dev": "cargo tauri dev",
"build": "cargo tauri build",
"dev": "tauri dev",
"build": "tauri build",
"tauri": "tauri",
"web:dev": "vite",
"web:build": "tsc && vite build",

View File

@@ -1,7 +1,8 @@
import { createRequire } from "module";
import fetch from "node-fetch";
import { getOctokit, context } from "@actions/github";
const require = createRequire(import.meta.url);
const UPDATE_TAG_NAME = "updater";
const UPDATE_JSON_FILE = "update.json";
/// generate update.json
/// upload to update tag's release asset
@@ -10,46 +11,85 @@ async function resolveRelease() {
throw new Error("GITHUB_TOKEN is required");
}
const packageJson = require("../package.json");
const options = { owner: context.repo.owner, repo: context.repo.repo };
const github = getOctokit(process.env.GITHUB_TOKEN);
const { data: tags } = await github.rest.repos.listTags({
...options,
per_page: 10,
page: 1,
});
// get the latest publish tag
const tag = tags.find((t) => t.name.startsWith("v"));
console.log(tag);
console.log();
const { data: latestRelease } = await github.rest.repos.getReleaseByTag({
...options,
tag: tag.name,
});
const { version } = packageJson;
const urlPrefix = "https://github.com/zzzgydi/clash-verge/releases/download";
const updateData = {
name: `v${version}`,
notes: `Version ${version} is available now!!!`,
name: tag.name,
notes: latestRelease.body, // use the release body directly
pub_date: new Date().toISOString(),
platforms: {
win64: {
signature: "",
url: `${urlPrefix}/v${version}/clash-verge_${version}_x64.msi.zip`,
},
darwin: {
signature: "",
url: `${urlPrefix}/v${version}/clash-verge.app.tar.gz`,
},
win64: { signature: "", url: "" },
darwin: { signature: "", url: "" },
},
};
console.log(`Generating Version "${version}" update.json`);
const promises = latestRelease.assets.map(async (asset) => {
const { name, browser_download_url } = asset;
const github = getOctokit(process.env.GITHUB_TOKEN);
const { data: release } = await github.rest.repos.getReleaseByTag({
owner: context.repo.owner,
repo: context.repo.repo,
tag: "updater",
});
const { data: assets } = await github.rest.repos.listReleaseAssets({
owner: context.repo.owner,
repo: context.repo.repo,
release_id: release.id,
// win64 url
if (/\.msi\.zip$/.test(name)) {
updateData.platforms.win64.url = browser_download_url;
}
// darwin url
if (/\.app\.tar\.gz$/.test(name)) {
updateData.platforms.darwin.url = browser_download_url;
}
// win64 signature
if (/\.msi\.zip\.sig$/.test(name)) {
updateData.platforms.win64.signature = await getSignature(
browser_download_url
);
}
// darwin signature
if (/\.app\.tar\.gz\.sig$/.test(name)) {
updateData.platforms.darwin.signature = await getSignature(
browser_download_url
);
}
});
for (let asset of assets) {
if (asset.name === "update.json") {
await Promise.allSettled(promises);
console.log(updateData);
// maybe should test the signature as well
const { darwin, win64 } = updateData.platforms;
if (!darwin.url) {
console.log(`[Error]: failed to parse release for darwin`);
delete updateData.platforms.darwin;
}
if (!win64.url) {
console.log(`[Error]: failed to parse release for win64`);
delete updateData.platforms.win64;
}
// update the update.json
const { data: updateRelease } = await github.rest.repos.getReleaseByTag({
...options,
tag: UPDATE_TAG_NAME,
});
for (let asset of updateRelease.assets) {
if (asset.name === UPDATE_JSON_FILE) {
await github.rest.repos.deleteReleaseAsset({
owner: context.repo.owner,
repo: context.repo.repo,
...options,
asset_id: asset.id,
});
break;
@@ -57,12 +97,21 @@ async function resolveRelease() {
}
await github.rest.repos.uploadReleaseAsset({
owner: context.repo.owner,
repo: context.repo.repo,
release_id: release.id,
name: "update.json",
...options,
release_id: updateRelease.id,
name: UPDATE_JSON_FILE,
data: JSON.stringify(updateData, null, 2),
});
}
resolveRelease();
// get the signature file content
async function getSignature(url) {
const response = await fetch(url, {
method: "GET",
headers: { "Content-Type": "application/octet-stream" },
});
return response.text();
}
resolveRelease().catch(console.error);

7
src-tauri/Cargo.lock generated
View File

@@ -448,6 +448,7 @@ dependencies = [
"auto-launch",
"chrono",
"dirs",
"dunce",
"log",
"log4rs",
"port_scanner",
@@ -868,6 +869,12 @@ dependencies = [
"dtoa",
]
[[package]]
name = "dunce"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "453440c271cf5577fd2a40e4942540cb7d0d2f85e27c8d07dd0023c925a67541"
[[package]]
name = "easy-parallel"
version = "3.2.0"

View File

@@ -14,6 +14,7 @@ tauri-build = { version = "1.0.0-rc.3", features = [] }
[dependencies]
dirs = "4.0.0"
dunce = "1.0.2"
chrono = "0.4.19"
serde_json = "1.0"
serde_yaml = "0.8"

View File

@@ -5,7 +5,7 @@ use crate::{
use auto_launch::{AutoLaunch, AutoLaunchBuilder};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use tauri::{api::path::resource_dir, async_runtime::Mutex};
use tauri::{async_runtime::Mutex, utils::platform::current_exe};
/// ### `verge.yaml` schema
#[derive(Default, Debug, Clone, Deserialize, Serialize)]
@@ -122,13 +122,11 @@ impl Verge {
}
/// init the auto launch
pub fn init_launch(&mut self, package_info: &tauri::PackageInfo) {
let app_name = "clash-verge";
let app_path = get_app_path(app_name);
let app_path = resource_dir(package_info, &tauri::Env::default())
.unwrap()
.join(app_path);
let app_path = app_path.as_os_str().to_str().unwrap();
pub fn init_launch(&mut self) {
let app_exe = current_exe().unwrap();
let app_exe = dunce::canonicalize(app_exe).unwrap();
let app_name = app_exe.file_stem().unwrap().to_str().unwrap();
let app_path = app_exe.as_os_str().to_str().unwrap();
let auto = AutoLaunchBuilder::new()
.set_app_name(app_name)
@@ -324,14 +322,3 @@ impl Verge {
});
}
}
// Get the target app_path
fn get_app_path(app_name: &str) -> String {
#[cfg(target_os = "linux")]
let ext = "";
#[cfg(target_os = "macos")]
let ext = "";
#[cfg(target_os = "windows")]
let ext = ".exe";
String::from(app_name) + ext
}

View File

@@ -31,7 +31,7 @@ pub fn resolve_setup(app: &App) {
}
verge.init_sysproxy(clash.info.port.clone());
verge.init_launch(app.package_info());
verge.init_launch();
if let Err(err) = verge.sync_launch() {
log::error!("{}", err);
}

View File

@@ -1,7 +1,7 @@
{
"package": {
"productName": "clash-verge",
"version": "0.0.16"
"version": "0.0.17"
},
"build": {
"distDir": "../dist",

View File

@@ -3,6 +3,7 @@ import { useEffect, useState } from "react";
import { useRecoilValue } from "recoil";
import { Box, Typography } from "@mui/material";
import { ArrowDownward, ArrowUpward } from "@mui/icons-material";
import { listen } from "@tauri-apps/api/event";
import { ApiType } from "../../services/types";
import { getInfomation } from "../../services/api";
import { getVergeConfig } from "../../services/cmds";
@@ -14,11 +15,21 @@ const LayoutTraffic = () => {
const portValue = useRecoilValue(atomClashPort);
const [traffic, setTraffic] = useState({ up: 0, down: 0 });
const { canvasRef, appendData, toggleStyle } = useTrafficGraph();
const [refresh, setRefresh] = useState({});
// whether hide traffic graph
const { data } = useSWR("getVergeConfig", getVergeConfig);
const trafficGraph = data?.traffic_graph ?? true;
useEffect(() => {
let unlisten: () => void = null!;
// should reconnect the traffic ws
listen("restart_clash", () => setRefresh({})).then((fn) => (unlisten = fn));
return () => unlisten?.();
}, []);
useEffect(() => {
let ws: WebSocket | null = null;
@@ -34,7 +45,7 @@ const LayoutTraffic = () => {
});
return () => ws?.close();
}, [portValue]);
}, [portValue, refresh]);
const [up, upUnit] = parseTraffic(traffic.up);
const [down, downUnit] = parseTraffic(traffic.down);