Update On Sun Jul 7 20:30:33 CEST 2024

This commit is contained in:
github-action[bot]
2024-07-07 20:30:33 +02:00
parent 9e781f8d94
commit 1b68d368b1
129 changed files with 1211 additions and 863 deletions

1
.github/update.log vendored
View File

@@ -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

View File

@@ -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",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 972 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -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"],

View File

@@ -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 {

View File

@@ -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",

View File

@@ -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>

View File

@@ -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} />;

View File

@@ -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;

View File

@@ -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"

View File

@@ -51,7 +51,7 @@ export const SettingClashWeb = () => {
if (!list) return;
if (editIndex) {
if (editIndex !== null) {
list[editIndex] = editString;
} else {
list.push(editString);

View File

@@ -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 />

View File

@@ -38,6 +38,7 @@ export default function RulesPage() {
full
title={t("Rules")}
contentStyle={{ height: "100%" }}
sectionStyle={{ height: "100%" }}
header={
<TextField
hiddenLabel

View File

@@ -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 {

View File

@@ -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%;

View File

@@ -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:

View File

@@ -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 }}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -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") {

View File

@@ -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(())
}
}

View File

@@ -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()
{

View File

@@ -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

View File

@@ -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

View File

@@ -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,

View File

@@ -6,7 +6,7 @@ export const BaseStyledTextField = styled((props: TextFieldProps) => {
return (
<TextField
autoComplete="off"
autoComplete="new-password"
hiddenLabel
fullWidth
size="small"

View File

@@ -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={

View File

@@ -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")}

View File

@@ -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)}
/>
)}
</>
);
};

View File

@@ -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={

View File

@@ -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}

View File

@@ -59,6 +59,7 @@ export const RuleItem = (props: Props) => {
sx={{ cursor: sortable ? "move" : "" }}
primary={
<StyledPrimary
title={ruleContent || "-"}
sx={{ textDecoration: type === "delete" ? "line-through" : "" }}
>
{ruleContent || "-"}

View File

@@ -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={

View File

@@ -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 }}
/>
</>
)}

View File

@@ -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"

View File

@@ -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}

View File

@@ -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")}

View File

@@ -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}

View File

@@ -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"

View File

@@ -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>
</>
)}

View File

@@ -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>

View File

@@ -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"

View File

@@ -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}

View File

@@ -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}

View File

@@ -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",

View File

@@ -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": "تنظیمات گسترده‌ی سراسری",

View File

@@ -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": "Глобальный расширенный Настройки",

View File

@@ -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": "全局扩展脚本",

View File

@@ -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 {

View File

@@ -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");
}

View File

@@ -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 {

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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))) {

View File

@@ -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,
}, {

View File

@@ -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,
}, {

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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,
}, {

View File

@@ -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;

View File

@@ -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;

View File

@@ -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 = {

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)
{

View File

@@ -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)
{

View File

@@ -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)

View File

@@ -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);

View File

@@ -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);

Some files were not shown because too many files have changed in this diff Show More