Update On Sun Jul 7 20:30:33 CEST 2024
1
.github/update.log
vendored
@@ -695,3 +695,4 @@ Update On Wed Jul 3 20:29:03 CEST 2024
|
||||
Update On Thu Jul 4 20:30:48 CEST 2024
|
||||
Update On Fri Jul 5 20:32:45 CEST 2024
|
||||
Update On Sat Jul 6 20:29:28 CEST 2024
|
||||
Update On Sun Jul 7 20:30:22 CEST 2024
|
||||
|
||||
8
clash-nyanpasu/backend/Cargo.lock
generated
@@ -5160,18 +5160,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.203"
|
||||
version = "1.0.204"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094"
|
||||
checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.203"
|
||||
version = "1.0.204"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
|
||||
checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
||||
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 9.2 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 972 B |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 71 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 22 KiB |
@@ -22,7 +22,7 @@
|
||||
"icons/32x32.png",
|
||||
"icons/128x128.png",
|
||||
"icons/128x128@2x.png",
|
||||
"icons/icon-new.icns",
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
],
|
||||
"resources": ["resources"],
|
||||
|
||||
@@ -188,6 +188,12 @@ export interface ProviderItem {
|
||||
proxies: Clash.Proxy[];
|
||||
updatedAt: string;
|
||||
vehicleType: string;
|
||||
subscriptionInfo?: {
|
||||
Upload?: number;
|
||||
Download?: number;
|
||||
Total?: number;
|
||||
Expire?: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface Traffic {
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
"clsx": "2.1.1",
|
||||
"react-resizable-panels": "2.0.20",
|
||||
"sass": "1.77.6",
|
||||
"shiki": "1.10.1",
|
||||
"shiki": "1.10.2",
|
||||
"tailwindcss-textshadow": "2.1.3",
|
||||
"vite": "5.3.3",
|
||||
"vite-plugin-monaco-editor": "1.1.3",
|
||||
|
||||
@@ -39,7 +39,7 @@ export const Dataline: FC<DatalineProps> = ({
|
||||
</div>
|
||||
|
||||
<div className=" h-5">
|
||||
{total && (
|
||||
{total !== undefined && (
|
||||
<span className="text-shadow-sm">
|
||||
{t("Total")}: {parseTraffic(total).join(" ")}
|
||||
</span>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { LogMessage } from "@nyanpasu/interface";
|
||||
import { useThrottleFn } from "ahooks";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { useDebounceEffect } from "ahooks";
|
||||
import { useRef } from "react";
|
||||
import { VList, VListHandle } from "virtua";
|
||||
import LogItem from "./log-item";
|
||||
|
||||
@@ -9,28 +9,24 @@ export const LogList = ({ data }: { data: LogMessage[] }) => {
|
||||
|
||||
const shouldStickToBottom = useRef(true);
|
||||
|
||||
const { run: scrollToBottom } = useThrottleFn(
|
||||
useDebounceEffect(
|
||||
() => {
|
||||
if (shouldStickToBottom.current) {
|
||||
setTimeout(() => {
|
||||
vListRef.current?.scrollToIndex(data.length - 1, {
|
||||
align: "end",
|
||||
smooth: true,
|
||||
});
|
||||
}, 100);
|
||||
vListRef.current?.scrollToIndex(data.length - 1, {
|
||||
align: "end",
|
||||
smooth: true,
|
||||
});
|
||||
}
|
||||
},
|
||||
[data],
|
||||
{ wait: 100 },
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
scrollToBottom();
|
||||
}, [data]);
|
||||
|
||||
return (
|
||||
<VList
|
||||
ref={vListRef}
|
||||
className="flex flex-col gap-2 p-2 overflow-auto select-text min-h-full"
|
||||
reverse
|
||||
>
|
||||
{data.map((item, index) => {
|
||||
return <LogItem key={index} value={item} />;
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import parseTraffic from "@/utils/parse-traffic";
|
||||
import { LinearProgress, Tooltip } from "@mui/material";
|
||||
import { ProxiesProviderProps } from "./proxies-provider";
|
||||
|
||||
export const ProxiesProviderTraffic = ({ provider }: ProxiesProviderProps) => {
|
||||
const calc = () => {
|
||||
let progress = 0;
|
||||
let total = 0;
|
||||
let used = 0;
|
||||
|
||||
if (provider.subscriptionInfo) {
|
||||
const {
|
||||
Download: download,
|
||||
Upload: upload,
|
||||
Total: t,
|
||||
} = provider.subscriptionInfo;
|
||||
|
||||
total = t ?? 0;
|
||||
|
||||
used = (download ?? 0) + (upload ?? 0);
|
||||
|
||||
progress = (used / (total ?? 0)) * 100;
|
||||
}
|
||||
|
||||
return { progress, total, used };
|
||||
};
|
||||
|
||||
const { progress, total, used } = calc();
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between gap-4">
|
||||
<div className="w-full">
|
||||
<LinearProgress variant="determinate" value={progress} />
|
||||
</div>
|
||||
|
||||
<Tooltip title={`${parseTraffic(used)} / ${parseTraffic(total)}`}>
|
||||
<div className="text-sm font-bold">
|
||||
{((used / total) * 100).toFixed(2)}%
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProxiesProviderTraffic;
|
||||
@@ -1,12 +1,14 @@
|
||||
import { useMessage } from "@/hooks/use-notification";
|
||||
import parseTraffic from "@/utils/parse-traffic";
|
||||
import { Refresh } from "@mui/icons-material";
|
||||
import LoadingButton from "@mui/lab/LoadingButton";
|
||||
import { Chip, Paper } from "@mui/material";
|
||||
import { Chip, LinearProgress, Paper, Tooltip } from "@mui/material";
|
||||
import { ProviderItem, useClashCore } from "@nyanpasu/interface";
|
||||
import { useLockFn } from "ahooks";
|
||||
import dayjs from "dayjs";
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import ProxiesProviderTraffic from "./proxies-provider-traffic";
|
||||
|
||||
export interface ProxiesProviderProps {
|
||||
provider: ProviderItem;
|
||||
@@ -36,7 +38,7 @@ export const ProxiesProvider = ({ provider }: ProxiesProviderProps) => {
|
||||
|
||||
return (
|
||||
<Paper
|
||||
className="p-5 flex flex-col gap-2"
|
||||
className="p-5 flex flex-col gap-2 justify-between h-full"
|
||||
sx={{
|
||||
borderRadius: 6,
|
||||
}}
|
||||
@@ -57,6 +59,10 @@ export const ProxiesProvider = ({ provider }: ProxiesProviderProps) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{provider.subscriptionInfo && (
|
||||
<ProxiesProviderTraffic provider={provider} />
|
||||
)}
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<Chip
|
||||
className="font-bold truncate"
|
||||
|
||||
@@ -51,7 +51,7 @@ export const SettingClashWeb = () => {
|
||||
|
||||
if (!list) return;
|
||||
|
||||
if (editIndex) {
|
||||
if (editIndex !== null) {
|
||||
list[editIndex] = editString;
|
||||
} else {
|
||||
list.push(editString);
|
||||
|
||||
@@ -38,6 +38,7 @@ export default function LogPage() {
|
||||
full
|
||||
title={t("Logs")}
|
||||
contentStyle={{ height: "100%" }}
|
||||
sectionStyle={{ height: "100%" }}
|
||||
header={
|
||||
<div className="flex gap-2">
|
||||
<LogToggle />
|
||||
|
||||
@@ -38,6 +38,7 @@ export default function RulesPage() {
|
||||
full
|
||||
title={t("Rules")}
|
||||
contentStyle={{ height: "100%" }}
|
||||
sectionStyle={{ height: "100%" }}
|
||||
header={
|
||||
<TextField
|
||||
hiddenLabel
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
background-color: var(--background-color);
|
||||
border-radius: var(--border-radius);
|
||||
border-radius: calc(var(--border-radius) * 2);
|
||||
scrollbar-gutter: stable;
|
||||
|
||||
.MDYBasePage-content {
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
background-color: var(--background-color);
|
||||
border-radius: var(--border-radius);
|
||||
border-radius: calc(var(--border-radius) * 2);
|
||||
|
||||
> section {
|
||||
position: relative;
|
||||
@@ -55,7 +55,7 @@
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
background-color: var(--background-color);
|
||||
border-radius: var(--border-radius);
|
||||
border-radius: calc(var(--border-radius) * 2);
|
||||
|
||||
.RightContainer-Content {
|
||||
height: 100%;
|
||||
|
||||
21
clash-nyanpasu/pnpm-lock.yaml
generated
@@ -313,8 +313,8 @@ importers:
|
||||
specifier: 1.77.6
|
||||
version: 1.77.6
|
||||
shiki:
|
||||
specifier: 1.10.1
|
||||
version: 1.10.1
|
||||
specifier: 1.10.2
|
||||
version: 1.10.2
|
||||
tailwindcss-textshadow:
|
||||
specifier: 2.1.3
|
||||
version: 2.1.3
|
||||
@@ -1505,8 +1505,8 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@shikijs/core@1.10.1':
|
||||
resolution: {integrity: sha512-qdiJS5a/QGCff7VUFIqd0hDdWly9rDp8lhVmXVrS11aazX8LOTRLHAXkkEeONNsS43EcCd7gax9LLoOz4vlFQA==}
|
||||
'@shikijs/core@1.10.2':
|
||||
resolution: {integrity: sha512-hCtKSC0PNmidU+TVBUiddE0sF1QsOPVbBBRQlugsKy0QJBfSj9aIQQ/pNEIv58wwM/9cAlWG1yihi+5ovZfYmA==}
|
||||
|
||||
'@sindresorhus/is@4.6.0':
|
||||
resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==}
|
||||
@@ -4988,8 +4988,8 @@ packages:
|
||||
shell-quote@1.8.1:
|
||||
resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==}
|
||||
|
||||
shiki@1.10.1:
|
||||
resolution: {integrity: sha512-uafV7WCgN4YYrccH6yxpnps6k38sSTlFRrwc4jycWmhWxJIm9dPrk+XkY1hZ2t0I7jmacMNb15Lf2fspa/Y3lg==}
|
||||
shiki@1.10.2:
|
||||
resolution: {integrity: sha512-wrddjiCJ6D8zB1MuAGZ37G37rGw+6Ntnqqbl2uXh3P8g5JxneJRRhccPnex/gqorJoXkbpTRC2x54QIsdx2b1Q==}
|
||||
|
||||
side-channel@1.0.6:
|
||||
resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==}
|
||||
@@ -6771,7 +6771,9 @@ snapshots:
|
||||
'@rollup/rollup-win32-x64-msvc@4.17.2':
|
||||
optional: true
|
||||
|
||||
'@shikijs/core@1.10.1': {}
|
||||
'@shikijs/core@1.10.2':
|
||||
dependencies:
|
||||
'@types/hast': 3.0.4
|
||||
|
||||
'@sindresorhus/is@4.6.0': {}
|
||||
|
||||
@@ -10618,9 +10620,10 @@ snapshots:
|
||||
|
||||
shell-quote@1.8.1: {}
|
||||
|
||||
shiki@1.10.1:
|
||||
shiki@1.10.2:
|
||||
dependencies:
|
||||
'@shikijs/core': 1.10.1
|
||||
'@shikijs/core': 1.10.2
|
||||
'@types/hast': 3.0.4
|
||||
|
||||
side-channel@1.0.6:
|
||||
dependencies:
|
||||
|
||||
11
clash-verge-rev/.github/workflows/release.yml
vendored
@@ -256,3 +256,14 @@ jobs:
|
||||
run: pnpm updater-fixed-webview2
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
submit-to-winget:
|
||||
runs-on: windows-latest
|
||||
needs: [release-update]
|
||||
steps:
|
||||
- name: Submit to Winget
|
||||
uses: vedantmgoyal9/winget-releaser@main
|
||||
with:
|
||||
identifer: ClashVergeRev.ClashVergeRev
|
||||
installers-regex: '_(arm64|x64|x86)-setup\.exe$'
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 16 KiB |
@@ -322,6 +322,17 @@ pub fn copy_icon_file(path: String, name: String) -> CmdResult<String> {
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn get_network_interfaces() -> Vec<String> {
|
||||
use sysinfo::Networks;
|
||||
let mut result = Vec::new();
|
||||
let networks = Networks::new_with_refreshed_list();
|
||||
for (interface_name, _) in &networks {
|
||||
result.push(interface_name.clone());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn open_devtools(app_handle: tauri::AppHandle) {
|
||||
if let Some(window) = app_handle.get_window("main") {
|
||||
|
||||
@@ -7,7 +7,7 @@ use once_cell::sync::OnceCell;
|
||||
use parking_lot::Mutex;
|
||||
use serde_yaml::Mapping;
|
||||
use std::{sync::Arc, time::Duration};
|
||||
use sysinfo::System;
|
||||
use sysinfo::{ProcessRefreshKind, RefreshKind, System};
|
||||
use tauri::api::process::{Command, CommandChild, CommandEvent};
|
||||
use tokio::time::sleep;
|
||||
|
||||
@@ -44,13 +44,27 @@ impl CoreManager {
|
||||
let config_path = dirs::path_to_str(&config_path)?;
|
||||
|
||||
let clash_core = { Config::verge().latest().clash_core.clone() };
|
||||
let clash_core = clash_core.unwrap_or("clash".into());
|
||||
let mut clash_core = clash_core.unwrap_or("verge-mihomo".into());
|
||||
|
||||
let app_dir = dirs::app_home_dir()?;
|
||||
let app_dir = dirs::path_to_str(&app_dir)?;
|
||||
// compatibility
|
||||
if clash_core.contains("clash") {
|
||||
clash_core = "verge-mihomo".to_string();
|
||||
Config::verge().draft().patch_config(IVerge {
|
||||
clash_core: Some("verge-mihomo".to_string()),
|
||||
..IVerge::default()
|
||||
});
|
||||
Config::verge().apply();
|
||||
match Config::verge().data().save_file() {
|
||||
Ok(_) => handle::Handle::refresh_verge(),
|
||||
Err(err) => log::error!(target: "app", "{err}"),
|
||||
}
|
||||
}
|
||||
|
||||
let test_dir = dirs::app_home_dir()?.join("test");
|
||||
let test_dir = dirs::path_to_str(&test_dir)?;
|
||||
|
||||
let output = Command::new_sidecar(clash_core)?
|
||||
.args(["-t", "-d", app_dir, "-f", config_path])
|
||||
.args(["-t", "-d", test_dir, "-f", config_path])
|
||||
.output()?;
|
||||
|
||||
if !output.status.success() {
|
||||
@@ -70,12 +84,6 @@ impl CoreManager {
|
||||
pub async fn run_core(&self) -> Result<()> {
|
||||
let config_path = Config::generate_file(ConfigType::Run)?;
|
||||
|
||||
#[allow(unused_mut)]
|
||||
let mut should_kill = match self.sidecar.lock().take() {
|
||||
Some(_) => true,
|
||||
None => false,
|
||||
};
|
||||
|
||||
// 关闭tun模式
|
||||
let mut disable = Mapping::new();
|
||||
let mut tun = Mapping::new();
|
||||
@@ -84,23 +92,19 @@ impl CoreManager {
|
||||
log::debug!(target: "app", "disable tun mode");
|
||||
let _ = clash_api::patch_configs(&disable).await;
|
||||
|
||||
let mut system = System::new();
|
||||
system.refresh_all();
|
||||
let procs = system.processes_by_name("verge-mihomo");
|
||||
for proc in procs {
|
||||
log::debug!(target: "app", "kill all clash process");
|
||||
proc.kill();
|
||||
}
|
||||
|
||||
if *self.use_service_mode.lock() {
|
||||
log::debug!(target: "app", "stop the core by service");
|
||||
log_err!(service::stop_core_by_service().await);
|
||||
should_kill = true;
|
||||
}
|
||||
} else {
|
||||
let system = System::new_with_specifics(
|
||||
RefreshKind::new().with_processes(ProcessRefreshKind::everything()),
|
||||
);
|
||||
let procs = system.processes_by_name("verge-mihomo");
|
||||
|
||||
// 这里得等一会儿
|
||||
if should_kill {
|
||||
sleep(Duration::from_millis(500)).await;
|
||||
for proc in procs {
|
||||
log::debug!(target: "app", "kill all clash process");
|
||||
proc.kill();
|
||||
}
|
||||
}
|
||||
|
||||
// 服务模式
|
||||
@@ -237,8 +241,9 @@ impl CoreManager {
|
||||
let mut sidecar = self.sidecar.lock();
|
||||
let _ = sidecar.take();
|
||||
|
||||
let mut system = System::new();
|
||||
system.refresh_all();
|
||||
let system = System::new_with_specifics(
|
||||
RefreshKind::new().with_processes(ProcessRefreshKind::everything()),
|
||||
);
|
||||
let procs = system.processes_by_name("verge-mihomo");
|
||||
for proc in procs {
|
||||
log::debug!(target: "app", "kill all clash process");
|
||||
@@ -287,7 +292,6 @@ impl CoreManager {
|
||||
/// 如果涉及端口和外部控制则需要重启
|
||||
pub async fn update_config(&self) -> Result<()> {
|
||||
log::debug!(target: "app", "try to update clash config");
|
||||
|
||||
// 更新订阅
|
||||
Config::generate().await?;
|
||||
|
||||
@@ -299,20 +303,19 @@ impl CoreManager {
|
||||
let path = dirs::path_to_str(&path)?;
|
||||
|
||||
// 发送请求 发送5次
|
||||
for i in 0..5 {
|
||||
for i in 0..10 {
|
||||
match clash_api::put_configs(path).await {
|
||||
Ok(_) => break,
|
||||
Err(err) => {
|
||||
if i < 4 {
|
||||
if i < 9 {
|
||||
log::info!(target: "app", "{err}");
|
||||
} else {
|
||||
bail!(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
sleep(Duration::from_millis(250)).await;
|
||||
sleep(Duration::from_millis(100)).await;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,48 +107,13 @@ pub async fn patch_clash(patch: Mapping) -> Result<()> {
|
||||
Config::clash().draft().patch_config(patch.clone());
|
||||
|
||||
let res = {
|
||||
let redir_port = patch.get("redir-port");
|
||||
let tproxy_port = patch.get("tproxy-port");
|
||||
let mixed_port = patch.get("mixed-port");
|
||||
let socks_port = patch.get("socks-port");
|
||||
let port = patch.get("port");
|
||||
let enable_random_port = Config::verge().latest().enable_random_port.unwrap_or(false);
|
||||
if mixed_port.is_some() && !enable_random_port {
|
||||
let changed = mixed_port.unwrap()
|
||||
!= Config::verge()
|
||||
.latest()
|
||||
.verge_mixed_port
|
||||
.unwrap_or(Config::clash().data().get_mixed_port());
|
||||
// 检查端口占用
|
||||
if changed {
|
||||
if let Some(port) = mixed_port.unwrap().as_u64() {
|
||||
if !port_scanner::local_port_available(port as u16) {
|
||||
Config::clash().discard();
|
||||
bail!("port already in use");
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 激活订阅
|
||||
if redir_port.is_some()
|
||||
|| tproxy_port.is_some()
|
||||
|| mixed_port.is_some()
|
||||
|| socks_port.is_some()
|
||||
|| port.is_some()
|
||||
|| patch.get("secret").is_some()
|
||||
|| patch.get("external-controller").is_some()
|
||||
{
|
||||
if patch.get("secret").is_some() || patch.get("external-controller").is_some() {
|
||||
Config::generate().await?;
|
||||
CoreManager::global().run_core().await?;
|
||||
handle::Handle::refresh_clash();
|
||||
}
|
||||
|
||||
// 更新系统代理
|
||||
if mixed_port.is_some() {
|
||||
log_err!(sysopt::Sysopt::global().init_sysproxy());
|
||||
}
|
||||
|
||||
if patch.get("mode").is_some() {
|
||||
log_err!(handle::Handle::update_systray_part());
|
||||
}
|
||||
@@ -174,7 +139,6 @@ pub async fn patch_clash(patch: Mapping) -> Result<()> {
|
||||
/// 一般都是一个个的修改
|
||||
pub async fn patch_verge(patch: IVerge) -> Result<()> {
|
||||
Config::verge().draft().patch_config(patch.clone());
|
||||
|
||||
let tun_mode = patch.enable_tun_mode;
|
||||
let auto_launch = patch.enable_auto_launch;
|
||||
let system_proxy = patch.enable_system_proxy;
|
||||
@@ -182,7 +146,7 @@ pub async fn patch_verge(patch: IVerge) -> Result<()> {
|
||||
let pac_content = patch.pac_file_content;
|
||||
let proxy_bypass = patch.system_proxy_bypass;
|
||||
let language = patch.language;
|
||||
let port = patch.verge_mixed_port;
|
||||
let mixed_port = patch.verge_mixed_port;
|
||||
#[cfg(target_os = "macos")]
|
||||
let tray_icon = patch.tray_icon;
|
||||
let common_tray_icon = patch.common_tray_icon;
|
||||
@@ -190,41 +154,62 @@ pub async fn patch_verge(patch: IVerge) -> Result<()> {
|
||||
let tun_tray_icon = patch.tun_tray_icon;
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let redir_enabled = patch.verge_redir_enabled;
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let redir_port = patch.verge_redir_port;
|
||||
#[cfg(target_os = "linux")]
|
||||
let tproxy_enabled = patch.verge_tproxy_enabled;
|
||||
#[cfg(target_os = "linux")]
|
||||
let tproxy_port = patch.verge_tproxy_port;
|
||||
let socks_enabled = patch.verge_socks_enabled;
|
||||
let socks_port = patch.verge_socks_port;
|
||||
let http_enabled = patch.verge_http_enabled;
|
||||
let http_port = patch.verge_port;
|
||||
let res = {
|
||||
let service_mode = patch.enable_service_mode;
|
||||
|
||||
let mut generated = false;
|
||||
if service_mode.is_some() {
|
||||
log::debug!(target: "app", "change service mode to {}", service_mode.unwrap());
|
||||
|
||||
Config::generate().await?;
|
||||
CoreManager::global().run_core().await?;
|
||||
if !generated {
|
||||
Config::generate().await?;
|
||||
CoreManager::global().run_core().await?;
|
||||
generated = true;
|
||||
}
|
||||
} else if tun_mode.is_some() {
|
||||
update_core_config().await?;
|
||||
}
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
if redir_enabled.is_some() {
|
||||
Config::generate().await?;
|
||||
CoreManager::global().run_core().await?;
|
||||
if redir_enabled.is_some() || redir_port.is_some() {
|
||||
if !generated {
|
||||
Config::generate().await?;
|
||||
CoreManager::global().run_core().await?;
|
||||
generated = true;
|
||||
}
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
if tproxy_enabled.is_some() {
|
||||
Config::generate().await?;
|
||||
CoreManager::global().run_core().await?;
|
||||
if tproxy_enabled.is_some() || tproxy_port.is_some() {
|
||||
if !generated {
|
||||
Config::generate().await?;
|
||||
CoreManager::global().run_core().await?;
|
||||
generated = true;
|
||||
}
|
||||
}
|
||||
if socks_enabled.is_some() || http_enabled.is_some() {
|
||||
Config::generate().await?;
|
||||
CoreManager::global().run_core().await?;
|
||||
if socks_enabled.is_some()
|
||||
|| http_enabled.is_some()
|
||||
|| socks_port.is_some()
|
||||
|| http_port.is_some()
|
||||
|| mixed_port.is_some()
|
||||
{
|
||||
if !generated {
|
||||
Config::generate().await?;
|
||||
CoreManager::global().run_core().await?;
|
||||
}
|
||||
}
|
||||
if auto_launch.is_some() {
|
||||
sysopt::Sysopt::global().update_launch()?;
|
||||
}
|
||||
if system_proxy.is_some()
|
||||
|| proxy_bypass.is_some()
|
||||
|| port.is_some()
|
||||
|| mixed_port.is_some()
|
||||
|| pac.is_some()
|
||||
|| pac_content.is_some()
|
||||
{
|
||||
|
||||
@@ -51,6 +51,7 @@ fn main() -> std::io::Result<()> {
|
||||
cmds::open_web_url,
|
||||
cmds::open_core_dir,
|
||||
cmds::get_portable_flag,
|
||||
cmds::get_network_interfaces,
|
||||
// cmds::kill_sidecar,
|
||||
cmds::restart_sidecar,
|
||||
// clash
|
||||
|
||||
@@ -26,7 +26,7 @@ type SearchProps = {
|
||||
export const BaseSearchBox = styled((props: SearchProps) => {
|
||||
const { t } = useTranslation();
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const [matchCase, setMatchCase] = useState(props.matchCase ?? true);
|
||||
const [matchCase, setMatchCase] = useState(props.matchCase ?? false);
|
||||
const [matchWholeWord, setMatchWholeWord] = useState(
|
||||
props.matchWholeWord ?? false
|
||||
);
|
||||
@@ -96,7 +96,7 @@ export const BaseSearchBox = styled((props: SearchProps) => {
|
||||
return (
|
||||
<Tooltip title={errorMessage} placement="bottom-start">
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
autoComplete="new-password"
|
||||
inputRef={inputRef}
|
||||
hiddenLabel
|
||||
fullWidth
|
||||
|
||||
@@ -4,7 +4,7 @@ export const BaseStyledSelect = styled((props: SelectProps<string>) => {
|
||||
return (
|
||||
<Select
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
autoComplete="new-password"
|
||||
sx={{
|
||||
width: 120,
|
||||
height: 33.375,
|
||||
|
||||
@@ -6,7 +6,7 @@ export const BaseStyledTextField = styled((props: TextFieldProps) => {
|
||||
|
||||
return (
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
autoComplete="new-password"
|
||||
hiddenLabel
|
||||
fullWidth
|
||||
size="small"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ReactNode, useEffect, useMemo, useState } from "react";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { useLockFn } from "ahooks";
|
||||
import yaml from "js-yaml";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogTitle,
|
||||
InputAdornment,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemText,
|
||||
@@ -30,7 +31,11 @@ import {
|
||||
styled,
|
||||
} from "@mui/material";
|
||||
import { GroupItem } from "@/components/profile/group-item";
|
||||
import { readProfileFile, saveProfileFile } from "@/services/cmds";
|
||||
import {
|
||||
getNetworkInterfaces,
|
||||
readProfileFile,
|
||||
saveProfileFile,
|
||||
} from "@/services/cmds";
|
||||
import { Notice, Switch } from "@/components/base";
|
||||
import getSystem from "@/utils/get-system";
|
||||
import { BaseSearchBox } from "../base/base-search-box";
|
||||
@@ -60,7 +65,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
const [currData, setCurrData] = useState("");
|
||||
const [visualization, setVisualization] = useState(true);
|
||||
const [match, setMatch] = useState(() => (_: string) => true);
|
||||
|
||||
const [interfaceNameList, setInterfaceNameList] = useState<string[]>([]);
|
||||
const { control, watch, register, ...formIns } = useForm<IProxyGroupConfig>({
|
||||
defaultValues: {
|
||||
type: "select",
|
||||
@@ -251,6 +256,10 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
setProxyProviderList(Object.keys(provider));
|
||||
setGroupList(originGroupsObj?.["proxy-groups"] || []);
|
||||
};
|
||||
const getInterfaceNameList = async () => {
|
||||
let list = await getNetworkInterfaces();
|
||||
setInterfaceNameList(list);
|
||||
};
|
||||
useEffect(() => {
|
||||
fetchProxyPolicy();
|
||||
}, [prependSeq, appendSeq, deleteSeq]);
|
||||
@@ -259,12 +268,13 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
fetchContent();
|
||||
fetchProxyPolicy();
|
||||
fetchProfile();
|
||||
getInterfaceNameList();
|
||||
}, [open]);
|
||||
|
||||
const validateGroup = () => {
|
||||
let group = formIns.getValues();
|
||||
if (group.name === "") {
|
||||
throw new Error(t("Group Name Cannot Be Empty"));
|
||||
throw new Error(t("Group Name Required"));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -333,6 +343,11 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
"relay",
|
||||
]}
|
||||
value={field.value}
|
||||
renderOption={(props, option) => (
|
||||
<li {...props} title={t(option)}>
|
||||
{option}
|
||||
</li>
|
||||
)}
|
||||
onChange={(_, value) => value && field.onChange(value)}
|
||||
renderInput={(params) => <TextField {...params} />}
|
||||
/>
|
||||
@@ -346,7 +361,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
<Item>
|
||||
<ListItemText primary={t("Group Name")} />
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
autoComplete="new-password"
|
||||
size="small"
|
||||
sx={{ width: "calc(100% - 150px)" }}
|
||||
{...field}
|
||||
@@ -361,9 +376,9 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Item>
|
||||
<ListItemText primary={t("Icon")} />
|
||||
<ListItemText primary={t("Proxy Group Icon")} />
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
autoComplete="new-password"
|
||||
size="small"
|
||||
sx={{ width: "calc(100% - 150px)" }}
|
||||
{...field}
|
||||
@@ -409,7 +424,6 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
</Item>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Controller
|
||||
name="url"
|
||||
control={control}
|
||||
@@ -417,7 +431,8 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
<Item>
|
||||
<ListItemText primary={t("Health Check Url")} />
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
autoComplete="new-password"
|
||||
placeholder="https://www.gstatic.com/generate_204"
|
||||
size="small"
|
||||
sx={{ width: "calc(100% - 150px)" }}
|
||||
{...field}
|
||||
@@ -425,6 +440,24 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
</Item>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
name="expected-status"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Item>
|
||||
<ListItemText primary={t("Expected Status")} />
|
||||
<TextField
|
||||
autoComplete="new-password"
|
||||
placeholder="*"
|
||||
size="small"
|
||||
sx={{ width: "calc(100% - 150px)" }}
|
||||
onChange={(e) => {
|
||||
field.onChange(parseInt(e.target.value));
|
||||
}}
|
||||
/>
|
||||
</Item>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
name="interval"
|
||||
control={control}
|
||||
@@ -432,13 +465,21 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
<Item>
|
||||
<ListItemText primary={t("Interval")} />
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
autoComplete="new-password"
|
||||
placeholder="300"
|
||||
type="number"
|
||||
size="small"
|
||||
sx={{ width: "calc(100% - 150px)" }}
|
||||
onChange={(e) => {
|
||||
field.onChange(parseInt(e.target.value));
|
||||
}}
|
||||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
{t("seconds")}
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</Item>
|
||||
)}
|
||||
@@ -450,13 +491,21 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
<Item>
|
||||
<ListItemText primary={t("Timeout")} />
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
autoComplete="new-password"
|
||||
placeholder="5000"
|
||||
type="number"
|
||||
size="small"
|
||||
sx={{ width: "calc(100% - 150px)" }}
|
||||
onChange={(e) => {
|
||||
field.onChange(parseInt(e.target.value));
|
||||
}}
|
||||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
{t("millis")}
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</Item>
|
||||
)}
|
||||
@@ -468,7 +517,8 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
<Item>
|
||||
<ListItemText primary={t("Max Failed Times")} />
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
autoComplete="new-password"
|
||||
placeholder="5"
|
||||
type="number"
|
||||
size="small"
|
||||
sx={{ width: "calc(100% - 150px)" }}
|
||||
@@ -485,11 +535,13 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
render={({ field }) => (
|
||||
<Item>
|
||||
<ListItemText primary={t("Interface Name")} />
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
<Autocomplete
|
||||
size="small"
|
||||
sx={{ width: "calc(100% - 150px)" }}
|
||||
{...field}
|
||||
options={interfaceNameList}
|
||||
value={field.value}
|
||||
onChange={(_, value) => value && field.onChange(value)}
|
||||
renderInput={(params) => <TextField {...params} />}
|
||||
/>
|
||||
</Item>
|
||||
)}
|
||||
@@ -501,7 +553,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
<Item>
|
||||
<ListItemText primary={t("Routing Mark")} />
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
autoComplete="new-password"
|
||||
type="number"
|
||||
size="small"
|
||||
sx={{ width: "calc(100% - 150px)" }}
|
||||
@@ -519,7 +571,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
<Item>
|
||||
<ListItemText primary={t("Filter")} />
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
autoComplete="new-password"
|
||||
size="small"
|
||||
sx={{ width: "calc(100% - 150px)" }}
|
||||
{...field}
|
||||
@@ -534,7 +586,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
<Item>
|
||||
<ListItemText primary={t("Exclude Filter")} />
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
autoComplete="new-password"
|
||||
size="small"
|
||||
sx={{ width: "calc(100% - 150px)" }}
|
||||
{...field}
|
||||
@@ -588,23 +640,6 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
</Item>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
name="expected-status"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Item>
|
||||
<ListItemText primary={t("Expected Status")} />
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
size="small"
|
||||
sx={{ width: "calc(100% - 150px)" }}
|
||||
onChange={(e) => {
|
||||
field.onChange(parseInt(e.target.value));
|
||||
}}
|
||||
/>
|
||||
</Item>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
name="include-all"
|
||||
control={control}
|
||||
@@ -673,7 +708,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
onClick={() => {
|
||||
try {
|
||||
validateGroup();
|
||||
for (const item of prependSeq) {
|
||||
for (const item of [...prependSeq, ...groupList]) {
|
||||
if (item.name === formIns.getValues().name) {
|
||||
throw new Error(t("Group Name Already Exists"));
|
||||
}
|
||||
@@ -694,7 +729,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
onClick={() => {
|
||||
try {
|
||||
validateGroup();
|
||||
for (const item of appendSeq) {
|
||||
for (const item of [...appendSeq, ...groupList]) {
|
||||
if (item.name === formIns.getValues().name) {
|
||||
throw new Error(t("Group Name Already Exists"));
|
||||
}
|
||||
@@ -716,10 +751,7 @@ export const GroupsEditorViewer = (props: Props) => {
|
||||
padding: "0 10px",
|
||||
}}
|
||||
>
|
||||
<BaseSearchBox
|
||||
matchCase={false}
|
||||
onSearch={(match) => setMatch(() => match)}
|
||||
/>
|
||||
<BaseSearchBox onSearch={(match) => setMatch(() => match)} />
|
||||
<Virtuoso
|
||||
style={{ height: "calc(100% - 24px)", marginTop: "8px" }}
|
||||
totalCount={
|
||||
|
||||
@@ -73,7 +73,10 @@ export const ProfileItem = (props: Props) => {
|
||||
const from = parseUrl(itemData.url);
|
||||
const description = itemData.desc;
|
||||
const expire = parseExpire(extra?.expire);
|
||||
const progress = Math.round(((download + upload) * 100) / (total + 0.01) + 1);
|
||||
const progress = Math.min(
|
||||
Math.round(((download + upload) * 100) / (total + 0.01)) + 1,
|
||||
100
|
||||
);
|
||||
|
||||
const loading = loadingCache[itemData.uid] ?? false;
|
||||
|
||||
@@ -472,64 +475,78 @@ export const ProfileItem = (props: Props) => {
|
||||
</MenuItem>
|
||||
))}
|
||||
</Menu>
|
||||
{fileOpen && (
|
||||
<EditorViewer
|
||||
open={true}
|
||||
initialData={readProfileFile(uid)}
|
||||
language="yaml"
|
||||
schema="clash"
|
||||
onSave={async (prev, curr) => {
|
||||
await saveProfileFile(uid, curr ?? "");
|
||||
onSave && onSave(prev, curr);
|
||||
}}
|
||||
onClose={() => setFileOpen(false)}
|
||||
/>
|
||||
)}
|
||||
{rulesOpen && (
|
||||
<RulesEditorViewer
|
||||
groupsUid={option?.groups ?? ""}
|
||||
mergeUid={option?.merge ?? ""}
|
||||
profileUid={uid}
|
||||
property={option?.rules ?? ""}
|
||||
open={true}
|
||||
onSave={onSave}
|
||||
onClose={() => setRulesOpen(false)}
|
||||
/>
|
||||
)}
|
||||
{proxiesOpen && (
|
||||
<ProxiesEditorViewer
|
||||
profileUid={uid}
|
||||
property={option?.proxies ?? ""}
|
||||
open={true}
|
||||
onSave={onSave}
|
||||
onClose={() => setProxiesOpen(false)}
|
||||
/>
|
||||
)}
|
||||
{groupsOpen && (
|
||||
<GroupsEditorViewer
|
||||
mergeUid={option?.merge ?? ""}
|
||||
proxiesUid={option?.proxies ?? ""}
|
||||
profileUid={uid}
|
||||
property={option?.groups ?? ""}
|
||||
open={true}
|
||||
onSave={onSave}
|
||||
onClose={() => {
|
||||
setGroupsOpen(false);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{mergeOpen && (
|
||||
<EditorViewer
|
||||
open={true}
|
||||
initialData={readProfileFile(option?.merge ?? "")}
|
||||
language="yaml"
|
||||
schema="clash"
|
||||
onSave={async (prev, curr) => {
|
||||
await saveProfileFile(option?.merge ?? "", curr ?? "");
|
||||
onSave && onSave(prev, curr);
|
||||
}}
|
||||
onClose={() => setMergeOpen(false)}
|
||||
/>
|
||||
)}
|
||||
{scriptOpen && (
|
||||
<EditorViewer
|
||||
open={true}
|
||||
initialData={readProfileFile(option?.script ?? "")}
|
||||
language="javascript"
|
||||
onSave={async (prev, curr) => {
|
||||
await saveProfileFile(option?.script ?? "", curr ?? "");
|
||||
onSave && onSave(prev, curr);
|
||||
}}
|
||||
onClose={() => setScriptOpen(false)}
|
||||
/>
|
||||
)}
|
||||
|
||||
<EditorViewer
|
||||
open={fileOpen}
|
||||
initialData={readProfileFile(uid)}
|
||||
language="yaml"
|
||||
schema="clash"
|
||||
onSave={async (prev, curr) => {
|
||||
await saveProfileFile(uid, curr ?? "");
|
||||
onSave && onSave(prev, curr);
|
||||
}}
|
||||
onClose={() => setFileOpen(false)}
|
||||
/>
|
||||
<RulesEditorViewer
|
||||
groupsUid={option?.groups ?? ""}
|
||||
mergeUid={option?.merge ?? ""}
|
||||
profileUid={uid}
|
||||
property={option?.rules ?? ""}
|
||||
open={rulesOpen}
|
||||
onSave={onSave}
|
||||
onClose={() => setRulesOpen(false)}
|
||||
/>
|
||||
<ProxiesEditorViewer
|
||||
profileUid={uid}
|
||||
property={option?.proxies ?? ""}
|
||||
open={proxiesOpen}
|
||||
onSave={onSave}
|
||||
onClose={() => setProxiesOpen(false)}
|
||||
/>
|
||||
<GroupsEditorViewer
|
||||
mergeUid={option?.merge ?? ""}
|
||||
proxiesUid={option?.proxies ?? ""}
|
||||
profileUid={uid}
|
||||
property={option?.groups ?? ""}
|
||||
open={groupsOpen}
|
||||
onSave={onSave}
|
||||
onClose={() => setGroupsOpen(false)}
|
||||
/>
|
||||
<EditorViewer
|
||||
open={mergeOpen}
|
||||
initialData={readProfileFile(option?.merge ?? "")}
|
||||
language="yaml"
|
||||
schema="clash"
|
||||
onSave={async (prev, curr) => {
|
||||
await saveProfileFile(option?.merge ?? "", curr ?? "");
|
||||
onSave && onSave(prev, curr);
|
||||
}}
|
||||
onClose={() => setMergeOpen(false)}
|
||||
/>
|
||||
<EditorViewer
|
||||
open={scriptOpen}
|
||||
initialData={readProfileFile(option?.script ?? "")}
|
||||
language="javascript"
|
||||
onSave={async (prev, curr) => {
|
||||
await saveProfileFile(option?.script ?? "", curr ?? "");
|
||||
onSave && onSave(prev, curr);
|
||||
}}
|
||||
onClose={() => setScriptOpen(false)}
|
||||
/>
|
||||
<ConfirmViewer
|
||||
title={t("Confirm deletion")}
|
||||
message={t("This operation is not reversible")}
|
||||
|
||||
@@ -167,25 +167,27 @@ export const ProfileMore = (props: Props) => {
|
||||
</MenuItem>
|
||||
))}
|
||||
</Menu>
|
||||
|
||||
<EditorViewer
|
||||
open={fileOpen}
|
||||
title={`${t("Global " + id)}`}
|
||||
initialData={readProfileFile(id)}
|
||||
language={id === "Merge" ? "yaml" : "javascript"}
|
||||
schema={id === "Merge" ? "clash" : undefined}
|
||||
onSave={async (prev, curr) => {
|
||||
await saveProfileFile(id, curr ?? "");
|
||||
onSave && onSave(prev, curr);
|
||||
}}
|
||||
onClose={() => setFileOpen(false)}
|
||||
/>
|
||||
|
||||
<LogViewer
|
||||
open={logOpen}
|
||||
logInfo={logInfo}
|
||||
onClose={() => setLogOpen(false)}
|
||||
/>
|
||||
{fileOpen && (
|
||||
<EditorViewer
|
||||
open={true}
|
||||
title={`${t("Global " + id)}`}
|
||||
initialData={readProfileFile(id)}
|
||||
language={id === "Merge" ? "yaml" : "javascript"}
|
||||
schema={id === "Merge" ? "clash" : undefined}
|
||||
onSave={async (prev, curr) => {
|
||||
await saveProfileFile(id, curr ?? "");
|
||||
onSave && onSave(prev, curr);
|
||||
}}
|
||||
onClose={() => setFileOpen(false)}
|
||||
/>
|
||||
)}
|
||||
{logOpen && (
|
||||
<LogViewer
|
||||
open={logOpen}
|
||||
logInfo={logInfo}
|
||||
onClose={() => setLogOpen(false)}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -256,7 +256,7 @@ export const ProxiesEditorViewer = (props: Props) => {
|
||||
>
|
||||
<Item>
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
autoComplete="new-password"
|
||||
placeholder={t("Use newlines for multiple uri")}
|
||||
fullWidth
|
||||
rows={9}
|
||||
@@ -298,10 +298,7 @@ export const ProxiesEditorViewer = (props: Props) => {
|
||||
padding: "0 10px",
|
||||
}}
|
||||
>
|
||||
<BaseSearchBox
|
||||
matchCase={false}
|
||||
onSearch={(match) => setMatch(() => match)}
|
||||
/>
|
||||
<BaseSearchBox onSearch={(match) => setMatch(() => match)} />
|
||||
<Virtuoso
|
||||
style={{ height: "calc(100% - 24px)", marginTop: "8px" }}
|
||||
totalCount={
|
||||
|
||||
@@ -56,6 +56,7 @@ export const ProxyItem = (props: Props) => {
|
||||
sx={{ cursor: sortable ? "move" : "" }}
|
||||
primary={
|
||||
<StyledPrimary
|
||||
title={proxy.name}
|
||||
sx={{ textDecoration: type === "delete" ? "line-through" : "" }}
|
||||
>
|
||||
{proxy.name}
|
||||
|
||||
@@ -59,6 +59,7 @@ export const RuleItem = (props: Props) => {
|
||||
sx={{ cursor: sortable ? "move" : "" }}
|
||||
primary={
|
||||
<StyledPrimary
|
||||
title={ruleContent || "-"}
|
||||
sx={{ textDecoration: type === "delete" ? "line-through" : "" }}
|
||||
>
|
||||
{ruleContent || "-"}
|
||||
|
||||
@@ -495,7 +495,7 @@ export const RulesEditorViewer = (props: Props) => {
|
||||
{ruleType.name !== "RULE-SET" &&
|
||||
ruleType.name !== "SUB-RULE" && (
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
autoComplete="new-password"
|
||||
size="small"
|
||||
sx={{ minWidth: "240px" }}
|
||||
value={ruleContent}
|
||||
@@ -573,10 +573,7 @@ export const RulesEditorViewer = (props: Props) => {
|
||||
padding: "0 10px",
|
||||
}}
|
||||
>
|
||||
<BaseSearchBox
|
||||
matchCase={false}
|
||||
onSearch={(match) => setMatch(() => match)}
|
||||
/>
|
||||
<BaseSearchBox onSearch={(match) => setMatch(() => match)} />
|
||||
<Virtuoso
|
||||
style={{ height: "calc(100% - 24px)", marginTop: "8px" }}
|
||||
totalCount={
|
||||
|
||||
@@ -105,8 +105,9 @@ export const ProviderButton = () => {
|
||||
const download = sub?.Download || 0;
|
||||
const total = sub?.Total || 0;
|
||||
const expire = sub?.Expire || 0;
|
||||
const progress = Math.round(
|
||||
((download + upload) * 100) / (total + 0.1)
|
||||
const progress = Math.min(
|
||||
Math.round(((download + upload) * 100) / (total + 0.01)) + 1,
|
||||
100
|
||||
);
|
||||
return (
|
||||
<>
|
||||
@@ -159,6 +160,7 @@ export const ProviderButton = () => {
|
||||
<LinearProgress
|
||||
variant="determinate"
|
||||
value={progress}
|
||||
style={{ opacity: total > 0 ? 1 : 0 }}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -132,7 +132,7 @@ export const ProxyHead = (props: Props) => {
|
||||
|
||||
{textState === "filter" && (
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
autoComplete="new-password"
|
||||
autoFocus={autoFocus}
|
||||
hiddenLabel
|
||||
value={filterText}
|
||||
@@ -146,7 +146,7 @@ export const ProxyHead = (props: Props) => {
|
||||
|
||||
{textState === "url" && (
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
autoComplete="new-password"
|
||||
autoFocus={autoFocus}
|
||||
hiddenLabel
|
||||
autoSave="off"
|
||||
|
||||
@@ -13,7 +13,6 @@ export const ClashPortViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
|
||||
const { clashInfo, patchInfo } = useClashInfo();
|
||||
const { verge, patchVerge } = useVerge();
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const [redirPort, setRedirPort] = useState(
|
||||
verge?.verge_redir_port ?? clashInfo?.redir_port ?? 7895
|
||||
@@ -94,24 +93,57 @@ export const ClashPortViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (OS !== "windows") {
|
||||
await patchInfo({ "redir-port": redirPort });
|
||||
await patchVerge({ verge_redir_port: redirPort });
|
||||
await patchVerge({ verge_redir_enabled: redirEnabled });
|
||||
if (OS === "windows") {
|
||||
await patchInfo({
|
||||
"mixed-port": mixedPort,
|
||||
"socks-port": socksPort,
|
||||
port,
|
||||
});
|
||||
await patchVerge({
|
||||
verge_mixed_port: mixedPort,
|
||||
verge_socks_port: socksPort,
|
||||
verge_socks_enabled: socksEnabled,
|
||||
verge_port: port,
|
||||
verge_http_enabled: httpEnabled,
|
||||
});
|
||||
}
|
||||
if (OS === "macos") {
|
||||
await patchInfo({
|
||||
"redir-port": redirPort,
|
||||
"mixed-port": mixedPort,
|
||||
"socks-port": socksPort,
|
||||
port,
|
||||
});
|
||||
await patchVerge({
|
||||
verge_redir_port: redirPort,
|
||||
verge_redir_enabled: redirEnabled,
|
||||
verge_mixed_port: mixedPort,
|
||||
verge_socks_port: socksPort,
|
||||
verge_socks_enabled: socksEnabled,
|
||||
verge_port: port,
|
||||
verge_http_enabled: httpEnabled,
|
||||
});
|
||||
}
|
||||
if (OS === "linux") {
|
||||
await patchInfo({ "tproxy-port": tproxyPort });
|
||||
await patchVerge({ verge_tproxy_port: tproxyPort });
|
||||
await patchVerge({ verge_tproxy_enabled: tproxyEnabled });
|
||||
await patchInfo({
|
||||
"redir-port": redirPort,
|
||||
"tproxy-port": tproxyPort,
|
||||
"mixed-port": mixedPort,
|
||||
"socks-port": socksPort,
|
||||
port,
|
||||
});
|
||||
await patchVerge({
|
||||
verge_redir_port: redirPort,
|
||||
verge_redir_enabled: redirEnabled,
|
||||
verge_tproxy_port: tproxyPort,
|
||||
verge_tproxy_enabled: tproxyEnabled,
|
||||
verge_mixed_port: mixedPort,
|
||||
verge_socks_port: socksPort,
|
||||
verge_socks_enabled: socksEnabled,
|
||||
verge_port: port,
|
||||
verge_http_enabled: httpEnabled,
|
||||
});
|
||||
}
|
||||
await patchInfo({ "mixed-port": mixedPort });
|
||||
await patchInfo({ "socks-port": socksPort });
|
||||
await patchInfo({ port });
|
||||
await patchVerge({ verge_mixed_port: mixedPort });
|
||||
await patchVerge({ verge_socks_port: socksPort });
|
||||
await patchVerge({ verge_port: port });
|
||||
await patchVerge({ verge_socks_enabled: socksEnabled });
|
||||
await patchVerge({ verge_http_enabled: httpEnabled });
|
||||
setOpen(false);
|
||||
Notice.success(t("Clash Port Modified"), 1000);
|
||||
} catch (err: any) {
|
||||
@@ -134,7 +166,7 @@ export const ClashPortViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("Mixed Port")} />
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
autoComplete="new-password"
|
||||
size="small"
|
||||
sx={{ width: 135 }}
|
||||
value={mixedPort}
|
||||
@@ -146,7 +178,7 @@ export const ClashPortViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("Socks Port")} />
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
autoComplete="new-password"
|
||||
size="small"
|
||||
sx={{ width: 135 }}
|
||||
value={socksPort}
|
||||
@@ -169,7 +201,7 @@ export const ClashPortViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("Http Port")} />
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
autoComplete="new-password"
|
||||
size="small"
|
||||
sx={{ width: 135 }}
|
||||
value={port}
|
||||
@@ -193,7 +225,7 @@ export const ClashPortViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("Redir Port")} />
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
autoComplete="new-password"
|
||||
size="small"
|
||||
sx={{ width: 135 }}
|
||||
value={redirPort}
|
||||
@@ -218,7 +250,7 @@ export const ClashPortViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("Tproxy Port")} />
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
autoComplete="new-password"
|
||||
size="small"
|
||||
sx={{ width: 135 }}
|
||||
value={tproxyPort}
|
||||
|
||||
@@ -20,9 +20,10 @@ export const ConfigViewer = forwardRef<DialogRef>((_, ref) => {
|
||||
close: () => setOpen(false),
|
||||
}));
|
||||
|
||||
if (!open) return null;
|
||||
return (
|
||||
<EditorViewer
|
||||
open={open}
|
||||
open={true}
|
||||
title={
|
||||
<Box>
|
||||
{t("Runtime Config")}
|
||||
|
||||
@@ -48,7 +48,7 @@ export const ControllerViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("External Controller")} />
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
autoComplete="new-password"
|
||||
size="small"
|
||||
sx={{ width: 175 }}
|
||||
value={controller}
|
||||
@@ -60,7 +60,7 @@ export const ControllerViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("Core Secret")} />
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
autoComplete="new-password"
|
||||
size="small"
|
||||
sx={{ width: 175 }}
|
||||
value={secret}
|
||||
|
||||
@@ -198,7 +198,7 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
/>
|
||||
<TooltipIcon title={t("Default Latency Test Info")} />
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
autoComplete="new-password"
|
||||
size="small"
|
||||
autoCorrect="off"
|
||||
autoCapitalize="off"
|
||||
@@ -215,7 +215,7 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("Default Latency Timeout")} />
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
autoComplete="new-password"
|
||||
size="small"
|
||||
type="number"
|
||||
autoCorrect="off"
|
||||
|
||||
@@ -188,7 +188,7 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("Guard Duration")} />
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
autoComplete="new-password"
|
||||
disabled={!enabled}
|
||||
size="small"
|
||||
value={value.duration}
|
||||
@@ -219,7 +219,7 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
<>
|
||||
<ListItemText primary={t("Proxy Bypass")} />
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
autoComplete="new-password"
|
||||
error={value.bypass ? !validReg.test(value.bypass) : false}
|
||||
disabled={!enabled}
|
||||
size="small"
|
||||
@@ -234,7 +234,7 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
<ListItemText primary={t("Bypass")} />
|
||||
<FlexBox>
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
autoComplete="new-password"
|
||||
disabled={true}
|
||||
size="small"
|
||||
multiline
|
||||
@@ -261,20 +261,22 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
>
|
||||
{t("Edit")} PAC
|
||||
</Button>
|
||||
<EditorViewer
|
||||
open={editorOpen}
|
||||
title={`${t("Edit")} PAC`}
|
||||
initialData={Promise.resolve(value.pac_content ?? "")}
|
||||
language="javascript"
|
||||
onSave={(_prev, curr) => {
|
||||
let pac = DEFAULT_PAC;
|
||||
if (curr && curr.trim().length > 0) {
|
||||
pac = curr;
|
||||
}
|
||||
setValue((v) => ({ ...v, pac_content: pac }));
|
||||
}}
|
||||
onClose={() => setEditorOpen(false)}
|
||||
/>
|
||||
{editorOpen && (
|
||||
<EditorViewer
|
||||
open={true}
|
||||
title={`${t("Edit")} PAC`}
|
||||
initialData={Promise.resolve(value.pac_content ?? "")}
|
||||
language="javascript"
|
||||
onSave={(_prev, curr) => {
|
||||
let pac = DEFAULT_PAC;
|
||||
if (curr && curr.trim().length > 0) {
|
||||
pac = curr;
|
||||
}
|
||||
setValue((v) => ({ ...v, pac_content: pac }));
|
||||
}}
|
||||
onClose={() => setEditorOpen(false)}
|
||||
/>
|
||||
)}
|
||||
</ListItem>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -123,19 +123,21 @@ export const ThemeViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
>
|
||||
{t("Edit")} CSS
|
||||
</Button>
|
||||
<EditorViewer
|
||||
open={editorOpen}
|
||||
title={`${t("Edit")} CSS`}
|
||||
initialData={Promise.resolve(theme.css_injection ?? "")}
|
||||
language="css"
|
||||
onSave={(_prev, curr) => {
|
||||
theme.css_injection = curr;
|
||||
handleChange("css_injection");
|
||||
}}
|
||||
onClose={() => {
|
||||
setEditorOpen(false);
|
||||
}}
|
||||
/>
|
||||
{editorOpen && (
|
||||
<EditorViewer
|
||||
open={true}
|
||||
title={`${t("Edit")} CSS`}
|
||||
initialData={Promise.resolve(theme.css_injection ?? "")}
|
||||
language="css"
|
||||
onSave={(_prev, curr) => {
|
||||
theme.css_injection = curr;
|
||||
handleChange("css_injection");
|
||||
}}
|
||||
onClose={() => {
|
||||
setEditorOpen(false);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Item>
|
||||
</List>
|
||||
</BaseDialog>
|
||||
|
||||
@@ -144,7 +144,7 @@ export const TunViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("Device")} />
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
autoComplete="new-password"
|
||||
size="small"
|
||||
autoCorrect="off"
|
||||
autoCapitalize="off"
|
||||
@@ -190,7 +190,7 @@ export const TunViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("DNS Hijack")} />
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
autoComplete="new-password"
|
||||
size="small"
|
||||
autoCorrect="off"
|
||||
autoCapitalize="off"
|
||||
@@ -207,7 +207,7 @@ export const TunViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("MTU")} />
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
autoComplete="new-password"
|
||||
size="small"
|
||||
type="number"
|
||||
autoCorrect="off"
|
||||
|
||||
@@ -43,7 +43,7 @@ export const WebUIItem = (props: Props) => {
|
||||
<>
|
||||
<Stack spacing={0.75} direction="row" mt={1} mb={1} alignItems="center">
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
autoComplete="new-password"
|
||||
fullWidth
|
||||
size="small"
|
||||
value={editValue}
|
||||
|
||||
@@ -125,7 +125,7 @@ const SettingClash = ({ onError }: Props) => {
|
||||
}
|
||||
>
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
autoComplete="new-password"
|
||||
disabled={enable_random_port}
|
||||
size="small"
|
||||
value={verge_mixed_port ?? 7897}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"millis": "millis",
|
||||
"seconds": "seconds",
|
||||
"mins": "mins",
|
||||
"Back": "Back",
|
||||
"Close": "Close",
|
||||
@@ -54,7 +55,7 @@
|
||||
"Create Profile": "Create Profile",
|
||||
"Edit Profile": "Edit Profile",
|
||||
"Edit Proxies": "Edit Proxies",
|
||||
"Use newlines for multiple uri": "Use newlines for multiple uri",
|
||||
"Use newlines for multiple uri": "Use newlines for multiple uri(Base64 encoding supported)",
|
||||
"Edit Rules": "Edit Rules",
|
||||
"Rule Type": "Rule Type",
|
||||
"Rule Content": "Rule Content",
|
||||
@@ -109,10 +110,16 @@
|
||||
"PASS": "Skips this rule when matched",
|
||||
"Edit Groups": "Edit Proxy Groups",
|
||||
"Group Type": "Group Type",
|
||||
"select": "Select proxy manually",
|
||||
"url-test": "Select proxy based on URL test delay",
|
||||
"fallback": "Switch to another proxy on error",
|
||||
"load-balance": "Distribute proxy based on load balancing",
|
||||
"relay": "Pass through the defined proxy chain",
|
||||
"Group Name": "Group Name",
|
||||
"Use Proxies": "Use Proxies",
|
||||
"Use Provider": "Use Provider",
|
||||
"Health Check Url": "Health Check Url",
|
||||
"Expected Status": "Expected Status",
|
||||
"Interval": "Interval",
|
||||
"Lazy": "Lazy",
|
||||
"Timeout": "Timeout",
|
||||
@@ -124,9 +131,10 @@
|
||||
"Include All Proxies": "Include All Proxies",
|
||||
"Exclude Filter": "Exclude Filter",
|
||||
"Exclude Type": "Exclude Type",
|
||||
"Expected Status": "Expected Status",
|
||||
"Disable UDP": "Disable UDP",
|
||||
"Hidden": "Hidden",
|
||||
"Group Name Required": "Group Name Required",
|
||||
"Group Name Already Exists": "Group Name Already Exists",
|
||||
"Extend Config": "Extend Config",
|
||||
"Extend Script": "Extend Script",
|
||||
"Global Merge": "Global Extend Config",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"millis": "میلیثانیه",
|
||||
"seconds": "ثانیهها",
|
||||
"mins": "دقیقه",
|
||||
"Back": "بازگشت",
|
||||
"Close": "بستن",
|
||||
@@ -54,7 +55,7 @@
|
||||
"Create Profile": "ایجاد پروفایل",
|
||||
"Edit Profile": "ویرایش پروفایل",
|
||||
"Edit Proxies": "ویرایش پروکسیها",
|
||||
"Use newlines for multiple uri": "استفاده از خطوط جدید برای چندین آدرس",
|
||||
"Use newlines for multiple uri": "استفاده از خطوط جدید برای چندین آدرس (پشتیبانی از رمزگذاری Base64)",
|
||||
"Edit Rules": "ویرایش قوانین",
|
||||
"Rule Type": "نوع قانون",
|
||||
"Rule Content": "محتوای قانون",
|
||||
@@ -107,10 +108,16 @@
|
||||
"PASS": "این قانون را در صورت تطابق نادیده میگیرد",
|
||||
"Edit Groups": "ویرایش گروههای پروکسی",
|
||||
"Group Type": "نوع گروه",
|
||||
"select": "انتخاب پروکسی به صورت دستی",
|
||||
"url-test": "انتخاب پروکسی بر اساس تأخیر آزمایش URL",
|
||||
"fallback": "تعویض به پروکسی دیگر در صورت بروز خطا",
|
||||
"load-balance": "توزیع پروکسی بر اساس توازن بار",
|
||||
"relay": "عبور از زنجیره پروکسی تعریف شده",
|
||||
"Group Name": "نام گروه",
|
||||
"Use Proxies": "استفاده از پروکسیها",
|
||||
"Use Provider": "استفاده از ارائهدهنده",
|
||||
"Health Check Url": "آدرس بررسی سلامت",
|
||||
"Expected Status": "وضعیت مورد انتظار",
|
||||
"Interval": "فاصله زمانی",
|
||||
"Lazy": "تنبل",
|
||||
"Timeout": "زمان قطع",
|
||||
@@ -122,9 +129,10 @@
|
||||
"Include All Proxies": "شامل همه پروکسیها",
|
||||
"Exclude Filter": "فیلتر استثناء",
|
||||
"Exclude Type": "نوع استثناء",
|
||||
"Expected Status": "وضعیت مورد انتظار",
|
||||
"Disable UDP": "غیرفعال کردن UDP",
|
||||
"Hidden": "مخفی",
|
||||
"Group Name Required": "نام گروه مورد نیاز است",
|
||||
"Group Name Already Exists": "نام گروه قبلا وجود دارد",
|
||||
"Extend Config": "توسعه پیکربندی",
|
||||
"Extend Script": "ادغام اسکریپت",
|
||||
"Global Merge": "تنظیمات گستردهی سراسری",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"millis": "миллисекунды",
|
||||
"seconds": "секунды",
|
||||
"mins": "минуты",
|
||||
"Back": "Назад",
|
||||
"Close": "Закрыть",
|
||||
@@ -54,7 +55,7 @@
|
||||
"Create Profile": "Создать профиль",
|
||||
"Edit Profile": "Изменить профиль",
|
||||
"Edit Proxies": "Редактировать прокси",
|
||||
"Use newlines for multiple uri": "Используйте новые строки для нескольких URI",
|
||||
"Use newlines for multiple uri": "Используйте символы новой строки для нескольких URI (поддерживается кодировка Base64)",
|
||||
"Edit Rules": "Редактировать правила",
|
||||
"Rule Type": "Тип правила",
|
||||
"Rule Content": "Содержимое правила",
|
||||
@@ -107,10 +108,16 @@
|
||||
"PASS": "Пропускает это правило при совпадении",
|
||||
"Edit Groups": "Редактировать группы прокси",
|
||||
"Group Type": "Тип группы",
|
||||
"select": "Выбор прокси вручную",
|
||||
"url-test": "Выбор прокси на основе задержки теста URL",
|
||||
"fallback": "Переключение на другой прокси при ошибке",
|
||||
"load-balance": "Распределение прокси на основе балансировки нагрузки",
|
||||
"relay": "Передача через определенную цепочку прокси",
|
||||
"Group Name": "Имя группы",
|
||||
"Use Proxies": "Использовать прокси",
|
||||
"Use Provider": "Использовать провайдера",
|
||||
"Health Check Url": "URL проверки здоровья",
|
||||
"Expected Status": "Ожидаемый статус",
|
||||
"Interval": "Интервал",
|
||||
"Lazy": "Ленивый",
|
||||
"Timeout": "Таймаут",
|
||||
@@ -122,9 +129,10 @@
|
||||
"Include All Proxies": "Включить все прокси",
|
||||
"Exclude Filter": "Исключить фильтр",
|
||||
"Exclude Type": "Тип исключения",
|
||||
"Expected Status": "Ожидаемый статус",
|
||||
"Disable UDP": "Отключить UDP",
|
||||
"Hidden": "Скрытый",
|
||||
"Group Name Required": "Требуется имя группы",
|
||||
"Group Name Already Exists": "Имя группы уже существует",
|
||||
"Extend Config": "Изменить Merge.",
|
||||
"Extend Script": "Изменить Script",
|
||||
"Global Merge": "Глобальный расширенный Настройки",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"millis": "毫秒",
|
||||
"mins": "分钟",
|
||||
"seconds": "秒",
|
||||
"Back": "返回",
|
||||
"Close": "关闭",
|
||||
"Cancel": "取消",
|
||||
@@ -54,7 +55,7 @@
|
||||
"Create Profile": "新建配置",
|
||||
"Edit Profile": "编辑配置",
|
||||
"Edit Proxies": "编辑节点",
|
||||
"Use newlines for multiple uri": "多条URI请使用换行分隔",
|
||||
"Use newlines for multiple uri": "多条URI请使用换行分隔(支持Base64编码)",
|
||||
"Edit Rules": "编辑规则",
|
||||
"Rule Type": "规则类型",
|
||||
"Rule Content": "规则内容",
|
||||
@@ -109,25 +110,32 @@
|
||||
"PASS": "跳过此规则",
|
||||
"Edit Groups": "编辑代理组",
|
||||
"Group Type": "代理组类型",
|
||||
"select": "手动选择代理",
|
||||
"url-test": "根据URL测试延迟选择代理",
|
||||
"fallback": "不可用时切换到另一个代理",
|
||||
"load-balance": "根据负载均衡分配代理",
|
||||
"relay": "根据定义的代理链传递",
|
||||
"Group Name": "代理组组名",
|
||||
"Use Proxies": "引入代理",
|
||||
"Use Provider": "引入代理集合",
|
||||
"Health Check Url": "健康检查测试地址",
|
||||
"Expected Status": "期望状态码",
|
||||
"Interval": "检查间隔",
|
||||
"Lazy": "懒惰状态",
|
||||
"Timeout": "超时时间",
|
||||
"Max Failed Times": "最大失败次数",
|
||||
"Interface Name": "出站接口",
|
||||
"Routing Mark": "路由标记",
|
||||
"Include All": "引入所有出站代理以及代理集合",
|
||||
"Include All": "引入所有出站代理、代理集合",
|
||||
"Include All Providers": "引入所有代理集合",
|
||||
"Include All Proxies": "引入所有出站代理",
|
||||
"Exclude Filter": "排除节点",
|
||||
"Exclude Type": "排除节点类型",
|
||||
"Expected Status": "期望状态码",
|
||||
"Disable UDP": "禁用UDP",
|
||||
"Hidden": "隐藏该组",
|
||||
"Hidden": "隐藏代理组",
|
||||
"Extend Config": "扩展配置",
|
||||
"Group Name Required": "代理组名称不能为空",
|
||||
"Group Name Already Exists": "代理组名称已存在",
|
||||
"Extend Script": "扩展脚本",
|
||||
"Global Merge": "全局扩展配置",
|
||||
"Global Script": "全局扩展脚本",
|
||||
|
||||
@@ -171,10 +171,11 @@ const ProfilePage = () => {
|
||||
}, 100);
|
||||
try {
|
||||
await patchProfiles({ current });
|
||||
mutateLogs();
|
||||
await mutateLogs();
|
||||
closeAllConnections();
|
||||
setTimeout(() => activateSelected(), 2000);
|
||||
Notice.success(t("Profile Switched"), 1000);
|
||||
activateSelected().then(() => {
|
||||
Notice.success(t("Profile Switched"), 1000);
|
||||
});
|
||||
} catch (err: any) {
|
||||
Notice.error(err?.message || err.toString(), 4000);
|
||||
} finally {
|
||||
|
||||
@@ -233,3 +233,7 @@ export async function copyIconFile(
|
||||
export async function downloadIconCache(url: string, name: string) {
|
||||
return invoke<string>("download_icon_cache", { url, name });
|
||||
}
|
||||
|
||||
export async function getNetworkInterfaces() {
|
||||
return invoke<string[]>("get_network_interfaces");
|
||||
}
|
||||
|
||||
21
clash-verge-rev/src/services/types.d.ts
vendored
@@ -260,8 +260,17 @@ interface RealityOptions {
|
||||
"public-key"?: string;
|
||||
"short-id"?: string;
|
||||
}
|
||||
|
||||
type NetworkType = "ws" | "http" | "h2" | "grpc";
|
||||
type ClientFingerprint =
|
||||
| "chrome"
|
||||
| "firefox"
|
||||
| "safari"
|
||||
| "iOS"
|
||||
| "android"
|
||||
| "edge"
|
||||
| "360"
|
||||
| "qq"
|
||||
| "random";
|
||||
type NetworkType = "ws" | "http" | "h2" | "grpc" | "tcp";
|
||||
type CipherType =
|
||||
| "none"
|
||||
| "auto"
|
||||
@@ -376,7 +385,7 @@ interface IProxyTrojanConfig extends IProxyBaseConfig {
|
||||
method?: string;
|
||||
password?: string;
|
||||
};
|
||||
"client-fingerprint"?: string;
|
||||
"client-fingerprint"?: ClientFingerprint;
|
||||
}
|
||||
// tuic
|
||||
interface IProxyTuicConfig extends IProxyBaseConfig {
|
||||
@@ -438,7 +447,7 @@ interface IProxyVlessConfig extends IProxyBaseConfig {
|
||||
"skip-cert-verify"?: boolean;
|
||||
fingerprint?: string;
|
||||
servername?: string;
|
||||
"client-fingerprint"?: string;
|
||||
"client-fingerprint"?: ClientFingerprint;
|
||||
}
|
||||
// vmess
|
||||
interface IProxyVmessConfig extends IProxyBaseConfig {
|
||||
@@ -466,7 +475,7 @@ interface IProxyVmessConfig extends IProxyBaseConfig {
|
||||
"packet-encoding"?: string;
|
||||
"global-padding"?: boolean;
|
||||
"authenticated-length"?: boolean;
|
||||
"client-fingerprint"?: string;
|
||||
"client-fingerprint"?: ClientFingerprint;
|
||||
}
|
||||
interface WireGuardPeerOptions {
|
||||
server?: string;
|
||||
@@ -574,7 +583,7 @@ interface IProxyShadowsocksConfig extends IProxyBaseConfig {
|
||||
};
|
||||
"udp-over-tcp"?: boolean;
|
||||
"udp-over-tcp-version"?: number;
|
||||
"client-fingerprint"?: string;
|
||||
"client-fingerprint"?: ClientFingerprint;
|
||||
}
|
||||
// shadowsocksR
|
||||
interface IProxyshadowsocksRConfig extends IProxyBaseConfig {
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
// global initializer
|
||||
{{
|
||||
function $set(obj, path, value) {
|
||||
if (Object(obj) !== obj) return obj;
|
||||
if (!Array.isArray(path)) path = path.toString().match(/[^.[\]]+/g) || [];
|
||||
path
|
||||
.slice(0, -1)
|
||||
.reduce((a, c, i) => (Object(a[c]) === a[c] ? a[c] : (a[c] = Math.abs(path[i + 1]) >> 0 === +path[i + 1] ? [] : {})), obj)[
|
||||
path[path.length - 1]
|
||||
] = value;
|
||||
return obj;
|
||||
}
|
||||
|
||||
function toBool(str) {
|
||||
if (typeof str === 'undefined' || str === null) return undefined;
|
||||
return /(TRUE)|1/i.test(str);
|
||||
}
|
||||
}}
|
||||
|
||||
{
|
||||
const proxy = {};
|
||||
const obfs = {};
|
||||
const $ = {};
|
||||
const params = {};
|
||||
}
|
||||
|
||||
start = (trojan) {
|
||||
return proxy
|
||||
}
|
||||
|
||||
trojan = "trojan://" password:password "@" server:server ":" port:port "/"? params? name:name?{
|
||||
proxy.type = "trojan";
|
||||
proxy.password = password;
|
||||
proxy.server = server;
|
||||
proxy.port = port;
|
||||
proxy.name = name;
|
||||
|
||||
// name may be empty
|
||||
if (!proxy.name) {
|
||||
proxy.name = server + ":" + port;
|
||||
}
|
||||
};
|
||||
|
||||
password = match:$[^@]+ {
|
||||
return decodeURIComponent(match);
|
||||
};
|
||||
|
||||
server = ip/domain;
|
||||
|
||||
domain = match:[0-9a-zA-z-_.]+ {
|
||||
const domain = match.join("");
|
||||
if (/(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]/.test(domain)) {
|
||||
return domain;
|
||||
}
|
||||
}
|
||||
|
||||
ip = & {
|
||||
const start = peg$currPos;
|
||||
let end;
|
||||
let j = start;
|
||||
while (j < input.length) {
|
||||
if (input[j] === ",") break;
|
||||
if (input[j] === ":") end = j;
|
||||
j++;
|
||||
}
|
||||
peg$currPos = end || j;
|
||||
$.ip = input.substring(start, end).trim();
|
||||
return true;
|
||||
} { return $.ip; }
|
||||
|
||||
port = digits:[0-9]+ {
|
||||
const port = parseInt(digits.join(""), 10);
|
||||
if (port >= 0 && port <= 65535) {
|
||||
return port;
|
||||
} else {
|
||||
throw new Error("Invalid port: " + port);
|
||||
}
|
||||
}
|
||||
|
||||
params = "?" head:param tail:("&"@param)* {
|
||||
proxy["skip-cert-verify"] = toBool(params["allowInsecure"]);
|
||||
proxy.sni = params["sni"] || params["peer"];
|
||||
|
||||
if (toBool(params["ws"])) {
|
||||
proxy.network = "ws";
|
||||
$set(proxy, "ws-opts.path", params["wspath"]);
|
||||
}
|
||||
|
||||
if (params["type"]) {
|
||||
let httpupgrade
|
||||
proxy.network = params["type"]
|
||||
if(proxy.network === 'httpupgrade') {
|
||||
proxy.network = 'ws'
|
||||
httpupgrade = true
|
||||
}
|
||||
if (['grpc'].includes(proxy.network)) {
|
||||
proxy[proxy.network + '-opts'] = {
|
||||
'grpc-service-name': params["serviceName"],
|
||||
'_grpc-type': params["mode"],
|
||||
};
|
||||
} else {
|
||||
if (params["path"]) {
|
||||
$set(proxy, proxy.network+"-opts.path", decodeURIComponent(params["path"]));
|
||||
}
|
||||
if (params["host"]) {
|
||||
$set(proxy, proxy.network+"-opts.headers.Host", decodeURIComponent(params["host"]));
|
||||
}
|
||||
if (httpupgrade) {
|
||||
$set(proxy, proxy.network+"-opts.v2ray-http-upgrade", true);
|
||||
$set(proxy, proxy.network+"-opts.v2ray-http-upgrade-fast-open", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proxy.udp = toBool(params["udp"]);
|
||||
proxy.tfo = toBool(params["tfo"]);
|
||||
}
|
||||
|
||||
param = kv/single;
|
||||
|
||||
kv = key:$[a-z]i+ "=" value:$[^&#]i* {
|
||||
params[key] = value;
|
||||
}
|
||||
|
||||
single = key:$[a-z]i+ {
|
||||
params[key] = true;
|
||||
};
|
||||
|
||||
name = "#" + match:$.* {
|
||||
return decodeURIComponent(match);
|
||||
}
|
||||
@@ -1,141 +0,0 @@
|
||||
import * as peggy from "peggy";
|
||||
const grammars = String.raw`
|
||||
// global initializer
|
||||
{{
|
||||
function $set(obj, path, value) {
|
||||
if (Object(obj) !== obj) return obj;
|
||||
if (!Array.isArray(path)) path = path.toString().match(/[^.[\]]+/g) || [];
|
||||
path
|
||||
.slice(0, -1)
|
||||
.reduce((a, c, i) => (Object(a[c]) === a[c] ? a[c] : (a[c] = Math.abs(path[i + 1]) >> 0 === +path[i + 1] ? [] : {})), obj)[
|
||||
path[path.length - 1]
|
||||
] = value;
|
||||
return obj;
|
||||
}
|
||||
|
||||
function toBool(str) {
|
||||
if (typeof str === 'undefined' || str === null) return undefined;
|
||||
return /(TRUE)|1/i.test(str);
|
||||
}
|
||||
}}
|
||||
|
||||
{
|
||||
const proxy = {};
|
||||
const obfs = {};
|
||||
const $ = {};
|
||||
const params = {};
|
||||
}
|
||||
|
||||
start = (trojan) {
|
||||
return proxy
|
||||
}
|
||||
|
||||
trojan = "trojan://" password:password "@" server:server ":" port:port "/"? params? name:name?{
|
||||
proxy.type = "trojan";
|
||||
proxy.password = password;
|
||||
proxy.server = server;
|
||||
proxy.port = port;
|
||||
proxy.name = name;
|
||||
|
||||
// name may be empty
|
||||
if (!proxy.name) {
|
||||
proxy.name = server + ":" + port;
|
||||
}
|
||||
};
|
||||
|
||||
password = match:$[^@]+ {
|
||||
return decodeURIComponent(match);
|
||||
};
|
||||
|
||||
server = ip/domain;
|
||||
|
||||
domain = match:[0-9a-zA-z-_.]+ {
|
||||
const domain = match.join("");
|
||||
if (/(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]/.test(domain)) {
|
||||
return domain;
|
||||
}
|
||||
}
|
||||
|
||||
ip = & {
|
||||
const start = peg$currPos;
|
||||
let end;
|
||||
let j = start;
|
||||
while (j < input.length) {
|
||||
if (input[j] === ",") break;
|
||||
if (input[j] === ":") end = j;
|
||||
j++;
|
||||
}
|
||||
peg$currPos = end || j;
|
||||
$.ip = input.substring(start, end).trim();
|
||||
return true;
|
||||
} { return $.ip; }
|
||||
|
||||
port = digits:[0-9]+ {
|
||||
const port = parseInt(digits.join(""), 10);
|
||||
if (port >= 0 && port <= 65535) {
|
||||
return port;
|
||||
} else {
|
||||
throw new Error("Invalid port: " + port);
|
||||
}
|
||||
}
|
||||
|
||||
params = "?" head:param tail:("&"@param)* {
|
||||
proxy["skip-cert-verify"] = toBool(params["allowInsecure"]);
|
||||
proxy.sni = params["sni"] || params["peer"];
|
||||
|
||||
if (toBool(params["ws"])) {
|
||||
proxy.network = "ws";
|
||||
$set(proxy, "ws-opts.path", params["wspath"]);
|
||||
}
|
||||
|
||||
if (params["type"]) {
|
||||
let httpupgrade
|
||||
proxy.network = params["type"]
|
||||
if(proxy.network === 'httpupgrade') {
|
||||
proxy.network = 'ws'
|
||||
httpupgrade = true
|
||||
}
|
||||
if (['grpc'].includes(proxy.network)) {
|
||||
proxy[proxy.network + '-opts'] = {
|
||||
'grpc-service-name': params["serviceName"],
|
||||
'_grpc-type': params["mode"],
|
||||
};
|
||||
} else {
|
||||
if (params["path"]) {
|
||||
$set(proxy, proxy.network+"-opts.path", decodeURIComponent(params["path"]));
|
||||
}
|
||||
if (params["host"]) {
|
||||
$set(proxy, proxy.network+"-opts.headers.Host", decodeURIComponent(params["host"]));
|
||||
}
|
||||
if (httpupgrade) {
|
||||
$set(proxy, proxy.network+"-opts.v2ray-http-upgrade", true);
|
||||
$set(proxy, proxy.network+"-opts.v2ray-http-upgrade-fast-open", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proxy.udp = toBool(params["udp"]);
|
||||
proxy.tfo = toBool(params["tfo"]);
|
||||
}
|
||||
|
||||
param = kv/single;
|
||||
|
||||
kv = key:$[a-z]i+ "=" value:$[^&#]i* {
|
||||
params[key] = value;
|
||||
}
|
||||
|
||||
single = key:$[a-z]i+ {
|
||||
params[key] = true;
|
||||
};
|
||||
|
||||
name = "#" + match:$.* {
|
||||
return decodeURIComponent(match);
|
||||
}
|
||||
`;
|
||||
let parser: any;
|
||||
export default function getParser() {
|
||||
if (!parser) {
|
||||
parser = peggy.generate(grammars);
|
||||
}
|
||||
return parser;
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
import getTrojanURIParser from "@/utils/trojan-uri";
|
||||
|
||||
export default function parseUri(uri: string): IProxyConfig {
|
||||
const head = uri.split("://")[0];
|
||||
switch (head) {
|
||||
@@ -467,7 +465,19 @@ function URI_VMESS(line: string): IProxyVmessConfig {
|
||||
opts["v2ray-http-upgrade"] = true;
|
||||
opts["v2ray-http-upgrade-fast-open"] = true;
|
||||
}
|
||||
proxy[`${proxy.network}-opts`] = opts;
|
||||
switch (proxy.network) {
|
||||
case "ws":
|
||||
proxy["ws-opts"] = opts;
|
||||
break;
|
||||
case "http":
|
||||
proxy["http-opts"] = opts;
|
||||
break;
|
||||
case "h2":
|
||||
proxy["h2-opts"] = opts;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
delete proxy.network;
|
||||
@@ -530,16 +540,7 @@ function URI_VLESS(line: string): IProxyVlessConfig {
|
||||
proxy.servername = params.sni || params.peer;
|
||||
proxy.flow = params.flow ? "xtls-rprx-vision" : undefined;
|
||||
|
||||
proxy["client-fingerprint"] = params.fp as
|
||||
| "chrome"
|
||||
| "firefox"
|
||||
| "safari"
|
||||
| "iOS"
|
||||
| "android"
|
||||
| "edge"
|
||||
| "360"
|
||||
| "qq"
|
||||
| "random";
|
||||
proxy["client-fingerprint"] = params.fp as ClientFingerprint;
|
||||
proxy.alpn = params.alpn ? params.alpn.split(",") : undefined;
|
||||
proxy["skip-cert-verify"] = /(TRUE)|1/i.test(params.allowInsecure);
|
||||
|
||||
@@ -635,16 +636,89 @@ function URI_VLESS(line: string): IProxyVlessConfig {
|
||||
}
|
||||
|
||||
function URI_Trojan(line: string): IProxyTrojanConfig {
|
||||
let [newLine, name] = line.split(/#(.+)/, 2);
|
||||
const parser = getTrojanURIParser();
|
||||
const proxy: IProxyTrojanConfig = parser.parse(newLine);
|
||||
if (isNotBlank(name)) {
|
||||
try {
|
||||
proxy.name = decodeURIComponent(name).trim();
|
||||
} catch (e) {
|
||||
throw Error("Can not get proxy name");
|
||||
line = line.split("trojan://")[1];
|
||||
let [__, password, server, ___, port, ____, addons = "", name] =
|
||||
/^(.*?)@(.*?)(:(\d+))?\/?(\?(.*?))?(?:#(.*?))?$/.exec(line) || [];
|
||||
|
||||
let portNum = parseInt(`${port}`, 10);
|
||||
if (isNaN(portNum)) {
|
||||
portNum = 443;
|
||||
}
|
||||
|
||||
password = decodeURIComponent(password);
|
||||
|
||||
let decodedName = trimStr(decodeURIComponent(name));
|
||||
|
||||
name = decodedName ?? `Trojan ${server}:${portNum}`;
|
||||
const proxy: IProxyTrojanConfig = {
|
||||
type: "trojan",
|
||||
name,
|
||||
server,
|
||||
port: portNum,
|
||||
password,
|
||||
};
|
||||
let host = "";
|
||||
let path = "";
|
||||
|
||||
for (const addon of addons.split("&")) {
|
||||
let [key, value] = addon.split("=");
|
||||
value = decodeURIComponent(value);
|
||||
switch (key) {
|
||||
case "type":
|
||||
if (["ws", "h2"].includes(value)) {
|
||||
proxy.network = value as NetworkType;
|
||||
} else {
|
||||
proxy.network = "tcp";
|
||||
}
|
||||
break;
|
||||
case "host":
|
||||
host = value;
|
||||
break;
|
||||
case "path":
|
||||
path = value;
|
||||
break;
|
||||
case "alpn":
|
||||
proxy["alpn"] = value ? value.split(",") : undefined;
|
||||
break;
|
||||
case "sni":
|
||||
proxy["sni"] = value;
|
||||
break;
|
||||
case "skip-cert-verify":
|
||||
proxy["skip-cert-verify"] = /(TRUE)|1/i.test(value);
|
||||
break;
|
||||
case "fingerprint":
|
||||
proxy["fingerprint"] = value;
|
||||
break;
|
||||
case "fp":
|
||||
proxy["fingerprint"] = value;
|
||||
break;
|
||||
case "encryption":
|
||||
let encryption = value.split(";");
|
||||
if (encryption.length === 3) {
|
||||
proxy["ss-opts"] = {
|
||||
enabled: true,
|
||||
method: encryption[1],
|
||||
password: encryption[2],
|
||||
};
|
||||
}
|
||||
case "client-fingerprint":
|
||||
proxy["client-fingerprint"] = value as ClientFingerprint;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (proxy.network === "ws") {
|
||||
proxy["ws-opts"] = {
|
||||
headers: { Host: host },
|
||||
path,
|
||||
} as WsOptions;
|
||||
} else if (proxy.network === "grpc") {
|
||||
proxy["grpc-opts"] = {
|
||||
"grpc-service-name": path,
|
||||
} as GrpcOptions;
|
||||
}
|
||||
|
||||
return proxy;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
LINUX_VERSION-6.1 = .96
|
||||
LINUX_KERNEL_HASH-6.1.96 = 3e77c9069de5e7ab02ff9c2dcfe77dab193613fc1de21071901b4153374862a9
|
||||
LINUX_VERSION-6.1 = .97
|
||||
LINUX_KERNEL_HASH-6.1.97 = 890b845f36452328716e62dd893b634584f607cdd44b4e685392d302d3be41af
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
LINUX_VERSION-6.6 = .36
|
||||
LINUX_KERNEL_HASH-6.6.36 = b9676828b737e8fb8eaa5198303d35d35e8df019550be153c8a42c99afe0cdd5
|
||||
LINUX_VERSION-6.6 = .37
|
||||
LINUX_KERNEL_HASH-6.6.37 = f3976e77708694fe4a1f8d1307c315c8a36cbc58f038a38e006b91e29a1f3214
|
||||
|
||||
@@ -13,6 +13,7 @@ elif grep -q "mvebu" "/etc/openwrt_release"; then
|
||||
elif grep -q "filogic" "/etc/openwrt_release"; then
|
||||
[ -f "/sys/devices/system/cpu/cpufreq/policy0/cpuinfo_cur_freq" ] && big_cpu_freq="$(expr $(cat /sys/devices/system/cpu/cpufreq/policy0/cpuinfo_cur_freq) / 1000)MHz"
|
||||
elif grep -q "rockchip" "/etc/openwrt_release"; then
|
||||
cpu_freq="$(expr $(cat /sys/devices/system/cpu/cpufreq/policy0/cpuinfo_cur_freq) / 1000)MHz"
|
||||
big_cpu_freq="$(expr $(cat /sys/devices/system/cpu/cpufreq/policy4/cpuinfo_cur_freq 2>"/dev/null") / 1000 2>"/dev/null")"
|
||||
[ -n "${big_cpu_freq}" ] && big_cpu_freq="${big_cpu_freq}MHz "
|
||||
else
|
||||
@@ -34,11 +35,11 @@ else
|
||||
fi
|
||||
if grep -q "filogic" "/etc/openwrt_release"; then
|
||||
if [ -n "${big_cpu_freq}" ] ; then
|
||||
echo -n "${cpu_arch} x ${cpu_cores} (${big_cpu_freq}, ${cpu_temp})"
|
||||
else
|
||||
echo -n "${cpu_arch} x ${cpu_cores} (${cpu_temp})"
|
||||
fi
|
||||
else
|
||||
echo -n "${cpu_arch} x ${cpu_cores} (${big_cpu_freq}${cpu_freq}, ${cpu_temp})"
|
||||
echo -n "${cpu_arch} x ${cpu_cores} (${big_cpu_freq}, ${cpu_temp})"
|
||||
else
|
||||
echo -n "${cpu_arch} x ${cpu_cores} (${cpu_temp})"
|
||||
fi
|
||||
else
|
||||
echo -n "${cpu_arch} x ${cpu_cores} (${big_cpu_freq}${cpu_freq}, ${cpu_temp})"
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -1987,7 +1987,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
|
||||
#define MAX_TUNING_LOOP 40
|
||||
|
||||
@@ -3233,7 +3233,7 @@ static void sdhci_timeout_timer(struct t
|
||||
@@ -3236,7 +3236,7 @@ static void sdhci_timeout_timer(struct t
|
||||
spin_lock_irqsave(&host->lock, flags);
|
||||
|
||||
if (host->cmd && !sdhci_data_line_cmd(host->cmd)) {
|
||||
@@ -1996,7 +1996,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
mmc_hostname(host->mmc));
|
||||
sdhci_err_stats_inc(host, REQ_TIMEOUT);
|
||||
sdhci_dumpregs(host);
|
||||
@@ -3256,7 +3256,7 @@ static void sdhci_timeout_data_timer(str
|
||||
@@ -3259,7 +3259,7 @@ static void sdhci_timeout_data_timer(str
|
||||
|
||||
if (host->data || host->data_cmd ||
|
||||
(host->cmd && sdhci_data_line_cmd(host->cmd))) {
|
||||
|
||||
@@ -15,7 +15,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
|
||||
--- a/drivers/gpu/drm/panel/panel-simple.c
|
||||
+++ b/drivers/gpu/drm/panel/panel-simple.c
|
||||
@@ -3196,6 +3196,31 @@ static const struct panel_desc qishenglo
|
||||
@@ -3197,6 +3197,31 @@ static const struct panel_desc qishenglo
|
||||
.connector_type = DRM_MODE_CONNECTOR_DPI,
|
||||
};
|
||||
|
||||
@@ -47,7 +47,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
static const struct display_timing rocktech_rk070er9427_timing = {
|
||||
.pixelclock = { 26400000, 33300000, 46800000 },
|
||||
.hactive = { 800, 800, 800 },
|
||||
@@ -4229,6 +4254,9 @@ static const struct of_device_id platfor
|
||||
@@ -4230,6 +4255,9 @@ static const struct of_device_id platfor
|
||||
.compatible = "qishenglong,gopher2b-lcd",
|
||||
.data = &qishenglong_gopher2b_lcd,
|
||||
}, {
|
||||
|
||||
@@ -46,7 +46,7 @@ Acked-by: Maxime Ripard <maxime@cerno.tech>
|
||||
static const struct drm_display_mode giantplus_gpg482739qs5_mode = {
|
||||
.clock = 9000,
|
||||
.hdisplay = 480,
|
||||
@@ -4113,6 +4139,9 @@ static const struct of_device_id platfor
|
||||
@@ -4114,6 +4140,9 @@ static const struct of_device_id platfor
|
||||
.compatible = "friendlyarm,hd702e",
|
||||
.data = &friendlyarm_hd702e,
|
||||
}, {
|
||||
|
||||
@@ -48,7 +48,7 @@ Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
|
||||
static bool _init_on_alloc_enabled_early __read_mostly
|
||||
= IS_ENABLED(CONFIG_INIT_ON_ALLOC_DEFAULT_ON);
|
||||
static int __init early_init_on_alloc(char *buf)
|
||||
@@ -3073,12 +3094,13 @@ __rmqueue(struct zone *zone, unsigned in
|
||||
@@ -3077,12 +3098,13 @@ __rmqueue(struct zone *zone, unsigned in
|
||||
if (IS_ENABLED(CONFIG_CMA)) {
|
||||
/*
|
||||
* Balance movable allocations between regular and CMA areas by
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
From b969ef21e3522c6829aafaa1fecd33fa653596e4 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Williams <mwp@mwp.id.au>
|
||||
Date: Wed, 7 Dec 2022 18:20:40 -0700
|
||||
Subject: [PATCH] drm/panel: panel-ilitek9881c: Use cansleep methods
|
||||
|
||||
Use cansleep version of gpiod_set_value so external IO drivers (like
|
||||
via I2C) can be used.
|
||||
|
||||
Signed-off-by: Mark Williams <mwp@mwp.id.au>
|
||||
---
|
||||
drivers/gpu/drm/panel/panel-ilitek-ili9881c.c | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c
|
||||
+++ b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c
|
||||
@@ -940,10 +940,10 @@ static int ili9881c_prepare(struct drm_p
|
||||
msleep(5);
|
||||
|
||||
/* And reset it */
|
||||
- gpiod_set_value(ctx->reset, 1);
|
||||
+ gpiod_set_value_cansleep(ctx->reset, 1);
|
||||
msleep(20);
|
||||
|
||||
- gpiod_set_value(ctx->reset, 0);
|
||||
+ gpiod_set_value_cansleep(ctx->reset, 0);
|
||||
msleep(20);
|
||||
|
||||
for (i = 0; i < ctx->desc->init_length; i++) {
|
||||
@@ -998,7 +998,7 @@ static int ili9881c_unprepare(struct drm
|
||||
|
||||
mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);
|
||||
regulator_disable(ctx->power);
|
||||
- gpiod_set_value(ctx->reset, 1);
|
||||
+ gpiod_set_value_cansleep(ctx->reset, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -165,7 +165,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
static const struct drm_display_mode innolux_at070tn92_mode = {
|
||||
.clock = 33333,
|
||||
.hdisplay = 800,
|
||||
@@ -4149,6 +4181,9 @@ static const struct of_device_id platfor
|
||||
@@ -4150,6 +4182,9 @@ static const struct of_device_id platfor
|
||||
.compatible = "innolux,at043tn24",
|
||||
.data = &innolux_at043tn24,
|
||||
}, {
|
||||
|
||||
@@ -63,7 +63,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
|
||||
|
||||
#include "sdhci-cqhci.h"
|
||||
#include "sdhci-pltfm.h"
|
||||
@@ -26,18 +28,43 @@
|
||||
@@ -27,18 +29,43 @@
|
||||
|
||||
#define BRCMSTB_PRIV_FLAGS_HAS_CQE BIT(0)
|
||||
#define BRCMSTB_PRIV_FLAGS_GATE_CLOCK BIT(1)
|
||||
@@ -107,7 +107,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
|
||||
struct sdhci_ops *ops;
|
||||
const unsigned int flags;
|
||||
};
|
||||
@@ -94,6 +121,124 @@ static void sdhci_brcmstb_set_clock(stru
|
||||
@@ -95,6 +122,124 @@ static void sdhci_brcmstb_set_clock(stru
|
||||
sdhci_enable_clk(host, clk);
|
||||
}
|
||||
|
||||
@@ -232,7 +232,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
|
||||
static void sdhci_brcmstb_set_uhs_signaling(struct sdhci_host *host,
|
||||
unsigned int timing)
|
||||
{
|
||||
@@ -123,6 +268,146 @@ static void sdhci_brcmstb_set_uhs_signal
|
||||
@@ -124,6 +269,146 @@ static void sdhci_brcmstb_set_uhs_signal
|
||||
sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
|
||||
}
|
||||
|
||||
@@ -379,7 +379,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
|
||||
static void sdhci_brcmstb_dumpregs(struct mmc_host *mmc)
|
||||
{
|
||||
sdhci_dumpregs(mmc_priv(mmc));
|
||||
@@ -155,6 +440,21 @@ static struct sdhci_ops sdhci_brcmstb_op
|
||||
@@ -156,6 +441,21 @@ static struct sdhci_ops sdhci_brcmstb_op
|
||||
.set_uhs_signaling = sdhci_set_uhs_signaling,
|
||||
};
|
||||
|
||||
@@ -401,7 +401,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
|
||||
static struct sdhci_ops sdhci_brcmstb_ops_7216 = {
|
||||
.set_clock = sdhci_brcmstb_set_clock,
|
||||
.set_bus_width = sdhci_set_bus_width,
|
||||
@@ -179,10 +479,16 @@ static const struct brcmstb_match_priv m
|
||||
@@ -180,10 +480,16 @@ static const struct brcmstb_match_priv m
|
||||
.ops = &sdhci_brcmstb_ops_7216,
|
||||
};
|
||||
|
||||
@@ -418,7 +418,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
|
||||
{},
|
||||
};
|
||||
|
||||
@@ -256,6 +562,7 @@ static int sdhci_brcmstb_probe(struct pl
|
||||
@@ -257,6 +563,7 @@ static int sdhci_brcmstb_probe(struct pl
|
||||
u32 actual_clock_mhz;
|
||||
struct sdhci_host *host;
|
||||
struct resource *iomem;
|
||||
@@ -426,7 +426,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
|
||||
struct clk *clk;
|
||||
struct clk *base_clk = NULL;
|
||||
int res;
|
||||
@@ -290,6 +597,11 @@ static int sdhci_brcmstb_probe(struct pl
|
||||
@@ -291,6 +598,11 @@ static int sdhci_brcmstb_probe(struct pl
|
||||
match_priv->ops->irq = sdhci_brcmstb_cqhci_irq;
|
||||
}
|
||||
|
||||
@@ -438,7 +438,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
|
||||
/* Map in the non-standard CFG registers */
|
||||
iomem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
priv->cfg_regs = devm_ioremap_resource(&pdev->dev, iomem);
|
||||
@@ -303,6 +615,43 @@ static int sdhci_brcmstb_probe(struct pl
|
||||
@@ -304,6 +616,43 @@ static int sdhci_brcmstb_probe(struct pl
|
||||
if (res)
|
||||
goto err;
|
||||
|
||||
@@ -482,7 +482,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
|
||||
/*
|
||||
* Automatic clock gating does not work for SD cards that may
|
||||
* voltage switch so only enable it for non-removable devices.
|
||||
@@ -319,6 +668,13 @@ static int sdhci_brcmstb_probe(struct pl
|
||||
@@ -320,6 +669,13 @@ static int sdhci_brcmstb_probe(struct pl
|
||||
(host->mmc->caps2 & MMC_CAP2_HS400_ES))
|
||||
host->mmc_host_ops.hs400_enhanced_strobe = match_priv->hs400es;
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ sdhci: remove PYA0_INTR_BUG quirk. Add quirks to disable some of the higher SDR
|
||||
static int dwcmshc_rk35xx_init(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv)
|
||||
--- a/drivers/mmc/host/sdhci.c
|
||||
+++ b/drivers/mmc/host/sdhci.c
|
||||
@@ -3071,6 +3071,15 @@ static void sdhci_card_event(struct mmc_
|
||||
@@ -3074,6 +3074,15 @@ static void sdhci_card_event(struct mmc_
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ sdhci: remove PYA0_INTR_BUG quirk. Add quirks to disable some of the higher SDR
|
||||
static const struct mmc_host_ops sdhci_ops = {
|
||||
.request = sdhci_request,
|
||||
.post_req = sdhci_post_req,
|
||||
@@ -3086,6 +3095,7 @@ static const struct mmc_host_ops sdhci_o
|
||||
@@ -3089,6 +3098,7 @@ static const struct mmc_host_ops sdhci_o
|
||||
.execute_tuning = sdhci_execute_tuning,
|
||||
.card_event = sdhci_card_event,
|
||||
.card_busy = sdhci_card_busy,
|
||||
@@ -50,7 +50,7 @@ sdhci: remove PYA0_INTR_BUG quirk. Add quirks to disable some of the higher SDR
|
||||
};
|
||||
|
||||
/*****************************************************************************\
|
||||
@@ -4611,6 +4621,15 @@ int sdhci_setup_host(struct sdhci_host *
|
||||
@@ -4614,6 +4624,15 @@ int sdhci_setup_host(struct sdhci_host *
|
||||
!(host->quirks2 & SDHCI_QUIRK2_BROKEN_DDR50))
|
||||
mmc->caps |= MMC_CAP_UHS_DDR50;
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
|
||||
--- a/drivers/gpu/drm/panel/panel-simple.c
|
||||
+++ b/drivers/gpu/drm/panel/panel-simple.c
|
||||
@@ -3244,11 +3244,11 @@ static const struct panel_desc qishenglo
|
||||
@@ -3245,11 +3245,11 @@ static const struct panel_desc qishenglo
|
||||
};
|
||||
|
||||
static const struct drm_display_mode raspberrypi_7inch_mode = {
|
||||
|
||||
@@ -36,7 +36,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
|
||||
sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
|
||||
|
||||
return true;
|
||||
@@ -3330,6 +3336,11 @@ static void sdhci_cmd_irq(struct sdhci_h
|
||||
@@ -3333,6 +3339,11 @@ static void sdhci_cmd_irq(struct sdhci_h
|
||||
if (intmask & SDHCI_INT_TIMEOUT) {
|
||||
host->cmd->error = -ETIMEDOUT;
|
||||
sdhci_err_stats_inc(host, CMD_TIMEOUT);
|
||||
|
||||
@@ -23,7 +23,7 @@ Signed-off-by: Timon Skerutsch <kernel@diodes-delight.com>
|
||||
|
||||
/**
|
||||
* struct panel_desc - Describes a simple panel.
|
||||
@@ -4665,6 +4666,9 @@ static const struct panel_desc_dsi osd10
|
||||
@@ -4666,6 +4667,9 @@ static const struct panel_desc_dsi osd10
|
||||
.lanes = 4,
|
||||
};
|
||||
|
||||
@@ -33,7 +33,7 @@ Signed-off-by: Timon Skerutsch <kernel@diodes-delight.com>
|
||||
static const struct of_device_id dsi_of_match[] = {
|
||||
{
|
||||
.compatible = "auo,b080uan01",
|
||||
@@ -4688,14 +4692,118 @@ static const struct of_device_id dsi_of_
|
||||
@@ -4689,14 +4693,118 @@ static const struct of_device_id dsi_of_
|
||||
.compatible = "osddisplays,osd101t2045-53ts",
|
||||
.data = &osd101t2045_53ts
|
||||
}, {
|
||||
@@ -152,7 +152,7 @@ Signed-off-by: Timon Skerutsch <kernel@diodes-delight.com>
|
||||
const struct of_device_id *id;
|
||||
int err;
|
||||
|
||||
@@ -4703,7 +4811,20 @@ static int panel_simple_dsi_probe(struct
|
||||
@@ -4704,7 +4812,20 @@ static int panel_simple_dsi_probe(struct
|
||||
if (!id)
|
||||
return -ENODEV;
|
||||
|
||||
|
||||
@@ -297,7 +297,7 @@ Signed-off-by: T.J. Mercier <tjmercier@google.com>
|
||||
|
||||
#endif /* CONFIG_LRU_GEN */
|
||||
|
||||
@@ -1219,6 +1330,8 @@ typedef struct pglist_data {
|
||||
@@ -1218,6 +1329,8 @@ typedef struct pglist_data {
|
||||
#ifdef CONFIG_LRU_GEN
|
||||
/* kswap mm walk data */
|
||||
struct lru_gen_mm_walk mm_walk;
|
||||
@@ -361,7 +361,7 @@ Signed-off-by: T.J. Mercier <tjmercier@google.com>
|
||||
static void mem_cgroup_css_free(struct cgroup_subsys_state *css)
|
||||
--- a/mm/page_alloc.c
|
||||
+++ b/mm/page_alloc.c
|
||||
@@ -7945,6 +7945,7 @@ static void __init free_area_init_node(i
|
||||
@@ -7949,6 +7949,7 @@ static void __init free_area_init_node(i
|
||||
pgdat_set_deferred_range(pgdat);
|
||||
|
||||
free_area_init_core(pgdat);
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
From 4c8a49854130da0117a0fdb858551824919a2389 Mon Sep 17 00:00:00 2001
|
||||
From: Ingo Molnar <mingo@kernel.org>
|
||||
Date: Tue, 27 Feb 2024 09:58:15 +0100
|
||||
Subject: [PATCH] smp: Avoid 'setup_max_cpus' namespace collision/shadowing
|
||||
|
||||
bringup_nonboot_cpus() gets passed the 'setup_max_cpus'
|
||||
variable in init/main.c - which is also the name of the parameter,
|
||||
shadowing the name.
|
||||
|
||||
To reduce confusion and to allow the 'setup_max_cpus' value
|
||||
to be #defined in the <linux/smp.h> header, use the 'max_cpus'
|
||||
name for the function parameter name.
|
||||
|
||||
Signed-off-by: Ingo Molnar <mingo@kernel.org>
|
||||
Cc: Thomas Gleixner <tglx@linutronix.de>
|
||||
Cc: linux-kernel@vger.kernel.org
|
||||
---
|
||||
include/linux/cpu.h | 2 +-
|
||||
kernel/cpu.c | 6 +++---
|
||||
2 files changed, 4 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/include/linux/cpu.h
|
||||
+++ b/include/linux/cpu.h
|
||||
@@ -109,7 +109,7 @@ void notify_cpu_starting(unsigned int cp
|
||||
extern void cpu_maps_update_begin(void);
|
||||
extern void cpu_maps_update_done(void);
|
||||
int bringup_hibernate_cpu(unsigned int sleep_cpu);
|
||||
-void bringup_nonboot_cpus(unsigned int setup_max_cpus);
|
||||
+void bringup_nonboot_cpus(unsigned int max_cpus);
|
||||
|
||||
#else /* CONFIG_SMP */
|
||||
#define cpuhp_tasks_frozen 0
|
||||
--- a/kernel/cpu.c
|
||||
+++ b/kernel/cpu.c
|
||||
@@ -1905,14 +1905,14 @@ static bool __init cpuhp_bringup_cpus_pa
|
||||
static inline bool cpuhp_bringup_cpus_parallel(unsigned int ncpus) { return false; }
|
||||
#endif /* CONFIG_HOTPLUG_PARALLEL */
|
||||
|
||||
-void __init bringup_nonboot_cpus(unsigned int setup_max_cpus)
|
||||
+void __init bringup_nonboot_cpus(unsigned int max_cpus)
|
||||
{
|
||||
/* Try parallel bringup optimization if enabled */
|
||||
- if (cpuhp_bringup_cpus_parallel(setup_max_cpus))
|
||||
+ if (cpuhp_bringup_cpus_parallel(max_cpus))
|
||||
return;
|
||||
|
||||
/* Full per CPU serialized bringup */
|
||||
- cpuhp_bringup_mask(cpu_present_mask, setup_max_cpus, CPUHP_ONLINE);
|
||||
+ cpuhp_bringup_mask(cpu_present_mask, max_cpus, CPUHP_ONLINE);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP_SMP
|
||||
@@ -0,0 +1,38 @@
|
||||
From 6ef8eb5125722c241fd60d7b0c872d5c2e5dd4ca Mon Sep 17 00:00:00 2001
|
||||
From: Huacai Chen <chenhuacai@loongson.cn>
|
||||
Date: Tue, 18 Jun 2024 16:13:36 +0800
|
||||
Subject: [PATCH] cpu: Fix broken cmdline "nosmp" and "maxcpus=0"
|
||||
|
||||
After the rework of "Parallel CPU bringup", the cmdline "nosmp" and
|
||||
"maxcpus=0" parameters are not working anymore. These parameters set
|
||||
setup_max_cpus to zero and that's handed to bringup_nonboot_cpus().
|
||||
|
||||
The code there does a decrement before checking for zero, which brings it
|
||||
into the negative space and brings up all CPUs.
|
||||
|
||||
Add a zero check at the beginning of the function to prevent this.
|
||||
|
||||
[ tglx: Massaged change log ]
|
||||
|
||||
Fixes: 18415f33e2ac4ab382 ("cpu/hotplug: Allow "parallel" bringup up to CPUHP_BP_KICK_AP_STATE")
|
||||
Fixes: 06c6796e0304234da6 ("cpu/hotplug: Fix off by one in cpuhp_bringup_mask()")
|
||||
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
|
||||
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
|
||||
Cc: stable@vger.kernel.org
|
||||
Link: https://lore.kernel.org/r/20240618081336.3996825-1-chenhuacai@loongson.cn
|
||||
---
|
||||
kernel/cpu.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
--- a/kernel/cpu.c
|
||||
+++ b/kernel/cpu.c
|
||||
@@ -1907,6 +1907,9 @@ static inline bool cpuhp_bringup_cpus_pa
|
||||
|
||||
void __init bringup_nonboot_cpus(unsigned int max_cpus)
|
||||
{
|
||||
+ if (!max_cpus)
|
||||
+ return;
|
||||
+
|
||||
/* Try parallel bringup optimization if enabled */
|
||||
if (cpuhp_bringup_cpus_parallel(max_cpus))
|
||||
return;
|
||||
@@ -278,7 +278,7 @@ mtdsplit_fit_parse(struct mtd_info *mtd,
|
||||
|
||||
parts[0].name = KERNEL_PART_NAME;
|
||||
parts[0].offset = fit_offset;
|
||||
parts[0].size = mtd_rounddown_to_eb(fit_size + offset_start, mtd) + mtd->erasesize;
|
||||
parts[0].size = mtd_roundup_to_eb(fit_size + offset_start, mtd);
|
||||
|
||||
if (type == MTDSPLIT_PART_TYPE_UBI)
|
||||
parts[1].name = UBI_PART_NAME;
|
||||
@@ -327,7 +327,7 @@ mtdsplit_fit_parse(struct mtd_info *mtd,
|
||||
return -ENOMEM;
|
||||
|
||||
parts[0].name = ROOTFS_SPLIT_NAME;
|
||||
parts[0].offset = fit_offset + mtd_rounddown_to_eb(max_size, mtd) + mtd->erasesize;
|
||||
parts[0].offset = fit_offset + mtd_roundup_to_eb(max_size, mtd);
|
||||
parts[0].size = mtd->size - parts[0].offset;
|
||||
|
||||
*pparts = parts;
|
||||
|
||||
@@ -891,7 +891,11 @@ ar8216_phy_write(struct ar8xxx_priv *priv, int addr, int regnum, u16 val)
|
||||
static int
|
||||
ar8229_hw_init(struct ar8xxx_priv *priv)
|
||||
{
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0)
|
||||
phy_interface_t phy_if_mode;
|
||||
#else
|
||||
int phy_if_mode;
|
||||
#endif
|
||||
|
||||
if (priv->initialized)
|
||||
return 0;
|
||||
@@ -899,7 +903,11 @@ ar8229_hw_init(struct ar8xxx_priv *priv)
|
||||
ar8xxx_write(priv, AR8216_REG_CTRL, AR8216_CTRL_RESET);
|
||||
ar8xxx_reg_wait(priv, AR8216_REG_CTRL, AR8216_CTRL_RESET, 0, 1000);
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0)
|
||||
of_get_phy_mode(priv->pdev->of_node, &phy_if_mode);
|
||||
#else
|
||||
phy_if_mode = of_get_phy_mode(priv->pdev->of_node);
|
||||
#endif
|
||||
|
||||
if (phy_if_mode == PHY_INTERFACE_MODE_GMII) {
|
||||
ar8xxx_write(priv, AR8229_REG_OPER_MODE0,
|
||||
@@ -1419,7 +1427,8 @@ ar8xxx_sw_reset_switch(struct switch_dev *dev)
|
||||
int i;
|
||||
|
||||
mutex_lock(&priv->reg_mutex);
|
||||
memset(&priv->ar8xxx_priv_volatile, 0, sizeof(priv->ar8xxx_priv_volatile));
|
||||
memset(&priv->vlan, 0, sizeof(struct ar8xxx_priv) -
|
||||
offsetof(struct ar8xxx_priv, vlan));
|
||||
|
||||
for (i = 0; i < dev->vlans; i++)
|
||||
priv->vlan_id[i] = i;
|
||||
@@ -2424,9 +2433,7 @@ static int
|
||||
ar8xxx_phy_config_init(struct phy_device *phydev)
|
||||
{
|
||||
struct ar8xxx_priv *priv = phydev->priv;
|
||||
#ifdef CONFIG_ETHERNET_PACKET_MANGLE
|
||||
struct net_device *dev = phydev->attached_dev;
|
||||
#endif
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(!priv))
|
||||
@@ -2458,11 +2465,7 @@ ar8xxx_phy_config_init(struct phy_device *phydev)
|
||||
/* VID fixup only needed on ar8216 */
|
||||
if (chip_is_ar8216(priv)) {
|
||||
dev->phy_ptr = priv;
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,1,0)
|
||||
dev->priv_flags |= IFF_NO_IP_ALIGN;
|
||||
#else
|
||||
dev->extra_priv_flags |= IFF_NO_IP_ALIGN;
|
||||
#endif
|
||||
dev->eth_mangle_rx = ar8216_mangle_rx;
|
||||
dev->eth_mangle_tx = ar8216_mangle_tx;
|
||||
}
|
||||
@@ -2697,11 +2700,7 @@ ar8xxx_phy_detach(struct phy_device *phydev)
|
||||
|
||||
#ifdef CONFIG_ETHERNET_PACKET_MANGLE
|
||||
dev->phy_ptr = NULL;
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,1,0)
|
||||
dev->priv_flags &= ~IFF_NO_IP_ALIGN;
|
||||
#else
|
||||
dev->extra_priv_flags &= ~IFF_NO_IP_ALIGN;
|
||||
#endif
|
||||
dev->eth_mangle_rx = NULL;
|
||||
dev->eth_mangle_tx = NULL;
|
||||
#endif
|
||||
|
||||
@@ -506,22 +506,20 @@ struct ar8xxx_priv {
|
||||
unsigned int use_count;
|
||||
|
||||
/* all fields below are cleared on reset */
|
||||
struct_group(ar8xxx_priv_volatile,
|
||||
bool vlan;
|
||||
bool vlan;
|
||||
|
||||
u16 vlan_id[AR8XXX_MAX_VLANS];
|
||||
u8 vlan_table[AR8XXX_MAX_VLANS];
|
||||
u8 vlan_tagged;
|
||||
u16 pvid[AR8X16_MAX_PORTS];
|
||||
int arl_age_time;
|
||||
u16 vlan_id[AR8XXX_MAX_VLANS];
|
||||
u8 vlan_table[AR8XXX_MAX_VLANS];
|
||||
u8 vlan_tagged;
|
||||
u16 pvid[AR8X16_MAX_PORTS];
|
||||
int arl_age_time;
|
||||
|
||||
/* mirroring */
|
||||
bool mirror_rx;
|
||||
bool mirror_tx;
|
||||
int source_port;
|
||||
int monitor_port;
|
||||
u8 port_vlan_prio[AR8X16_MAX_PORTS];
|
||||
);
|
||||
/* mirroring */
|
||||
bool mirror_rx;
|
||||
bool mirror_tx;
|
||||
int source_port;
|
||||
int monitor_port;
|
||||
u8 port_vlan_prio[AR8X16_MAX_PORTS];
|
||||
};
|
||||
|
||||
u32
|
||||
|
||||
@@ -183,7 +183,7 @@ ar8327_phy_fixup(struct ar8xxx_priv *priv, int phy)
|
||||
|
||||
case 2:
|
||||
ar8xxx_phy_mmd_write(priv, phy, 0x7, 0x3c, 0x0);
|
||||
fallthrough;
|
||||
/* fallthrough */
|
||||
case 4:
|
||||
ar8xxx_phy_mmd_write(priv, phy, 0x3, 0x800d, 0x803f);
|
||||
ar8xxx_phy_dbg_write(priv, phy, 0x3d, 0x6860);
|
||||
|
||||
@@ -55,7 +55,7 @@ Signed-off-by: David Bauer <mail@david-bauer.net>
|
||||
/* SGMII */
|
||||
#define VSPEC1_SGMII_CTRL 0x08
|
||||
#define VSPEC1_SGMII_CTRL_ANEN BIT(12) /* Aneg enable */
|
||||
@@ -258,6 +265,35 @@ out:
|
||||
@@ -258,10 +265,39 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -91,3 +91,8 @@ Signed-off-by: David Bauer <mail@david-bauer.net>
|
||||
static int gpy_config_init(struct phy_device *phydev)
|
||||
{
|
||||
/* Nothing to configure. Configuration Requirement Placeholder */
|
||||
- return 0;
|
||||
+ return gpy_led_write(phydev);
|
||||
}
|
||||
|
||||
static bool gpy_has_broken_mdint(struct phy_device *phydev)
|
||||
|
||||
@@ -55,7 +55,7 @@ Signed-off-by: David Bauer <mail@david-bauer.net>
|
||||
#define PHY_PMA_MGBT_POLARITY 0x82
|
||||
#define PHY_MDI_MDI_X_MASK GENMASK(1, 0)
|
||||
#define PHY_MDI_MDI_X_NORMAL 0x3
|
||||
@@ -270,6 +277,35 @@ out:
|
||||
@@ -270,10 +277,39 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -91,3 +91,8 @@ Signed-off-by: David Bauer <mail@david-bauer.net>
|
||||
static int gpy_config_init(struct phy_device *phydev)
|
||||
{
|
||||
/* Nothing to configure. Configuration Requirement Placeholder */
|
||||
- return 0;
|
||||
+ return gpy_led_write(phydev);
|
||||
}
|
||||
|
||||
static int gpy_probe(struct phy_device *phydev)
|
||||
|
||||
@@ -235,7 +235,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
if (!pe)
|
||||
--- a/mm/vmalloc.c
|
||||
+++ b/mm/vmalloc.c
|
||||
@@ -4438,6 +4438,8 @@ static const struct seq_operations vmall
|
||||
@@ -4447,6 +4447,8 @@ static const struct seq_operations vmall
|
||||
|
||||
static int __init proc_vmalloc_init(void)
|
||||
{
|
||||
|
||||
@@ -88,7 +88,7 @@ This reverts commit bffcc6882a1bb2be8c9420184966f4c2c822078e.
|
||||
genl_info_net_set(&info, net);
|
||||
--- a/net/openvswitch/conntrack.c
|
||||
+++ b/net/openvswitch/conntrack.c
|
||||
@@ -1606,7 +1606,7 @@ static struct sk_buff *
|
||||
@@ -1611,7 +1611,7 @@ static struct sk_buff *
|
||||
ovs_ct_limit_cmd_reply_start(struct genl_info *info, u8 cmd,
|
||||
struct ovs_header **ovs_reply_header)
|
||||
{
|
||||
|
||||
@@ -71,7 +71,7 @@ Signed-off-by: Tobias Wolf <dev-NTEO@vplace.de>
|
||||
|
||||
--- a/mm/page_alloc.c
|
||||
+++ b/mm/page_alloc.c
|
||||
@@ -7899,7 +7899,7 @@ static void __init alloc_node_mem_map(st
|
||||
@@ -7903,7 +7903,7 @@ static void __init alloc_node_mem_map(st
|
||||
if (pgdat == NODE_DATA(0)) {
|
||||
mem_map = NODE_DATA(0)->node_mem_map;
|
||||
if (page_to_pfn(mem_map) != pgdat->node_start_pfn)
|
||||
|
||||
@@ -18,7 +18,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
--- a/net/netfilter/nf_tables_api.c
|
||||
+++ b/net/netfilter/nf_tables_api.c
|
||||
@@ -7959,7 +7959,7 @@ static int nft_register_flowtable_net_ho
|
||||
@@ -7958,7 +7958,7 @@ static int nft_register_flowtable_net_ho
|
||||
err = flowtable->data.type->setup(&flowtable->data,
|
||||
hook->ops.dev,
|
||||
FLOW_BLOCK_BIND);
|
||||
|
||||
@@ -18,7 +18,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
--- a/net/netfilter/nf_tables_api.c
|
||||
+++ b/net/netfilter/nf_tables_api.c
|
||||
@@ -8268,7 +8268,7 @@ static int nft_register_flowtable_net_ho
|
||||
@@ -8267,7 +8267,7 @@ static int nft_register_flowtable_net_ho
|
||||
err = flowtable->data.type->setup(&flowtable->data,
|
||||
hook->ops.dev,
|
||||
FLOW_BLOCK_BIND);
|
||||
|
||||