Update On Tue Nov 4 19:40:31 CET 2025

This commit is contained in:
github-action[bot]
2025-11-04 19:40:32 +01:00
parent a96af7ed12
commit bb569cc785
35 changed files with 1347 additions and 1161 deletions

1
.github/update.log vendored
View File

@@ -1171,3 +1171,4 @@ Update On Fri Oct 31 19:38:32 CET 2025
Update On Sat Nov 1 19:37:41 CET 2025
Update On Sun Nov 2 19:34:13 CET 2025
Update On Mon Nov 3 19:37:13 CET 2025
Update On Tue Nov 4 19:40:23 CET 2025

View File

@@ -24,6 +24,8 @@ var WriteBuffer = bufio.WriteBuffer
type ReadWaitOptions = network.ReadWaitOptions
var NewReadWaitOptions = network.NewReadWaitOptions
var CalculateFrontHeadroom = network.CalculateFrontHeadroom
var CalculateRearHeadroom = network.CalculateRearHeadroom
type ReaderWithUpstream = network.ReaderWithUpstream
type WithUpstreamReader = network.WithUpstreamReader

View File

@@ -16,7 +16,7 @@ require (
github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905
github.com/klauspost/compress v1.17.9 // lastest version compatible with golang1.20
github.com/mdlayher/netlink v1.7.2
github.com/metacubex/amneziawg-go v0.0.0-20250902133113-a7f637c14281
github.com/metacubex/amneziawg-go v0.0.0-20251104174305-5a0e9f7e361d
github.com/metacubex/bart v0.26.0
github.com/metacubex/bbolt v0.0.0-20250725135710-010dbbbb7a5b
github.com/metacubex/blake3 v0.1.0

View File

@@ -90,8 +90,8 @@ github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
github.com/metacubex/amneziawg-go v0.0.0-20250902133113-a7f637c14281 h1:09EM0sOLb2kfL0KETGhHujsBLB5iy5U/2yHRHsxf/pI=
github.com/metacubex/amneziawg-go v0.0.0-20250902133113-a7f637c14281/go.mod h1:MsM/5czONyXMJ3PRr5DbQ4O/BxzAnJWOIcJdLzW6qHY=
github.com/metacubex/amneziawg-go v0.0.0-20251104174305-5a0e9f7e361d h1:vAJ0ZT4aO803F1uw2roIA9yH7Sxzox34tVVyye1bz6c=
github.com/metacubex/amneziawg-go v0.0.0-20251104174305-5a0e9f7e361d/go.mod h1:MsM/5czONyXMJ3PRr5DbQ4O/BxzAnJWOIcJdLzW6qHY=
github.com/metacubex/ascon v0.1.0 h1:6ZWxmXYszT1XXtwkf6nxfFhc/OTtQ9R3Vyj1jN32lGM=
github.com/metacubex/ascon v0.1.0/go.mod h1:eV5oim4cVPPdEL8/EYaTZ0iIKARH9pnhAK/fcT5Kacc=
github.com/metacubex/bart v0.26.0 h1:d/bBTvVatfVWGfQbiDpYKI1bXUJgjaabB2KpK1Tnk6w=

View File

@@ -242,14 +242,26 @@ func (vc *Conn) WriteBuffer(buffer *buf.Buffer) (err error) {
}
func (vc *Conn) FrontHeadroom() int {
fontHeadroom := PaddingHeaderLen - uuid.Size
if vc.readFilterUUID || vc.writeOnceUserUUID != nil {
return PaddingHeaderLen
fontHeadroom = PaddingHeaderLen
}
return PaddingHeaderLen - uuid.Size
if vc.writeFilterApplicationData { // The writer may be replaced, add the required value for vc.netConn
if abs := N.CalculateFrontHeadroom(vc.netConn) - N.CalculateFrontHeadroom(vc.Conn); abs > 0 {
fontHeadroom += abs
}
}
return fontHeadroom
}
func (vc *Conn) RearHeadroom() int {
return 500 + 900
rearHeadroom := 500 + 900
if vc.writeFilterApplicationData { // The writer may be replaced, add the required value for vc.netConn
if abs := N.CalculateRearHeadroom(vc.netConn) - N.CalculateRearHeadroom(vc.Conn); abs > 0 {
rearHeadroom += abs
}
}
return rearHeadroom
}
func (vc *Conn) NeedHandshake() bool {

View File

@@ -16,9 +16,9 @@
"@emotion/styled": "11.14.1",
"@juggle/resize-observer": "3.4.0",
"@material/material-color-utilities": "0.3.0",
"@mui/icons-material": "7.3.4",
"@mui/icons-material": "7.3.5",
"@mui/lab": "7.0.0-beta.17",
"@mui/material": "7.3.4",
"@mui/material": "7.3.5",
"@mui/x-date-pickers": "8.16.0",
"@nyanpasu/interface": "workspace:^",
"@nyanpasu/ui": "workspace:^",
@@ -59,9 +59,9 @@
"@iconify/json": "2.2.403",
"@monaco-editor/react": "4.7.0",
"@tanstack/react-query": "5.90.6",
"@tanstack/react-router": "1.134.9",
"@tanstack/react-router-devtools": "1.134.9",
"@tanstack/router-plugin": "1.134.9",
"@tanstack/react-router": "1.134.12",
"@tanstack/react-router-devtools": "1.134.12",
"@tanstack/router-plugin": "1.134.12",
"@tauri-apps/plugin-clipboard-manager": "2.3.0",
"@tauri-apps/plugin-dialog": "2.4.0",
"@tauri-apps/plugin-fs": "2.4.2",

View File

@@ -12,9 +12,9 @@
},
"dependencies": {
"@material/material-color-utilities": "0.3.0",
"@mui/icons-material": "7.3.4",
"@mui/icons-material": "7.3.5",
"@mui/lab": "7.0.0-beta.17",
"@mui/material": "7.3.4",
"@mui/material": "7.3.5",
"@radix-ui/react-portal": "1.1.9",
"@radix-ui/react-scroll-area": "1.2.10",
"@tauri-apps/api": "2.8.0",

View File

@@ -2,10 +2,10 @@
"manifest_version": 1,
"latest": {
"mihomo": "v1.19.15",
"mihomo_alpha": "alpha-6fb1f79",
"mihomo_alpha": "alpha-fd39c2a",
"clash_rs": "v0.9.1",
"clash_premium": "2023-09-05-gdcc8d87",
"clash_rs_alpha": "0.9.1-alpha+sha.4479974"
"clash_rs_alpha": "0.9.1-alpha+sha.cff16c6"
},
"arch_template": {
"mihomo": {
@@ -69,5 +69,5 @@
"linux-armv7hf": "clash-armv7-unknown-linux-gnueabihf"
}
},
"updated_at": "2025-11-02T22:20:46.358Z"
"updated_at": "2025-11-03T22:21:13.590Z"
}

View File

@@ -67,13 +67,13 @@
"@types/fs-extra": "11.0.4",
"@types/lodash-es": "4.17.12",
"@types/node": "24.10.0",
"@typescript-eslint/eslint-plugin": "8.46.2",
"@typescript-eslint/parser": "8.46.2",
"@typescript-eslint/eslint-plugin": "8.46.3",
"@typescript-eslint/parser": "8.46.3",
"autoprefixer": "10.4.21",
"conventional-changelog-conventionalcommits": "9.1.0",
"cross-env": "10.1.0",
"dedent": "1.7.0",
"eslint": "9.39.0",
"eslint": "9.39.1",
"eslint-config-prettier": "10.1.8",
"eslint-import-resolver-alias": "1.1.2",
"eslint-plugin-html": "8.1.3",
@@ -85,7 +85,7 @@
"eslint-plugin-react-compiler": "19.1.0-rc.2",
"eslint-plugin-react-hooks": "7.0.1",
"globals": "16.5.0",
"knip": "5.67.0",
"knip": "5.67.1",
"lint-staged": "16.2.6",
"neostandard": "0.12.2",
"npm-run-all2": "8.0.4",
@@ -108,7 +108,7 @@
"tailwindcss": "4.1.16",
"tsx": "4.20.6",
"typescript": "5.9.3",
"typescript-eslint": "8.46.2"
"typescript-eslint": "8.46.3"
},
"packageManager": "pnpm@10.20.0",
"engines": {

File diff suppressed because it is too large Load Diff

View File

@@ -60,7 +60,9 @@ CONFIG_BINFMT_MISC=y
CONFIG_BLK_DEV_BSGLIB=y
CONFIG_BLK_DEV_BSG_COMMON=y
CONFIG_BLK_DEV_INTEGRITY=y
CONFIG_BLK_DEV_INTEGRITY_T10=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_SD=y
CONFIG_BLK_MQ_PCI=y
CONFIG_BLK_MQ_VIRTIO=y
CONFIG_BLK_PM=y
@@ -532,6 +534,13 @@ CONFIG_SCHED_INFO=y
CONFIG_SCHED_MC=y
CONFIG_SCHED_SMT=y
CONFIG_SCHED_THERMAL_PRESSURE=y
CONFIG_SCSI=y
CONFIG_SCSI_COMMON=y
# CONFIG_SCSI_LOWLEVEL is not set
# CONFIG_SCSI_PROC_FS is not set
CONFIG_SCSI_SAS_ATTRS=y
CONFIG_SCSI_SAS_HOST_SMP=y
CONFIG_SCSI_SAS_LIBSAS=y
CONFIG_SECURITY=y
# CONFIG_SECURITY_NETWORK is not set
CONFIG_SERIAL_8250_FSL=y

View File

@@ -31,7 +31,7 @@ function delete_mieru_client_log() {
}
function run_new_conn_test() {
config="$1"
local config="$1"
sleep 1
echo ">>> socks5 - new connections with API server - $config <<<"
./sockshttpclient -dst_host=127.0.0.1 -dst_port=8080 \
@@ -45,7 +45,7 @@ function run_new_conn_test() {
}
function run_udp_associate_test() {
config="$1"
local config="$1"
sleep 1
echo ">>> socks5 UDP associate - with API server - $config <<<"
./socksudpclient -dst_host=127.0.0.1 -dst_port=9090 \

View File

@@ -21,11 +21,11 @@ WORKDIR /test
# Copy binaries, data and test script into the container.
COPY mihomo mita httpserver sockshttpclient socksudpclient udpserver \
test/deploy/mihomo/mihomo-config.yaml \
test/deploy/mihomo/mihomo-config-no-wait.yaml \
test/deploy/mihomo/mihomo-client-tcp.yaml \
test/deploy/mihomo/mihomo-client-tcp-no-wait.yaml \
test/deploy/mihomo/server_tcp.json \
test/deploy/mihomo/libtest.sh \
test/deploy/mihomo/test_tcp.sh \
test/deploy/mihomo/test_client_tcp.sh \
test/deploy/mihomo/test.sh /test/
# Create mita user and server config directory.

View File

@@ -37,7 +37,7 @@ sleep 1
# Run TCP test.
echo "========== BEGIN OF TCP TEST =========="
./test_tcp.sh
./test_client_tcp.sh
echo "========== END OF TCP TEST =========="
echo "Test is successful."

View File

@@ -0,0 +1,109 @@
#!/bin/bash
# Copyright (C) 2024 mieru authors
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# Make sure this script has executable permission:
# git update-index --chmod=+x <file>
# Load test library.
source ./libtest.sh
# Update mieru server with TCP config.
./mita apply config server_tcp.json
if [[ "$?" -ne 0 ]]; then
echo "command 'mita apply config server_tcp.json' failed"
exit 1
fi
echo "mieru server config:"
./mita describe config
# Start mieru server proxy.
./mita start
if [[ "$?" -ne 0 ]]; then
echo "command 'mita start' failed"
exit 1
fi
# Start mihomo.
./mihomo -f mihomo-client-tcp.yaml &
sleep 1
./mihomo -f mihomo-client-tcp-no-wait.yaml &
sleep 1
function run_tcp_tests() {
local port="$1"
local suffix="${2:-}"
sleep 1
echo ">>> socks5 - new connections - TCP ${suffix} <<<"
./sockshttpclient -dst_host=127.0.0.1 -dst_port=8080 \
-local_proxy_host=127.0.0.1 -local_proxy_port=${port} \
-test_case=new_conn -num_request=3000
if [ "$?" -ne "0" ]; then
print_mieru_server_thread_dump
echo "TCP - test socks5 new_conn ${suffix} failed."
exit 1
fi
sleep 1
echo ">>> http - new connections - TCP ${suffix} <<<"
./sockshttpclient -proxy_mode=http -dst_host=127.0.0.1 -dst_port=8080 \
-local_http_host=127.0.0.1 -local_http_port=${port} \
-test_case=new_conn -num_request=1000
if [ "$?" -ne "0" ]; then
print_mieru_server_thread_dump
echo "TCP - test HTTP new_conn ${suffix} failed."
exit 1
fi
sleep 1
echo ">>> socks5 - reuse one connection - TCP ${suffix} <<<"
./sockshttpclient -dst_host=127.0.0.1 -dst_port=8080 \
-local_proxy_host=127.0.0.1 -local_proxy_port=${port} \
-test_case=reuse_conn -test_time_sec=30
if [ "$?" -ne "0" ]; then
print_mieru_server_thread_dump
echo "TCP - test socks5 reuse_conn ${suffix} failed."
exit 1
fi
sleep 1
echo ">>> socks5 UDP associate - TCP ${suffix} <<<"
./socksudpclient -dst_host=127.0.0.1 -dst_port=9090 \
-local_proxy_host=127.0.0.1 -local_proxy_port=${port} \
-interval_ms=10 -num_request=100 -num_conn=60
if [ "$?" -ne "0" ]; then
print_mieru_server_thread_dump
echo "TCP - test socks5 udp_associate ${suffix} failed."
exit 1
fi
}
# Start testing.
run_tcp_tests 1080
run_tcp_tests 1081 "(handshake no wait)"
# Print metrics and memory statistics.
print_mieru_server_metrics
sleep 1
# Stop mieru server proxy.
./mita stop
if [[ "$?" -ne 0 ]]; then
echo "command 'mita stop' failed"
exit 1
fi
sleep 1

View File

@@ -1,145 +0,0 @@
#!/bin/bash
# Copyright (C) 2024 mieru authors
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# Make sure this script has executable permission:
# git update-index --chmod=+x <file>
# Load test library.
source ./libtest.sh
# Update mieru server with TCP config.
./mita apply config server_tcp.json
if [[ "$?" -ne 0 ]]; then
echo "command 'mita apply config server_tcp.json' failed"
exit 1
fi
echo "mieru server config:"
./mita describe config
# Start mieru server proxy.
./mita start
if [[ "$?" -ne 0 ]]; then
echo "command 'mita start' failed"
exit 1
fi
# Start mihomo.
./mihomo -f mihomo-config.yaml &
sleep 1
./mihomo -f mihomo-config-no-wait.yaml &
sleep 1
# Start testing.
sleep 2
echo ">>> socks5 - new connections - TCP <<<"
./sockshttpclient -dst_host=127.0.0.1 -dst_port=8080 \
-local_proxy_host=127.0.0.1 -local_proxy_port=1080 \
-test_case=new_conn -num_request=3000
if [ "$?" -ne "0" ]; then
print_mieru_server_thread_dump
echo "TCP - test socks5 new_conn failed."
exit 1
fi
sleep 1
echo ">>> http - new connections - TCP <<<"
./sockshttpclient -proxy_mode=http -dst_host=127.0.0.1 -dst_port=8080 \
-local_http_host=127.0.0.1 -local_http_port=1080 \
-test_case=new_conn -num_request=1000
if [ "$?" -ne "0" ]; then
print_mieru_server_thread_dump
echo "TCP - test HTTP new_conn failed."
exit 1
fi
sleep 1
echo ">>> socks5 - reuse one connection - TCP <<<"
./sockshttpclient -dst_host=127.0.0.1 -dst_port=8080 \
-local_proxy_host=127.0.0.1 -local_proxy_port=1080 \
-test_case=reuse_conn -test_time_sec=30
if [ "$?" -ne "0" ]; then
print_mieru_server_thread_dump
echo "TCP - test socks5 reuse_conn failed."
exit 1
fi
sleep 1
echo ">>> socks5 UDP associate - TCP <<<"
./socksudpclient -dst_host=127.0.0.1 -dst_port=9090 \
-local_proxy_host=127.0.0.1 -local_proxy_port=1080 \
-interval_ms=10 -num_request=100 -num_conn=60
if [ "$?" -ne "0" ]; then
print_mieru_server_thread_dump
echo "TCP - test socks5 udp_associate failed."
exit 1
fi
sleep 1
echo ">>> socks5 - new connections - TCP - handshake no wait <<<"
./sockshttpclient -dst_host=127.0.0.1 -dst_port=8080 \
-local_proxy_host=127.0.0.1 -local_proxy_port=1081 \
-test_case=new_conn -num_request=3000
if [ "$?" -ne "0" ]; then
print_mieru_server_thread_dump
echo "TCP - test socks5 new_conn (handshake no wait) failed."
exit 1
fi
sleep 1
echo ">>> http - new connections - TCP - handshake no wait <<<"
./sockshttpclient -proxy_mode=http -dst_host=127.0.0.1 -dst_port=8080 \
-local_http_host=127.0.0.1 -local_http_port=1081 \
-test_case=new_conn -num_request=1000
if [ "$?" -ne "0" ]; then
print_mieru_server_thread_dump
echo "TCP - test HTTP new_conn (handshake no wait) failed."
exit 1
fi
sleep 1
echo ">>> socks5 - reuse one connection - TCP - handshake no wait <<<"
./sockshttpclient -dst_host=127.0.0.1 -dst_port=8080 \
-local_proxy_host=127.0.0.1 -local_proxy_port=1081 \
-test_case=reuse_conn -test_time_sec=30
if [ "$?" -ne "0" ]; then
print_mieru_server_thread_dump
echo "TCP - test socks5 reuse_conn (handshake no wait) failed."
exit 1
fi
sleep 1
echo ">>> socks5 UDP associate - TCP - handshake no wait <<<"
./socksudpclient -dst_host=127.0.0.1 -dst_port=9090 \
-local_proxy_host=127.0.0.1 -local_proxy_port=1081 \
-interval_ms=10 -num_request=100 -num_conn=60
if [ "$?" -ne "0" ]; then
print_mieru_server_thread_dump
echo "TCP - test socks5 udp_associate (handshake no wait) failed."
exit 1
fi
# Print metrics and memory statistics.
print_mieru_server_metrics
sleep 1
# Stop mieru server proxy.
./mita stop
if [[ "$?" -ne 0 ]]; then
echo "command 'mita stop' failed"
exit 1
fi
sleep 1

View File

@@ -24,6 +24,8 @@ var WriteBuffer = bufio.WriteBuffer
type ReadWaitOptions = network.ReadWaitOptions
var NewReadWaitOptions = network.NewReadWaitOptions
var CalculateFrontHeadroom = network.CalculateFrontHeadroom
var CalculateRearHeadroom = network.CalculateRearHeadroom
type ReaderWithUpstream = network.ReaderWithUpstream
type WithUpstreamReader = network.WithUpstreamReader

View File

@@ -16,7 +16,7 @@ require (
github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905
github.com/klauspost/compress v1.17.9 // lastest version compatible with golang1.20
github.com/mdlayher/netlink v1.7.2
github.com/metacubex/amneziawg-go v0.0.0-20250902133113-a7f637c14281
github.com/metacubex/amneziawg-go v0.0.0-20251104174305-5a0e9f7e361d
github.com/metacubex/bart v0.26.0
github.com/metacubex/bbolt v0.0.0-20250725135710-010dbbbb7a5b
github.com/metacubex/blake3 v0.1.0

View File

@@ -90,8 +90,8 @@ github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
github.com/metacubex/amneziawg-go v0.0.0-20250902133113-a7f637c14281 h1:09EM0sOLb2kfL0KETGhHujsBLB5iy5U/2yHRHsxf/pI=
github.com/metacubex/amneziawg-go v0.0.0-20250902133113-a7f637c14281/go.mod h1:MsM/5czONyXMJ3PRr5DbQ4O/BxzAnJWOIcJdLzW6qHY=
github.com/metacubex/amneziawg-go v0.0.0-20251104174305-5a0e9f7e361d h1:vAJ0ZT4aO803F1uw2roIA9yH7Sxzox34tVVyye1bz6c=
github.com/metacubex/amneziawg-go v0.0.0-20251104174305-5a0e9f7e361d/go.mod h1:MsM/5czONyXMJ3PRr5DbQ4O/BxzAnJWOIcJdLzW6qHY=
github.com/metacubex/ascon v0.1.0 h1:6ZWxmXYszT1XXtwkf6nxfFhc/OTtQ9R3Vyj1jN32lGM=
github.com/metacubex/ascon v0.1.0/go.mod h1:eV5oim4cVPPdEL8/EYaTZ0iIKARH9pnhAK/fcT5Kacc=
github.com/metacubex/bart v0.26.0 h1:d/bBTvVatfVWGfQbiDpYKI1bXUJgjaabB2KpK1Tnk6w=

View File

@@ -242,14 +242,26 @@ func (vc *Conn) WriteBuffer(buffer *buf.Buffer) (err error) {
}
func (vc *Conn) FrontHeadroom() int {
fontHeadroom := PaddingHeaderLen - uuid.Size
if vc.readFilterUUID || vc.writeOnceUserUUID != nil {
return PaddingHeaderLen
fontHeadroom = PaddingHeaderLen
}
return PaddingHeaderLen - uuid.Size
if vc.writeFilterApplicationData { // The writer may be replaced, add the required value for vc.netConn
if abs := N.CalculateFrontHeadroom(vc.netConn) - N.CalculateFrontHeadroom(vc.Conn); abs > 0 {
fontHeadroom += abs
}
}
return fontHeadroom
}
func (vc *Conn) RearHeadroom() int {
return 500 + 900
rearHeadroom := 500 + 900
if vc.writeFilterApplicationData { // The writer may be replaced, add the required value for vc.netConn
if abs := N.CalculateRearHeadroom(vc.netConn) - N.CalculateRearHeadroom(vc.Conn); abs > 0 {
rearHeadroom += abs
}
}
return rearHeadroom
}
func (vc *Conn) NeedHandshake() bool {

View File

@@ -49,6 +49,9 @@ func (s *Service) loadCache() error {
os.RemoveAll(basePath)
return err
}
s.cacheMutex.Lock()
s.lastSavedCache = cacheBinary
s.cacheMutex.Unlock()
return nil
}
@@ -56,16 +59,30 @@ func (s *Service) saveCache() error {
if s.cachePath == "" {
return nil
}
cacheBinary, err := s.encodeCache()
if err != nil {
return err
}
s.cacheMutex.Lock()
defer s.cacheMutex.Unlock()
if bytes.Equal(s.lastSavedCache, cacheBinary) {
return nil
}
return s.writeCache(cacheBinary)
}
func (s *Service) writeCache(cacheBinary []byte) error {
basePath := filemanager.BasePath(s.ctx, s.cachePath)
err := os.MkdirAll(filepath.Dir(basePath), 0o777)
if err != nil {
return err
}
cacheBinary, err := s.encodeCache()
err = os.WriteFile(basePath, cacheBinary, 0o644)
if err != nil {
return err
}
return os.WriteFile(s.cachePath, cacheBinary, 0o644)
s.lastSavedCache = cacheBinary
return nil
}
func (s *Service) decodeCache(cacheBinary []byte) error {

View File

@@ -4,6 +4,8 @@ import (
"context"
"errors"
"net/http"
"sync"
"time"
"github.com/sagernet/sing-box/adapter"
boxService "github.com/sagernet/sing-box/adapter/service"
@@ -28,21 +30,27 @@ func RegisterService(registry *boxService.Registry) {
type Service struct {
boxService.Adapter
ctx context.Context
logger log.ContextLogger
listener *listener.Listener
tlsConfig tls.ServerConfig
httpServer *http.Server
traffics map[string]*TrafficManager
users map[string]*UserManager
cachePath string
ctx context.Context
cancel context.CancelFunc
logger log.ContextLogger
listener *listener.Listener
tlsConfig tls.ServerConfig
httpServer *http.Server
traffics map[string]*TrafficManager
users map[string]*UserManager
cachePath string
saveTicker *time.Ticker
lastSavedCache []byte
cacheMutex sync.Mutex
}
func NewService(ctx context.Context, logger log.ContextLogger, tag string, options option.SSMAPIServiceOptions) (adapter.Service, error) {
ctx, cancel := context.WithCancel(ctx)
chiRouter := chi.NewRouter()
s := &Service{
Adapter: boxService.NewAdapter(C.TypeSSMAPI, tag),
ctx: ctx,
cancel: cancel,
logger: logger,
listener: listener.New(listener.Options{
Context: ctx,
@@ -95,6 +103,8 @@ func (s *Service) Start(stage adapter.StartStage) error {
if err != nil {
s.logger.Error(E.Cause(err, "load cache"))
}
s.saveTicker = time.NewTicker(1 * time.Minute)
go s.loopSaveCache()
if s.tlsConfig != nil {
err = s.tlsConfig.Start()
if err != nil {
@@ -120,7 +130,27 @@ func (s *Service) Start(stage adapter.StartStage) error {
return nil
}
func (s *Service) loopSaveCache() {
for {
select {
case <-s.ctx.Done():
return
case <-s.saveTicker.C:
err := s.saveCache()
if err != nil {
s.logger.Error(E.Cause(err, "save cache"))
}
}
}
}
func (s *Service) Close() error {
if s.cancel != nil {
s.cancel()
}
if s.saveTicker != nil {
s.saveTicker.Stop()
}
err := s.saveCache()
if err != nil {
s.logger.Error(E.Cause(err, "save cache"))

View File

@@ -1285,15 +1285,26 @@ o = s:option(ListValue, "tuic_alpn", translate("TUIC ALPN"))
o.default = ""
o:value("", translate("Default"))
o:value("h3")
o:value("h2")
o:value("h3,h2")
o:value("spdy/3.1")
o:value("h3,spdy/3.1")
o:depends("type", "tuic")
-- IP STACK PREFERENCE
o = s:option(ListValue, "ipstack_prefer", translate("IP Stack Preference"))
o.default = ""
o:value("", translate("Default"))
o:value("v4first")
o:value("v6first")
o:depends("tuic_dual_stack", true)
-- [[ allowInsecure ]]--
o = s:option(Flag, "insecure", translate("allowInsecure"))
o.rmempty = false
o:depends("tls", true)
o:depends("type", "hysteria2")
o:depends("type", "tuic")
o.description = translate("If true, allowss insecure connection at TLS client, e.g., TLS server uses unverifiable certificates.")
-- [[ Hysteria2 TLS pinSHA256 ]] --

View File

@@ -862,12 +862,37 @@ function import_ssr_url(btn, urlname, sid) {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server')[0].value = url.hostname;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server_port')[0].value = url.port;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tuic_uuid')[0].value = method;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tuic_ip')[0].value = params.sni || "";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tuic_ip')[0].value = params.ip || "";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tuic_passwd')[0].value = password;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.udp_relay_mode')[0].value = params.udp_relay_mode || "native";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.congestion_control')[0].value = params.congestion_control || "cubic";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tuic_alpn')[0].value = params.alpn || "";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.heartbeat')[0].value = params.heartbeat || "3";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.timeout')[0].value = params.timeout || "8";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.gc_interval')[0].value = params.gc_interval || "3";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.gc_lifetime')[0].value = params.gc_lifetime || "15";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.send_window')[0].value = params.send_window || "20971520";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.receive_window')[0].value = params.receive_window || "10485760";
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tuic_max_package_size')[0].value = params.max_packet_size || "1500";
if (params["disable_sni"] === "1" || params["disable_sni"] === "true") {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.disable_sni')[0].checked = true;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.disable_sni')[0].dispatchEvent(event);
}
if (params["zero_rtt_handshake"] === "1" || params["zero_rtt_handshake"] === "true") {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.zero_rtt_handshake')[0].checked = true;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.zero_rtt_handshake')[0].dispatchEvent(event);
}
if (params["dual_stack"] === "1" || params["dual_stack"] === "true") {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tuic_dual_stack')[0].checked = true;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tuic_dual_stack')[0].dispatchEvent(event);
if (params.ipstack_prefer && params.ipstack_prefer.trim() !== "") {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.ipstack_prefer')[0].value = params.ipstack_prefer;
}
}
if (params["allowInsecure"] === "1" || params["allowInsecure"] === "true") {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.insecure')[0].checked = true;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.insecure')[0].dispatchEvent(event);
}
if (param != undefined) {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0].value = decodeURIComponent(param);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -331,8 +331,8 @@ end
mux = (server.v2ray_protocol ~= "wireguard") and {
-- mux
enabled = (server.mux == "1"), -- Mux
concurrency = (server.mux == "1" and (tonumber(server.concurrency) or -1)) or nil, -- TCP 最大并发
xudpConcurrency = (server.mux == "1" and (tonumber(server.xudpConcurrency) or 16)) or nil, -- UDP 最大并发
concurrency = (server.mux == "1" and (tonumber(server.concurrency) or -1)) or nil, -- TCP 最大并发连接数
xudpConcurrency = (server.mux == "1" and (tonumber(server.xudpConcurrency) or 16)) or nil, -- UDP 最大并发连接数
xudpProxyUDP443 = (server.mux == "1" and (server.xudpProxyUDP443 or "reject")) or nil -- 对被代理的 UDP/443 流量处理方式
} or nil
}
@@ -631,6 +631,8 @@ local tuic = {
return nil
end
end)() or nil,
ipstack_prefer = (server.tuic_dual_stack == "1") and server.ipstack_prefer or nil,
skip_cert_verify = (server.insecure == "1" or server.insecure == true or server.insecure == "true"),
disable_sni = (server.disable_sni == "1") and true or false,
zero_rtt_handshake = (server.zero_rtt_handshake == "1") and true or false,
send_window = tonumber(server.send_window),
@@ -715,3 +717,4 @@ function config:handleIndex(index)
end
local f = config:new()
f:handleIndex(server.type)

View File

@@ -877,7 +877,7 @@ local function processData(szType, content)
-- TLS / Reality 标志
local security = params.security or ""
result.tls = (params.security == "tls" or security == "xtls") and "1" or "0"
result.tls = (security == "tls" or security == "xtls") and "1" or "0"
result.reality = (security == "reality") and "1" or "0"
-- 统一 TLS / Reality 公共字段
@@ -1012,9 +1012,16 @@ local function processData(szType, content)
end
result.type = tuic_type
result.tuic_ip = params.sni or ""
result.tuic_ip = params.ip or ""
result.udp_relay_mode = params.udp_relay_mode or "native"
result.congestion_control = params.congestion_control or "cubic"
result.heartbeat = params.heartbeat or "3"
result.timeout = params.timeout or "8"
result.gc_interval = params.gc_interval or "3"
result.gc_lifetime = params.gc_lifetime or "15"
result.send_window = params.send_window or "20971520"
result.receive_window = params.receive_window or "10485760"
result.tuic_max_package_size = params.max_packet_size or "1500"
-- alpn 支持逗号或分号分隔
if params.alpn and params.alpn ~= "" then
@@ -1024,6 +1031,46 @@ local function processData(szType, content)
end
result.tuic_alpn = alpn
end
-- 处理 disable_sni 参数
if params.disable_sni then
if params.disable_sni == "1" or params.disable_sni == "0" then
result.disable_sni = params.disable_sni
else
result.disable_sni = string.lower(params.disable_sni) == "true" and "1" or "0"
end
end
-- 处理 zero_rtt_handshake 参数
if params.zero_rtt_handshake then
if params.zero_rtt_handshake == "1" or params.zero_rtt_handshake == "0" then
result.zero_rtt_handshake = params.zero_rtt_handshake
else
result.zero_rtt_handshake = string.lower(params.zero_rtt_handshake) == "true" and "1" or "0"
end
end
-- 处理 dual_stack 参数
if params.dual_stack then
if params.dual_stack == "1" or params.dual_stack == "0" then
result.dual_stack = params.dual_stack
else
result.dual_stack = string.lower(params.dual_stack) == "true" and "1" or "0"
end
-- 处理 ipstack_prefer 参数
if params.ipstack_prefer and params.ipstack_prefer ~= "" then
result.ipstack_prefer = params.ipstack_prefer
end
end
-- 处理 insecure 参数
if params.allowInsecure then
if params.allowinsecure == "1" or params.allowinsecure == "0" then
result.insecure = params.allowInsecure
else
result.insecure = string.lower(params.allowinsecure) == "true" and "1" or "0"
end
end
end
if not result.alias then
if result.server and result.server_port then

View File

@@ -1840,7 +1840,7 @@ The following extractors use this feature:
#### youtube
* `lang`: Prefer translated metadata (`title`, `description` etc) of this language code (case-sensitive). By default, the video primary language metadata is preferred, with a fallback to `en` translated. See [youtube/_base.py](https://github.com/yt-dlp/yt-dlp/blob/415b4c9f955b1a0391204bd24a7132590e7b3bdb/yt_dlp/extractor/youtube/_base.py#L402-L409) for the list of supported content language codes
* `skip`: One or more of `hls`, `dash` or `translated_subs` to skip extraction of the m3u8 manifests, dash manifests and [auto-translated subtitles](https://github.com/yt-dlp/yt-dlp/issues/4090#issuecomment-1158102032) respectively
* `player_client`: Clients to extract video data from. The currently available clients are `web`, `web_safari`, `web_embedded`, `web_music`, `web_creator`, `mweb`, `ios`, `android`, `android_sdkless`, `android_vr`, `tv`, `tv_simply` and `tv_embedded`. By default, `tv,android_sdkless,web` is used. If no JavaScript runtime is available, then `android_sdkless,web_safari,web` is used. If logged-in cookies are passed to yt-dlp, then `tv,web_safari,web` is used for free accounts and `tv,web_creator,web` is used for premium accounts. The `web_music` client is added for `music.youtube.com` URLs when logged-in cookies are used. The `web_embedded` client is added for age-restricted videos but only works if the video is embeddable. The `tv_embedded` and `web_creator` clients are added for age-restricted videos if account age-verification is required. Some clients, such as `web` and `web_music`, require a `po_token` for their formats to be downloadable. Some clients, such as `web_creator`, will only work with authentication. Not all clients support authentication via cookies. You can use `default` for the default clients, or you can use `all` for all clients (not recommended). You can prefix a client with `-` to exclude it, e.g. `youtube:player_client=default,-ios`
* `player_client`: Clients to extract video data from. The currently available clients are `web`, `web_safari`, `web_embedded`, `web_music`, `web_creator`, `mweb`, `ios`, `android`, `android_sdkless`, `android_vr`, `tv`, `tv_simply`, `tv_downgraded`, and `tv_embedded`. By default, `tv,android_sdkless,web` is used. If no JavaScript runtime is available, then `android_sdkless,web_safari,web` is used. If logged-in cookies are passed to yt-dlp, then `tv_downgraded,web_safari,web` is used for free accounts and `tv_downgraded,web_creator,web` is used for premium accounts. The `web_music` client is added for `music.youtube.com` URLs when logged-in cookies are used. The `web_embedded` client is added for age-restricted videos but only works if the video is embeddable. The `tv_embedded` and `web_creator` clients are added for age-restricted videos if account age-verification is required. Some clients, such as `web` and `web_music`, require a `po_token` for their formats to be downloadable. Some clients, such as `web_creator`, will only work with authentication. Not all clients support authentication via cookies. You can use `default` for the default clients, or you can use `all` for all clients (not recommended). You can prefix a client with `-` to exclude it, e.g. `youtube:player_client=default,-ios`
* `player_skip`: Skip some network requests that are generally needed for robust extraction. One or more of `configs` (skip client configs), `webpage` (skip initial webpage), `js` (skip js player), `initial_data` (skip initial data/next ep request). While these options can help reduce the number of requests needed or avoid some rate-limiting, they could cause issues such as missing formats or metadata. See [#860](https://github.com/yt-dlp/yt-dlp/pull/860) and [#12826](https://github.com/yt-dlp/yt-dlp/issues/12826) for more details
* `webpage_skip`: Skip extraction of embedded webpage data. One or both of `player_response`, `initial_data`. These options are for testing purposes and don't skip any network requests
* `player_params`: YouTube player parameters to use for player requests. Will overwrite any default ones set by yt-dlp.

View File

@@ -488,20 +488,6 @@ class FFmpegFD(ExternalFD):
if not self.params.get('verbose'):
args += ['-hide_banner']
args += traverse_obj(info_dict, ('downloader_options', 'ffmpeg_args', ...))
# These exists only for compatibility. Extractors should use
# info_dict['downloader_options']['ffmpeg_args'] instead
args += info_dict.get('_ffmpeg_args') or []
seekable = info_dict.get('_seekable')
if seekable is not None:
# setting -seekable prevents ffmpeg from guessing if the server
# supports seeking(by adding the header `Range: bytes=0-`), which
# can cause problems in some cases
# https://github.com/ytdl-org/youtube-dl/issues/11800#issuecomment-275037127
# http://trac.ffmpeg.org/ticket/6125#comment:10
args += ['-seekable', '1' if seekable else '0']
env = None
proxy = self.params.get('proxy')
if proxy:
@@ -521,39 +507,10 @@ class FFmpegFD(ExternalFD):
env['HTTP_PROXY'] = proxy
env['http_proxy'] = proxy
protocol = info_dict.get('protocol')
if protocol == 'rtmp':
player_url = info_dict.get('player_url')
page_url = info_dict.get('page_url')
app = info_dict.get('app')
play_path = info_dict.get('play_path')
tc_url = info_dict.get('tc_url')
flash_version = info_dict.get('flash_version')
live = info_dict.get('rtmp_live', False)
conn = info_dict.get('rtmp_conn')
if player_url is not None:
args += ['-rtmp_swfverify', player_url]
if page_url is not None:
args += ['-rtmp_pageurl', page_url]
if app is not None:
args += ['-rtmp_app', app]
if play_path is not None:
args += ['-rtmp_playpath', play_path]
if tc_url is not None:
args += ['-rtmp_tcurl', tc_url]
if flash_version is not None:
args += ['-rtmp_flashver', flash_version]
if live:
args += ['-rtmp_live', 'live']
if isinstance(conn, list):
for entry in conn:
args += ['-rtmp_conn', entry]
elif isinstance(conn, str):
args += ['-rtmp_conn', conn]
start_time, end_time = info_dict.get('section_start') or 0, info_dict.get('section_end')
fallback_input_args = traverse_obj(info_dict, ('downloader_options', 'ffmpeg_args', ...))
selected_formats = info_dict.get('requested_formats') or [info_dict]
for i, fmt in enumerate(selected_formats):
is_http = re.match(r'https?://', fmt['url'])
@@ -572,6 +529,37 @@ class FFmpegFD(ExternalFD):
if end_time:
args += ['-t', str(end_time - start_time)]
protocol = fmt.get('protocol')
if protocol == 'rtmp':
player_url = fmt.get('player_url')
page_url = fmt.get('page_url')
app = fmt.get('app')
play_path = fmt.get('play_path')
tc_url = fmt.get('tc_url')
flash_version = fmt.get('flash_version')
live = fmt.get('rtmp_live', False)
conn = fmt.get('rtmp_conn')
if player_url is not None:
args += ['-rtmp_swfverify', player_url]
if page_url is not None:
args += ['-rtmp_pageurl', page_url]
if app is not None:
args += ['-rtmp_app', app]
if play_path is not None:
args += ['-rtmp_playpath', play_path]
if tc_url is not None:
args += ['-rtmp_tcurl', tc_url]
if flash_version is not None:
args += ['-rtmp_flashver', flash_version]
if live:
args += ['-rtmp_live', 'live']
if isinstance(conn, list):
for entry in conn:
args += ['-rtmp_conn', entry]
elif isinstance(conn, str):
args += ['-rtmp_conn', conn]
url = fmt['url']
if self.params.get('enable_file_urls') and url.startswith('file:'):
# The default protocol_whitelist is 'file,crypto,data' when reading local m3u8 URLs,
@@ -586,6 +574,7 @@ class FFmpegFD(ExternalFD):
# https://trac.ffmpeg.org/ticket/2702
url = re.sub(r'^file://(?:localhost)?/', 'file:' if os.name == 'nt' else 'file:/', url)
args += traverse_obj(fmt, ('downloader_options', 'ffmpeg_args', ...)) or fallback_input_args
args += [*self._configuration_args((f'_i{i + 1}', '_i')), '-i', url]
if not (start_time or end_time) or not self.params.get('force_keyframes_at_cuts'):

View File

@@ -327,6 +327,17 @@ INNERTUBE_CLIENTS = {
# See: https://github.com/youtube/cobalt/blob/main/cobalt/browser/user_agent/user_agent_platform_info.cc#L506
'AUTHENTICATED_USER_AGENT': 'Mozilla/5.0 (ChromiumStylePlatform) Cobalt/25.lts.30.1034943-gold (unlike Gecko), Unknown_TV_Unknown_0/Unknown (Unknown, Unknown)',
},
'tv_downgraded': {
'INNERTUBE_CONTEXT': {
'client': {
'clientName': 'TVHTML5',
'clientVersion': '4',
'userAgent': 'Mozilla/5.0 (ChromiumStylePlatform) Cobalt/Version',
},
},
'INNERTUBE_CONTEXT_CLIENT_NAME': 7,
'SUPPORTS_COOKIES': True,
},
'tv_simply': {
'INNERTUBE_CONTEXT': {
'client': {

View File

@@ -147,9 +147,9 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
_SUBTITLE_FORMATS = ('json3', 'srv1', 'srv2', 'srv3', 'ttml', 'srt', 'vtt')
_DEFAULT_CLIENTS = ('tv', 'android_sdkless', 'web')
_DEFAULT_JSLESS_CLIENTS = ('android_sdkless', 'web_safari', 'web')
_DEFAULT_AUTHED_CLIENTS = ('tv', 'web_safari', 'web')
_DEFAULT_AUTHED_CLIENTS = ('tv_downgraded', 'web_safari', 'web')
# Premium does not require POT (except for subtitles)
_DEFAULT_PREMIUM_CLIENTS = ('tv', 'web_creator', 'web')
_DEFAULT_PREMIUM_CLIENTS = ('tv_downgraded', 'web_creator', 'web')
_GEO_BYPASS = False