Update On Thu Jul 17 20:42:45 CEST 2025

This commit is contained in:
github-action[bot]
2025-07-17 20:42:46 +02:00
parent c862c33495
commit 269634f2ed
108 changed files with 2106 additions and 1784 deletions
+1
View File
@@ -1061,3 +1061,4 @@ Update On Mon Jul 14 14:45:36 CEST 2025
Update On Mon Jul 14 20:43:09 CEST 2025
Update On Tue Jul 15 20:40:52 CEST 2025
Update On Wed Jul 16 20:41:54 CEST 2025
Update On Thu Jul 17 20:42:37 CEST 2025
+9
View File
@@ -296,6 +296,10 @@ type RawTun struct {
Inet6RouteAddress []netip.Prefix `yaml:"inet6-route-address" json:"inet6-route-address,omitempty"`
Inet4RouteExcludeAddress []netip.Prefix `yaml:"inet4-route-exclude-address" json:"inet4-route-exclude-address,omitempty"`
Inet6RouteExcludeAddress []netip.Prefix `yaml:"inet6-route-exclude-address" json:"inet6-route-exclude-address,omitempty"`
// darwin special config
RecvMsgX bool `yaml:"recvmsgx" json:"recvmsgx,omitempty"`
SendMsgX bool `yaml:"sendmsgx" json:"sendmsgx,omitempty"`
}
type RawTuicServer struct {
@@ -513,6 +517,8 @@ func DefaultRawConfig() *RawConfig {
AutoRoute: true,
AutoDetectInterface: true,
Inet6Address: []netip.Prefix{netip.MustParsePrefix("fdfe:dcba:9876::1/126")},
RecvMsgX: true,
SendMsgX: false, // In the current implementation, if enabled, the kernel may freeze during multi-thread downloads, so it is disabled by default.
},
TuicServer: RawTuicServer{
Enable: false,
@@ -1554,6 +1560,9 @@ func parseTun(rawTun RawTun, general *General) error {
Inet6RouteAddress: rawTun.Inet6RouteAddress,
Inet4RouteExcludeAddress: rawTun.Inet4RouteExcludeAddress,
Inet6RouteExcludeAddress: rawTun.Inet6RouteExcludeAddress,
RecvMsgX: rawTun.RecvMsgX,
SendMsgX: rawTun.SendMsgX,
}
return nil
+1 -1
View File
@@ -31,7 +31,7 @@ require (
github.com/metacubex/sing-shadowsocks v0.2.11-0.20250621023810-0e9ef9dd0c92
github.com/metacubex/sing-shadowsocks2 v0.2.5-0.20250621023950-93d605a2143d
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2
github.com/metacubex/sing-tun v0.4.7-0.20250611091011-60774779fdd8
github.com/metacubex/sing-tun v0.4.7-0.20250717140042-aefff29eb853
github.com/metacubex/sing-vmess v0.2.2
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee
+2 -2
View File
@@ -129,8 +129,8 @@ github.com/metacubex/sing-shadowsocks2 v0.2.5-0.20250621023950-93d605a2143d h1:E
github.com/metacubex/sing-shadowsocks2 v0.2.5-0.20250621023950-93d605a2143d/go.mod h1:+ukTd0OPFglT3bnKAYTJWYPbuox6HYNXE235r5tHdUk=
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2 h1:gXU+MYPm7Wme3/OAY2FFzVq9d9GxPHOqu5AQfg/ddhI=
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2/go.mod h1:mbfboaXauKJNIHJYxQRa+NJs4JU9NZfkA+I33dS2+9E=
github.com/metacubex/sing-tun v0.4.7-0.20250611091011-60774779fdd8 h1:4zWKqxTx75TbfW2EmlQ3hxM6RTRg2PYOAVMCnU4I61I=
github.com/metacubex/sing-tun v0.4.7-0.20250611091011-60774779fdd8/go.mod h1:2YywXPWW8Z97kTH7RffOeykKzU+l0aiKlglWV1PAS64=
github.com/metacubex/sing-tun v0.4.7-0.20250717140042-aefff29eb853 h1:HJb4CS7XP3sjc4fDDnAlNN9393ewSCn9yuGXjmZ7bJc=
github.com/metacubex/sing-tun v0.4.7-0.20250717140042-aefff29eb853/go.mod h1:2YywXPWW8Z97kTH7RffOeykKzU+l0aiKlglWV1PAS64=
github.com/metacubex/sing-vmess v0.2.2 h1:nG6GIKF1UOGmlzs+BIetdGHkFZ20YqFVIYp5Htqzp+4=
github.com/metacubex/sing-vmess v0.2.2/go.mod h1:CVDNcdSLVYFgTHQlubr88d8CdqupAUDqLjROos+H9xk=
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f h1:Sr/DYKYofKHKc4GF3qkRGNuj6XA6c0eqPgEDN+VAsYU=
+10
View File
@@ -100,6 +100,10 @@ type tunSchema struct {
Inet6RouteAddress *[]netip.Prefix `yaml:"inet6-route-address" json:"inet6-route-address,omitempty"`
Inet4RouteExcludeAddress *[]netip.Prefix `yaml:"inet4-route-exclude-address" json:"inet4-route-exclude-address,omitempty"`
Inet6RouteExcludeAddress *[]netip.Prefix `yaml:"inet6-route-exclude-address" json:"inet6-route-exclude-address,omitempty"`
// darwin special config
RecvMsgX *bool `yaml:"recvmsgx" json:"recvmsgx,omitempty"`
SendMsgX *bool `yaml:"sendmsgx" json:"sendmsgx,omitempty"`
}
type tuicServerSchema struct {
@@ -243,6 +247,12 @@ func pointerOrDefaultTun(p *tunSchema, def LC.Tun) LC.Tun {
if p.FileDescriptor != nil {
def.FileDescriptor = *p.FileDescriptor
}
if p.RecvMsgX != nil {
def.RecvMsgX = *p.RecvMsgX
}
if p.SendMsgX != nil {
def.SendMsgX = *p.SendMsgX
}
}
return def
}
+11
View File
@@ -54,6 +54,10 @@ type Tun struct {
Inet6RouteAddress []netip.Prefix `yaml:"inet6-route-address" json:"inet6-route-address,omitempty"`
Inet4RouteExcludeAddress []netip.Prefix `yaml:"inet4-route-exclude-address" json:"inet4-route-exclude-address,omitempty"`
Inet6RouteExcludeAddress []netip.Prefix `yaml:"inet6-route-exclude-address" json:"inet6-route-exclude-address,omitempty"`
// darwin special config
RecvMsgX bool `yaml:"recvmsgx" json:"recvmsgx,omitempty"`
SendMsgX bool `yaml:"sendmsgx" json:"sendmsgx,omitempty"`
}
func (t *Tun) Sort() {
@@ -199,5 +203,12 @@ func (t *Tun) Equal(other Tun) bool {
return false
}
if t.RecvMsgX != other.RecvMsgX {
return false
}
if t.SendMsgX != other.SendMsgX {
return false
}
return true
}
+7
View File
@@ -55,6 +55,10 @@ type TunOption struct {
Inet6RouteAddress []netip.Prefix `inbound:"inet6-route-address,omitempty"`
Inet4RouteExcludeAddress []netip.Prefix `inbound:"inet4-route-exclude-address,omitempty"`
Inet6RouteExcludeAddress []netip.Prefix `inbound:"inet6-route-exclude-address,omitempty"`
// darwin special config
RecvMsgX bool `inbound:"recvmsgx,omitempty"`
SendMsgX bool `inbound:"sendmsgx,omitempty"`
}
var _ encoding.TextUnmarshaler = (*netip.Addr)(nil) // ensure netip.Addr can decode direct by structure package
@@ -124,6 +128,9 @@ func NewTun(options *TunOption) (*Tun, error) {
Inet6RouteAddress: options.Inet6RouteAddress,
Inet4RouteExcludeAddress: options.Inet4RouteExcludeAddress,
Inet6RouteExcludeAddress: options.Inet6RouteExcludeAddress,
RecvMsgX: options.RecvMsgX,
SendMsgX: options.SendMsgX,
},
}, nil
}
+2
View File
@@ -365,6 +365,8 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis
ExcludePackage: options.ExcludePackage,
FileDescriptor: options.FileDescriptor,
InterfaceMonitor: defaultInterfaceMonitor,
EXP_RecvMsgX: options.RecvMsgX,
EXP_SendMsgX: options.SendMsgX,
}
if options.AutoRedirect {
+562 -419
View File
File diff suppressed because it is too large Load Diff
@@ -22,7 +22,7 @@ use boa_engine::{
};
use boa_gc::{Finalize, Trace};
use rustc_hash::FxHashMap;
use std::{cell::RefCell, collections::hash_map::Entry, rc::Rc, sync::Arc, time::SystemTime};
use std::{cell::RefCell, collections::hash_map::Entry, rc::Rc, time::SystemTime};
/// This represents the different types of log messages.
#[derive(Debug)]
@@ -153,14 +153,13 @@ impl ModuleLoader for HttpModuleLoader {
if err.kind() == std::io::ErrorKind::NotFound
&& let Err(e) = async_fs::metadata(&parent_dir).await
&& e.kind() == std::io::ErrorKind::NotFound
&& let Err(err) = create_dir_all(parent_dir).await
{
if let Err(err) = create_dir_all(parent_dir).await {
log::error!(
"failed to create cache directory for `{url}`; path: `{}`. error: `{}`",
cache_path.display(),
err
);
}
log::error!(
"failed to create cache directory for `{url}`; path: `{}`. error: `{}`",
cache_path.display(),
err
);
}
false
}
@@ -4,7 +4,6 @@ use std::sync::{Arc, LazyLock};
use crate::{
ipc::Message,
utils::svg::{SvgExt, render_svg_with_current_color_replace},
widget::get_window_state_path,
};
use eframe::{
egui::{
@@ -157,11 +156,11 @@ impl NyanpasuNetworkStatisticLargeWidget {
loop {
match rx.recv() {
Ok(msg) => {
println!("Received message: {:?}", msg);
println!("Received message: {msg:?}");
let _ = this.handle_message(msg);
}
Err(e) => {
eprintln!("Failed to receive message: {}", e);
eprintln!("Failed to receive message: {e}");
if matches!(
e,
ipc_channel::ipc::IpcError::Disconnected
@@ -3,12 +3,11 @@ use std::sync::{Arc, LazyLock};
use eframe::egui::{
self, Color32, CornerRadius, Id, Image, Label, Layout, Margin, RichText, Sense, Stroke, Style,
TextWrapMode, Theme, Vec2, ViewportCommand, Visuals, WidgetText, include_image,
style::Selection,
TextWrapMode, Theme, Vec2, ViewportCommand, WidgetText, include_image, style::Selection,
};
use parking_lot::RwLock;
use crate::{ipc::Message, widget::get_window_state_path};
use crate::ipc::Message;
// Presets
const STATUS_ICON_CONTAINER_WIDTH: f32 = 20.0;
@@ -122,11 +121,11 @@ impl NyanpasuNetworkStatisticSmallWidget {
loop {
match rx.recv() {
Ok(msg) => {
println!("Received message: {:?}", msg);
println!("Received message: {msg:?}");
let _ = this.handle_message(msg);
}
Err(e) => {
eprintln!("Failed to receive message: {}", e);
eprintln!("Failed to receive message: {e}");
if matches!(
e,
ipc_channel::ipc::IpcError::Disconnected
@@ -188,7 +187,7 @@ impl NyanpasuNetworkStatisticSmallWidget {
this.egui_ctx.send_viewport_cmd(ViewportCommand::Close);
}
_ => {
eprintln!("Unsupported message: {:?}", msg);
eprintln!("Unsupported message: {msg:?}");
}
}
Ok(())
@@ -11,50 +11,51 @@ pub fn builder_update(input: DeriveInput) -> syn::Result<TokenStream> {
// search #[builder_update(getter)] or #[builder_update(getter = "get_{}")]
let mut generate_getter: Option<String> = None;
for attr in &input.attrs {
if let Some(attr_meta_name) = attr.path().get_ident() {
if attr_meta_name == "builder_update" {
let meta = &attr.meta;
match meta {
Meta::List(list) => {
list.parse_nested_meta(|meta| {
let path = &meta.path;
match path {
path if path.is_ident("ty") => {
let value = meta.value()?;
let lit_str: LitStr = value.parse()?;
partial_ty = Some(lit_str.parse()?);
}
path if path.is_ident("patch_fn") => {
let value = meta.value()?;
let lit_str: LitStr = value.parse()?;
patch_fn = Some(lit_str.parse()?);
}
path if path.is_ident("getter") => {
match meta.value() {
Ok(value) => {
let lit_str: LitStr = value.parse()?;
generate_getter = Some(lit_str.value());
}
Err(_) => {
// it should be default getter
generate_getter = Some("get_{}".to_string());
}
if let Some(attr_meta_name) = attr.path().get_ident()
&& attr_meta_name == "builder_update"
{
let meta = &attr.meta;
match meta {
Meta::List(list) => {
list.parse_nested_meta(|meta| {
let path = &meta.path;
match path {
path if path.is_ident("ty") => {
let value = meta.value()?;
let lit_str: LitStr = value.parse()?;
partial_ty = Some(lit_str.parse()?);
}
path if path.is_ident("patch_fn") => {
let value = meta.value()?;
let lit_str: LitStr = value.parse()?;
patch_fn = Some(lit_str.parse()?);
}
path if path.is_ident("getter") => {
match meta.value() {
Ok(value) => {
let lit_str: LitStr = value.parse()?;
generate_getter = Some(lit_str.value());
}
Err(_) => {
// it should be default getter
generate_getter = Some("get_{}".to_string());
}
}
_ => {
return Err(meta
.error("Only #[builder_update(ty = \"T\")] is supported"));
}
}
Ok(())
})?;
}
_ => {
return Err(Error::new(
attr.span(),
"Only #[builder_update(ty = \"T\")] is supported",
));
}
_ => {
return Err(
meta.error("Only #[builder_update(ty = \"T\")] is supported")
);
}
}
Ok(())
})?;
}
_ => {
return Err(Error::new(
attr.span(),
"Only #[builder_update(ty = \"T\")] is supported",
));
}
}
}
@@ -82,28 +83,27 @@ pub fn builder_update(input: DeriveInput) -> syn::Result<TokenStream> {
// check whether the field has #[update(nest)]
let mut nested = false;
for attr in &field.attrs {
if attr.path().is_ident("builder_update") {
if let Meta::List(ref list) = attr.meta {
list.parse_nested_meta(|meta| {
let path = &meta.path;
match path {
path if path.is_ident("nested") => {
nested = true;
}
path if path.is_ident("getter_ty") => {
let value = meta.value()?;
let lit_str: LitStr = value.parse()?;
getter_type = syn::parse_str(&lit_str.value())?;
}
_ => {
return Err(meta.error(
"Only #[builder_update(nested)] is supported",
));
}
if attr.path().is_ident("builder_update")
&& let Meta::List(ref list) = attr.meta
{
list.parse_nested_meta(|meta| {
let path = &meta.path;
match path {
path if path.is_ident("nested") => {
nested = true;
}
Ok(())
})?;
}
path if path.is_ident("getter_ty") => {
let value = meta.value()?;
let lit_str: LitStr = value.parse()?;
getter_type = syn::parse_str(&lit_str.value())?;
}
_ => {
return Err(meta
.error("Only #[builder_update(nested)] is supported"));
}
}
Ok(())
})?;
}
}
@@ -21,7 +21,7 @@ tauri-utils = { version = "2" }
[target.'cfg(windows)'.dependencies]
interprocess = { version = "2" }
windows-sys = { version = "0.59.0", features = [
windows-sys = { version = "0.60", features = [
"Win32_Foundation",
"Win32_UI_Input_KeyboardAndMouse",
"Win32_UI_WindowsAndMessaging",
@@ -104,14 +104,14 @@ pub fn listen<F: FnMut(String) + Send + 'static>(mut handler: F) -> Result<()> {
let mut reader = BufReader::new(rx);
let mut buf = String::new();
if let Err(e) = reader.read_line(&mut buf).await {
log::error!("Error reading from connection: {}", e);
log::error!("Error reading from connection: {e}");
continue;
}
buf.pop();
let current_pid = std::process::id();
let response = format!("{current_pid}\n");
if let Err(e) = tx.write_all(response.as_bytes()).await {
log::error!("Error writing to connection: {}", e);
log::error!("Error writing to connection: {e}");
continue;
}
handler(buf);
@@ -121,7 +121,7 @@ pub fn listen<F: FnMut(String) + Send + 'static>(mut handler: F) -> Result<()> {
break;
}
Err(e) => {
log::error!("Error accepting connection: {}", e);
log::error!("Error accepting connection: {e}");
}
}
}
@@ -177,7 +177,7 @@ pub fn prepare(identifier: &str) {
let mut reader = BufReader::new(&mut socket_rx);
let mut buf = String::new();
if let Err(e) = reader.read_line(&mut buf).await {
eprintln!("Error reading from connection: {}", e);
eprintln!("Error reading from connection: {e}");
}
buf.pop();
dummy_keypress();
@@ -191,7 +191,7 @@ pub fn prepare(identifier: &str) {
std::process::exit(0);
}
Err(e) => {
eprintln!("Failed to connect to local socket: {}", e);
eprintln!("Failed to connect to local socket: {e}");
std::thread::sleep(std::time::Duration::from_millis(1));
}
};
+6 -5
View File
@@ -90,7 +90,7 @@ axum = "0.8"
url = "2"
mime = "0.3"
reqwest = { version = "0.12", features = ["json", "stream"] }
tokio-tungstenite = "0.26.1"
tokio-tungstenite = "0.27"
urlencoding = "2.1"
port_scanner = "0.1.5"
sysproxy = { git = "https://github.com/libnyanpasu/sysproxy-rs.git", version = "0.3" }
@@ -132,9 +132,9 @@ delay_timer = { version = "0.11", git = "https://github.com/libnyanpasu/delay-ti
dunce = "1.0.4" # for cross platform path normalization
runas = { git = "https://github.com/libnyanpasu/rust-runas.git" }
single-instance = "0.3.3"
which = "7"
which = "8"
open = "5.0.1"
sysinfo = "0.35"
sysinfo = "0.36"
num_cpus = "1"
os_pipe = "1.2.1"
whoami = "1.5.1"
@@ -242,14 +242,15 @@ nix = { version = "0.30.0", features = ["user", "fs"] }
deelevate = "0.2.0"
winreg = { version = "0.55", features = ["transactions"] }
windows-registry = "0.5.1"
windows-sys = { version = "0.59", features = [
windows-sys = { version = "0.60", features = [
"Win32_System_LibraryLoader",
"Win32_System_SystemInformation",
"Win32_UI_WindowsAndMessaging",
"Win32_System_Shutdown",
"Win32_Graphics_Gdi",
] }
windows-core = "0.61"
webview2-com = "0.37"
webview2-com = "0.38"
[features]
default = ["custom-protocol", "default-meta"]
+5 -5
View File
@@ -30,7 +30,7 @@ fn main() {
};
let version = semver::Version::parse(&version).unwrap();
let is_prerelase = !version.pre.is_empty();
println!("cargo:rustc-env=NYANPASU_VERSION={}", version);
println!("cargo:rustc-env=NYANPASU_VERSION={version}");
// Git Information
let (commit_hash, commit_author, commit_date) = if let Ok(true) = exists("./tmp/git-info.json")
{
@@ -60,17 +60,17 @@ fn main() {
command_args[2].clone(),
)
};
println!("cargo:rustc-env=COMMIT_HASH={}", commit_hash);
println!("cargo:rustc-env=COMMIT_AUTHOR={}", commit_author);
println!("cargo:rustc-env=COMMIT_HASH={commit_hash}");
println!("cargo:rustc-env=COMMIT_AUTHOR={commit_author}");
let commit_date = DateTime::parse_from_rfc3339(&commit_date)
.unwrap()
.with_timezone(&Utc)
.to_rfc3339_opts(SecondsFormat::Millis, true);
println!("cargo:rustc-env=COMMIT_DATE={}", commit_date);
println!("cargo:rustc-env=COMMIT_DATE={commit_date}");
// Build Date
let build_date = Utc::now().to_rfc3339_opts(SecondsFormat::Millis, true);
println!("cargo:rustc-env=BUILD_DATE={}", build_date);
println!("cargo:rustc-env=BUILD_DATE={build_date}");
// Build Profile
println!(
File diff suppressed because one or more lines are too long
@@ -37,7 +37,7 @@
],
"definitions": {
"Capability": {
"description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\nIt controls application windows' and webviews' fine grained access to the Tauri core, application, or plugin commands. If a webview or its window is not matching any capability then it has no access to the IPC layer at all.\n\nThis can be done to create groups of windows, based on their required system access, which can reduce impact of frontend vulnerabilities in less privileged windows. Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`. A Window can have none, one, or multiple associated capabilities.\n\n## Example\n\n```json { \"identifier\": \"main-user-files-write\", \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.\", \"windows\": [ \"main\" ], \"permissions\": [ \"core:default\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] }, ], \"platforms\": [\"macOS\",\"windows\"] } ```",
"description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\nIt controls application windows' and webviews' fine grained access to the Tauri core, application, or plugin commands. If a webview or its window is not matching any capability then it has no access to the IPC layer at all.\n\nThis can be done to create groups of windows, based on their required system access, which can reduce impact of frontend vulnerabilities in less privileged windows. Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`. A Window can have none, one, or multiple associated capabilities.\n\n## Example\n\n```json { \"identifier\": \"main-user-files-write\", \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programmatic access to files selected by the user.\", \"windows\": [ \"main\" ], \"permissions\": [ \"core:default\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] }, ], \"platforms\": [\"macOS\",\"windows\"] } ```",
"type": "object",
"required": [
"identifier",
@@ -49,7 +49,7 @@
"type": "string"
},
"description": {
"description": "Description of what the capability is intended to allow on associated windows.\n\nIt should contain a description of what the grouped permissions should allow.\n\n## Example\n\nThis capability allows the `main` window access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.",
"description": "Description of what the capability is intended to allow on associated windows.\n\nIt should contain a description of what the grouped permissions should allow.\n\n## Example\n\nThis capability allows the `main` window access to `filesystem` write related commands and `dialog` commands to enable programmatic access to files selected by the user.",
"default": "",
"type": "string"
},
@@ -3104,6 +3104,12 @@
"const": "core:webview:allow-reparent",
"markdownDescription": "Enables the reparent command without any pre-configured scope."
},
{
"description": "Enables the set_webview_auto_resize command without any pre-configured scope.",
"type": "string",
"const": "core:webview:allow-set-webview-auto-resize",
"markdownDescription": "Enables the set_webview_auto_resize command without any pre-configured scope."
},
{
"description": "Enables the set_webview_background_color command without any pre-configured scope.",
"type": "string",
@@ -3206,6 +3212,12 @@
"const": "core:webview:deny-reparent",
"markdownDescription": "Denies the reparent command without any pre-configured scope."
},
{
"description": "Denies the set_webview_auto_resize command without any pre-configured scope.",
"type": "string",
"const": "core:webview:deny-set-webview-auto-resize",
"markdownDescription": "Denies the set_webview_auto_resize command without any pre-configured scope."
},
{
"description": "Denies the set_webview_background_color command without any pre-configured scope.",
"type": "string",
@@ -37,7 +37,7 @@
],
"definitions": {
"Capability": {
"description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\nIt controls application windows' and webviews' fine grained access to the Tauri core, application, or plugin commands. If a webview or its window is not matching any capability then it has no access to the IPC layer at all.\n\nThis can be done to create groups of windows, based on their required system access, which can reduce impact of frontend vulnerabilities in less privileged windows. Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`. A Window can have none, one, or multiple associated capabilities.\n\n## Example\n\n```json { \"identifier\": \"main-user-files-write\", \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.\", \"windows\": [ \"main\" ], \"permissions\": [ \"core:default\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] }, ], \"platforms\": [\"macOS\",\"windows\"] } ```",
"description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\nIt controls application windows' and webviews' fine grained access to the Tauri core, application, or plugin commands. If a webview or its window is not matching any capability then it has no access to the IPC layer at all.\n\nThis can be done to create groups of windows, based on their required system access, which can reduce impact of frontend vulnerabilities in less privileged windows. Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`. A Window can have none, one, or multiple associated capabilities.\n\n## Example\n\n```json { \"identifier\": \"main-user-files-write\", \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programmatic access to files selected by the user.\", \"windows\": [ \"main\" ], \"permissions\": [ \"core:default\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] }, ], \"platforms\": [\"macOS\",\"windows\"] } ```",
"type": "object",
"required": [
"identifier",
@@ -49,7 +49,7 @@
"type": "string"
},
"description": {
"description": "Description of what the capability is intended to allow on associated windows.\n\nIt should contain a description of what the grouped permissions should allow.\n\n## Example\n\nThis capability allows the `main` window access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.",
"description": "Description of what the capability is intended to allow on associated windows.\n\nIt should contain a description of what the grouped permissions should allow.\n\n## Example\n\nThis capability allows the `main` window access to `filesystem` write related commands and `dialog` commands to enable programmatic access to files selected by the user.",
"default": "",
"type": "string"
},
@@ -3104,6 +3104,12 @@
"const": "core:webview:allow-reparent",
"markdownDescription": "Enables the reparent command without any pre-configured scope."
},
{
"description": "Enables the set_webview_auto_resize command without any pre-configured scope.",
"type": "string",
"const": "core:webview:allow-set-webview-auto-resize",
"markdownDescription": "Enables the set_webview_auto_resize command without any pre-configured scope."
},
{
"description": "Enables the set_webview_background_color command without any pre-configured scope.",
"type": "string",
@@ -3206,6 +3212,12 @@
"const": "core:webview:deny-reparent",
"markdownDescription": "Denies the reparent command without any pre-configured scope."
},
{
"description": "Denies the set_webview_auto_resize command without any pre-configured scope.",
"type": "string",
"const": "core:webview:deny-set-webview-auto-resize",
"markdownDescription": "Denies the set_webview_auto_resize command without any pre-configured scope."
},
{
"description": "Denies the set_webview_background_color command without any pre-configured scope.",
"type": "string",
@@ -36,9 +36,9 @@ pub fn parse(args: &MigrateOpts) {
println!(
"[{}] {} - {}",
match &advice {
MigrationAdvice::Pending => format!("{}", advice).yellow(),
MigrationAdvice::Ignored => format!("{}", advice).cyan(),
MigrationAdvice::Done => format!("{}", advice).green(),
MigrationAdvice::Pending => format!("{advice}").yellow(),
MigrationAdvice::Ignored => format!("{advice}").cyan(),
MigrationAdvice::Done => format!("{advice}").green(),
},
migration.version(),
migration.name()
@@ -94,7 +94,7 @@ pub fn migrate_home_dir_handler(target_path: &str) -> anyhow::Result<()> {
use std::{borrow::Cow, path::PathBuf, process::Command, str::FromStr, thread, time::Duration};
use sysinfo::System;
use tauri::utils::platform::current_exe;
println!("target path {}", target_path);
println!("target path {target_path}");
let token = Token::with_current_process()?;
if let PrivilegeLevel::NotPrivileged = token.privilege_level()? {
@@ -137,12 +137,9 @@ pub fn migrate_home_dir_handler(target_path: &str) -> anyhow::Result<()> {
};
for name in related_names.iter() {
if process_name.ends_with(name) {
println!(
"Process found: {} should be killed. killing...",
process_name
);
println!("Process found: {process_name} should be killed. killing...");
if !process.kill() {
eprintln!("failed to kill {}.", process_name)
eprintln!("failed to kill {process_name}.")
}
continue 'outer;
}
+1 -1
View File
@@ -89,7 +89,7 @@ pub fn parse() -> anyhow::Result<()> {
}
Commands::Collect => {
let envs = crate::utils::collect::collect_envs().unwrap();
println!("{:#?}", envs);
println!("{envs:#?}");
}
Commands::PanicDialog { message } => {
crate::utils::dialog::panic_dialog(message);
@@ -111,11 +111,8 @@ impl IClashTemp {
let server_port = server_port.parse::<u16>().unwrap_or(9090);
let port = get_clash_external_port(&strategy, server_port)?;
if port != server_port {
let new_server = format!("{}:{}", server_ip, port);
warn!(
"The external controller port has been changed to {}",
new_server
);
let new_server = format!("{server_ip}:{port}");
warn!("The external controller port has been changed to {new_server}");
let mut map = Mapping::new();
map.insert("external-controller".into(), new_server.into());
self.patch_config(map);
@@ -41,8 +41,7 @@ impl<'de> Deserialize<'de> for ProfileBuilder {
type_field =
Some(ProfileItemType::deserialize(value.clone()).map_err(|err| {
serde::de::Error::custom(format!(
"failed to deserialize profile builder type: {}",
err
"failed to deserialize profile builder type: {err}"
))
})?);
}
@@ -55,32 +54,28 @@ impl<'de> Deserialize<'de> for ProfileBuilder {
.map(ProfileBuilder::Remote)
.map_err(|err| {
serde::de::Error::custom(format!(
"failed to deserialize remote profile builder: {}",
err
"failed to deserialize remote profile builder: {err}"
))
}),
ProfileItemType::Local => LocalProfileBuilder::deserialize(mapping)
.map(ProfileBuilder::Local)
.map_err(|err| {
serde::de::Error::custom(format!(
"failed to deserialize local profile builder: {}",
err
"failed to deserialize local profile builder: {err}"
))
}),
ProfileItemType::Merge => MergeProfileBuilder::deserialize(mapping)
.map(ProfileBuilder::Merge)
.map_err(|err| {
serde::de::Error::custom(format!(
"failed to deserialize merge profile builder: {}",
err
"failed to deserialize merge profile builder: {err}"
))
}),
ProfileItemType::Script(_) => ScriptProfileBuilder::deserialize(mapping)
.map(ProfileBuilder::Script)
.map_err(|err| {
serde::de::Error::custom(format!(
"failed to deserialize script profile builder: {}",
err
"failed to deserialize script profile builder: {err}"
))
}),
}
@@ -142,8 +142,7 @@ impl<'de> Deserialize<'de> for Profile {
type_field =
Some(ProfileItemType::deserialize(value.clone()).map_err(|err| {
serde::de::Error::custom(format!(
"failed to deserialize type: {}",
err
"failed to deserialize type: {err}"
))
})?);
}
@@ -52,15 +52,13 @@ pub struct ProfileShared {
impl ProfileFileIo for ProfileShared {
async fn read_file(&self) -> std::io::Result<String> {
let path =
app_profiles_dir().map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
let path = app_profiles_dir().map_err(std::io::Error::other)?;
let file = path.join(&self.file);
tokio::fs::read_to_string(file).await
}
async fn write_file(&self, content: String) -> std::io::Result<()> {
let path =
app_profiles_dir().map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
let path = app_profiles_dir().map_err(std::io::Error::other)?;
let file = path.join(&self.file);
let mut file = tokio::fs::OpenOptions::new()
.write(true)
@@ -54,7 +54,7 @@ impl Profiles {
match dirs::profiles_path().and_then(|path| help::read_yaml::<Self>(&path)) {
Ok(profiles) => profiles,
Err(err) => {
log::error!(target: "app", "{:?}\n - use the default profiles", err);
log::error!(target: "app", "{err:?}\n - use the default profiles");
Self::default()
}
}
@@ -322,7 +322,7 @@ fn clash_client_info() -> Result<(String, HeaderMap)> {
headers.insert("Content-Type", "application/json".parse()?);
if let Some(secret) = client.secret {
let secret = format!("Bearer {}", secret).parse()?;
let secret = format!("Bearer {secret}").parse()?;
headers.insert("Authorization", secret);
}
@@ -5,7 +5,8 @@ use crate::{
log_err,
utils::dirs,
};
use anyhow::{Result, bail};
use anyhow::{Context, Result, bail};
use camino::Utf8PathBuf;
#[cfg(target_os = "macos")]
use nyanpasu_ipc::api::network::set_dns::NetworkSetDnsReq;
use nyanpasu_ipc::{
@@ -35,9 +36,6 @@ use std::{
use tokio::time::sleep;
use tracing_attributes::instrument;
#[cfg(windows)]
use std::os::windows::process::CommandExt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, Type)]
#[serde(rename_all = "snake_case")]
pub enum RunType {
@@ -174,19 +172,19 @@ impl Instance {
CommandEvent::Stdout(line) => {
if is_premium {
let log = api::parse_log(line.clone());
log::info!(target: "app", "[{}]: {}", core_type, log);
log::info!(target: "app", "[{core_type}]: {log}");
} else {
log::info!(target: "app", "[{}]: {}", core_type, line);
log::info!(target: "app", "[{core_type}]: {line}");
}
Logger::global().set_log(line);
}
CommandEvent::Stderr(line) => {
log::error!(target: "app", "[{}]: {}", core_type, line);
log::error!(target: "app", "[{core_type}]: {line}");
err_buf.push(line.clone());
Logger::global().set_log(line);
}
CommandEvent::Error(e) => {
log::error!(target: "app", "[{}]: {}", core_type, e);
log::error!(target: "app", "[{core_type}]: {e}");
let err = anyhow::anyhow!(format!(
"{}\n{}",
e,
@@ -201,8 +199,7 @@ impl Instance {
CommandEvent::Terminated(status) => {
log::error!(
target: "app",
"core terminated with status: {:?}",
status
"core terminated with status: {status:?}"
);
stated_changed_at
.store(get_current_ts(), Ordering::Relaxed);
@@ -420,33 +417,27 @@ impl CoreManager {
}
/// 检查配置是否正确
pub fn check_config(&self) -> Result<()> {
pub async fn check_config(&self) -> Result<()> {
use nyanpasu_utils::core::instance::CoreInstance;
let config_path = Config::generate_file(ConfigType::Check)?;
let config_path = dirs::path_to_str(&config_path)?;
let config_path = Utf8PathBuf::from_path_buf(config_path)
.map_err(|_| anyhow::anyhow!("failed to convert config path to utf8 path"))?;
let clash_core = { Config::verge().latest().clash_core };
let clash_core = clash_core.unwrap_or(ClashCore::ClashPremium).to_string();
let clash_core = clash_core.unwrap_or(ClashCore::ClashPremium);
let clash_core: nyanpasu_utils::core::CoreType = (&clash_core).into();
let app_dir = dirs::app_data_dir()?;
let app_dir = dirs::path_to_str(&app_dir)?;
let app_dir = Utf8PathBuf::from_path_buf(app_dir)
.map_err(|_| anyhow::anyhow!("failed to convert app dir to utf8 path"))?;
let binary_path = find_binary_path(&clash_core)?;
let binary_path = Utf8PathBuf::from_path_buf(binary_path)
.map_err(|_| anyhow::anyhow!("failed to convert binary path to utf8 path"))?;
log::debug!(target: "app", "check config in `{clash_core}`");
let mut builder = std::process::Command::new(dirs::get_data_or_sidecar_path(&clash_core)?);
builder.args(["-t", "-d", app_dir, "-f", config_path]);
#[cfg(windows)]
let builder = builder.creation_flags(0x08000000); // CREATE_NO_WINDOW
let output = builder.output()?;
if !output.status.success() {
let stdout = String::from_utf8_lossy(&output.stdout);
let error = api::parse_check_output(stdout.to_string());
let error = match !error.is_empty() {
true => error,
false => stdout.to_string(),
};
Logger::global().set_log(stdout.to_string());
bail!("{error}");
}
CoreInstance::check_config_(&clash_core, &config_path, &binary_path, &app_dir)
.await
.context("failed to check config")
.inspect_err(|e| log::error!(target: "app", "failed to check config: {e:?}"))?;
Ok(())
}
@@ -458,11 +449,11 @@ impl CoreManager {
let instance = self.instance.lock();
instance.as_ref().cloned()
};
if let Some(instance) = instance.as_ref() {
if matches!(instance.state().await.as_ref(), CoreState::Running) {
log::debug!(target: "app", "core is already running, stop it first...");
instance.stop().await?;
}
if let Some(instance) = instance.as_ref()
&& matches!(instance.state().await.as_ref(), CoreState::Running)
{
log::debug!(target: "app", "core is already running, stop it first...");
instance.stop().await?;
}
}
@@ -497,11 +488,11 @@ impl CoreManager {
let mut this = self.instance.lock();
this.take()
};
if let Some(instance) = instance {
if matches!(instance.state().await.as_ref(), CoreState::Running) {
log::debug!(target: "app", "core is running, stop it first...");
instance.stop().await?;
}
if let Some(instance) = instance
&& matches!(instance.state().await.as_ref(), CoreState::Running)
{
log::debug!(target: "app", "core is running, stop it first...");
instance.stop().await?;
}
}
@@ -548,7 +539,7 @@ impl CoreManager {
// 更新配置
Config::generate().await?;
self.check_config()?;
self.check_config().await?;
// 清掉旧日志
Logger::global().clear_log();
@@ -580,7 +571,7 @@ impl CoreManager {
Config::generate().await?;
// 检查配置是否正常
self.check_config()?;
self.check_config().await?;
// 更新运行时配置
let path = Config::generate_file(ConfigType::Run)?;
@@ -227,7 +227,7 @@ impl ProxiesGuard {
if let Err(e) = self.sender.send(()) {
warn!(
target: "clash::proxies",
"send update signal failed: {:?}", e
"send update signal failed: {e:?}"
);
}
}
@@ -126,14 +126,14 @@ impl ClashConnectionsConnector {
let info = crate::Config::clash().data().get_client_info();
(info.server, info.secret)
};
let url = format!("ws://{}/connections", server);
let url = format!("ws://{server}/connections");
let mut request = url
.into_client_request()
.context("failed to create client request")?;
if let Some(secret) = secret {
request.headers_mut().insert(
"Authorization",
format!("Bearer {}", secret)
format!("Bearer {secret}")
.parse()
.context("failed to create header value")?,
);
@@ -148,7 +148,7 @@ impl ClashConnectionsConnector {
async {
self.dispatch_state_changed(ClashConnectionsConnectorState::Connecting);
let endpoint = Self::endpoint().context("failed to create endpoint")?;
log::debug!("connecting to clash connections ws server: {:?}", endpoint);
log::debug!("connecting to clash connections ws server: {endpoint:?}");
let mut rx = connect_clash_server::<ClashConnectionsMessage>(endpoint).await?;
self.dispatch_state_changed(ClashConnectionsConnectorState::Connected);
let this = self.clone();
@@ -52,8 +52,8 @@ impl<'a> MigrationFile<'a> {
/// Create or Truncate the lock file and write the content.
pub fn write_file(&self) -> Result<(), std::io::Error> {
let content = serde_yaml::to_string(self).map_err(|e| {
log::error!("Failed to serialize the migration file: {}", e);
std::io::Error::new(std::io::ErrorKind::Other, e)
log::error!("Failed to serialize the migration file: {e}");
std::io::Error::other(e)
})?;
let mut file = std::fs::OpenOptions::new()
.write(true)
@@ -65,7 +65,7 @@ impl<'a> MigrationFile<'a> {
.as_bytes(),
)
.map_err(|e| {
log::error!("Failed to write the migration file: {}", e);
log::error!("Failed to write the migration file: {e}");
e
})?;
file.write_all(content.as_bytes())
@@ -111,19 +111,17 @@ pub trait Migration<'a>: DynClone {
clone_trait_object!(Migration<'_>);
auto trait NotDynMigration {}
impl !NotDynMigration for DynMigration<'_> {}
/// Impl From T for DynMigration excludes itself.
impl<'a, T> From<T> for DynMigration<'a>
pub trait MigrationExt<'a>: Migration<'a>
where
T: Clone + Migration<'a> + Send + Sync + NotDynMigration + 'a,
Self: Sized + 'static + Send + Sync,
{
fn from(item: T) -> Self {
Box::new(item)
fn boxed(self) -> DynMigration<'a> {
Box::new(self) as DynMigration
}
}
impl<'a, T> MigrationExt<'a> for T where T: Sized + 'static + Migration<'a> + Send + Sync {}
impl<'a, T> Migration<'a> for Unit<'a, T>
where
T: Clone + Migration<'a> + Send + Sync,
@@ -259,7 +257,7 @@ impl Runner<'_> {
{
println!("Running migration: {}", migration.name());
let advice = self.advice_migration(migration);
println!("Advice: {:?}", advice);
println!("Advice: {advice:?}");
if matches!(advice, MigrationAdvice::Ignored | MigrationAdvice::Done) {
return Ok(());
}
@@ -267,21 +265,18 @@ impl Runner<'_> {
let mut store = self.store.borrow_mut();
match migration.migrate() {
Ok(_) => {
println!("Migration {} completed.", name);
println!("Migration {name} completed.");
store.set_state(Cow::Owned(name.to_string()), MigrationState::Completed);
Ok(())
}
Err(e) => {
eprintln!(
"Migration {} failed: {}; trying to discard changes",
name, e
);
eprintln!("Migration {name} failed: {e}; trying to discard changes");
match migration.discard() {
Ok(_) => {
eprintln!("Migration {} discarded.", name);
eprintln!("Migration {name} discarded.");
}
Err(e) => {
eprintln!("Migration {} discard failed: {}", name, e);
eprintln!("Migration {name} discard failed: {e}");
}
}
store.set_state(Cow::Owned(name.to_string()), MigrationState::Failed);
@@ -307,7 +302,7 @@ impl Runner<'_> {
}
pub fn run_units_up_to_version(&self, to_ver: &Version) -> std::io::Result<()> {
println!("Running units up to version: {}", to_ver);
println!("Running units up to version: {to_ver}");
let version = {
let store = self.store.borrow();
store.version.clone()
@@ -8,14 +8,14 @@ use serde_yaml::{
use crate::{
config::RUNTIME_CONFIG,
core::migration::{DynMigration, Migration},
core::migration::{DynMigration, Migration, MigrationExt},
};
pub static UNITS: Lazy<Vec<DynMigration>> = Lazy::new(|| {
vec![
MigrateAppHomeDir.into(),
MigrateProxiesSelectorMode.into(),
MigrateScriptProfileType.into(),
MigrateAppHomeDir.boxed(),
MigrateProxiesSelectorMode.boxed(),
MigrateScriptProfileType.boxed(),
]
});
@@ -5,15 +5,15 @@ use semver::Version;
use serde_yaml::Mapping;
use crate::{
core::migration::{DynMigration, Migration},
core::migration::{DynMigration, Migration, MigrationExt},
utils::dirs,
};
pub static UNITS: Lazy<Vec<DynMigration>> = Lazy::new(|| {
vec![
MigrateProfilesNullValue.into(),
MigrateLanguageOption.into(),
MigrateThemeSetting.into(),
MigrateProfilesNullValue.boxed(),
MigrateLanguageOption.boxed(),
MigrateThemeSetting.boxed(),
]
});
@@ -32,25 +32,17 @@ impl Migration<'_> for MigrateProfilesNullValue {
}
fn migrate(&self) -> std::io::Result<()> {
let profiles_path =
dirs::profiles_path().map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
let profiles_path = dirs::profiles_path().map_err(std::io::Error::other)?;
if !profiles_path.exists() {
return Ok(());
}
let profiles = std::fs::read_to_string(profiles_path.clone())?;
let mut profiles: Mapping = serde_yaml::from_str(&profiles).map_err(|e| {
std::io::Error::new(
std::io::ErrorKind::Other,
format!("failed to parse profiles: {}", e),
)
})?;
let mut profiles: Mapping = serde_yaml::from_str(&profiles)
.map_err(|e| std::io::Error::other(format!("failed to parse profiles: {e}")))?;
profiles.iter_mut().for_each(|(key, value)| {
if value.is_null() {
println!(
"detected null value in profiles {:?} should be migrated",
key
);
println!("detected null value in profiles {key:?} should be migrated");
*value = serde_yaml::Value::Sequence(Vec::new());
}
});
@@ -58,38 +50,26 @@ impl Migration<'_> for MigrateProfilesNullValue {
.write(true)
.truncate(true)
.open(profiles_path)?;
serde_yaml::to_writer(file, &profiles)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
serde_yaml::to_writer(file, &profiles).map_err(std::io::Error::other)?;
Ok(())
}
fn discard(&self) -> std::io::Result<()> {
let profiles_path =
dirs::profiles_path().map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
let profiles_path = dirs::profiles_path().map_err(std::io::Error::other)?;
if !profiles_path.exists() {
return Ok(());
}
let profiles = std::fs::read_to_string(profiles_path.clone())?;
let mut profiles: Mapping = serde_yaml::from_str(&profiles).map_err(|e| {
std::io::Error::new(
std::io::ErrorKind::Other,
format!("failed to parse profiles: {}", e),
)
})?;
let mut profiles: Mapping = serde_yaml::from_str(&profiles)
.map_err(|e| std::io::Error::other(format!("failed to parse profiles: {e}")))?;
profiles.iter_mut().for_each(|(key, value)| {
if key.is_string() && key.as_str().unwrap() == "chain" && value.is_sequence() {
println!(
"detected sequence value in profiles {:?} should be migrated",
key
);
println!("detected sequence value in profiles {key:?} should be migrated");
*value = serde_yaml::Value::Null;
}
if key.is_string() && key.as_str().unwrap() == "current" && value.is_sequence() {
println!(
"detected sequence value in profiles {:?} should be migrated",
key
);
println!("detected sequence value in profiles {key:?} should be migrated");
*value = serde_yaml::Value::Null;
}
});
@@ -97,8 +77,7 @@ impl Migration<'_> for MigrateProfilesNullValue {
.write(true)
.truncate(true)
.open(profiles_path)?;
serde_yaml::to_writer(file, &profiles)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
serde_yaml::to_writer(file, &profiles).map_err(std::io::Error::other)?;
Ok(())
}
}
@@ -166,21 +145,18 @@ impl<'a> Migration<'a> for MigrateThemeSetting {
return Ok(());
}
let raw_config = std::fs::read_to_string(&config_path)?;
let mut config: Mapping = serde_yaml::from_str(&raw_config)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
if let Some(theme) = config.get("theme_setting") {
if !theme.is_null() {
if let Some(theme_obj) = theme.as_mapping() {
if let Some(color) = theme_obj.get("primary_color") {
println!("color: {:?}", color);
config.insert("theme_color".into(), color.clone());
}
}
}
let mut config: Mapping =
serde_yaml::from_str(&raw_config).map_err(std::io::Error::other)?;
if let Some(theme) = config.get("theme_setting")
&& !theme.is_null()
&& let Some(theme_obj) = theme.as_mapping()
&& let Some(color) = theme_obj.get("primary_color")
{
println!("color: {color:?}");
config.insert("theme_color".into(), color.clone());
}
config.remove("theme_setting");
let new_config = serde_yaml::to_string(&config)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
let new_config = serde_yaml::to_string(&config).map_err(std::io::Error::other)?;
std::fs::write(&config_path, new_config)?;
Ok(())
}
@@ -191,8 +167,8 @@ impl<'a> Migration<'a> for MigrateThemeSetting {
return Ok(());
}
let raw_config = std::fs::read_to_string(&config_path)?;
let mut config: Mapping = serde_yaml::from_str(&raw_config)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
let mut config: Mapping =
serde_yaml::from_str(&raw_config).map_err(std::io::Error::other)?;
if let Some(color) = config.get("theme_color") {
let mut theme_obj = Mapping::new();
theme_obj.insert("primary_color".into(), color.clone());
@@ -202,8 +178,7 @@ impl<'a> Migration<'a> for MigrateThemeSetting {
);
config.remove("theme_color");
}
let new_config = serde_yaml::to_string(&config)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
let new_config = serde_yaml::to_string(&config).map_err(std::io::Error::other)?;
std::fs::write(&config_path, new_config)?;
Ok(())
}
@@ -26,12 +26,11 @@ pub async fn init_service() {
status: nyanpasu_ipc::types::ServiceStatus::Running,
..
}) = control::status().await
&& enable_service
{
if enable_service {
ipc::spawn_health_check();
while !ipc::HEALTH_CHECK_RUNNING.load(std::sync::atomic::Ordering::Acquire) {
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
}
ipc::spawn_health_check();
while !ipc::HEALTH_CHECK_RUNNING.load(std::sync::atomic::Ordering::Acquire) {
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
}
}
}
@@ -31,7 +31,7 @@ impl AsyncJobExecutor for EventsRotateJob {
for task_id in task_ids {
let event_ids = storage
.get_event_ids(task_id)
.context(format!("failed to get event ids for task {}", task_id))?
.context(format!("failed to get event ids for task {task_id}"))?
.unwrap_or_default();
let mut events_to_remove = Vec::new();
let mut events = event_ids
@@ -55,10 +55,10 @@ impl AsyncJobExecutor for EventsRotateJob {
events_to_remove.extend(events);
// remove events
for event_id in events_to_remove {
log::debug!("removing event {} for task {}", event_id, task_id);
log::debug!("removing event {event_id} for task {task_id}");
storage
.remove_event(event_id, task_id)
.context(format!("failed to remove event {}", event_id))?;
.context(format!("failed to remove event {event_id}"))?;
}
}
Ok(())
@@ -204,7 +204,7 @@ fn get_task_id(uid: &str) -> TaskID {
fn new_task(task_id: TaskID, profile_uid: &str, interval: Minutes) -> Task {
Task {
id: task_id,
name: format!("profile-updater-{}", profile_uid),
name: format!("profile-updater-{profile_uid}"),
executor: TaskExecutor::Async(Box::new(ProfileUpdater(profile_uid.to_owned().to_string()))),
schedule: TaskSchedule::Interval(Duration::from_secs(interval * 60)),
..Task::default()
@@ -76,7 +76,7 @@ impl TaskStorage {
/// get_event get a task event by event id
pub fn get_event(&self, event_id: TaskEventID) -> Result<Option<TaskEvent>> {
let db = self.storage.get_instance();
let key = format!("task:event:id:{}", event_id);
let key = format!("task:event:id:{event_id}");
let read_txn = db.begin_read()?;
let table = read_txn.open_table(NYANPASU_TABLE)?;
let value = table.get(key.as_bytes())?;
@@ -107,7 +107,7 @@ impl TaskStorage {
pub fn get_event_ids(&self, task_id: TaskID) -> Result<Option<Vec<TaskEventID>>> {
let db = self.storage.get_instance();
let key = format!("task:events:task_id:{}", task_id);
let key = format!("task:events:task_id:{task_id}");
let read_txn = db.begin_read()?;
let table = read_txn.open_table(NYANPASU_TABLE)?;
let value = table.get(key.as_bytes())?;
@@ -160,8 +160,8 @@ impl TaskStorage {
None => return Ok(()),
};
let db = self.storage.get_instance();
let event_key = format!("task:event:id:{}", event_id);
let event_ids_key = format!("task:events:task_id:{}", event_id);
let event_key = format!("task:event:id:{event_id}");
let event_ids_key = format!("task:events:task_id:{event_id}");
let write_txn = db.begin_write()?;
{
let mut table = write_txn.open_table(NYANPASU_TABLE)?;
@@ -247,6 +247,6 @@ mod tests {
.trim();
let hashset: HashSet<i32> = serde_json::from_str(json).unwrap();
let new_json = serde_json::to_string(&hashset).unwrap();
println!("{}", new_json);
println!("{new_json}");
}
}
@@ -310,11 +310,11 @@ impl TaskManager {
build_task(task, list.len())
};
let restored_task = self.get_task_from_restored(task.id);
if let Some(restored_task) = restored_task {
if restored_task.name == task.name {
task.last_run = restored_task.last_run;
task.created_at = restored_task.created_at;
}
if let Some(restored_task) = restored_task
&& restored_task.name == task.name
{
task.last_run = restored_task.last_run;
task.created_at = restored_task.created_at;
}
let task_id = task.id;
@@ -93,10 +93,10 @@ fn resize_image(mode: TrayIcon, scale_factor: f64) {
}
};
let cache_dir = crate::utils::dirs::cache_dir().unwrap().join("icons");
if !cache_dir.exists() {
if let Err(e) = std::fs::create_dir_all(&cache_dir) {
tracing::error!("failed to create cache dir: {:?}", e);
}
if !cache_dir.exists()
&& let Err(e) = std::fs::create_dir_all(&cache_dir)
{
tracing::error!("failed to create cache dir: {:?}", e);
}
if let Err(e) = std::fs::write(cache_dir.join(format!("tray_{mode}.png")), icon) {
tracing::error!("failed to write icon file: {:?}", e);
@@ -186,7 +186,7 @@ impl Tray {
.text("restart_clash", t!("tray.more.restart_clash"))
.text("restart_app", t!("tray.more.restart_app"))
.item(
&MenuItemBuilder::new(format!("Version {}", version))
&MenuItemBuilder::new(format!("Version {version}"))
.id("app_version")
.enabled(false)
.build(app_handle)?,
@@ -257,12 +257,12 @@ mod platform_impl {
let id = item_ids.len();
item_ids.insert(key, id);
let mut sub_item_builder = CheckMenuItemBuilder::new(item.clone())
.id(format!("proxy_node_{}", id))
.id(format!("proxy_node_{id}"))
.checked(false);
if let Some(now) = group.current.clone() {
if now == item.as_str() {
sub_item_builder = sub_item_builder.checked(true);
}
if let Some(now) = group.current.clone()
&& now == item.as_str()
{
sub_item_builder = sub_item_builder.checked(true);
}
if !matches!(group.r#type.as_str(), "Selector" | "Fallback") {
@@ -521,7 +521,7 @@ pub fn on_system_tray_event(event: &str) {
ProxiesGuard::global()
.select_proxy(&group, &name)
.await
.with_context(|| format!("select proxy failed, {} {}, cause: ", group, name))?;
.with_context(|| format!("select proxy failed, {group} {name}, cause: "))?;
debug!("select proxy success: {} {}", group, name);
Ok::<(), anyhow::Error>(())
@@ -158,7 +158,7 @@ impl UpdaterManager {
mirror,
"/libnyanpasu/clash-nyanpasu/raw/main/manifest/version.json",
)?;
log::debug!("{}", url);
log::debug!("{url}");
let res = self.client.get(url).send().await?;
let status_code = res.status();
if !status_code.is_success() {
@@ -178,11 +178,11 @@ impl UpdaterManager {
let clash_rs_alpha_version = self.get_clash_rs_alpha_version();
let (latest, mihomo_alpha_version, clash_rs_alpha_version) =
join!(latest, mihomo_alpha_version, clash_rs_alpha_version);
log::debug!("latest version: {:?}", latest);
log::debug!("latest version: {latest:?}");
self.manifest_version = latest?;
log::debug!("mihomo alpha version: {:?}", mihomo_alpha_version);
log::debug!("mihomo alpha version: {mihomo_alpha_version:?}");
self.manifest_version.latest.mihomo_alpha = mihomo_alpha_version?;
log::debug!("clash rs alpha version: {:?}", clash_rs_alpha_version);
log::debug!("clash rs alpha version: {clash_rs_alpha_version:?}");
self.manifest_version.latest.clash_rs_alpha = clash_rs_alpha_version?;
Ok(())
}
@@ -191,10 +191,10 @@ impl UpdaterManager {
pub async fn mirror_speed_test(&self) -> Result<()> {
{
let mirror = self.mirror.read();
if let Some((_, timestamp)) = mirror.as_ref() {
if chrono::Utc::now().timestamp() - (*timestamp as i64) < 3600 {
return Ok(());
}
if let Some((_, timestamp)) = mirror.as_ref()
&& chrono::Utc::now().timestamp() - (*timestamp as i64) < 3600
{
return Ok(());
}
}
let mirrors = crate::utils::candy::INTERNAL_MIRRORS;
@@ -35,21 +35,19 @@ pub(super) enum CoreTypeMeta {
pub(super) fn get_download_path(core_type: CoreTypeMeta, artifact: &str) -> String {
match core_type {
CoreTypeMeta::Mihomo(tag) => {
format!("MetaCubeX/mihomo/releases/download/{}/{}", tag, artifact)
format!("MetaCubeX/mihomo/releases/download/{tag}/{artifact}")
}
CoreTypeMeta::MihomoAlpha => {
format!("MetaCubeX/mihomo/releases/download/Prerelease-Alpha/{artifact}")
}
CoreTypeMeta::MihomoAlpha => format!(
"MetaCubeX/mihomo/releases/download/Prerelease-Alpha/{}",
artifact
),
CoreTypeMeta::ClashRs(tag) => {
format!("Watfaq/clash-rs/releases/download/{}/{}", tag, artifact)
format!("Watfaq/clash-rs/releases/download/{tag}/{artifact}")
}
CoreTypeMeta::ClashRsAlpha => {
format!("Watfaq/clash-rs/releases/download/latest/{}", artifact)
format!("Watfaq/clash-rs/releases/download/latest/{artifact}")
}
CoreTypeMeta::ClashPremium(tag) => {
format!("zhongfly/Clash-premium-backup/releases/download/{tag}/{artifact}")
}
CoreTypeMeta::ClashPremium(tag) => format!(
"zhongfly/Clash-premium-backup/releases/download/{}/{}",
tag, artifact
),
}
}
@@ -85,10 +85,10 @@ pub fn use_whitelist_fields_filter(config: Mapping, filter: &[String], enable: b
let mut ret = Mapping::new();
for (key, value) in config.into_iter() {
if let Some(key) = key.as_str() {
if filter.contains(&key.to_string()) {
ret.insert(Value::from(key), value);
}
if let Some(key) = key.as_str()
&& filter.contains(&key.to_string())
{
ret.insert(Value::from(key), value);
}
}
ret
@@ -70,7 +70,7 @@ fn run_expr<T: DeserializeOwned>(logs: &mut Logs, item: &Value, expr: &str) -> O
let item = match lua_runtime.to_value(item) {
Ok(v) => v,
Err(e) => {
logs.error(format!("failed to convert item to lua value: {:#?}", e));
logs.error(format!("failed to convert item to lua value: {e:#?}"));
return None;
}
};
@@ -90,7 +90,7 @@ fn run_expr<T: DeserializeOwned>(logs: &mut Logs, item: &Value, expr: &str) -> O
}
}
Err(e) => {
logs.error(format!("failed to run expr: {:#?}", e));
logs.error(format!("failed to run expr: {e:#?}"));
None
}
}
@@ -99,12 +99,12 @@ fn run_expr<T: DeserializeOwned>(logs: &mut Logs, item: &Value, expr: &str) -> O
fn do_filter(logs: &mut Logs, config: &mut Value, field_str: &str, filter: &Value) {
let field = match find_field(config, field_str) {
Some(field) if !field.is_sequence() => {
logs.warn(format!("field is not sequence: {:#?}", field_str));
logs.warn(format!("field is not sequence: {field_str:#?}"));
return;
}
Some(field) => field,
None => {
logs.warn(format!("field not found: {:#?}", field_str));
logs.warn(format!("field not found: {field_str:#?}"));
return;
}
};
@@ -208,7 +208,7 @@ fn do_filter(logs: &mut Logs, config: &mut Value, field_str: &str, filter: &Valu
}
}
_ => {
logs.info(format!("invalid key: {:#?}", last_key));
logs.info(format!("invalid key: {last_key:#?}"));
}
}
}
@@ -223,7 +223,7 @@ fn do_filter(logs: &mut Logs, config: &mut Value, field_str: &str, filter: &Valu
}
}
_ => {
logs.info(format!("invalid key: {:#?}", key));
logs.info(format!("invalid key: {key:#?}"));
}
}
}
@@ -233,7 +233,7 @@ fn do_filter(logs: &mut Logs, config: &mut Value, field_str: &str, filter: &Valu
}
_ => {
logs.warn(format!("invalid filter: {:#?}", filter));
logs.warn(format!("invalid filter: {filter:#?}"));
}
}
}
@@ -249,7 +249,7 @@ pub fn use_merge(merge: &Mapping, mut config: Mapping) -> ProcessOutput {
match key_str {
key_str if key_str.starts_with("prepend__") || key_str.starts_with("prepend-") => {
if !value.is_sequence() {
logs.warn(format!("prepend value is not sequence: {:#?}", key_str));
logs.warn(format!("prepend value is not sequence: {key_str:#?}"));
continue;
}
let key_str = key_str.replace("prepend__", "").replace("prepend-", "");
@@ -259,18 +259,18 @@ pub fn use_merge(merge: &Mapping, mut config: Mapping) -> ProcessOutput {
if field.is_sequence() {
merge_sequence(field, value, false);
} else {
logs.warn(format!("field is not sequence: {:#?}", key_str));
logs.warn(format!("field is not sequence: {key_str:#?}"));
}
}
None => {
logs.warn(format!("field not found: {:#?}", key_str));
logs.warn(format!("field not found: {key_str:#?}"));
}
}
continue;
}
key_str if key_str.starts_with("append__") || key_str.starts_with("append-") => {
if !value.is_sequence() {
logs.warn(format!("append value is not sequence: {:#?}", key_str));
logs.warn(format!("append value is not sequence: {key_str:#?}"));
continue;
}
let key_str = key_str.replace("append__", "").replace("append-", "");
@@ -280,11 +280,11 @@ pub fn use_merge(merge: &Mapping, mut config: Mapping) -> ProcessOutput {
if field.is_sequence() {
merge_sequence(field, value, true);
} else {
logs.warn(format!("field is not sequence: {:#?}", key_str));
logs.warn(format!("field is not sequence: {key_str:#?}"));
}
}
None => {
logs.warn(format!("field not found: {:#?}", key_str));
logs.warn(format!("field not found: {key_str:#?}"));
}
}
continue;
@@ -297,7 +297,7 @@ pub fn use_merge(merge: &Mapping, mut config: Mapping) -> ProcessOutput {
*field = value.clone();
}
None => {
logs.warn(format!("field not found: {:#?}", key_str));
logs.warn(format!("field not found: {key_str:#?}"));
}
}
continue;
@@ -331,7 +331,7 @@ mod tests {
- 222
";
let mut config = serde_yaml::from_str::<super::Value>(config).unwrap();
eprintln!("{:#?}", config);
eprintln!("{config:#?}");
let field = super::find_field(&mut config, "a.b.c");
assert!(field.is_some(), "a.b.c should be found");
let field = super::find_field(&mut config, "a.b");
@@ -382,7 +382,7 @@ mod tests {
let merge = serde_yaml::from_str::<super::Mapping>(merge).unwrap();
let config = serde_yaml::from_str::<super::Mapping>(config).unwrap();
let (result, logs) = super::use_merge(&merge, config);
eprintln!("{:#?}\n\n{:#?}", logs, result);
eprintln!("{logs:#?}\n\n{result:#?}");
let expected = serde_yaml::from_str::<super::Mapping>(expected).unwrap();
assert_eq!(logs.len(), 1); // field not found: nothing
assert_eq!(result.unwrap(), expected);
@@ -426,7 +426,7 @@ mod tests {
let merge = serde_yaml::from_str::<super::Mapping>(merge).unwrap();
let config = serde_yaml::from_str::<super::Mapping>(config).unwrap();
let (result, logs) = super::use_merge(&merge, config);
eprintln!("{:#?}\n\n{:#?}", logs, result);
eprintln!("{logs:#?}\n\n{result:#?}");
let expected = serde_yaml::from_str::<super::Mapping>(expected).unwrap();
assert_eq!(logs.len(), 1); // field not found: nothing
assert_eq!(result.unwrap(), expected);
@@ -469,7 +469,7 @@ mod tests {
let merge = serde_yaml::from_str::<super::Mapping>(merge).unwrap();
let config = serde_yaml::from_str::<super::Mapping>(config).unwrap();
let (result, logs) = super::use_merge(&merge, config);
eprintln!("{:#?}\n\n{:#?}", logs, result);
eprintln!("{logs:#?}\n\n{result:#?}");
let expected = serde_yaml::from_str::<super::Mapping>(expected).unwrap();
assert_eq!(logs.len(), 1); // field not found: nothing
assert_eq!(result.unwrap(), expected);
@@ -566,7 +566,7 @@ mod tests {
let merge = serde_yaml::from_str::<super::Mapping>(merge).unwrap();
let config = serde_yaml::from_str::<super::Mapping>(config).unwrap();
let (result, logs) = super::use_merge(&merge, config);
eprintln!("{:#?}\n\n{:#?}", logs, result);
eprintln!("{logs:#?}\n\n{result:#?}");
assert!(logs.len() == 1, "filter_wow should not work");
let expected = serde_yaml::from_str::<super::Mapping>(expected).unwrap();
assert_eq!(result.unwrap(), expected);
@@ -651,7 +651,7 @@ mod tests {
let merge = serde_yaml::from_str::<super::Mapping>(merge).unwrap();
let config = serde_yaml::from_str::<super::Mapping>(config).unwrap();
let (result, logs) = super::use_merge(&merge, config);
eprintln!("{:#?}\n\n{:#?}", logs, result);
eprintln!("{logs:#?}\n\n{result:#?}");
assert_eq!(logs.len(), 1);
let expected = serde_yaml::from_str::<super::Mapping>(expected).unwrap();
assert_eq!(result.unwrap(), expected);
@@ -716,7 +716,7 @@ mod tests {
let merge = serde_yaml::from_str::<super::Mapping>(merge).unwrap();
let config = serde_yaml::from_str::<super::Mapping>(config).unwrap();
let (result, logs) = super::use_merge(&merge, config);
eprintln!("{:#?}\n\n{:#?}", logs, result);
eprintln!("{logs:#?}\n\n{result:#?}");
assert_eq!(logs.len(), 0);
let expected = serde_yaml::from_str::<super::Mapping>(expected).unwrap();
assert_eq!(result.unwrap(), expected);
@@ -799,7 +799,7 @@ mod tests {
let merge = serde_yaml::from_str::<super::Mapping>(merge).unwrap();
let config = serde_yaml::from_str::<super::Mapping>(config).unwrap();
let (result, logs) = super::use_merge(&merge, config);
eprintln!("{:#?}\n\n{:#?}", logs, result);
eprintln!("{logs:#?}\n\n{result:#?}");
assert_eq!(logs.len(), 1);
let expected = serde_yaml::from_str::<super::Mapping>(expected).unwrap();
assert_eq!(result.unwrap(), expected);
@@ -933,7 +933,7 @@ mod tests {
let merge = serde_yaml::from_str::<super::Mapping>(merge).unwrap();
let config = serde_yaml::from_str::<super::Mapping>(config).unwrap();
let (result, logs) = super::use_merge(&merge, config);
eprintln!("{:#?}\n\n{:#?}", logs, result);
eprintln!("{logs:#?}\n\n{result:#?}");
assert_eq!(logs.len(), 0);
let expected = serde_yaml::from_str::<super::Mapping>(expected).unwrap();
assert_eq!(result.unwrap(), expected);
@@ -1022,7 +1022,7 @@ mod tests {
let merge = serde_yaml::from_str::<super::Mapping>(merge).unwrap();
let config = serde_yaml::from_str::<super::Mapping>(config).unwrap();
let (result, logs) = super::use_merge(&merge, config);
eprintln!("{:#?}\n\n{:#?}", logs, result);
eprintln!("{logs:#?}\n\n{result:#?}");
assert_eq!(logs.len(), 0);
let expected = serde_yaml::from_str::<super::Mapping>(expected).unwrap();
assert_eq!(result.unwrap(), expected);
@@ -1054,7 +1054,7 @@ mod tests {
let config = serde_yaml::from_str::<super::Mapping>(config).unwrap();
let (result, logs) = super::use_merge(&merge, config);
eprintln!("{:#?}\n\n{:#?}", logs, result);
eprintln!("{logs:#?}\n\n{result:#?}");
assert_eq!(logs.len(), 0);
let expected = r#"
a:
@@ -1,5 +1,5 @@
use super::runner::{ProcessOutput, Runner, wrap_result};
use crate::enhance::utils::{LogSpan, Logs, LogsExt, take_logs};
use crate::enhance::utils::{LogSpan, Logs, LogsExt};
use anyhow::Context as _;
use async_trait::async_trait;
use boa_engine::{
@@ -204,7 +204,7 @@ impl Runner for JSRunner {
async fn process_honey(&self, mapping: Mapping, script: &str) -> ProcessOutput {
let script = wrap_result!(wrap_script_if_not_esm(script));
let hash = crate::utils::help::get_uid("script");
let path = CUSTOM_SCRIPTS_DIR.join(format!("{}.mjs", hash));
let path = CUSTOM_SCRIPTS_DIR.join(format!("{hash}.mjs"));
wrap_result!(
tokio::fs::write(&path, script.as_bytes())
.await
@@ -470,7 +470,7 @@ const foreignNameservers = [
.unwrap()
.block_on(async move {
let (res, logs) = runner.process_honey(mapping, script).await;
eprintln!("logs: {:?}", logs);
eprintln!("logs: {logs:?}");
let mapping = res.unwrap();
assert_eq!(
mapping["rules"],
@@ -542,7 +542,7 @@ const foreignNameservers = [
.unwrap()
.block_on(async move {
let (res, logs) = runner.process_honey(mapping, script).await;
eprintln!("logs: {:?}", logs);
eprintln!("logs: {logs:?}");
let mapping = res.unwrap();
assert_eq!(
mapping["rules"],
@@ -184,7 +184,7 @@ mod tests {
let (result, logs) = tokio::runtime::Runtime::new()
.unwrap()
.block_on(runner.process_honey(mapping, script));
eprintln!("{:?}\n{:?}", logs, result);
eprintln!("{logs:?}\n{result:?}");
assert!(result.is_ok());
assert_eq!(logs.len(), 3);
let expected = serde_yaml::from_str::<Mapping>(expected).unwrap();
@@ -1,5 +1,3 @@
use crate::config::nyanpasu::NetworkStatisticWidgetConfig;
use anyhow::Context;
use tauri::{AppHandle, Event, Runtime};
pub enum WidgetInstance {
+12 -14
View File
@@ -14,7 +14,6 @@ use crate::{
};
use anyhow::{Result, bail};
use handle::Message;
use nyanpasu_egui::widget::network_statistic_large;
use nyanpasu_ipc::api::status::CoreState;
use serde_yaml::{Mapping, Value};
use tauri::{AppHandle, Manager};
@@ -207,13 +206,12 @@ pub async fn patch_clash(patch: Mapping) -> Result<()> {
.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 changed
&& let Some(port) = mixed_port.unwrap().as_u64()
&& !port_scanner::local_port_available(port as u16)
{
Config::clash().discard();
bail!("port already in use");
}
};
@@ -447,8 +445,8 @@ async fn update_core_config() -> Result<()> {
/// copy env variable
pub fn copy_clash_env(app_handle: &AppHandle, option: &str) {
let port = { Config::verge().latest().verge_mixed_port.unwrap_or(7890) };
let http_proxy = format!("http://127.0.0.1:{}", port);
let socks5_proxy = format!("socks5://127.0.0.1:{}", port);
let http_proxy = format!("http://127.0.0.1:{port}");
let socks5_proxy = format!("socks5://127.0.0.1:{port}");
let sh =
format!("export https_proxy={http_proxy} http_proxy={http_proxy} all_proxy={socks5_proxy}");
@@ -481,10 +479,10 @@ pub fn update_proxies_buff(rx: Option<tokio::sync::oneshot::Receiver<()>>) {
use crate::core::clash::proxies::{ProxiesGuard, ProxiesGuardExt};
tauri::async_runtime::spawn(async move {
if let Some(rx) = rx {
if let Err(e) = rx.await {
log::error!(target: "app::clash::proxies", "update proxies buff by rx failed: {e}");
}
if let Some(rx) = rx
&& let Err(e) = rx.await
{
log::error!(target: "app::clash::proxies", "update proxies buff by rx failed: {e}");
}
match ProxiesGuard::global().update().await {
Ok(_) => {
+11 -17
View File
@@ -53,7 +53,7 @@ impl serde::Serialize for IpcError {
where
S: serde::ser::Serializer,
{
serializer.serialize_str(format!("{:#?}", self).as_str())
serializer.serialize_str(format!("{self:#?}").as_str())
}
}
@@ -598,7 +598,7 @@ pub async fn get_core_version(
#[specta::specta]
pub async fn collect_logs(app_handle: AppHandle) -> Result {
let now = Local::now().format("%Y-%m-%d");
let fname = format!("{}-log", now);
let fname = format!("{now}-log");
let builder = FileDialogBuilder::new(app_handle.dialog().clone());
builder
.add_filter("archive files", &["zip"])
@@ -606,7 +606,7 @@ pub async fn collect_logs(app_handle: AppHandle) -> Result {
.set_title("Save log archive")
.save_file(|file_path| match file_path {
Some(path) if path.as_path().is_some() => {
debug!("{:#?}", path);
debug!("{path:#?}");
match candy::collect_logs(path.as_path().unwrap()) {
Ok(_) => (),
Err(err) => {
@@ -866,10 +866,8 @@ pub mod service {
.as_ref()
.unwrap_or(&false)
};
if enabled_service {
if let Err(e) = crate::core::CoreManager::global().run_core().await {
log::error!(target: "app", "{e}");
}
if enabled_service && let Err(e) = crate::core::CoreManager::global().run_core().await {
log::error!(target: "app", "{e}");
}
Ok(res?)
}
@@ -885,10 +883,8 @@ pub mod service {
.as_ref()
.unwrap_or(&false)
};
if enabled_service {
if let Err(e) = crate::core::CoreManager::global().run_core().await {
log::error!(target: "app", "{e}");
}
if enabled_service && let Err(e) = crate::core::CoreManager::global().run_core().await {
log::error!(target: "app", "{e}");
}
Ok(res?)
}
@@ -904,10 +900,8 @@ pub mod service {
.as_ref()
.unwrap_or(&false)
};
if enabled_service {
if let Err(e) = crate::core::CoreManager::global().run_core().await {
log::error!(target: "app", "{e}");
}
if enabled_service && let Err(e) = crate::core::CoreManager::global().run_core().await {
log::error!(target: "app", "{e}");
}
Ok(res?)
}
@@ -932,9 +926,9 @@ pub async fn get_service_install_prompt() -> Result<String> {
.map(|arg| arg.to_string_lossy().to_string())
.collect::<Vec<_>>()
.join(" ");
let mut prompt = format!("./nyanpasu-service {}", args);
let mut prompt = format!("./nyanpasu-service {args}");
if cfg!(not(windows)) {
prompt = format!("sudo {}", prompt);
prompt = format!("sudo {prompt}");
}
Ok(prompt)
}
+9 -15
View File
@@ -108,14 +108,12 @@ pub fn run() -> std::io::Result<()> {
if single_instance_result
.as_ref()
.is_ok_and(|instance| instance.is_some())
&& let Err(e) = init::run_pending_migrations()
{
if let Err(e) = init::run_pending_migrations() {
utils::dialog::panic_dialog(&format!(
"Failed to finish migration event: {}\nYou can see the detailed information at migration.log in your local data dir.\nYou're supposed to submit it as the attachment of new issue.",
e,
));
std::process::exit(1);
}
utils::dialog::panic_dialog(&format!(
"Failed to finish migration event: {e}\nYou can see the detailed information at migration.log in your local data dir.\nYou're supposed to submit it as the attachment of new issue.",
));
std::process::exit(1);
}
crate::log_err!(init::init_config());
@@ -159,8 +157,7 @@ pub fn run() -> std::io::Result<()> {
// FIXME: maybe move this logic to a util function?
let msg = format!(
"Oops, we encountered some issues and program will exit immediately.\n\npayload: {:#?}\nlocation: {:?}\nbacktrace: {:#?}\n\n",
payload, location, backtrace,
"Oops, we encountered some issues and program will exit immediately.\n\npayload: {payload:#?}\nlocation: {location:?}\nbacktrace: {backtrace:#?}\n\n",
);
let child = std::process::Command::new(tauri::utils::platform::current_exe().unwrap())
.arg("panic-dialog")
@@ -288,20 +285,17 @@ pub fn run() -> std::io::Result<()> {
.arg(file)
.output()
.map(|_| ())
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))
.map_err(io::Error::other)
})
.bigint(BigIntExportBehavior::Number)
.header("/* eslint-disable */\n// @ts-nocheck"),
SPECTA_BINDINGS_PATH,
) {
Ok(_) => {
log::debug!(
"Exported typescript bindings, path: {}",
SPECTA_BINDINGS_PATH
);
log::debug!("Exported typescript bindings, path: {SPECTA_BINDINGS_PATH}");
}
Err(e) => {
panic!("Failed to export typescript bindings: {}", e);
panic!("Failed to export typescript bindings: {e}");
}
};
}
@@ -508,7 +508,7 @@ mod tests {
fn create_test_log_file(entries: Vec<&str>) -> anyhow::Result<(NamedTempFile, Utf8PathBuf)> {
let mut file = NamedTempFile::new()?;
for entry in entries {
writeln!(file, "{}", entry)?;
writeln!(file, "{entry}")?;
}
file.flush()?;
@@ -520,7 +520,7 @@ mod tests {
fn append_to_log_file(file: &mut NamedTempFile, entries: Vec<&str>) -> anyhow::Result<()> {
for entry in entries {
writeln!(file, "{}", entry)?;
writeln!(file, "{entry}")?;
}
file.flush()?;
Ok(())
@@ -10,7 +10,6 @@ use notify_debouncer_full::{
};
use tokio::{
sync::{
RwLock,
mpsc::{Receiver, UnboundedSender},
oneshot,
},
@@ -86,7 +86,7 @@ async fn cache_icon_inner(url: &str) -> Result<(HeaderValue, Bytes)> {
let outdated_time = now
.checked_sub(CACHE_TIMEOUT)
.expect("cache timeout is too long");
let cache_file = cache_dir.join(format!("{:x}.bin", hash));
let cache_file = cache_dir.join(format!("{hash:x}.bin"));
let meta = tokio::fs::metadata(&cache_file).await.ok();
match meta {
Some(meta) if meta.modified().is_ok_and(|t| t < outdated_time) => {
@@ -1,7 +1,5 @@
//! a shutdown handler for Windows
use std::sync::atomic::AtomicBool;
use atomic_enum::atomic_enum;
use once_cell::sync::OnceCell;
use windows_core::{Error, w};
@@ -35,7 +35,7 @@ pub fn get_reqwest_client() -> Result<reqwest::Client> {
let app_version = super::dirs::get_app_version();
let client = builder
.swift_set_nyanpasu_proxy()
.user_agent(format!("clash-nyanpasu/{}", app_version))
.user_agent(format!("clash-nyanpasu/{app_version}"))
.build()?;
Ok(client)
}
@@ -138,6 +138,6 @@ mod test {
)
.await
.unwrap();
println!("{:?}", results);
println!("{results:?}");
}
}
@@ -66,7 +66,7 @@ pub fn collect_envs<'a>() -> Result<EnvInfo<'a>, std::io::Error> {
let mut command = std::process::Command::new(
super::dirs::get_data_or_sidecar_path(name)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?,
.map_err(|e| std::io::Error::other(e.to_string()))?,
);
command.args(if matches!(c, CoreType::Clash(ClashCoreType::ClashRust)) {
["-V"]
+8 -11
View File
@@ -226,7 +226,7 @@ pub fn service_log_file() -> Result<PathBuf> {
let log_dir = app_logs_dir()?.join("service");
let local_time = Local::now().format("%Y-%m-%d-%H%M").to_string();
let log_file = format!("{}.log", local_time);
let log_file = format!("{local_time}.log");
let log_file = log_dir.join(log_file);
let _ = std::fs::create_dir_all(&log_dir);
@@ -260,16 +260,13 @@ pub fn get_single_instance_placeholder() -> String {
fn create_dir_all(dir: &PathBuf) -> Result<(), std::io::Error> {
let meta = fs::metadata(dir);
if let Ok(meta) = meta {
if !meta.is_dir() {
fs::remove_file(dir)?;
}
if let Ok(meta) = meta
&& !meta.is_dir()
{
fs::remove_file(dir)?;
}
fs_extra::dir::create_all(dir, false).map_err(|e| {
std::io::Error::new(
std::io::ErrorKind::Other,
format!("failed to create dir: {:?}, kind: {:?}", e, e.kind),
)
std::io::Error::other(format!("failed to create dir: {:?}, kind: {:?}", e, e.kind))
})?;
Ok(())
}
@@ -278,7 +275,7 @@ pub fn get_data_or_sidecar_path(binary_name: impl AsRef<str>) -> Result<PathBuf>
let binary_name = binary_name.as_ref();
let data_dir = app_data_dir()?;
let path = data_dir.join(if cfg!(windows) && !binary_name.ends_with(".exe") {
format!("{}.exe", binary_name)
format!("{binary_name}.exe")
} else {
binary_name.to_string()
});
@@ -288,7 +285,7 @@ pub fn get_data_or_sidecar_path(binary_name: impl AsRef<str>) -> Result<PathBuf>
let install_dir = app_install_dir()?;
let path = install_dir.join(if cfg!(windows) && !binary_name.ends_with(".exe") {
format!("{}.exe", binary_name)
format!("{binary_name}.exe")
} else {
binary_name.to_string()
});
@@ -211,7 +211,7 @@ impl Serialize for DownloaderError {
where
S: serde::Serializer,
{
format!("{}", self).serialize(serializer)
format!("{self}").serialize(serializer)
}
}
@@ -432,7 +432,7 @@ impl<F: Fn(DownloaderState)> Downloader<F> {
match result {
Ok(_) => Ok(()),
Err(e) => {
self.dispatch_event(DownloaderState::Failed(format!("{}", e)));
self.dispatch_event(DownloaderState::Failed(format!("{e}")));
Err(e)
}
}
@@ -533,7 +533,7 @@ impl SafeChunkThread for RwLock<ChunkThread> {
};
client
.get(url.as_str())
.header(reqwest::header::RANGE, format!("bytes={}-{}", start, end))
.header(reqwest::header::RANGE, format!("bytes={start}-{end}"))
.send()
.await?
.error_for_status()?
@@ -630,7 +630,7 @@ mod test {
let file = TokioFile::create("QQ9.7.17.29225.exe").await.unwrap();
let tick = time::Instant::now();
let on_event = |state: DownloaderState| {
println!("{:?}", state);
println!("{state:?}");
match state {
DownloaderState::Failed(e) => {
panic!("{}", e);
@@ -673,7 +673,7 @@ mod test {
std::thread::sleep(std::time::Duration::from_millis(10));
loop {
let status = downloader_clone.get_current_status();
println!("{:#?}", status);
println!("{status:#?}");
if matches!(
status.state,
DownloaderState::Finished | DownloaderState::Failed(_)
@@ -130,7 +130,7 @@ pub fn open_file(app: tauri::AppHandle, path: PathBuf) -> Result<()> {
// default open
shell
.open(path.to_string_lossy().to_string(), None)
.map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err))
.map_err(std::io::Error::other)
}
},
"Can't open file"
@@ -245,7 +245,7 @@ pub fn cleanup_processes(app_handle: &AppHandle) {
let widget_manager = app_handle.state::<crate::widget::WidgetManager>();
let _ = nyanpasu_utils::runtime::block_on(async {
if let Err(e) = widget_manager.stop().await {
log::error!("failed to stop widget manager: {:?}", e);
log::error!("failed to stop widget manager: {e:?}");
};
crate::core::CoreManager::global().stop_core().await
});
@@ -65,8 +65,8 @@ pub fn init() -> Result<()> {
std::convert::Into::<filter::LevelFilter>::into(LoggingLevel::Warn).into(),
)
.from_env_lossy()
.add_directive(format!("nyanpasu={}", log_level).parse().unwrap())
.add_directive(format!("clash_nyanpasu={}", log_level).parse().unwrap()),
.add_directive(format!("nyanpasu={log_level}").parse().unwrap())
.add_directive(format!("clash_nyanpasu={log_level}").parse().unwrap()),
);
// register the logger
@@ -98,8 +98,8 @@ pub fn init() -> Result<()> {
.into(),
)
.from_env_lossy()
.add_directive(format!("nyanpasu={}", level).parse().unwrap())
.add_directive(format!("clash_nyanpasu={}", level).parse().unwrap()),
.add_directive(format!("nyanpasu={level}").parse().unwrap())
.add_directive(format!("clash_nyanpasu={level}").parse().unwrap()),
)
.unwrap(); // panic if error
}
@@ -52,9 +52,9 @@ pub fn run_pending_migrations() -> Result<()> {
let _ = file.write_all(&buf);
}
Err(e) => {
eprintln!("failed to read stdout: {:?}", e);
eprintln!("failed to read stdout: {e:?}");
let mut errs = errs_.lock();
errs.push_str(&format!("failed to read stdout: {:?}\n", e));
errs.push_str(&format!("failed to read stdout: {e:?}\n"));
break;
}
}
@@ -77,9 +77,9 @@ pub fn run_pending_migrations() -> Result<()> {
errs.push_str(unsafe { std::str::from_utf8_unchecked(&buf) });
}
Err(e) => {
eprintln!("failed to read stderr: {:?}", e);
eprintln!("failed to read stderr: {e:?}");
let mut errs = errs_.lock();
errs.push_str(&format!("failed to read stderr: {:?}\n", e));
errs.push_str(&format!("failed to read stderr: {e:?}\n"));
break;
}
}
@@ -249,13 +249,13 @@ pub fn init_service() -> Result<()> {
"client service ver is newer than exist one, do service update"
);
if let Err(e) = crate::core::service::control::update_service().await {
log::error!(target: "app", "failed to update service: {:?}", e);
log::error!(target: "app", "failed to update service: {e:?}");
}
}
}
}
Err(e) => {
log::error!(target: "app", "failed to get service status: {:?}", e);
log::error!(target: "app", "failed to get service status: {e:?}");
}
}
}
@@ -86,7 +86,7 @@ pub fn find_unused_port() -> Result<u16> {
.latest()
.verge_mixed_port
.unwrap_or(Config::clash().data().get_mixed_port());
log::warn!(target: "app", "use default port: {}", port);
log::warn!(target: "app", "use default port: {port}");
Ok(port)
}
}
@@ -465,10 +465,10 @@ pub async fn resolve_core_version(app_handle: &AppHandle, core_type: &ClashCore)
return Err(anyhow::anyhow!("failed to get core version"));
}
let out = String::from_utf8_lossy(&out.stdout);
log::trace!(target: "app", "get core version: {:?}", out);
log::trace!(target: "app", "get core version: {out:?}");
let out = out.trim().split(' ').collect::<Vec<&str>>();
for item in out {
log::debug!(target: "app", "check item: {}", item);
log::debug!(target: "app", "check item: {item}");
if item.starts_with('v')
|| item.starts_with('n')
|| item.starts_with("alpha")
+23 -27
View File
@@ -7,10 +7,7 @@ use nyanpasu_egui::{
ipc::{IpcSender, Message, StatisticMessage, create_ipc_server},
widget::StatisticWidgetVariant,
};
use std::{
process::Stdio,
sync::{Arc, atomic::AtomicBool},
};
use std::sync::{Arc, atomic::AtomicBool};
use tauri::{Manager, Runtime, utils::platform::current_exe};
use tokio::{
process::Child,
@@ -53,11 +50,11 @@ impl WidgetManager {
match receiver.recv().await {
Ok(event) => {
if let Err(e) = this.handle_event(event).await {
log::error!("Failed to handle event: {}", e);
log::error!("Failed to handle event: {e}");
}
}
Err(e) => {
log::error!("Error receiving event: {}", e);
log::error!("Error receiving event: {e}");
if BroadcastRecvError::Closed == e {
signal.store(false, std::sync::atomic::Ordering::Release);
break;
@@ -72,27 +69,26 @@ impl WidgetManager {
async fn handle_event(&self, event: ClashConnectionsConnectorEvent) -> anyhow::Result<()> {
let mut instance = self.instance.clone().lock_owned().await;
if let ClashConnectionsConnectorEvent::Update(info) = event {
if instance
if let ClashConnectionsConnectorEvent::Update(info) = event
&& instance
.as_mut()
.is_some_and(|instance| instance.is_alive())
{
tokio::task::spawn_blocking(move || {
let instance = instance.as_ref().unwrap();
// we only care about the update event now
instance
.send_message(Message::UpdateStatistic(StatisticMessage {
download_total: info.download_total,
upload_total: info.upload_total,
download_speed: info.download_speed,
upload_speed: info.upload_speed,
}))
.context("Failed to send event to widget")?;
Ok::<(), anyhow::Error>(())
})
.await
.context("Failed to send event to widget")??;
}
{
tokio::task::spawn_blocking(move || {
let instance = instance.as_ref().unwrap();
// we only care about the update event now
instance
.send_message(Message::UpdateStatistic(StatisticMessage {
download_total: info.download_total,
upload_total: info.upload_total,
download_speed: info.download_speed,
upload_speed: info.upload_speed,
}))
.context("Failed to send event to widget")?;
Ok::<(), anyhow::Error>(())
})
.await
.context("Failed to send event to widget")??;
}
Ok(())
}
@@ -107,11 +103,11 @@ impl WidgetManager {
// This operation is blocking, but it internal just a system call, so I think it's okay
let (mut ipc_server, server_name) = create_ipc_server()?;
// spawn a process to run the widget
let variant = format!("{}", widget);
let variant = format!("{widget}");
tracing::debug!("Spawning widget process for {}...", variant);
let widget_win_state_path = crate::utils::dirs::app_data_dir()
.context("Failed to get app data dir")?
.join(format!("widget_{}.state", variant));
.join(format!("widget_{variant}.state"));
let mut child = tokio::process::Command::new(current_exe)
.arg("statistic-widget")
.arg(variant)
@@ -12,7 +12,7 @@
},
"dependencies": {
"@tanstack/react-query": "5.83.0",
"@tauri-apps/api": "2.5.0",
"@tauri-apps/api": "2.6.0",
"ahooks": "3.9.0",
"dayjs": "1.11.13",
"lodash-es": "4.17.21",
+16 -16
View File
@@ -24,7 +24,7 @@
"@nyanpasu/ui": "workspace:^",
"@tailwindcss/postcss": "4.1.11",
"@tanstack/router-zod-adapter": "1.81.5",
"@tauri-apps/api": "2.5.0",
"@tauri-apps/api": "2.6.0",
"@types/json-schema": "7.0.15",
"ahooks": "3.9.0",
"allotment": "1.20.4",
@@ -58,27 +58,27 @@
"@iconify/json": "2.2.359",
"@monaco-editor/react": "4.7.0",
"@tanstack/react-query": "5.83.0",
"@tanstack/react-router": "1.127.8",
"@tanstack/react-router-devtools": "1.127.8",
"@tanstack/router-plugin": "1.127.8",
"@tauri-apps/plugin-clipboard-manager": "2.2.2",
"@tauri-apps/plugin-dialog": "2.2.2",
"@tauri-apps/plugin-fs": "2.3.0",
"@tauri-apps/plugin-notification": "2.2.2",
"@tauri-apps/plugin-os": "2.2.1",
"@tauri-apps/plugin-process": "2.2.1",
"@tauri-apps/plugin-shell": "2.2.1",
"@tauri-apps/plugin-updater": "2.7.1",
"@tanstack/react-router": "1.128.0",
"@tanstack/react-router-devtools": "1.128.0",
"@tanstack/router-plugin": "1.128.0",
"@tauri-apps/plugin-clipboard-manager": "2.3.0",
"@tauri-apps/plugin-dialog": "2.3.0",
"@tauri-apps/plugin-fs": "2.4.0",
"@tauri-apps/plugin-notification": "2.3.0",
"@tauri-apps/plugin-os": "2.3.0",
"@tauri-apps/plugin-process": "2.3.0",
"@tauri-apps/plugin-shell": "2.3.0",
"@tauri-apps/plugin-updater": "2.9.0",
"@types/react": "19.1.8",
"@types/react-dom": "19.1.6",
"@types/validator": "13.15.2",
"@vitejs/plugin-legacy": "7.0.0",
"@vitejs/plugin-legacy": "7.0.1",
"@vitejs/plugin-react": "4.6.0",
"@vitejs/plugin-react-swc": "3.10.2",
"change-case": "5.4.4",
"clsx": "2.1.1",
"core-js": "3.44.0",
"filesize": "11.0.1",
"filesize": "11.0.2",
"meta-json-schema": "1.19.11",
"monaco-yaml": "5.4.0",
"nanoid": "5.1.5",
@@ -87,11 +87,11 @@
"unplugin-auto-import": "19.3.0",
"unplugin-icons": "22.1.0",
"validator": "13.15.15",
"vite": "7.0.4",
"vite": "7.0.5",
"vite-plugin-html": "3.2.2",
"vite-plugin-sass-dts": "1.3.31",
"vite-plugin-svgr": "4.3.0",
"vite-tsconfig-paths": "5.1.4",
"zod": "3.25.76"
"zod": "4.0.5"
}
}
@@ -3,6 +3,7 @@ import { useAtomValue } from 'jotai'
import { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { atomIsDrawer } from '@/store'
import { formatError } from '@/utils'
import { message } from '@/utils/notification'
import { NetworkPing, SettingsEthernet } from '@mui/icons-material'
import { Chip, Paper, type ChipProps } from '@mui/material'
@@ -87,7 +88,7 @@ export const ProxyShortcuts = () => {
try {
await tunMode.upsert(!tunMode.value)
} catch (error) {
message(`Activation TUN Mode failed!`, {
message(`Activation TUN Mode failed! \n Error: ${formatError(error)}`, {
title: t('Error'),
kind: 'error',
})
@@ -1,6 +1,7 @@
import { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { useCoreType } from '@/hooks/use-store'
import { formatError } from '@/utils'
import getSystem from '@/utils/get-system'
import { message } from '@/utils/notification'
import { Button, List, ListItem, ListItemText } from '@mui/material'
@@ -93,15 +94,22 @@ const TunStack = () => {
options={tunStackOptions}
selected={selected}
onSelected={async (value) => {
await upsertTunStack(value as TunStackType)
try {
await upsertTunStack(value as TunStackType)
if (enableTun) {
// just to reload clash config
await upsertTun(true)
if (enableTun) {
// just to reload clash config
await upsertTun(true)
}
// need manual mutate to refetch runtime profile
await runtimeProfile.refetch()
} catch (error) {
message(`Change Tun Stack failed ! \n Error: ${formatError(error)}`, {
title: t('Error'),
kind: 'error',
})
}
// need manual mutate to refetch runtime profile
await runtimeProfile.refetch()
}}
/>
)
+2 -2
View File
@@ -17,7 +17,7 @@
"@mui/material": "7.2.0",
"@radix-ui/react-portal": "1.1.9",
"@radix-ui/react-scroll-area": "1.2.9",
"@tauri-apps/api": "2.5.0",
"@tauri-apps/api": "2.6.0",
"@types/d3": "7.4.3",
"@types/react": "19.1.8",
"@vitejs/plugin-react": "4.6.0",
@@ -30,7 +30,7 @@
"react-i18next": "15.6.0",
"react-use": "17.6.0",
"tailwindcss": "4.1.11",
"vite": "7.0.4",
"vite": "7.0.5",
"vite-tsconfig-paths": "5.1.4"
},
"devDependencies": {
+3 -3
View File
@@ -2,10 +2,10 @@
"manifest_version": 1,
"latest": {
"mihomo": "v1.19.11",
"mihomo_alpha": "alpha-300eb8b",
"mihomo_alpha": "alpha-6337151",
"clash_rs": "v0.8.1",
"clash_premium": "2023-09-05-gdcc8d87",
"clash_rs_alpha": "0.8.1-alpha+sha.42a8443"
"clash_rs_alpha": "0.8.1-alpha+sha.4db1bc0"
},
"arch_template": {
"mihomo": {
@@ -69,5 +69,5 @@
"linux-armv7hf": "clash-armv7-unknown-linux-gnueabihf"
}
},
"updated_at": "2025-07-14T22:21:28.083Z"
"updated_at": "2025-07-16T22:21:37.735Z"
}
+2 -2
View File
@@ -62,7 +62,7 @@
"@eslint/compat": "1.3.1",
"@eslint/eslintrc": "3.3.1",
"@ianvs/prettier-plugin-sort-imports": "4.4.2",
"@tauri-apps/cli": "2.5.0",
"@tauri-apps/cli": "2.6.2",
"@types/fs-extra": "11.0.4",
"@types/lodash-es": "4.17.12",
"@types/node": "22.16.4",
@@ -110,7 +110,7 @@
},
"packageManager": "pnpm@10.13.1",
"engines": {
"node": "22.17.0"
"node": "22.17.1"
},
"pnpm": {
"overrides": {
+640 -528
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,2 +1,2 @@
[toolchain]
channel = "nightly-2025-02-25"
channel = "nightly"
+2 -2
View File
@@ -7,10 +7,10 @@
"@types/figlet": "1.7.0",
"@types/semver": "7.7.0",
"figlet": "1.8.2",
"filesize": "11.0.1",
"filesize": "11.0.2",
"p-retry": "6.2.1",
"semver": "7.7.2",
"zod": "3.25.76"
"zod": "4.0.5"
},
"devDependencies": {
"@octokit/types": "14.1.0",
+12
View File
@@ -2,6 +2,18 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
### [2.40.2](https://github.com/filebrowser/filebrowser/compare/v2.40.1...v2.40.2) (2025-07-17)
### Bug Fixes
* Location header on TUS endpoint ([#5302](https://github.com/filebrowser/filebrowser/issues/5302)) ([607f570](https://github.com/filebrowser/filebrowser/commit/607f5708a2484428ab837781a5ef26b8cc3194f4))
### Build
* **deps:** bump vue-i18n from 11.1.9 to 11.1.10 in /frontend ([d61110e](https://github.com/filebrowser/filebrowser/commit/d61110e4d7155a5849557adf3b75dc0191f17e80))
### [2.40.1](https://github.com/filebrowser/filebrowser/compare/v2.40.0...v2.40.1) (2025-07-15)
+1 -1
View File
@@ -43,7 +43,7 @@
"videojs-mobile-ui": "^1.1.1",
"vue": "^3.5.17",
"vue-final-modal": "^4.5.5",
"vue-i18n": "^11.1.9",
"vue-i18n": "^11.1.10",
"vue-lazyload": "^3.0.0",
"vue-reader": "^1.2.17",
"vue-router": "^4.5.1",
+33 -33
View File
@@ -84,8 +84,8 @@ importers:
specifier: ^4.5.5
version: 4.5.5(@vueuse/core@12.5.0(typescript@5.6.3))(@vueuse/integrations@12.5.0(focus-trap@7.6.2)(jwt-decode@4.0.0)(typescript@5.6.3))(focus-trap@7.6.2)(vue@3.5.17(typescript@5.6.3))
vue-i18n:
specifier: ^11.1.9
version: 11.1.9(vue@3.5.17(typescript@5.6.3))
specifier: ^11.1.10
version: 11.1.10(vue@3.5.17(typescript@5.6.3))
vue-lazyload:
specifier: ^3.0.0
version: 3.0.0
@@ -101,7 +101,7 @@ importers:
devDependencies:
'@intlify/unplugin-vue-i18n':
specifier: ^6.0.8
version: 6.0.8(@vue/compiler-dom@3.5.17)(eslint@9.31.0)(rollup@4.40.1)(typescript@5.6.3)(vue-i18n@11.1.9(vue@3.5.17(typescript@5.6.3)))(vue@3.5.17(typescript@5.6.3))
version: 6.0.8(@vue/compiler-dom@3.5.17)(eslint@9.31.0)(rollup@4.40.1)(typescript@5.6.3)(vue-i18n@11.1.10(vue@3.5.17(typescript@5.6.3)))(vue@3.5.17(typescript@5.6.3))
'@playwright/test':
specifier: ^1.54.1
version: 1.54.1
@@ -963,16 +963,20 @@ packages:
vue-i18n:
optional: true
'@intlify/core-base@11.1.9':
resolution: {integrity: sha512-Lrdi4wp3XnGhWmB/mMD/XtfGUw1Jt+PGpZI/M63X1ZqhTDjNHRVCs/i8vv8U1cwaj1A9fb0bkCQHLSL0SK+pIQ==}
'@intlify/core-base@11.1.10':
resolution: {integrity: sha512-JhRb40hD93Vk0BgMgDc/xMIFtdXPHoytzeK6VafBNOj6bb6oUZrGamXkBKecMsmGvDQQaPRGG2zpa25VCw8pyw==}
engines: {node: '>= 16'}
'@intlify/message-compiler@11.1.10':
resolution: {integrity: sha512-TABl3c8tSLWbcD+jkQTyBhrnW251dzqW39MPgEUCsd69Ua3ceoimsbIzvkcPzzZvt1QDxNkenMht+5//V3JvLQ==}
engines: {node: '>= 16'}
'@intlify/message-compiler@11.1.2':
resolution: {integrity: sha512-T/xbNDzi+Yv0Qn2Dfz2CWCAJiwNgU5d95EhhAEf4YmOgjCKktpfpiUSmLcBvK1CtLpPQ85AMMQk/2NCcXnNj1g==}
engines: {node: '>= 16'}
'@intlify/message-compiler@11.1.9':
resolution: {integrity: sha512-84SNs3Ikjg0rD1bOuchzb3iK1vR2/8nxrkyccIl5DjFTeMzE/Fxv6X+A7RN5ZXjEWelc1p5D4kHA6HEOhlKL5Q==}
'@intlify/shared@11.1.10':
resolution: {integrity: sha512-6ZW/f3Zzjxfa1Wh0tYQI5pLKUtU+SY7l70pEG+0yd0zjcsYcK0EBt6Fz30Dy0tZhEqemziQQy2aNU3GJzyrMUA==}
engines: {node: '>= 16'}
'@intlify/shared@11.1.2':
@@ -983,10 +987,6 @@ packages:
resolution: {integrity: sha512-4yZeMt2Aa/7n5Ehy4KalUlvt3iRLcg1tq9IBVfOgkyWFArN4oygn6WxgGIFibP3svpaH8DarbNaottq+p0gUZQ==}
engines: {node: '>= 16'}
'@intlify/shared@11.1.9':
resolution: {integrity: sha512-H/83xgU1l8ox+qG305p6ucmoy93qyjIPnvxGWRA7YdOoHe1tIiW9IlEu4lTdsOR7cfP1ecrwyflQSqXdXBacXA==}
engines: {node: '>= 16'}
'@intlify/unplugin-vue-i18n@6.0.8':
resolution: {integrity: sha512-Vvm3KhjE6TIBVUQAk37rBiaYy2M5OcWH0ZcI1XKEsOTeN1o0bErk+zeuXmcrcMc/73YggfI8RoxOUz9EB/69JQ==}
engines: {node: '>= 18'}
@@ -2731,8 +2731,8 @@ packages:
focus-trap: '>=7.2.0'
vue: '>=3.2.0'
vue-i18n@11.1.9:
resolution: {integrity: sha512-N9ZTsXdRmX38AwS9F6Rh93RtPkvZTkSy/zNv63FTIwZCUbLwwrpqlKz9YQuzFLdlvRdZTnWAUE5jMxr8exdl7g==}
vue-i18n@11.1.10:
resolution: {integrity: sha512-C+IwnSg8QDSOAox0gdFYP5tsKLx5jNWxiawNoiNB/Tw4CReXmM1VJMXbduhbrEzAFLhreqzfDocuSVjGbxQrag==}
engines: {node: '>= 16'}
peerDependencies:
vue: ^3.0.0
@@ -3719,7 +3719,7 @@ snapshots:
'@humanwhocodes/retry@0.4.3': {}
'@intlify/bundle-utils@10.0.1(vue-i18n@11.1.9(vue@3.5.17(typescript@5.6.3)))':
'@intlify/bundle-utils@10.0.1(vue-i18n@11.1.10(vue@3.5.17(typescript@5.6.3)))':
dependencies:
'@intlify/message-compiler': 11.1.2
'@intlify/shared': 11.1.7
@@ -3731,35 +3731,35 @@ snapshots:
source-map-js: 1.2.1
yaml-eslint-parser: 1.2.3
optionalDependencies:
vue-i18n: 11.1.9(vue@3.5.17(typescript@5.6.3))
vue-i18n: 11.1.10(vue@3.5.17(typescript@5.6.3))
'@intlify/core-base@11.1.9':
'@intlify/core-base@11.1.10':
dependencies:
'@intlify/message-compiler': 11.1.9
'@intlify/shared': 11.1.9
'@intlify/message-compiler': 11.1.10
'@intlify/shared': 11.1.10
'@intlify/message-compiler@11.1.10':
dependencies:
'@intlify/shared': 11.1.10
source-map-js: 1.2.1
'@intlify/message-compiler@11.1.2':
dependencies:
'@intlify/shared': 11.1.2
source-map-js: 1.2.1
'@intlify/message-compiler@11.1.9':
dependencies:
'@intlify/shared': 11.1.9
source-map-js: 1.2.1
'@intlify/shared@11.1.10': {}
'@intlify/shared@11.1.2': {}
'@intlify/shared@11.1.7': {}
'@intlify/shared@11.1.9': {}
'@intlify/unplugin-vue-i18n@6.0.8(@vue/compiler-dom@3.5.17)(eslint@9.31.0)(rollup@4.40.1)(typescript@5.6.3)(vue-i18n@11.1.9(vue@3.5.17(typescript@5.6.3)))(vue@3.5.17(typescript@5.6.3))':
'@intlify/unplugin-vue-i18n@6.0.8(@vue/compiler-dom@3.5.17)(eslint@9.31.0)(rollup@4.40.1)(typescript@5.6.3)(vue-i18n@11.1.10(vue@3.5.17(typescript@5.6.3)))(vue@3.5.17(typescript@5.6.3))':
dependencies:
'@eslint-community/eslint-utils': 4.4.1(eslint@9.31.0)
'@intlify/bundle-utils': 10.0.1(vue-i18n@11.1.9(vue@3.5.17(typescript@5.6.3)))
'@intlify/bundle-utils': 10.0.1(vue-i18n@11.1.10(vue@3.5.17(typescript@5.6.3)))
'@intlify/shared': 11.1.7
'@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.1.7)(@vue/compiler-dom@3.5.17)(vue-i18n@11.1.9(vue@3.5.17(typescript@5.6.3)))(vue@3.5.17(typescript@5.6.3))
'@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.1.7)(@vue/compiler-dom@3.5.17)(vue-i18n@11.1.10(vue@3.5.17(typescript@5.6.3)))(vue@3.5.17(typescript@5.6.3))
'@rollup/pluginutils': 5.1.4(rollup@4.40.1)
'@typescript-eslint/scope-manager': 8.21.0
'@typescript-eslint/typescript-estree': 8.21.0(typescript@5.6.3)
@@ -3773,7 +3773,7 @@ snapshots:
unplugin: 1.16.1
vue: 3.5.17(typescript@5.6.3)
optionalDependencies:
vue-i18n: 11.1.9(vue@3.5.17(typescript@5.6.3))
vue-i18n: 11.1.10(vue@3.5.17(typescript@5.6.3))
transitivePeerDependencies:
- '@vue/compiler-dom'
- eslint
@@ -3781,14 +3781,14 @@ snapshots:
- supports-color
- typescript
'@intlify/vue-i18n-extensions@8.0.0(@intlify/shared@11.1.7)(@vue/compiler-dom@3.5.17)(vue-i18n@11.1.9(vue@3.5.17(typescript@5.6.3)))(vue@3.5.17(typescript@5.6.3))':
'@intlify/vue-i18n-extensions@8.0.0(@intlify/shared@11.1.7)(@vue/compiler-dom@3.5.17)(vue-i18n@11.1.10(vue@3.5.17(typescript@5.6.3)))(vue@3.5.17(typescript@5.6.3))':
dependencies:
'@babel/parser': 7.26.7
optionalDependencies:
'@intlify/shared': 11.1.7
'@vue/compiler-dom': 3.5.17
vue: 3.5.17(typescript@5.6.3)
vue-i18n: 11.1.9(vue@3.5.17(typescript@5.6.3))
vue-i18n: 11.1.10(vue@3.5.17(typescript@5.6.3))
'@jridgewell/gen-mapping@0.3.5':
dependencies:
@@ -5538,10 +5538,10 @@ snapshots:
focus-trap: 7.6.2
vue: 3.5.17(typescript@5.6.3)
vue-i18n@11.1.9(vue@3.5.17(typescript@5.6.3)):
vue-i18n@11.1.10(vue@3.5.17(typescript@5.6.3)):
dependencies:
'@intlify/core-base': 11.1.9
'@intlify/shared': 11.1.9
'@intlify/core-base': 11.1.10
'@intlify/shared': 11.1.10
'@vue/devtools-api': 6.6.4
vue: 3.5.17(typescript@5.6.3)
+6 -2
View File
@@ -6,6 +6,7 @@ import (
"fmt"
"io"
"net/http"
"net/url"
"os"
"path/filepath"
"strconv"
@@ -147,9 +148,12 @@ func tusPostHandler() handleFunc {
// Enables the user to utilize the PATCH endpoint for uploading file data
registerUpload(file.RealPath(), uploadLength)
// Signal the frontend to reuse the current request URL
w.Header().Set("Location", "")
path, err := url.JoinPath("/", d.server.BaseURL, "/api/tus", r.URL.Path)
if err != nil {
return http.StatusBadRequest, fmt.Errorf("invalid path: %w", err)
}
w.Header().Set("Location", path)
return http.StatusCreated, nil
})
}
+23 -151
View File
@@ -2,129 +2,20 @@ include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=bcm27xx-gpu-fw
PKG_VERSION:=2022-05-16
PKG_RELEASE:=3673be308132de102fdff491d1333d9d0f823557
PKG_VERSION:=2025.04.30
PKG_VERSION_REAL:=1.$(subst .,,$(PKG_VERSION))
PKG_RELEASE:=1
PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/$(PKG_NAME)/rpi-firmware-$(PKG_RELEASE)
PKG_SOURCE:=raspi-firmware_$(PKG_VERSION_REAL).orig.tar.xz
PKG_SOURCE_URL:=https://github.com/raspberrypi/firmware/releases/download/$(PKG_VERSION_REAL)
PKG_HASH:=25bcff5992c6d7057de4a5c6834b7f90b7136fe12aa63fa32793329bf74a95bf
PKG_FLAGS:=nonshared
include $(INCLUDE_DIR)/package.mk
RPI_FIRMWARE_URL:=@GITHUB/raspberrypi/firmware/$(PKG_RELEASE)/boot/
RPI_FIRMWARE_FILE:=rpi-firmware-$(PKG_RELEASE)
define Download/LICENCE_broadcom
FILE:=$(RPI_FIRMWARE_FILE)-LICENCE.broadcom
URL:=$(RPI_FIRMWARE_URL)
URL_FILE:=LICENCE.broadcom
HASH:=c7283ff51f863d93a275c66e3b4cb08021a5dd4d8c1e7acc47d872fbe52d3d6b
endef
$(eval $(call Download,LICENCE_broadcom))
define Download/bootcode_bin
FILE:=$(RPI_FIRMWARE_FILE)-bootcode.bin
URL:=$(RPI_FIRMWARE_URL)
URL_FILE:=bootcode.bin
HASH:=69309823da13dc96b89e3d82b44f820e4f84efa79d207adad2c8784559794f03
endef
$(eval $(call Download,bootcode_bin))
define Download/fixup_dat
FILE:=$(RPI_FIRMWARE_FILE)-fixup.dat
URL:=$(RPI_FIRMWARE_URL)
URL_FILE:=fixup.dat
HASH:=921f56c62ad1995addb984b156c869202dc5d46bbe9ebcbd02c20f0def9058e3
endef
$(eval $(call Download,fixup_dat))
define Download/fixup_cd_dat
FILE:=$(RPI_FIRMWARE_FILE)-fixup_cd.dat
URL:=$(RPI_FIRMWARE_URL)
URL_FILE:=fixup_cd.dat
HASH:=83a985aa0d73844786f3b3bf674826c520212f6f72fc6a890f2ebb5f87de5d8c
endef
$(eval $(call Download,fixup_cd_dat))
define Download/fixup_x_dat
FILE:=$(RPI_FIRMWARE_FILE)-fixup_x.dat
URL:=$(RPI_FIRMWARE_URL)
URL_FILE:=fixup_x.dat
HASH:=8b00b00678adafe01e087240d156dbc87822e745b269be4f282596b69265cd1e
endef
$(eval $(call Download,fixup_x_dat))
define Download/fixup4_dat
FILE:=$(RPI_FIRMWARE_FILE)-fixup4.dat
URL:=$(RPI_FIRMWARE_URL)
URL_FILE:=fixup4.dat
HASH:=ef2b5d2a0a95ca48e00a1ce78b7650ee9e947cc1c588704c8ae30c1623122e2f
endef
$(eval $(call Download,fixup4_dat))
define Download/fixup4cd_dat
FILE:=$(RPI_FIRMWARE_FILE)-fixup4cd.dat
URL:=$(RPI_FIRMWARE_URL)
URL_FILE:=fixup4cd.dat
HASH:=83a985aa0d73844786f3b3bf674826c520212f6f72fc6a890f2ebb5f87de5d8c
endef
$(eval $(call Download,fixup4cd_dat))
define Download/fixup4x_dat
FILE:=$(RPI_FIRMWARE_FILE)-fixup4x.dat
URL:=$(RPI_FIRMWARE_URL)
URL_FILE:=fixup4x.dat
HASH:=a6c4e30ada5a00fe7de83c460638ca824647651bb4a3644b8c65d7ba1d9f2d2b
endef
$(eval $(call Download,fixup4x_dat))
define Download/start_elf
FILE:=$(RPI_FIRMWARE_FILE)-start.elf
URL:=$(RPI_FIRMWARE_URL)
URL_FILE:=start.elf
HASH:=5455c148f4b8b04c553809bd22b995ee49ba5279ca3848df8bde6f80a388f7e0
endef
$(eval $(call Download,start_elf))
define Download/start_cd_elf
FILE:=$(RPI_FIRMWARE_FILE)-start_cd.elf
URL:=$(RPI_FIRMWARE_URL)
URL_FILE:=start_cd.elf
HASH:=168c0a9178d5a3b4bd89ef770826a85b4ea3132560ba3600c212c0cec4c575c6
endef
$(eval $(call Download,start_cd_elf))
define Download/start_x_elf
FILE:=$(RPI_FIRMWARE_FILE)-start_x.elf
URL:=$(RPI_FIRMWARE_URL)
URL_FILE:=start_x.elf
HASH:=30c6a7f32a25185053ca3ca9e4bcfe932246ed42a1b7c37f8803209f93d86404
endef
$(eval $(call Download,start_x_elf))
define Download/start4_elf
FILE:=$(RPI_FIRMWARE_FILE)-start4.elf
URL:=$(RPI_FIRMWARE_URL)
URL_FILE:=start4.elf
HASH:=be8bbff41dba2749b7b0e812f0a9d87a9122d18508f7b5ff3cd20f303d15bc07
endef
$(eval $(call Download,start4_elf))
define Download/start4cd_elf
FILE:=$(RPI_FIRMWARE_FILE)-start4cd.elf
URL:=$(RPI_FIRMWARE_URL)
URL_FILE:=start4cd.elf
HASH:=000372e9cf6815ade595948dbd6328665f2a535eeee44e74b0ec8e56b6fbbf90
endef
$(eval $(call Download,start4cd_elf))
define Download/start4x_elf
FILE:=$(RPI_FIRMWARE_FILE)-start4x.elf
URL:=$(RPI_FIRMWARE_URL)
URL_FILE:=start4x.elf
HASH:=48895858f7936570dfab44c67bdcb0357ac8fcd630162c36ac9ed8f2de85c038
endef
$(eval $(call Download,start4x_elf))
TAR_OPTIONS+=--strip-components 1
TAR_CMD=$(HOST_TAR) -C $(1) $(TAR_OPTIONS)
define Package/bcm27xx-gpu-fw
SECTION:=boot
@@ -135,26 +26,7 @@ define Package/bcm27xx-gpu-fw
endef
define Package/bcm27xx-gpu-fw/description
GPU and kernel boot firmware for bcm27xx.
endef
define Build/Prepare
rm -rf $(PKG_BUILD_DIR)
mkdir -p $(PKG_BUILD_DIR)
$(CP) $(DL_DIR)/$(RPI_FIRMWARE_FILE)-LICENCE.broadcom $(PKG_BUILD_DIR)/LICENCE.broadcom
$(CP) $(DL_DIR)/$(RPI_FIRMWARE_FILE)-bootcode.bin $(PKG_BUILD_DIR)/bootcode.bin
$(CP) $(DL_DIR)/$(RPI_FIRMWARE_FILE)-fixup.dat $(PKG_BUILD_DIR)/fixup.dat
$(CP) $(DL_DIR)/$(RPI_FIRMWARE_FILE)-fixup_cd.dat $(PKG_BUILD_DIR)/fixup_cd.dat
$(CP) $(DL_DIR)/$(RPI_FIRMWARE_FILE)-fixup_x.dat $(PKG_BUILD_DIR)/fixup_x.dat
$(CP) $(DL_DIR)/$(RPI_FIRMWARE_FILE)-fixup4.dat $(PKG_BUILD_DIR)/fixup4.dat
$(CP) $(DL_DIR)/$(RPI_FIRMWARE_FILE)-fixup4cd.dat $(PKG_BUILD_DIR)/fixup4cd.dat
$(CP) $(DL_DIR)/$(RPI_FIRMWARE_FILE)-fixup4x.dat $(PKG_BUILD_DIR)/fixup4x.dat
$(CP) $(DL_DIR)/$(RPI_FIRMWARE_FILE)-start.elf $(PKG_BUILD_DIR)/start.elf
$(CP) $(DL_DIR)/$(RPI_FIRMWARE_FILE)-start_cd.elf $(PKG_BUILD_DIR)/start_cd.elf
$(CP) $(DL_DIR)/$(RPI_FIRMWARE_FILE)-start_x.elf $(PKG_BUILD_DIR)/start_x.elf
$(CP) $(DL_DIR)/$(RPI_FIRMWARE_FILE)-start4.elf $(PKG_BUILD_DIR)/start4.elf
$(CP) $(DL_DIR)/$(RPI_FIRMWARE_FILE)-start4cd.elf $(PKG_BUILD_DIR)/start4cd.elf
$(CP) $(DL_DIR)/$(RPI_FIRMWARE_FILE)-start4x.elf $(PKG_BUILD_DIR)/start4x.elf
GPU and kernel boot firmware for bcm27xx.
endef
define Build/Compile
@@ -166,20 +38,20 @@ define Package/bcm27xx-gpu-fw/install
endef
define Build/InstallDev
$(CP) $(PKG_BUILD_DIR)/bootcode.bin $(KERNEL_BUILD_DIR)
$(CP) $(PKG_BUILD_DIR)/LICENCE.broadcom $(KERNEL_BUILD_DIR)
$(CP) $(PKG_BUILD_DIR)/start.elf $(KERNEL_BUILD_DIR)
$(CP) $(PKG_BUILD_DIR)/start_cd.elf $(KERNEL_BUILD_DIR)
$(CP) $(PKG_BUILD_DIR)/start_x.elf $(KERNEL_BUILD_DIR)
$(CP) $(PKG_BUILD_DIR)/start4.elf $(KERNEL_BUILD_DIR)
$(CP) $(PKG_BUILD_DIR)/start4cd.elf $(KERNEL_BUILD_DIR)
$(CP) $(PKG_BUILD_DIR)/start4x.elf $(KERNEL_BUILD_DIR)
$(CP) $(PKG_BUILD_DIR)/fixup.dat $(KERNEL_BUILD_DIR)
$(CP) $(PKG_BUILD_DIR)/fixup_cd.dat $(KERNEL_BUILD_DIR)
$(CP) $(PKG_BUILD_DIR)/fixup_x.dat $(KERNEL_BUILD_DIR)
$(CP) $(PKG_BUILD_DIR)/fixup4.dat $(KERNEL_BUILD_DIR)
$(CP) $(PKG_BUILD_DIR)/fixup4cd.dat $(KERNEL_BUILD_DIR)
$(CP) $(PKG_BUILD_DIR)/fixup4x.dat $(KERNEL_BUILD_DIR)
$(CP) $(PKG_BUILD_DIR)/boot/bootcode.bin $(KERNEL_BUILD_DIR)
$(CP) $(PKG_BUILD_DIR)/boot/LICENCE.broadcom $(KERNEL_BUILD_DIR)
$(CP) $(PKG_BUILD_DIR)/boot/start.elf $(KERNEL_BUILD_DIR)
$(CP) $(PKG_BUILD_DIR)/boot/start_cd.elf $(KERNEL_BUILD_DIR)
$(CP) $(PKG_BUILD_DIR)/boot/start_x.elf $(KERNEL_BUILD_DIR)
$(CP) $(PKG_BUILD_DIR)/boot/start4.elf $(KERNEL_BUILD_DIR)
$(CP) $(PKG_BUILD_DIR)/boot/start4cd.elf $(KERNEL_BUILD_DIR)
$(CP) $(PKG_BUILD_DIR)/boot/start4x.elf $(KERNEL_BUILD_DIR)
$(CP) $(PKG_BUILD_DIR)/boot/fixup.dat $(KERNEL_BUILD_DIR)
$(CP) $(PKG_BUILD_DIR)/boot/fixup_cd.dat $(KERNEL_BUILD_DIR)
$(CP) $(PKG_BUILD_DIR)/boot/fixup_x.dat $(KERNEL_BUILD_DIR)
$(CP) $(PKG_BUILD_DIR)/boot/fixup4.dat $(KERNEL_BUILD_DIR)
$(CP) $(PKG_BUILD_DIR)/boot/fixup4cd.dat $(KERNEL_BUILD_DIR)
$(CP) $(PKG_BUILD_DIR)/boot/fixup4x.dat $(KERNEL_BUILD_DIR)
endef
$(eval $(call BuildPackage,bcm27xx-gpu-fw))
+9
View File
@@ -296,6 +296,10 @@ type RawTun struct {
Inet6RouteAddress []netip.Prefix `yaml:"inet6-route-address" json:"inet6-route-address,omitempty"`
Inet4RouteExcludeAddress []netip.Prefix `yaml:"inet4-route-exclude-address" json:"inet4-route-exclude-address,omitempty"`
Inet6RouteExcludeAddress []netip.Prefix `yaml:"inet6-route-exclude-address" json:"inet6-route-exclude-address,omitempty"`
// darwin special config
RecvMsgX bool `yaml:"recvmsgx" json:"recvmsgx,omitempty"`
SendMsgX bool `yaml:"sendmsgx" json:"sendmsgx,omitempty"`
}
type RawTuicServer struct {
@@ -513,6 +517,8 @@ func DefaultRawConfig() *RawConfig {
AutoRoute: true,
AutoDetectInterface: true,
Inet6Address: []netip.Prefix{netip.MustParsePrefix("fdfe:dcba:9876::1/126")},
RecvMsgX: true,
SendMsgX: false, // In the current implementation, if enabled, the kernel may freeze during multi-thread downloads, so it is disabled by default.
},
TuicServer: RawTuicServer{
Enable: false,
@@ -1554,6 +1560,9 @@ func parseTun(rawTun RawTun, general *General) error {
Inet6RouteAddress: rawTun.Inet6RouteAddress,
Inet4RouteExcludeAddress: rawTun.Inet4RouteExcludeAddress,
Inet6RouteExcludeAddress: rawTun.Inet6RouteExcludeAddress,
RecvMsgX: rawTun.RecvMsgX,
SendMsgX: rawTun.SendMsgX,
}
return nil
+1 -1
View File
@@ -31,7 +31,7 @@ require (
github.com/metacubex/sing-shadowsocks v0.2.11-0.20250621023810-0e9ef9dd0c92
github.com/metacubex/sing-shadowsocks2 v0.2.5-0.20250621023950-93d605a2143d
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2
github.com/metacubex/sing-tun v0.4.7-0.20250611091011-60774779fdd8
github.com/metacubex/sing-tun v0.4.7-0.20250717140042-aefff29eb853
github.com/metacubex/sing-vmess v0.2.2
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f
github.com/metacubex/smux v0.0.0-20250503055512-501391591dee
+2 -2
View File
@@ -129,8 +129,8 @@ github.com/metacubex/sing-shadowsocks2 v0.2.5-0.20250621023950-93d605a2143d h1:E
github.com/metacubex/sing-shadowsocks2 v0.2.5-0.20250621023950-93d605a2143d/go.mod h1:+ukTd0OPFglT3bnKAYTJWYPbuox6HYNXE235r5tHdUk=
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2 h1:gXU+MYPm7Wme3/OAY2FFzVq9d9GxPHOqu5AQfg/ddhI=
github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2/go.mod h1:mbfboaXauKJNIHJYxQRa+NJs4JU9NZfkA+I33dS2+9E=
github.com/metacubex/sing-tun v0.4.7-0.20250611091011-60774779fdd8 h1:4zWKqxTx75TbfW2EmlQ3hxM6RTRg2PYOAVMCnU4I61I=
github.com/metacubex/sing-tun v0.4.7-0.20250611091011-60774779fdd8/go.mod h1:2YywXPWW8Z97kTH7RffOeykKzU+l0aiKlglWV1PAS64=
github.com/metacubex/sing-tun v0.4.7-0.20250717140042-aefff29eb853 h1:HJb4CS7XP3sjc4fDDnAlNN9393ewSCn9yuGXjmZ7bJc=
github.com/metacubex/sing-tun v0.4.7-0.20250717140042-aefff29eb853/go.mod h1:2YywXPWW8Z97kTH7RffOeykKzU+l0aiKlglWV1PAS64=
github.com/metacubex/sing-vmess v0.2.2 h1:nG6GIKF1UOGmlzs+BIetdGHkFZ20YqFVIYp5Htqzp+4=
github.com/metacubex/sing-vmess v0.2.2/go.mod h1:CVDNcdSLVYFgTHQlubr88d8CdqupAUDqLjROos+H9xk=
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f h1:Sr/DYKYofKHKc4GF3qkRGNuj6XA6c0eqPgEDN+VAsYU=
+10
View File
@@ -100,6 +100,10 @@ type tunSchema struct {
Inet6RouteAddress *[]netip.Prefix `yaml:"inet6-route-address" json:"inet6-route-address,omitempty"`
Inet4RouteExcludeAddress *[]netip.Prefix `yaml:"inet4-route-exclude-address" json:"inet4-route-exclude-address,omitempty"`
Inet6RouteExcludeAddress *[]netip.Prefix `yaml:"inet6-route-exclude-address" json:"inet6-route-exclude-address,omitempty"`
// darwin special config
RecvMsgX *bool `yaml:"recvmsgx" json:"recvmsgx,omitempty"`
SendMsgX *bool `yaml:"sendmsgx" json:"sendmsgx,omitempty"`
}
type tuicServerSchema struct {
@@ -243,6 +247,12 @@ func pointerOrDefaultTun(p *tunSchema, def LC.Tun) LC.Tun {
if p.FileDescriptor != nil {
def.FileDescriptor = *p.FileDescriptor
}
if p.RecvMsgX != nil {
def.RecvMsgX = *p.RecvMsgX
}
if p.SendMsgX != nil {
def.SendMsgX = *p.SendMsgX
}
}
return def
}
+11
View File
@@ -54,6 +54,10 @@ type Tun struct {
Inet6RouteAddress []netip.Prefix `yaml:"inet6-route-address" json:"inet6-route-address,omitempty"`
Inet4RouteExcludeAddress []netip.Prefix `yaml:"inet4-route-exclude-address" json:"inet4-route-exclude-address,omitempty"`
Inet6RouteExcludeAddress []netip.Prefix `yaml:"inet6-route-exclude-address" json:"inet6-route-exclude-address,omitempty"`
// darwin special config
RecvMsgX bool `yaml:"recvmsgx" json:"recvmsgx,omitempty"`
SendMsgX bool `yaml:"sendmsgx" json:"sendmsgx,omitempty"`
}
func (t *Tun) Sort() {
@@ -199,5 +203,12 @@ func (t *Tun) Equal(other Tun) bool {
return false
}
if t.RecvMsgX != other.RecvMsgX {
return false
}
if t.SendMsgX != other.SendMsgX {
return false
}
return true
}
+7
View File
@@ -55,6 +55,10 @@ type TunOption struct {
Inet6RouteAddress []netip.Prefix `inbound:"inet6-route-address,omitempty"`
Inet4RouteExcludeAddress []netip.Prefix `inbound:"inet4-route-exclude-address,omitempty"`
Inet6RouteExcludeAddress []netip.Prefix `inbound:"inet6-route-exclude-address,omitempty"`
// darwin special config
RecvMsgX bool `inbound:"recvmsgx,omitempty"`
SendMsgX bool `inbound:"sendmsgx,omitempty"`
}
var _ encoding.TextUnmarshaler = (*netip.Addr)(nil) // ensure netip.Addr can decode direct by structure package
@@ -124,6 +128,9 @@ func NewTun(options *TunOption) (*Tun, error) {
Inet6RouteAddress: options.Inet6RouteAddress,
Inet4RouteExcludeAddress: options.Inet4RouteExcludeAddress,
Inet6RouteExcludeAddress: options.Inet6RouteExcludeAddress,
RecvMsgX: options.RecvMsgX,
SendMsgX: options.SendMsgX,
},
}, nil
}
+2
View File
@@ -365,6 +365,8 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis
ExcludePackage: options.ExcludePackage,
FileDescriptor: options.FileDescriptor,
InterfaceMonitor: defaultInterfaceMonitor,
EXP_RecvMsgX: options.RecvMsgX,
EXP_SendMsgX: options.SendMsgX,
}
if options.AutoRedirect {
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1595,6 +1595,13 @@ tr > th,
line-height: 1.3rem;
}
[data-page="admin-services-ddns"] {
#syslog {
overflow: auto;
font-size: 12px!important;
}
}
[data-page="admin-network-network"] {
.cbi-value-field {
.cbi-dynlist {
@@ -3041,6 +3048,10 @@ td > .ifacebadge,
outline: 0;
}
#cbi-ddns #syslog {
overflow: auto;
}
/* config changes */
.uci-change-list {
font-family: inherit;
@@ -4044,6 +4055,10 @@ pre.command-output {
}
[data-page="admin-system-fileassistant"] {
#upload-toggle {
display: none !important;
}
.fb-container .panel-title {
padding: .5rem .75rem !important;
}
@@ -4066,7 +4081,7 @@ pre.command-output {
div#list-content {
table.cbi-section-table {
thead {
thead, tbody {
td.cbi-section-table-cell {
width: 232px;
}
@@ -4113,6 +4128,92 @@ pre.command-output {
}
[data-page^="admin-services-openclash"] {
.oc {
--bg-light: #fff;
--bg-gray: #fff;
border-radius: 8px;
.developer-container {
background: transparent;
}
}
#cbi-openclash > fieldset {
background: none;
padding: 0;
> table > tbody > tr > td {
border: none;
padding: 0;
}
.main-card {
border: none;
box-shadow: none;
padding: 0 10px 10px 10px;
background: transparent;
}
.myip-main-card {
margin: 0;
padding: 10px;
border: none;
background: transparent;
.myip-section-title {
margin: 0;
border-width: 1px;
}
}
}
.sub-card .card-title {
margin-top: 5px;
}
.oc .main-cards-container {
margin: 0 !important;
gap: 0 !important;
}
.oc .config-file-bottom {
margin-bottom: 5px;
.card-actions {
margin-bottom: 2px !important;
}
}
.oc .card-content {
align-items: center !important;
justify-content: center !important;
}
.oc .card-controls {
align-self: center;
}
.oc .core-main-controls {
justify-content: center !important;
}
.oc .plugin-toggle-container {
margin-left: inherit !important;
}
.oc .core-status-toggle {
flex: 0 !important;
min-width: auto !important;
}
.oc .config-upload-content {
background: #fff !important;
}
.oc .subscription-info-container {
background: transparent !important;
}
.cbi-tabmenu > li {
border-right: none !important;
margin: 0 0.4rem 0 0 !important;
@@ -4167,12 +4268,6 @@ pre.command-output {
select#RELEASE_BRANCH {
width: auto;
}
[id="container.openclash.config.version_update"] {
table tr:nth-of-type(n+1) {
}
}
}
[data-page="admin-services-npc"] {
@@ -4189,6 +4284,19 @@ pre.command-output {
border: none;
}
}
div[id^="cbid.npc."][id$=".server_addr"]:not([id="cbid.npc.config.server_addr"]),
div[id^="cbid.npc."][id$=".vkey"]:not([id="cbid.npc.config.vkey"]),
div[id^="cbid.npc."][id$=".protocol"]:not([id="cbid.npc.config.protocol"]),
div[id^="cbid.npc."][id$=".dns"]:not([id="cbid.npc.config.dns"]) {
+ br {
display: none;
}
}
div.cbi-value.nowrap {
white-space: normal;
}
}
[data-page="admin-system-package-manager"] {
@@ -1016,7 +1016,7 @@ input,
tr {
border-top: thin solid #4d4d4d;
&:last-child {
border-bottom: thin solid #4d4d4d;
}
@@ -1048,6 +1048,19 @@ input,
}
[data-page^="admin-services-openclash"] {
.oc {
--bg-light: #1e1e1e !important;
--bg-gray: #1e1e1e !important;
.developer-container {
background: transparent !important;
}
}
.config-upload-content{
background: #1e1e1e !important;
}
.cbi-tabmenu::-webkit-scrollbar-thumb {
background-color: #5b5b5b;
}
@@ -300,9 +300,10 @@ o:depends({ _tcp_node_bool = "1" })
---- DNS
o = s:option(ListValue, "dns_shunt", "DNS " .. translate("Shunt"))
o:depends({ _tcp_node_bool = "1" })
o.default = "chinadns-ng"
o:value("dnsmasq", "Dnsmasq")
o:value("chinadns-ng", translate("ChinaDNS-NG (recommended)"))
o:depends({ _tcp_node_bool = "1" })
o = s:option(DummyValue, "view_chinadns_log", " ")
o.template = appname .. "/acl/view_chinadns_log"
@@ -41,9 +41,6 @@ o = s:option(ListValue, _n("protocol"), translate("Protocol"))
o:value("socks", "Socks")
o:value("http", "HTTP")
o:value("shadowsocks", "Shadowsocks")
if singbox_tags:find("with_shadowsocksr") then
o:value("shadowsocksr", "ShadowsocksR")
end
o:value("vmess", "Vmess")
o:value("trojan", "Trojan")
if singbox_tags:find("with_wireguard") then
@@ -257,7 +254,6 @@ o.password = true
o:depends({ [_n("protocol")] = "http" })
o:depends({ [_n("protocol")] = "socks" })
o:depends({ [_n("protocol")] = "shadowsocks" })
o:depends({ [_n("protocol")] = "shadowsocksr" })
o:depends({ [_n("protocol")] = "trojan" })
o:depends({ [_n("protocol")] = "tuic" })
o:depends({ [_n("protocol")] = "anytls" })
@@ -272,39 +268,6 @@ for a, t in ipairs(ss_method_new_list) do o:value(t) end
for a, t in ipairs(ss_method_old_list) do o:value(t) end
o:depends({ [_n("protocol")] = "shadowsocks" })
if singbox_tags:find("with_shadowsocksr") then
o = s:option(ListValue, _n("ssr_method"), translate("Encrypt Method"))
o.rewrite_option = "method"
for a, t in ipairs(ss_method_old_list) do o:value(t) end
o:depends({ [_n("protocol")] = "shadowsocksr" })
local ssr_protocol_list = {
"origin", "verify_simple", "verify_deflate", "verify_sha1", "auth_simple",
"auth_sha1", "auth_sha1_v2", "auth_sha1_v4", "auth_aes128_md5",
"auth_aes128_sha1", "auth_chain_a", "auth_chain_b", "auth_chain_c",
"auth_chain_d", "auth_chain_e", "auth_chain_f"
}
o = s:option(ListValue, _n("ssr_protocol"), translate("Protocol"))
for a, t in ipairs(ssr_protocol_list) do o:value(t) end
o:depends({ [_n("protocol")] = "shadowsocksr" })
o = s:option(Value, _n("ssr_protocol_param"), translate("Protocol_param"))
o:depends({ [_n("protocol")] = "shadowsocksr" })
local ssr_obfs_list = {
"plain", "http_simple", "http_post", "random_head", "tls_simple",
"tls1.0_session_auth", "tls1.2_ticket_auth"
}
o = s:option(ListValue, _n("ssr_obfs"), translate("Obfs"))
for a, t in ipairs(ssr_obfs_list) do o:value(t) end
o:depends({ [_n("protocol")] = "shadowsocksr" })
o = s:option(Value, _n("ssr_obfs_param"), translate("Obfs_param"))
o:depends({ [_n("protocol")] = "shadowsocksr" })
end
o = s:option(Flag, _n("uot"), translate("UDP over TCP"))
o:depends({ [_n("protocol")] = "socks" })
o:depends({ [_n("protocol")] = "shadowsocks" })
@@ -761,7 +724,6 @@ o:value("ipv6_only", translate("IPv6 Only"))
o:depends({ [_n("protocol")] = "socks" })
o:depends({ [_n("protocol")] = "http" })
o:depends({ [_n("protocol")] = "shadowsocks" })
o:depends({ [_n("protocol")] = "shadowsocksr" })
o:depends({ [_n("protocol")] = "vmess" })
o:depends({ [_n("protocol")] = "trojan" })
o:depends({ [_n("protocol")] = "wireguard" })
@@ -289,17 +289,6 @@ function gen_outbound(flag, node, tag, proxy_table)
}
end
if node.protocol == "shadowsocksr" then
protocol_table = {
method = node.method or nil,
password = node.password or "",
obfs = node.ssr_obfs,
obfs_param = node.ssr_obfs_param,
protocol = node.ssr_protocol,
protocol_param = node.ssr_protocol_param,
}
end
if node.protocol == "trojan" then
protocol_table = {
password = node.password,
@@ -408,7 +408,7 @@ local hysteria2_type = map:get("@global_subscribe[0]", "hysteria2_type") or "sin
params += opt.query("path", dom_prefix + "ws_path");
if (v_type == "sing-box" && opt.get(dom_prefix + "ws_enableEarlyData").checked) {
var ws_maxEarlyData = opt.get(dom_prefix + "ws_maxEarlyData").value;
params += "?ed=" + ws_maxEarlyData;
params += encodeURIComponent("?ed=" + ws_maxEarlyData);
}
} else if (v_transport === "h2") {
v_transport = "http";
@@ -444,7 +444,11 @@ local hysteria2_type = map:get("@global_subscribe[0]", "hysteria2_type") or "sin
}
params += "&type=" + v_transport;
params += opt.query("encryption", dom_prefix + "encryption");
if (v_type === "sing-box") {
params += "&encryption=none";
} else {
params += opt.query("encryption", dom_prefix + "encryption");
}
if (opt.get(dom_prefix + "tls").checked) {
var v_security = "tls";
@@ -465,6 +469,7 @@ local hysteria2_type = map:get("@global_subscribe[0]", "hysteria2_type") or "sin
params += "&security=" + v_security;
params += opt.query("alpn", dom_prefix + "alpn");
params += opt.query("sni", dom_prefix + "tls_serverName");
params += opt.query("allowinsecure", dom_prefix + "tls_allowInsecure");
}
params += "#" + encodeURI(v_alias.value);
@@ -532,6 +537,7 @@ local hysteria2_type = map:get("@global_subscribe[0]", "hysteria2_type") or "sin
params += "&security=" + v_security;
params += opt.query("alpn", dom_prefix + "alpn");
params += opt.query("sni", dom_prefix + "tls_serverName");
params += opt.query("allowinsecure", dom_prefix + "tls_allowInsecure");
}
params += "#" + encodeURI(v_alias.value);
if (params[0] == "&") {
+10 -11
View File
@@ -904,19 +904,18 @@ dependencies = [
[[package]]
name = "dynosaur"
version = "0.2.0"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "277b2cb52d2df4acece06bb16bc0bb0a006970c7bf504eac2d310927a6f65890"
checksum = "a12303417f378f29ba12cb12fc78a9df0d8e16ccb1ad94abf04d48d96bdda532"
dependencies = [
"dynosaur_derive",
"trait-variant",
]
[[package]]
name = "dynosaur_derive"
version = "0.2.0"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a4102713839a8c01c77c165bc38ef2e83948f6397fa1e1dcfacec0f07b149d3"
checksum = "0b0713d5c1d52e774c5cd7bb8b043d7c0fc4f921abfb678556140bfbe6ab2364"
dependencies = [
"proc-macro2",
"quote",
@@ -1025,7 +1024,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad"
dependencies = [
"libc",
"windows-sys 0.52.0",
"windows-sys 0.60.2",
]
[[package]]
@@ -1978,7 +1977,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667"
dependencies = [
"cfg-if",
"windows-targets 0.48.5",
"windows-targets 0.53.2",
]
[[package]]
@@ -2742,7 +2741,7 @@ dependencies = [
"once_cell",
"socket2 0.5.10",
"tracing",
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
@@ -3063,7 +3062,7 @@ dependencies = [
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
@@ -3745,7 +3744,7 @@ dependencies = [
"getrandom 0.3.3",
"once_cell",
"rustix",
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
@@ -4385,7 +4384,7 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
"windows-sys 0.48.0",
"windows-sys 0.59.0",
]
[[package]]
@@ -71,7 +71,7 @@ percent-encoding = "2.1"
futures = "0.3"
trait-variant = "0.1"
dynosaur = "0.2.0"
dynosaur = "0.3.0"
sealed = "0.6"
socket2 = { version = "0.6", features = ["all"] }
@@ -31,7 +31,7 @@ use super::hickory_dns_resolver::DnsResolver as HickoryDnsResolver;
/// Abstract DNS resolver
#[trait_variant::make(Send)]
#[dynosaur::dynosaur(DynDnsResolve)]
#[dynosaur::dynosaur(DynDnsResolve = dyn(box) DnsResolve, bridge(dyn))]
pub trait DnsResolve {
/// Resolves `addr:port` to a list of `SocketAddr`
async fn resolve(&self, addr: &str, port: u16) -> io::Result<Vec<SocketAddr>>;
@@ -284,7 +284,7 @@ impl DnsResolver {
where
R: DnsResolve + Send + Sync + 'static,
{
Self::Custom(DynDnsResolve::boxed(custom))
Self::Custom(DynDnsResolve::new_box(custom))
}
/// Resolve address into `SocketAddr`s

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