mirror of
https://github.com/bolucat/Archive.git
synced 2026-04-22 16:07:49 +08:00
Update On Thu Jul 17 20:42:45 CEST 2025
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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=
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Generated
+562
-419
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));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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(_) => {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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()
|
||||
}}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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": {
|
||||
|
||||
Generated
+640
-528
File diff suppressed because it is too large
Load Diff
@@ -1,2 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly-2025-02-25"
|
||||
channel = "nightly"
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
Generated
+33
-33
@@ -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,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
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
@@ -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
@@ -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=
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
+8
-2
@@ -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] == "&") {
|
||||
|
||||
Generated
+10
-11
@@ -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
Reference in New Issue
Block a user