Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
46ef348f0d | ||
|
|
1a55cca8af | ||
|
|
81ee989f1f | ||
|
|
c9c06f8a3d | ||
|
|
72127979c3 |
5
.github/workflows/ci.yml
vendored
5
.github/workflows/ci.yml
vendored
@@ -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 }}
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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
7
src-tauri/Cargo.lock
generated
@@ -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"
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user