5 Commits

Author SHA1 Message Date
GyDi
46ef348f0d v0.0.17 2022-02-22 02:08:31 +08:00
GyDi
1a55cca8af fix: reconnect websocket when restart clash 2022-02-22 02:05:22 +08:00
GyDi
81ee989f1f chore: enhance publish ci 2022-02-22 01:56:06 +08:00
GyDi
c9c06f8a3d fix: wrong exe path 2022-02-21 22:33:37 +08:00
GyDi
72127979c3 chore: use tauri cli 2022-02-21 22:31:00 +08:00
9 changed files with 118 additions and 64 deletions

View File

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

View File

@@ -1,10 +1,10 @@
{ {
"name": "clash-verge", "name": "clash-verge",
"version": "0.0.16", "version": "0.0.17",
"license": "GPL-3.0", "license": "GPL-3.0",
"scripts": { "scripts": {
"dev": "cargo tauri dev", "dev": "tauri dev",
"build": "cargo tauri build", "build": "tauri build",
"tauri": "tauri", "tauri": "tauri",
"web:dev": "vite", "web:dev": "vite",
"web:build": "tsc && vite build", "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"; 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 /// generate update.json
/// upload to update tag's release asset /// upload to update tag's release asset
@@ -10,46 +11,85 @@ async function resolveRelease() {
throw new Error("GITHUB_TOKEN is required"); 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 = { const updateData = {
name: `v${version}`, name: tag.name,
notes: `Version ${version} is available now!!!`, notes: latestRelease.body, // use the release body directly
pub_date: new Date().toISOString(), pub_date: new Date().toISOString(),
platforms: { platforms: {
win64: { win64: { signature: "", url: "" },
signature: "", darwin: { signature: "", url: "" },
url: `${urlPrefix}/v${version}/clash-verge_${version}_x64.msi.zip`,
},
darwin: {
signature: "",
url: `${urlPrefix}/v${version}/clash-verge.app.tar.gz`,
},
}, },
}; };
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); // win64 url
if (/\.msi\.zip$/.test(name)) {
const { data: release } = await github.rest.repos.getReleaseByTag({ updateData.platforms.win64.url = browser_download_url;
owner: context.repo.owner, }
repo: context.repo.repo, // darwin url
tag: "updater", if (/\.app\.tar\.gz$/.test(name)) {
}); updateData.platforms.darwin.url = browser_download_url;
const { data: assets } = await github.rest.repos.listReleaseAssets({ }
owner: context.repo.owner, // win64 signature
repo: context.repo.repo, if (/\.msi\.zip\.sig$/.test(name)) {
release_id: release.id, 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) { await Promise.allSettled(promises);
if (asset.name === "update.json") { 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({ await github.rest.repos.deleteReleaseAsset({
owner: context.repo.owner, ...options,
repo: context.repo.repo,
asset_id: asset.id, asset_id: asset.id,
}); });
break; break;
@@ -57,12 +97,21 @@ async function resolveRelease() {
} }
await github.rest.repos.uploadReleaseAsset({ await github.rest.repos.uploadReleaseAsset({
owner: context.repo.owner, ...options,
repo: context.repo.repo, release_id: updateRelease.id,
release_id: release.id, name: UPDATE_JSON_FILE,
name: "update.json",
data: JSON.stringify(updateData, null, 2), 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", "auto-launch",
"chrono", "chrono",
"dirs", "dirs",
"dunce",
"log", "log",
"log4rs", "log4rs",
"port_scanner", "port_scanner",
@@ -868,6 +869,12 @@ dependencies = [
"dtoa", "dtoa",
] ]
[[package]]
name = "dunce"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "453440c271cf5577fd2a40e4942540cb7d0d2f85e27c8d07dd0023c925a67541"
[[package]] [[package]]
name = "easy-parallel" name = "easy-parallel"
version = "3.2.0" version = "3.2.0"

View File

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

View File

@@ -5,7 +5,7 @@ use crate::{
use auto_launch::{AutoLaunch, AutoLaunchBuilder}; use auto_launch::{AutoLaunch, AutoLaunchBuilder};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::sync::Arc; 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 /// ### `verge.yaml` schema
#[derive(Default, Debug, Clone, Deserialize, Serialize)] #[derive(Default, Debug, Clone, Deserialize, Serialize)]
@@ -122,13 +122,11 @@ impl Verge {
} }
/// init the auto launch /// init the auto launch
pub fn init_launch(&mut self, package_info: &tauri::PackageInfo) { pub fn init_launch(&mut self) {
let app_name = "clash-verge"; let app_exe = current_exe().unwrap();
let app_path = get_app_path(app_name); let app_exe = dunce::canonicalize(app_exe).unwrap();
let app_path = resource_dir(package_info, &tauri::Env::default()) let app_name = app_exe.file_stem().unwrap().to_str().unwrap();
.unwrap() let app_path = app_exe.as_os_str().to_str().unwrap();
.join(app_path);
let app_path = app_path.as_os_str().to_str().unwrap();
let auto = AutoLaunchBuilder::new() let auto = AutoLaunchBuilder::new()
.set_app_name(app_name) .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_sysproxy(clash.info.port.clone());
verge.init_launch(app.package_info()); verge.init_launch();
if let Err(err) = verge.sync_launch() { if let Err(err) = verge.sync_launch() {
log::error!("{}", err); log::error!("{}", err);
} }

View File

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

View File

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