mirror of
https://github.com/bolucat/Archive.git
synced 2025-09-26 20:21:35 +08:00
Update On Tue Sep 17 20:34:17 CEST 2024
This commit is contained in:
1
.github/update.log
vendored
1
.github/update.log
vendored
@@ -766,3 +766,4 @@ Update On Fri Sep 13 20:34:47 CEST 2024
|
||||
Update On Sat Sep 14 20:32:28 CEST 2024
|
||||
Update On Sun Sep 15 20:33:53 CEST 2024
|
||||
Update On Mon Sep 16 20:36:05 CEST 2024
|
||||
Update On Tue Sep 17 20:34:06 CEST 2024
|
||||
|
@@ -505,17 +505,14 @@ func NewVless(option VlessOption) (*Vless, error) {
|
||||
var addons *vless.Addons
|
||||
if option.Network != "ws" && len(option.Flow) >= 16 {
|
||||
option.Flow = option.Flow[:16]
|
||||
switch option.Flow {
|
||||
case vless.XRV:
|
||||
if option.Flow != vless.XRV {
|
||||
return nil, fmt.Errorf("unsupported xtls flow type: %s", option.Flow)
|
||||
}
|
||||
|
||||
log.Warnln("To use %s, ensure your server is upgrade to Xray-core v1.8.0+", vless.XRV)
|
||||
addons = &vless.Addons{
|
||||
Flow: option.Flow,
|
||||
}
|
||||
case vless.XRO, vless.XRD, vless.XRS:
|
||||
log.Fatalln("Legacy XTLS protocol %s is deprecated and no longer supported", option.Flow)
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported xtls flow type: %s", option.Flow)
|
||||
}
|
||||
}
|
||||
|
||||
switch option.PacketEncoding {
|
||||
|
44
clash-nyanpasu/backend/Cargo.lock
generated
44
clash-nyanpasu/backend/Cargo.lock
generated
@@ -696,7 +696,7 @@ dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"itertools 0.12.1",
|
||||
"itertools 0.11.0",
|
||||
"lazy_static",
|
||||
"lazycell",
|
||||
"log",
|
||||
@@ -7322,9 +7322,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
|
||||
|
||||
[[package]]
|
||||
name = "tauri"
|
||||
version = "2.0.0-rc.14"
|
||||
version = "2.0.0-rc.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fa32e2741bda64c1da02d93252a466893180052fc6de61c8803b0356504b70d"
|
||||
checksum = "eb3c3b1c7ac5b72d59da307b84af900a0098c74c9d7369f65018cd8ec0eb50fb"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@@ -7360,7 +7360,7 @@ dependencies = [
|
||||
"tauri-macros",
|
||||
"tauri-runtime",
|
||||
"tauri-runtime-wry",
|
||||
"tauri-utils 2.0.0-rc.11",
|
||||
"tauri-utils 2.0.0-rc.12",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tray-icon",
|
||||
@@ -7374,9 +7374,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-build"
|
||||
version = "2.0.0-rc.11"
|
||||
version = "2.0.0-rc.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "148441d64674b2885c1ba5baf3ae61662bb8753859ffcfb541962cbc6b847f39"
|
||||
checksum = "6ff5713e81e02e0b99f5219b275abbd7d2c0cc0f30180e25b1b650e08feeac63"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cargo_toml",
|
||||
@@ -7388,7 +7388,7 @@ dependencies = [
|
||||
"semver 1.0.23",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri-utils 2.0.0-rc.11",
|
||||
"tauri-utils 2.0.0-rc.12",
|
||||
"tauri-winres",
|
||||
"toml 0.8.2",
|
||||
"walkdir",
|
||||
@@ -7396,9 +7396,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-codegen"
|
||||
version = "2.0.0-rc.11"
|
||||
version = "2.0.0-rc.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72a15c3f9282c82871c69ddb65d02ae552738bbac848c8adcab521bf14d8b9e6"
|
||||
checksum = "5370f2591dcc93d4ff08d9dd168f5097f79b34e859883586a409c627544190e3"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"brotli",
|
||||
@@ -7413,7 +7413,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"sha2 0.10.8",
|
||||
"syn 2.0.77",
|
||||
"tauri-utils 2.0.0-rc.11",
|
||||
"tauri-utils 2.0.0-rc.12",
|
||||
"thiserror",
|
||||
"time",
|
||||
"url",
|
||||
@@ -7423,16 +7423,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-macros"
|
||||
version = "2.0.0-rc.10"
|
||||
version = "2.0.0-rc.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f12d1aa317bec56f78388cf6012d788876d838595a48f95cbd7835642db356a0"
|
||||
checksum = "19442dc8ee002ab1926586f6aecb90114f3a1226766008b0c9ac2d9fec9eeb7e"
|
||||
dependencies = [
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.77",
|
||||
"tauri-codegen",
|
||||
"tauri-utils 2.0.0-rc.11",
|
||||
"tauri-utils 2.0.0-rc.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -7447,7 +7447,7 @@ dependencies = [
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri-utils 2.0.0-rc.11",
|
||||
"tauri-utils 2.0.0-rc.12",
|
||||
"toml 0.8.2",
|
||||
"walkdir",
|
||||
]
|
||||
@@ -7627,9 +7627,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-runtime"
|
||||
version = "2.0.0-rc.11"
|
||||
version = "2.0.0-rc.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "389f78c8e8e6eff3897d8d9581087943b5976ea96a0ab5036be691f28c2b0df0"
|
||||
checksum = "c5f38d8aaa1e81d20e8e208e3e317f81b59fb75c530fbae8a90e72d02001d687"
|
||||
dependencies = [
|
||||
"dpi",
|
||||
"gtk",
|
||||
@@ -7638,7 +7638,7 @@ dependencies = [
|
||||
"raw-window-handle",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri-utils 2.0.0-rc.11",
|
||||
"tauri-utils 2.0.0-rc.12",
|
||||
"thiserror",
|
||||
"url",
|
||||
"windows 0.58.0",
|
||||
@@ -7646,9 +7646,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-runtime-wry"
|
||||
version = "2.0.0-rc.12"
|
||||
version = "2.0.0-rc.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e17625b7cf63958d53945e199391d11c9f195fb3d1cb8aeb64dc3084d0091b92"
|
||||
checksum = "cf1ef5171e14c8fe3b5a63e75004c20d057747bc3e7fdc5f8ded625f0b29f5c7"
|
||||
dependencies = [
|
||||
"gtk",
|
||||
"http 1.1.0",
|
||||
@@ -7662,7 +7662,7 @@ dependencies = [
|
||||
"softbuffer",
|
||||
"tao",
|
||||
"tauri-runtime",
|
||||
"tauri-utils 2.0.0-rc.11",
|
||||
"tauri-utils 2.0.0-rc.12",
|
||||
"url",
|
||||
"webkit2gtk",
|
||||
"webview2-com",
|
||||
@@ -7697,9 +7697,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-utils"
|
||||
version = "2.0.0-rc.11"
|
||||
version = "2.0.0-rc.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3019641087c9039b57ebfca95fa42a93c07056845b7d8d57c8966061bcee83b4"
|
||||
checksum = "31fe4c9148e1b35225e1c00753f24b517ce00041d02eb4b4d6fd10613a47736c"
|
||||
dependencies = [
|
||||
"brotli",
|
||||
"cargo_metadata",
|
||||
|
@@ -11,7 +11,7 @@
|
||||
"build": "tsc"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "2.0.0-rc.4",
|
||||
"@tauri-apps/api": "2.0.0-rc.5",
|
||||
"ahooks": "3.8.1",
|
||||
"ofetch": "1.3.4",
|
||||
"react": "rc",
|
||||
|
@@ -16,12 +16,12 @@
|
||||
"@generouted/react-router": "1.19.6",
|
||||
"@juggle/resize-observer": "3.4.0",
|
||||
"@material/material-color-utilities": "0.3.0",
|
||||
"@mui/icons-material": "6.0.2",
|
||||
"@mui/icons-material": "6.1.0",
|
||||
"@mui/lab": "6.0.0-beta.9",
|
||||
"@mui/material": "6.0.2",
|
||||
"@mui/material": "6.1.0",
|
||||
"@nyanpasu/interface": "workspace:^",
|
||||
"@nyanpasu/ui": "workspace:^",
|
||||
"@tauri-apps/api": "2.0.0-rc.4",
|
||||
"@tauri-apps/api": "2.0.0-rc.5",
|
||||
"@types/json-schema": "7.0.15",
|
||||
"ahooks": "3.8.1",
|
||||
"allotment": "1.20.2",
|
||||
@@ -76,7 +76,7 @@
|
||||
"unplugin-auto-import": "0.18.3",
|
||||
"unplugin-icons": "0.19.3",
|
||||
"validator": "13.12.0",
|
||||
"vite": "5.4.5",
|
||||
"vite": "5.4.6",
|
||||
"vite-plugin-monaco-editor": "1.1.3",
|
||||
"vite-plugin-sass-dts": "1.3.29",
|
||||
"vite-plugin-svgr": "4.2.0",
|
||||
|
@@ -17,12 +17,12 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@material/material-color-utilities": "0.3.0",
|
||||
"@mui/icons-material": "6.0.2",
|
||||
"@mui/icons-material": "6.1.0",
|
||||
"@mui/lab": "6.0.0-beta.9",
|
||||
"@mui/material": "6.0.2",
|
||||
"@mui/material": "6.1.0",
|
||||
"@radix-ui/react-portal": "1.1.1",
|
||||
"@radix-ui/react-scroll-area": "1.1.0",
|
||||
"@tauri-apps/api": "2.0.0-rc.4",
|
||||
"@tauri-apps/api": "2.0.0-rc.5",
|
||||
"@types/d3": "7.4.3",
|
||||
"@types/react": "18.3.5",
|
||||
"@vitejs/plugin-react": "4.3.1",
|
||||
@@ -34,7 +34,7 @@
|
||||
"react-error-boundary": "4.0.13",
|
||||
"react-i18next": "15.0.2",
|
||||
"react-use": "17.5.1",
|
||||
"vite": "5.4.5",
|
||||
"vite": "5.4.6",
|
||||
"vite-tsconfig-paths": "5.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@@ -59,7 +59,7 @@
|
||||
"@commitlint/cli": "19.4.1",
|
||||
"@commitlint/config-conventional": "19.4.1",
|
||||
"@ianvs/prettier-plugin-sort-imports": "4.3.1",
|
||||
"@tauri-apps/cli": "2.0.0-rc.15",
|
||||
"@tauri-apps/cli": "2.0.0-rc.16",
|
||||
"@types/fs-extra": "11.0.4",
|
||||
"@types/lodash-es": "4.17.12",
|
||||
"@types/node": "22.5.4",
|
||||
|
768
clash-nyanpasu/pnpm-lock.yaml
generated
768
clash-nyanpasu/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -30,7 +30,7 @@ For an explanation of the mieru protocol, see [mieru Proxy Protocol](./docs/prot
|
||||
1. The server software supports socks5 outbound (proxy chain).
|
||||
1. The client software supports Windows, Mac OS, Linux and Android. Android clients include
|
||||
- [NekoBox](https://github.com/MatsuriDayo/NekoBoxForAndroid) version 1.3.1 or above, with [mieru plugin](https://github.com/enfein/NekoBoxPlugins).
|
||||
- [Exclave](https://github.com/dyhkwong/Exclave), with mieru plugin.
|
||||
- [Exclave](https://github.com/dyhkwong/Exclave), with [mieru plugin](https://github.com/dyhkwong/Exclave/releases?q=mieru-plugin).
|
||||
1. If you need advanced features like global proxy or customized routing rules, you can use mieru as the backend of a proxy platform such as [Xray](https://github.com/XTLS/Xray-core) and [sing-box](https://github.com/SagerNet/sing-box).
|
||||
|
||||
## User Guide
|
||||
|
@@ -28,7 +28,7 @@ mieru 的翻墙原理与 shadowsocks / v2ray 等软件类似,在客户端和
|
||||
1. 服务器软件支持 socks5 出站(链式代理)。
|
||||
1. 客户端软件支持 Windows, Mac OS, Linux 和 Android 系统。Android 客户端包括
|
||||
- [NekoBox](https://github.com/MatsuriDayo/NekoBoxForAndroid) 1.3.1 及以上版本,并安装 [mieru 插件](https://github.com/enfein/NekoBoxPlugins)。
|
||||
- [Exclave](https://github.com/dyhkwong/Exclave) 并安装 mieru 插件。
|
||||
- [Exclave](https://github.com/dyhkwong/Exclave) 并安装 [mieru 插件](https://github.com/dyhkwong/Exclave/releases?q=mieru-plugin)。
|
||||
1. 如果需要全局代理或自定义路由规则等高级功能,可以将 mieru 作为 [Xray](https://github.com/XTLS/Xray-core) 和 [sing-box](https://github.com/SagerNet/sing-box) 等代理平台的后端。
|
||||
|
||||
## 使用教程
|
||||
|
@@ -30,7 +30,7 @@ import (
|
||||
pb "github.com/enfein/mieru/pkg/appctl/appctlpb"
|
||||
"github.com/enfein/mieru/pkg/log"
|
||||
"github.com/enfein/mieru/pkg/metrics"
|
||||
"github.com/enfein/mieru/pkg/protocolv2"
|
||||
"github.com/enfein/mieru/pkg/protocol"
|
||||
"github.com/enfein/mieru/pkg/socks5"
|
||||
"github.com/enfein/mieru/pkg/stderror"
|
||||
"github.com/enfein/mieru/pkg/util"
|
||||
@@ -67,7 +67,7 @@ var (
|
||||
clientSocks5ServerRef atomic.Pointer[socks5.Server]
|
||||
|
||||
// clientMuxRef holds a pointer to client multiplexier.
|
||||
clientMuxRef atomic.Pointer[protocolv2.Mux]
|
||||
clientMuxRef atomic.Pointer[protocol.Mux]
|
||||
)
|
||||
|
||||
func SetClientRPCServerRef(server *grpc.Server) {
|
||||
@@ -78,7 +78,7 @@ func SetClientSocks5ServerRef(server *socks5.Server) {
|
||||
clientSocks5ServerRef.Store(server)
|
||||
}
|
||||
|
||||
func SetClientMuxRef(mux *protocolv2.Mux) {
|
||||
func SetClientMuxRef(mux *protocol.Mux) {
|
||||
clientMuxRef.Store(mux)
|
||||
}
|
||||
|
||||
|
@@ -31,7 +31,7 @@ import (
|
||||
"github.com/enfein/mieru/pkg/egress"
|
||||
"github.com/enfein/mieru/pkg/log"
|
||||
"github.com/enfein/mieru/pkg/metrics"
|
||||
"github.com/enfein/mieru/pkg/protocolv2"
|
||||
"github.com/enfein/mieru/pkg/protocol"
|
||||
"github.com/enfein/mieru/pkg/socks5"
|
||||
"github.com/enfein/mieru/pkg/stderror"
|
||||
"github.com/enfein/mieru/pkg/util"
|
||||
@@ -57,7 +57,7 @@ var (
|
||||
socks5ServerRef atomic.Pointer[socks5.Server]
|
||||
|
||||
// serverMuxRef holds a pointer to server multiplexier.
|
||||
serverMuxRef atomic.Pointer[protocolv2.Mux]
|
||||
serverMuxRef atomic.Pointer[protocol.Mux]
|
||||
)
|
||||
|
||||
func SetServerRPCServerRef(server *grpc.Server) {
|
||||
@@ -68,7 +68,7 @@ func SetSocks5Server(server *socks5.Server) {
|
||||
socks5ServerRef.Store(server)
|
||||
}
|
||||
|
||||
func SetServerMuxRef(mux *protocolv2.Mux) {
|
||||
func SetServerMuxRef(mux *protocol.Mux) {
|
||||
serverMuxRef.Store(mux)
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ func (s *serverLifecycleService) Start(ctx context.Context, req *pb.Empty) (*pb.
|
||||
|
||||
SetAppStatus(pb.AppStatus_STARTING)
|
||||
|
||||
mux := protocolv2.NewMux(false).SetServerUsers(UserListToMap(config.GetUsers()))
|
||||
mux := protocol.NewMux(false).SetServerUsers(UserListToMap(config.GetUsers()))
|
||||
SetServerMuxRef(mux)
|
||||
mtu := util.DefaultMTU
|
||||
if config.GetMtu() != 0 {
|
||||
@@ -653,8 +653,8 @@ func ValidateFullServerConfig(config *pb.ServerConfig) error {
|
||||
}
|
||||
|
||||
// PortBindingsToUnderlayProperties converts port bindings to underlay properties.
|
||||
func PortBindingsToUnderlayProperties(portBindings []*pb.PortBinding, mtu int) ([]protocolv2.UnderlayProperties, error) {
|
||||
endpoints := make([]protocolv2.UnderlayProperties, 0)
|
||||
func PortBindingsToUnderlayProperties(portBindings []*pb.PortBinding, mtu int) ([]protocol.UnderlayProperties, error) {
|
||||
endpoints := make([]protocol.UnderlayProperties, 0)
|
||||
listenIP := net.ParseIP(util.AllIPAddr())
|
||||
ipVersion := util.GetIPVersion(listenIP.String())
|
||||
if listenIP == nil {
|
||||
@@ -666,17 +666,17 @@ func PortBindingsToUnderlayProperties(portBindings []*pb.PortBinding, mtu int) (
|
||||
}
|
||||
n := len(portBindings)
|
||||
for i := 0; i < n; i++ {
|
||||
protocol := portBindings[i].GetProtocol()
|
||||
proto := portBindings[i].GetProtocol()
|
||||
port := portBindings[i].GetPort()
|
||||
switch protocol {
|
||||
switch proto {
|
||||
case pb.TransportProtocol_TCP:
|
||||
endpoint := protocolv2.NewUnderlayProperties(mtu, ipVersion, util.TCPTransport, &net.TCPAddr{IP: listenIP, Port: int(port)}, nil)
|
||||
endpoint := protocol.NewUnderlayProperties(mtu, ipVersion, util.TCPTransport, &net.TCPAddr{IP: listenIP, Port: int(port)}, nil)
|
||||
endpoints = append(endpoints, endpoint)
|
||||
case pb.TransportProtocol_UDP:
|
||||
endpoint := protocolv2.NewUnderlayProperties(mtu, ipVersion, util.UDPTransport, &net.UDPAddr{IP: listenIP, Port: int(port)}, nil)
|
||||
endpoint := protocol.NewUnderlayProperties(mtu, ipVersion, util.UDPTransport, &net.UDPAddr{IP: listenIP, Port: int(port)}, nil)
|
||||
endpoints = append(endpoints, endpoint)
|
||||
default:
|
||||
return []protocolv2.UnderlayProperties{}, fmt.Errorf(stderror.InvalidTransportProtocol)
|
||||
return []protocol.UnderlayProperties{}, fmt.Errorf(stderror.InvalidTransportProtocol)
|
||||
}
|
||||
}
|
||||
return endpoints, nil
|
||||
|
@@ -37,7 +37,7 @@ import (
|
||||
"github.com/enfein/mieru/pkg/http2socks"
|
||||
"github.com/enfein/mieru/pkg/log"
|
||||
"github.com/enfein/mieru/pkg/metrics"
|
||||
"github.com/enfein/mieru/pkg/protocolv2"
|
||||
"github.com/enfein/mieru/pkg/protocol"
|
||||
"github.com/enfein/mieru/pkg/socks5"
|
||||
"github.com/enfein/mieru/pkg/socks5client"
|
||||
"github.com/enfein/mieru/pkg/stderror"
|
||||
@@ -459,7 +459,7 @@ var clientRunFunc = func(s []string) error {
|
||||
}
|
||||
|
||||
// Collect remote proxy addresses and password.
|
||||
mux := protocolv2.NewMux(true)
|
||||
mux := protocol.NewMux(true)
|
||||
appctl.SetClientMuxRef(mux)
|
||||
var hashedPassword []byte
|
||||
activeProfile, err := appctl.GetActiveProfileFromConfig(config, config.GetActiveProfile())
|
||||
@@ -492,7 +492,7 @@ var clientRunFunc = func(s []string) error {
|
||||
multiplexFactor = 3
|
||||
}
|
||||
mux = mux.SetClientMultiplexFactor(multiplexFactor)
|
||||
endpoints := make([]protocolv2.UnderlayProperties, 0)
|
||||
endpoints := make([]protocol.UnderlayProperties, 0)
|
||||
resolver := &util.DNSResolver{}
|
||||
for _, serverInfo := range activeProfile.GetServers() {
|
||||
var proxyHost string
|
||||
@@ -519,10 +519,10 @@ var clientRunFunc = func(s []string) error {
|
||||
proxyPort := bindingInfo.GetPort()
|
||||
switch bindingInfo.GetProtocol() {
|
||||
case appctlpb.TransportProtocol_TCP:
|
||||
endpoint := protocolv2.NewUnderlayProperties(mtu, ipVersion, util.TCPTransport, nil, &net.TCPAddr{IP: proxyIP, Port: int(proxyPort)})
|
||||
endpoint := protocol.NewUnderlayProperties(mtu, ipVersion, util.TCPTransport, nil, &net.TCPAddr{IP: proxyIP, Port: int(proxyPort)})
|
||||
endpoints = append(endpoints, endpoint)
|
||||
case appctlpb.TransportProtocol_UDP:
|
||||
endpoint := protocolv2.NewUnderlayProperties(mtu, ipVersion, util.UDPTransport, nil, &net.UDPAddr{IP: proxyIP, Port: int(proxyPort)})
|
||||
endpoint := protocol.NewUnderlayProperties(mtu, ipVersion, util.UDPTransport, nil, &net.UDPAddr{IP: proxyIP, Port: int(proxyPort)})
|
||||
endpoints = append(endpoints, endpoint)
|
||||
default:
|
||||
return fmt.Errorf(stderror.InvalidTransportProtocol)
|
||||
|
@@ -35,7 +35,7 @@ import (
|
||||
"github.com/enfein/mieru/pkg/http2socks"
|
||||
"github.com/enfein/mieru/pkg/log"
|
||||
"github.com/enfein/mieru/pkg/metrics"
|
||||
"github.com/enfein/mieru/pkg/protocolv2"
|
||||
"github.com/enfein/mieru/pkg/protocol"
|
||||
"github.com/enfein/mieru/pkg/socks5"
|
||||
"github.com/enfein/mieru/pkg/stderror"
|
||||
"github.com/enfein/mieru/pkg/util"
|
||||
@@ -404,7 +404,7 @@ var serverRunFunc = func(s []string) error {
|
||||
if err = appctl.ValidateFullServerConfig(config); err == nil {
|
||||
appctl.SetAppStatus(appctlpb.AppStatus_STARTING)
|
||||
|
||||
mux := protocolv2.NewMux(false).SetServerUsers(appctl.UserListToMap(config.GetUsers()))
|
||||
mux := protocol.NewMux(false).SetServerUsers(appctl.UserListToMap(config.GetUsers()))
|
||||
appctl.SetServerMuxRef(mux)
|
||||
mtu := util.DefaultMTU
|
||||
if config.GetMtu() != 0 {
|
||||
|
@@ -53,9 +53,6 @@ const (
|
||||
// Allow 1 extra outstanding byte for each byte acknowledged.
|
||||
stateConservation
|
||||
|
||||
// Allow 1.5 extra outstanding bytes for each byte acknowledged.
|
||||
stateMediumGrowth
|
||||
|
||||
// Allow 2 extra outstanding bytes for each byte acknowledged (slow start).
|
||||
stateGrowth
|
||||
)
|
||||
@@ -279,6 +276,7 @@ type BBRSender struct {
|
||||
minRTTSinceLastProbeRTT time.Duration
|
||||
}
|
||||
|
||||
// NewBBRSender constructs a new BBR sender object.
|
||||
func NewBBRSender(loggingContext string, rttStats *RTTStats) *BBRSender {
|
||||
s := &BBRSender{
|
||||
loggingContext: loggingContext,
|
||||
@@ -309,6 +307,7 @@ func NewBBRSender(loggingContext string, rttStats *RTTStats) *BBRSender {
|
||||
return s
|
||||
}
|
||||
|
||||
// OnPacketSent updates BBR sender state when a packet is being sent.
|
||||
func (b *BBRSender) OnPacketSent(sentTime time.Time, bytesInFlight int64, packetNumber int64, bytes int64, hasRetransmittableData bool) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
@@ -325,50 +324,13 @@ func (b *BBRSender) OnPacketSent(sentTime time.Time, bytesInFlight int64, packet
|
||||
}
|
||||
|
||||
b.sampler.OnPacketSent(sentTime, packetNumber, bytes, bytesInFlight, hasRetransmittableData)
|
||||
b.pacer.OnPacketSent(sentTime, bytes, b.PacingRate(bytesInFlight))
|
||||
b.pacer.OnPacketSent(sentTime, bytes, b.getPacingRate())
|
||||
if log.IsLevelEnabled(log.TraceLevel) {
|
||||
log.Tracef("[BBRSender %s] OnPacketSent(bytesInFlight=%d, packetNumber=%d, bytes=%d), pacingRate=%d => pacingBudget=%d", b.loggingContext, bytesInFlight, packetNumber, bytes, b.PacingRate(bytesInFlight), b.pacer.Budget(sentTime, b.PacingRate(bytesInFlight)))
|
||||
log.Tracef("[BBRSender %s] OnPacketSent(bytesInFlight=%d, packetNumber=%d, bytes=%d), pacingRate=%d => pacingBudget=%d", b.loggingContext, bytesInFlight, packetNumber, bytes, b.getPacingRate(), b.pacer.Budget(sentTime, b.getPacingRate()))
|
||||
}
|
||||
}
|
||||
|
||||
func (b *BBRSender) CanSend(bytesInFlight, bytes int64) bool {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
pacerCanSend := b.pacer.CanSend(time.Now(), bytes, b.PacingRate(bytesInFlight))
|
||||
return bytesInFlight < b.GetCongestionWindow() && pacerCanSend
|
||||
}
|
||||
|
||||
func (b *BBRSender) PacingRate(bytesInFlight int64) int64 {
|
||||
if b.pacingRate <= 0 {
|
||||
return int64(highGain * float64(BandwidthFromBytesAndTimeDelta(b.initialCongestionWindow, b.GetMinRTT())))
|
||||
}
|
||||
return b.pacingRate
|
||||
}
|
||||
|
||||
func (b *BBRSender) BandwidthEstimate() int64 {
|
||||
return b.maxBandwidth.GetBest()
|
||||
}
|
||||
|
||||
func (b *BBRSender) GetCongestionWindow() int64 {
|
||||
if b.mode == modeProbeRTT {
|
||||
return b.ProbeRTTCongestionWindow()
|
||||
}
|
||||
|
||||
if b.InRecovery() && !b.rateBasedRecovery && !(b.mode == modeStartUp && b.rateBasedStartup) {
|
||||
return mathext.Min(b.congestionWindow, b.recoveryWindow)
|
||||
}
|
||||
|
||||
return b.congestionWindow
|
||||
}
|
||||
|
||||
func (b *BBRSender) InRecovery() bool {
|
||||
return b.recoveryState != stateNotInRecovery
|
||||
}
|
||||
|
||||
func (b *BBRSender) IsProbingForMoreBandwidth() bool {
|
||||
return (b.mode == modeProbeBW && b.pacingGain > 1) || b.mode == modeStartUp
|
||||
}
|
||||
|
||||
// OnCongestionEvent updates BBR sender state from acknowledged and lost packets.
|
||||
func (b *BBRSender) OnCongestionEvent(priorInFlight int64, eventTime time.Time, ackedPackets []AckedPacketInfo, lostPackets []LostPacketInfo) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
@@ -386,20 +348,20 @@ func (b *BBRSender) OnCongestionEvent(priorInFlight int64, eventTime time.Time,
|
||||
}
|
||||
b.bytesInFlight = mathext.Max(b.bytesInFlight, 0)
|
||||
|
||||
b.DiscardLostPackets(lostPackets)
|
||||
b.discardLostPackets(lostPackets)
|
||||
|
||||
// Input the new data into the BBR model of the connection.
|
||||
if len(ackedPackets) > 0 {
|
||||
lastAckedPacket := ackedPackets[len(ackedPackets)-1].PacketNumber
|
||||
isRoundStart = b.UpdateRoundTripCounter(lastAckedPacket)
|
||||
isMinRTTExpired = b.UpdateBandwidthAndMinRTT(eventTime, ackedPackets)
|
||||
b.UpdateRecoveryState(lastAckedPacket, len(lostPackets) > 0, isRoundStart)
|
||||
isRoundStart = b.updateRoundTripCounter(lastAckedPacket)
|
||||
isMinRTTExpired = b.updateBandwidthAndMinRTT(eventTime, ackedPackets)
|
||||
b.updateRecoveryState(lastAckedPacket, len(lostPackets) > 0, isRoundStart)
|
||||
|
||||
bytesAcked := b.sampler.TotalBytesAcked() - totalBytesAckedBefore
|
||||
|
||||
b.UpdateAckAggregationBytes(eventTime, bytesAcked)
|
||||
b.updateAckAggregationBytes(eventTime, bytesAcked)
|
||||
if b.maxAggregationBytesMultiplier > 0 {
|
||||
if b.bytesInFlight <= int64(1.25*float64(b.GetTargetCongestionWindow(b.pacingGain))) {
|
||||
if b.bytesInFlight <= int64(1.25*float64(b.getTargetCongestionWindow(b.pacingGain))) {
|
||||
b.bytesAckedSinceQueueDrained = 0
|
||||
} else {
|
||||
b.bytesAckedSinceQueueDrained += bytesAcked
|
||||
@@ -409,17 +371,17 @@ func (b *BBRSender) OnCongestionEvent(priorInFlight int64, eventTime time.Time,
|
||||
|
||||
// Handle logic specific to PROBE BW mode.
|
||||
if b.mode == modeProbeBW {
|
||||
b.UpdateGainCyclePhase(eventTime, priorInFlight, len(lostPackets) > 0)
|
||||
b.updateGainCyclePhase(eventTime, priorInFlight, len(lostPackets) > 0)
|
||||
}
|
||||
|
||||
// Handle logic specific to STARTUP and DRAIN modes.
|
||||
if isRoundStart && !b.isAtFullBandwidth {
|
||||
b.CheckIfFullBandwidthReached()
|
||||
b.checkIfFullBandwidthReached()
|
||||
}
|
||||
b.MaybeExitStartupOrDrain(eventTime)
|
||||
b.maybeExitStartupOrDrain(eventTime)
|
||||
|
||||
// Handle logic specific to PROBE RTT.
|
||||
b.MaybeEnterOrExitProbeRTT(eventTime, isRoundStart, isMinRTTExpired)
|
||||
b.maybeEnterOrExitProbeRTT(eventTime, isRoundStart, isMinRTTExpired)
|
||||
|
||||
// Calculate number of packets acked and lost.
|
||||
bytesAcked := b.sampler.TotalBytesAcked() - totalBytesAckedBefore
|
||||
@@ -430,9 +392,9 @@ func (b *BBRSender) OnCongestionEvent(priorInFlight int64, eventTime time.Time,
|
||||
|
||||
// After the model is updated, recalculate the pacing rate and congestion
|
||||
// window.
|
||||
b.CalculatePacingRate()
|
||||
b.CalculateCongestionWindow(bytesAcked)
|
||||
b.CalculateRecoveryWindow(bytesAcked, bytesLost)
|
||||
b.calculatePacingRate()
|
||||
b.calculateCongestionWindow(bytesAcked)
|
||||
b.calculateRecoveryWindow(bytesAcked, bytesLost)
|
||||
|
||||
// Cleanup internal state.
|
||||
// This is where we clean up obsolete (acked or lost) packets from the bandwidth sampler.
|
||||
@@ -448,15 +410,62 @@ func (b *BBRSender) OnCongestionEvent(priorInFlight int64, eventTime time.Time,
|
||||
b.sampler.RemoveObsoletePackets(leastUnacked)
|
||||
}
|
||||
|
||||
func (b *BBRSender) GetMinRTT() time.Duration {
|
||||
// OnApplicationLimited updates BBR sender state when there is no application
|
||||
// data to send.
|
||||
func (b *BBRSender) OnApplicationLimited(bytesInFlight int64) {
|
||||
if bytesInFlight >= b.getCongestionWindow() {
|
||||
return
|
||||
}
|
||||
|
||||
b.appLimitedSinceLastProbeRTT = true
|
||||
b.sampler.OnAppLimited()
|
||||
}
|
||||
|
||||
// CanSend returns true if a packet can be sent based on the congestion window.
|
||||
func (b *BBRSender) CanSend(bytesInFlight, bytes int64) bool {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
pacerCanSend := b.pacer.CanSend(time.Now(), bytes, b.getPacingRate())
|
||||
return bytesInFlight < b.getCongestionWindow() && pacerCanSend
|
||||
}
|
||||
|
||||
// BandwidthEstimate returns the estimate of maximum bandwidth.
|
||||
func (b *BBRSender) BandwidthEstimate() int64 {
|
||||
return b.maxBandwidth.GetBest()
|
||||
}
|
||||
|
||||
func (b *BBRSender) getPacingRate() int64 {
|
||||
if b.pacingRate <= 0 {
|
||||
return int64(highGain * float64(BandwidthFromBytesAndTimeDelta(b.initialCongestionWindow, b.getMinRTT())))
|
||||
}
|
||||
return b.pacingRate
|
||||
}
|
||||
|
||||
func (b *BBRSender) getCongestionWindow() int64 {
|
||||
if b.mode == modeProbeRTT {
|
||||
return b.probeRTTCongestionWindow()
|
||||
}
|
||||
|
||||
if b.inRecovery() && !b.rateBasedRecovery && !(b.mode == modeStartUp && b.rateBasedStartup) {
|
||||
return mathext.Min(b.congestionWindow, b.recoveryWindow)
|
||||
}
|
||||
|
||||
return b.congestionWindow
|
||||
}
|
||||
|
||||
func (b *BBRSender) inRecovery() bool {
|
||||
return b.recoveryState != stateNotInRecovery
|
||||
}
|
||||
|
||||
func (b *BBRSender) getMinRTT() time.Duration {
|
||||
if b.minRTT > 0 {
|
||||
return b.minRTT
|
||||
}
|
||||
return defaultInitialRTT
|
||||
}
|
||||
|
||||
func (b *BBRSender) GetTargetCongestionWindow(gain float64) int64 {
|
||||
bdp := (b.GetMinRTT().Nanoseconds() * b.BandwidthEstimate()) / int64(time.Second)
|
||||
func (b *BBRSender) getTargetCongestionWindow(gain float64) int64 {
|
||||
bdp := (b.getMinRTT().Nanoseconds() * b.BandwidthEstimate()) / int64(time.Second)
|
||||
congestionWindow := int64(gain * float64(bdp))
|
||||
|
||||
// BDP estimate will be zero if no bandwidth samples are available yet.
|
||||
@@ -467,11 +476,11 @@ func (b *BBRSender) GetTargetCongestionWindow(gain float64) int64 {
|
||||
return mathext.Max(congestionWindow, b.minCongestionWindow)
|
||||
}
|
||||
|
||||
func (b *BBRSender) ProbeRTTCongestionWindow() int64 {
|
||||
func (b *BBRSender) probeRTTCongestionWindow() int64 {
|
||||
return b.minCongestionWindow
|
||||
}
|
||||
|
||||
func (b *BBRSender) EnterStartupMode() {
|
||||
func (b *BBRSender) enterStartupMode() {
|
||||
b.mode = modeStartUp
|
||||
if log.IsLevelEnabled(log.TraceLevel) {
|
||||
log.Tracef("[BBRSender %s] Enter start up mode", b.loggingContext)
|
||||
@@ -480,7 +489,7 @@ func (b *BBRSender) EnterStartupMode() {
|
||||
b.congestionWindowGain = highGain
|
||||
}
|
||||
|
||||
func (b *BBRSender) EnterProbeBandwidthMode(now time.Time) {
|
||||
func (b *BBRSender) enterProbeBandwidthMode(now time.Time) {
|
||||
b.mode = modeProbeBW
|
||||
if log.IsLevelEnabled(log.TraceLevel) {
|
||||
log.Tracef("[BBRSender %s] Enter probe bandwidth mode", b.loggingContext)
|
||||
@@ -498,13 +507,13 @@ func (b *BBRSender) EnterProbeBandwidthMode(now time.Time) {
|
||||
b.pacingGain = pacingGainList[cycleOffset]
|
||||
}
|
||||
|
||||
func (b *BBRSender) DiscardLostPackets(lostPackets []LostPacketInfo) {
|
||||
func (b *BBRSender) discardLostPackets(lostPackets []LostPacketInfo) {
|
||||
for _, lost := range lostPackets {
|
||||
b.sampler.OnPacketLost(lost.PacketNumber)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *BBRSender) UpdateRoundTripCounter(lastAckedPacket int64) bool {
|
||||
func (b *BBRSender) updateRoundTripCounter(lastAckedPacket int64) bool {
|
||||
if lastAckedPacket > b.currentRoundTripEnd {
|
||||
b.roundTripCount++
|
||||
b.currentRoundTripEnd = lastAckedPacket
|
||||
@@ -513,7 +522,7 @@ func (b *BBRSender) UpdateRoundTripCounter(lastAckedPacket int64) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (b *BBRSender) UpdateBandwidthAndMinRTT(now time.Time, ackedPackets []AckedPacketInfo) bool {
|
||||
func (b *BBRSender) updateBandwidthAndMinRTT(now time.Time, ackedPackets []AckedPacketInfo) bool {
|
||||
sampleMinRTT := infDuration
|
||||
for _, acked := range ackedPackets {
|
||||
bandwidthSample := b.sampler.OnPacketAcknowledged(now, acked.PacketNumber)
|
||||
@@ -545,16 +554,16 @@ func (b *BBRSender) UpdateBandwidthAndMinRTT(now time.Time, ackedPackets []Acked
|
||||
return minRTTExpired
|
||||
}
|
||||
|
||||
func (b *BBRSender) UpdateGainCyclePhase(now time.Time, priorInFlight int64, hasLosses bool) {
|
||||
func (b *BBRSender) updateGainCyclePhase(now time.Time, priorInFlight int64, hasLosses bool) {
|
||||
// In most cases, the cycle is advanced after an RTT passes.
|
||||
shouldAdvanceGainCycling := now.Sub(b.lastCycleStart) > b.GetMinRTT()
|
||||
shouldAdvanceGainCycling := now.Sub(b.lastCycleStart) > b.getMinRTT()
|
||||
|
||||
// If the pacing gain is above 1.0, the connection is trying to probe the
|
||||
// bandwidth by increasing the number of bytes in flight to at least
|
||||
// pacing gain * BDP. Make sure that it actually reaches the target, as long
|
||||
// as there are no losses suggesting that the buffers are not able to hold
|
||||
// that much.
|
||||
if b.pacingGain > 1.0 && !hasLosses && priorInFlight < b.GetTargetCongestionWindow(b.pacingGain) {
|
||||
if b.pacingGain > 1.0 && !hasLosses && priorInFlight < b.getTargetCongestionWindow(b.pacingGain) {
|
||||
shouldAdvanceGainCycling = false
|
||||
}
|
||||
|
||||
@@ -562,7 +571,7 @@ func (b *BBRSender) UpdateGainCyclePhase(now time.Time, priorInFlight int64, has
|
||||
// queue which could have been incurred by probing prior to it. If the number
|
||||
// of bytes in flight falls down to the estimated BDP value earlier, conclude
|
||||
// that the queue has been successfully drained and exit this cycle early.
|
||||
if b.pacingGain < 1.0 && priorInFlight <= b.GetTargetCongestionWindow(1.0) {
|
||||
if b.pacingGain < 1.0 && priorInFlight <= b.getTargetCongestionWindow(1.0) {
|
||||
shouldAdvanceGainCycling = true
|
||||
}
|
||||
|
||||
@@ -573,7 +582,7 @@ func (b *BBRSender) UpdateGainCyclePhase(now time.Time, priorInFlight int64, has
|
||||
}
|
||||
}
|
||||
|
||||
func (b *BBRSender) CheckIfFullBandwidthReached() {
|
||||
func (b *BBRSender) checkIfFullBandwidthReached() {
|
||||
if b.lastSampleIsAppLimited {
|
||||
return
|
||||
}
|
||||
@@ -586,12 +595,12 @@ func (b *BBRSender) CheckIfFullBandwidthReached() {
|
||||
}
|
||||
|
||||
b.roundsWithoutBandwidthGain++
|
||||
if b.roundsWithoutBandwidthGain >= b.numStartupRTTs || (b.exitStartupOnLoss && b.InRecovery()) {
|
||||
if b.roundsWithoutBandwidthGain >= b.numStartupRTTs || (b.exitStartupOnLoss && b.inRecovery()) {
|
||||
b.isAtFullBandwidth = true
|
||||
}
|
||||
}
|
||||
|
||||
func (b *BBRSender) MaybeExitStartupOrDrain(now time.Time) {
|
||||
func (b *BBRSender) maybeExitStartupOrDrain(now time.Time) {
|
||||
if b.mode == modeStartUp && b.isAtFullBandwidth {
|
||||
b.mode = modeDrain
|
||||
if log.IsLevelEnabled(log.TraceLevel) {
|
||||
@@ -601,12 +610,12 @@ func (b *BBRSender) MaybeExitStartupOrDrain(now time.Time) {
|
||||
b.congestionWindowGain = highGain
|
||||
}
|
||||
|
||||
if b.mode == modeDrain && b.bytesInFlight <= b.GetTargetCongestionWindow(1) {
|
||||
b.EnterProbeBandwidthMode(now)
|
||||
if b.mode == modeDrain && b.bytesInFlight <= b.getTargetCongestionWindow(1) {
|
||||
b.enterProbeBandwidthMode(now)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *BBRSender) MaybeEnterOrExitProbeRTT(now time.Time, isRoundStart bool, minRTTExpired bool) {
|
||||
func (b *BBRSender) maybeEnterOrExitProbeRTT(now time.Time, isRoundStart bool, minRTTExpired bool) {
|
||||
if minRTTExpired && !b.exitingQuiescence && b.mode != modeProbeRTT {
|
||||
b.mode = modeProbeRTT
|
||||
if log.IsLevelEnabled(log.TraceLevel) {
|
||||
@@ -623,7 +632,7 @@ func (b *BBRSender) MaybeEnterOrExitProbeRTT(now time.Time, isRoundStart bool, m
|
||||
if b.exitProbeRTTAt.IsZero() {
|
||||
// If the window has reached the appropriate size, schedule exiting
|
||||
// PROBE RTT.
|
||||
if b.bytesInFlight < b.ProbeRTTCongestionWindow()+maxDatagramSize {
|
||||
if b.bytesInFlight < b.probeRTTCongestionWindow()+maxDatagramSize {
|
||||
b.exitProbeRTTAt = now.Add(probeRTTTime)
|
||||
b.probeRTTRoundPassed = false
|
||||
}
|
||||
@@ -634,9 +643,9 @@ func (b *BBRSender) MaybeEnterOrExitProbeRTT(now time.Time, isRoundStart bool, m
|
||||
if now.After(b.exitProbeRTTAt) && b.probeRTTRoundPassed {
|
||||
b.minRTTTimestamp = now
|
||||
if !b.isAtFullBandwidth {
|
||||
b.EnterStartupMode()
|
||||
b.enterStartupMode()
|
||||
} else {
|
||||
b.EnterProbeBandwidthMode(now)
|
||||
b.enterProbeBandwidthMode(now)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -645,7 +654,7 @@ func (b *BBRSender) MaybeEnterOrExitProbeRTT(now time.Time, isRoundStart bool, m
|
||||
b.exitingQuiescence = false
|
||||
}
|
||||
|
||||
func (b *BBRSender) UpdateRecoveryState(lastAckedPacket int64, hasLosses bool, isRoundStart bool) {
|
||||
func (b *BBRSender) updateRecoveryState(lastAckedPacket int64, hasLosses bool, isRoundStart bool) {
|
||||
// Exit recovery when there are no losses for a round.
|
||||
if hasLosses {
|
||||
b.endRecoveryAt = b.lastSentPacket
|
||||
@@ -667,8 +676,6 @@ func (b *BBRSender) UpdateRecoveryState(lastAckedPacket int64, hasLosses bool, i
|
||||
b.currentRoundTripEnd = b.lastSentPacket
|
||||
}
|
||||
case stateConservation:
|
||||
fallthrough
|
||||
case stateMediumGrowth:
|
||||
if isRoundStart {
|
||||
b.recoveryState = stateGrowth
|
||||
}
|
||||
@@ -681,7 +688,7 @@ func (b *BBRSender) UpdateRecoveryState(lastAckedPacket int64, hasLosses bool, i
|
||||
}
|
||||
}
|
||||
|
||||
func (b *BBRSender) UpdateAckAggregationBytes(ackTime time.Time, newlyAckedBytes int64) {
|
||||
func (b *BBRSender) updateAckAggregationBytes(ackTime time.Time, newlyAckedBytes int64) {
|
||||
// Compute how many bytes are expected to be delivered, assuming max bandwidth
|
||||
// is correct.
|
||||
expectedBytesAcked := b.maxBandwidth.GetBest() * int64(ackTime.Sub(b.aggregationEpochStartTime)) / int64(time.Second)
|
||||
@@ -700,13 +707,13 @@ func (b *BBRSender) UpdateAckAggregationBytes(ackTime time.Time, newlyAckedBytes
|
||||
b.maxAckHeight.Update(b.aggregationEpochBytes-expectedBytesAcked, b.roundTripCount)
|
||||
}
|
||||
|
||||
func (b *BBRSender) CalculatePacingRate() {
|
||||
func (b *BBRSender) calculatePacingRate() {
|
||||
if b.BandwidthEstimate() <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
targetRate := int64(b.pacingGain * float64(b.BandwidthEstimate()))
|
||||
if b.rateBasedRecovery && b.InRecovery() {
|
||||
if b.rateBasedRecovery && b.inRecovery() {
|
||||
b.pacingRate = int64(b.pacingGain * float64(b.maxBandwidth.GetThirdBest()))
|
||||
}
|
||||
if b.isAtFullBandwidth {
|
||||
@@ -731,12 +738,12 @@ func (b *BBRSender) CalculatePacingRate() {
|
||||
b.pacingRate = mathext.Max(b.pacingRate, targetRate)
|
||||
}
|
||||
|
||||
func (b *BBRSender) CalculateCongestionWindow(bytesAcked int64) {
|
||||
func (b *BBRSender) calculateCongestionWindow(bytesAcked int64) {
|
||||
if b.mode == modeProbeRTT {
|
||||
return
|
||||
}
|
||||
|
||||
targetWindow := b.GetTargetCongestionWindow(b.congestionWindowGain)
|
||||
targetWindow := b.getTargetCongestionWindow(b.congestionWindowGain)
|
||||
if log.IsLevelEnabled(log.TraceLevel) {
|
||||
log.Tracef("[BBRSender %s] targetCongestionWindow=%d", b.loggingContext, targetWindow)
|
||||
}
|
||||
@@ -756,7 +763,7 @@ func (b *BBRSender) CalculateCongestionWindow(bytesAcked int64) {
|
||||
b.congestionWindow = mathext.Min(b.congestionWindow, b.maxCongestionWindow)
|
||||
}
|
||||
|
||||
func (b *BBRSender) CalculateRecoveryWindow(bytesAcked int64, bytesLost int64) {
|
||||
func (b *BBRSender) calculateRecoveryWindow(bytesAcked int64, bytesLost int64) {
|
||||
if b.rateBasedRecovery || (b.mode == modeStartUp && b.rateBasedStartup) {
|
||||
return
|
||||
}
|
||||
@@ -781,11 +788,8 @@ func (b *BBRSender) CalculateRecoveryWindow(bytesAcked int64, bytesLost int64) {
|
||||
|
||||
// In CONSERVATION mode, just subtracting losses is sufficient. In GROWTH,
|
||||
// release additional bytesAcked to achieve a slow-start-like behavior.
|
||||
// In MEDIUM_GROWTH, release bytesAcked / 2 to split the difference.
|
||||
if b.recoveryState == stateGrowth {
|
||||
b.recoveryWindow += bytesAcked
|
||||
} else if b.recoveryState == stateMediumGrowth {
|
||||
b.recoveryWindow += bytesAcked / 2
|
||||
}
|
||||
|
||||
// Sanity checks. Ensure that we always allow to send at least
|
||||
@@ -793,12 +797,3 @@ func (b *BBRSender) CalculateRecoveryWindow(bytesAcked int64, bytesLost int64) {
|
||||
b.recoveryWindow = mathext.Max(b.recoveryWindow, b.bytesInFlight+bytesAcked)
|
||||
b.recoveryWindow = mathext.Max(b.recoveryWindow, b.minCongestionWindow)
|
||||
}
|
||||
|
||||
func (b *BBRSender) OnApplicationLimited(bytesInFlight int64) {
|
||||
if bytesInFlight >= b.GetCongestionWindow() {
|
||||
return
|
||||
}
|
||||
|
||||
b.appLimitedSinceLastProbeRTT = true
|
||||
b.sampler.OnAppLimited()
|
||||
}
|
||||
|
@@ -15,7 +15,7 @@
|
||||
|
||||
//go:build !android
|
||||
|
||||
package protocolv2
|
||||
package protocol
|
||||
|
||||
import "time"
|
||||
|
@@ -15,7 +15,7 @@
|
||||
|
||||
//go:build android
|
||||
|
||||
package protocolv2
|
||||
package protocol
|
||||
|
||||
import "time"
|
||||
|
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package protocolv2
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package protocolv2
|
||||
package protocol
|
||||
|
||||
import (
|
||||
mrand "math/rand"
|
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package protocolv2
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"context"
|
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package protocolv2
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"bytes"
|
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
|
||||
package protocolv2
|
||||
package protocol
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
|
||||
package protocolv2
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"testing"
|
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package protocolv2
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"sync"
|
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package protocolv2
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"fmt"
|
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package protocolv2
|
||||
package protocol
|
||||
|
||||
import (
|
||||
mrand "math/rand"
|
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package protocolv2
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"context"
|
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
|
||||
package protocolv2
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"context"
|
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
|
||||
package protocolv2
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"context"
|
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
|
||||
package protocolv2
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"context"
|
@@ -13,7 +13,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
|
||||
package protocolv2
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"context"
|
@@ -12,7 +12,7 @@ import (
|
||||
"github.com/enfein/mieru/pkg/egress"
|
||||
"github.com/enfein/mieru/pkg/log"
|
||||
"github.com/enfein/mieru/pkg/metrics"
|
||||
"github.com/enfein/mieru/pkg/protocolv2"
|
||||
"github.com/enfein/mieru/pkg/protocol"
|
||||
"github.com/enfein/mieru/pkg/stderror"
|
||||
"github.com/enfein/mieru/pkg/util"
|
||||
)
|
||||
@@ -40,7 +40,7 @@ var (
|
||||
// Config is used to setup and configure a socks5 server.
|
||||
type Config struct {
|
||||
// Mieru proxy multiplexer.
|
||||
ProxyMux *protocolv2.Mux
|
||||
ProxyMux *protocol.Mux
|
||||
|
||||
// Egress controller.
|
||||
EgressController egress.Controller
|
||||
|
@@ -505,17 +505,14 @@ func NewVless(option VlessOption) (*Vless, error) {
|
||||
var addons *vless.Addons
|
||||
if option.Network != "ws" && len(option.Flow) >= 16 {
|
||||
option.Flow = option.Flow[:16]
|
||||
switch option.Flow {
|
||||
case vless.XRV:
|
||||
if option.Flow != vless.XRV {
|
||||
return nil, fmt.Errorf("unsupported xtls flow type: %s", option.Flow)
|
||||
}
|
||||
|
||||
log.Warnln("To use %s, ensure your server is upgrade to Xray-core v1.8.0+", vless.XRV)
|
||||
addons = &vless.Addons{
|
||||
Flow: option.Flow,
|
||||
}
|
||||
case vless.XRO, vless.XRD, vless.XRS:
|
||||
log.Fatalln("Legacy XTLS protocol %s is deprecated and no longer supported", option.Flow)
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported xtls flow type: %s", option.Flow)
|
||||
}
|
||||
}
|
||||
|
||||
switch option.PacketEncoding {
|
||||
|
@@ -619,23 +619,27 @@ function gen_config_server(node)
|
||||
end
|
||||
|
||||
if node.protocol == "tuic" then
|
||||
if node.uuid then
|
||||
local users = {}
|
||||
for i = 1, #node.uuid do
|
||||
users[i] = {
|
||||
name = node.uuid[i],
|
||||
uuid = node.uuid[i],
|
||||
password = node.password
|
||||
}
|
||||
end
|
||||
tls.alpn = (node.tuic_alpn and node.tuic_alpn ~= "") and {
|
||||
node.tuic_alpn
|
||||
} or nil
|
||||
protocol_table = {
|
||||
users = {
|
||||
{
|
||||
name = "user1",
|
||||
uuid = node.uuid,
|
||||
password = node.password
|
||||
}
|
||||
},
|
||||
users = users,
|
||||
congestion_control = node.tuic_congestion_control or "cubic",
|
||||
zero_rtt_handshake = (node.tuic_zero_rtt_handshake == "1") and true or false,
|
||||
heartbeat = node.tuic_heartbeat .. "s",
|
||||
tls = tls
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
if node.protocol == "hysteria2" then
|
||||
protocol_table = {
|
||||
|
@@ -5,5 +5,6 @@ namespace Ryujinx.Graphics.GAL
|
||||
Bilinear,
|
||||
Nearest,
|
||||
Fsr,
|
||||
Area,
|
||||
}
|
||||
}
|
||||
|
106
ryujinx/src/Ryujinx.Graphics.OpenGL/Effects/AreaScalingFilter.cs
Normal file
106
ryujinx/src/Ryujinx.Graphics.OpenGL/Effects/AreaScalingFilter.cs
Normal file
@@ -0,0 +1,106 @@
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.OpenGL.Image;
|
||||
using System;
|
||||
using static Ryujinx.Graphics.OpenGL.Effects.ShaderHelper;
|
||||
|
||||
namespace Ryujinx.Graphics.OpenGL.Effects
|
||||
{
|
||||
internal class AreaScalingFilter : IScalingFilter
|
||||
{
|
||||
private readonly OpenGLRenderer _renderer;
|
||||
private int _inputUniform;
|
||||
private int _outputUniform;
|
||||
private int _srcX0Uniform;
|
||||
private int _srcX1Uniform;
|
||||
private int _srcY0Uniform;
|
||||
private int _scalingShaderProgram;
|
||||
private int _srcY1Uniform;
|
||||
private int _dstX0Uniform;
|
||||
private int _dstX1Uniform;
|
||||
private int _dstY0Uniform;
|
||||
private int _dstY1Uniform;
|
||||
|
||||
public float Level { get; set; }
|
||||
|
||||
public AreaScalingFilter(OpenGLRenderer renderer)
|
||||
{
|
||||
Initialize();
|
||||
|
||||
_renderer = renderer;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_scalingShaderProgram != 0)
|
||||
{
|
||||
GL.DeleteProgram(_scalingShaderProgram);
|
||||
}
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
var scalingShader = EmbeddedResources.ReadAllText("Ryujinx.Graphics.OpenGL/Effects/Shaders/area_scaling.glsl");
|
||||
|
||||
_scalingShaderProgram = CompileProgram(scalingShader, ShaderType.ComputeShader);
|
||||
|
||||
_inputUniform = GL.GetUniformLocation(_scalingShaderProgram, "Source");
|
||||
_outputUniform = GL.GetUniformLocation(_scalingShaderProgram, "imgOutput");
|
||||
|
||||
_srcX0Uniform = GL.GetUniformLocation(_scalingShaderProgram, "srcX0");
|
||||
_srcX1Uniform = GL.GetUniformLocation(_scalingShaderProgram, "srcX1");
|
||||
_srcY0Uniform = GL.GetUniformLocation(_scalingShaderProgram, "srcY0");
|
||||
_srcY1Uniform = GL.GetUniformLocation(_scalingShaderProgram, "srcY1");
|
||||
_dstX0Uniform = GL.GetUniformLocation(_scalingShaderProgram, "dstX0");
|
||||
_dstX1Uniform = GL.GetUniformLocation(_scalingShaderProgram, "dstX1");
|
||||
_dstY0Uniform = GL.GetUniformLocation(_scalingShaderProgram, "dstY0");
|
||||
_dstY1Uniform = GL.GetUniformLocation(_scalingShaderProgram, "dstY1");
|
||||
}
|
||||
|
||||
public void Run(
|
||||
TextureView view,
|
||||
TextureView destinationTexture,
|
||||
int width,
|
||||
int height,
|
||||
Extents2D source,
|
||||
Extents2D destination)
|
||||
{
|
||||
int previousProgram = GL.GetInteger(GetPName.CurrentProgram);
|
||||
int previousUnit = GL.GetInteger(GetPName.ActiveTexture);
|
||||
GL.ActiveTexture(TextureUnit.Texture0);
|
||||
int previousTextureBinding = GL.GetInteger(GetPName.TextureBinding2D);
|
||||
|
||||
GL.BindImageTexture(0, destinationTexture.Handle, 0, false, 0, TextureAccess.ReadWrite, SizedInternalFormat.Rgba8);
|
||||
|
||||
int threadGroupWorkRegionDim = 16;
|
||||
int dispatchX = (width + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
|
||||
int dispatchY = (height + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
|
||||
|
||||
// Scaling pass
|
||||
GL.UseProgram(_scalingShaderProgram);
|
||||
view.Bind(0);
|
||||
GL.Uniform1(_inputUniform, 0);
|
||||
GL.Uniform1(_outputUniform, 0);
|
||||
GL.Uniform1(_srcX0Uniform, (float)source.X1);
|
||||
GL.Uniform1(_srcX1Uniform, (float)source.X2);
|
||||
GL.Uniform1(_srcY0Uniform, (float)source.Y1);
|
||||
GL.Uniform1(_srcY1Uniform, (float)source.Y2);
|
||||
GL.Uniform1(_dstX0Uniform, (float)destination.X1);
|
||||
GL.Uniform1(_dstX1Uniform, (float)destination.X2);
|
||||
GL.Uniform1(_dstY0Uniform, (float)destination.Y1);
|
||||
GL.Uniform1(_dstY1Uniform, (float)destination.Y2);
|
||||
GL.DispatchCompute(dispatchX, dispatchY, 1);
|
||||
|
||||
GL.UseProgram(previousProgram);
|
||||
GL.MemoryBarrier(MemoryBarrierFlags.ShaderImageAccessBarrierBit);
|
||||
|
||||
(_renderer.Pipeline as Pipeline).RestoreImages1And2();
|
||||
|
||||
GL.ActiveTexture(TextureUnit.Texture0);
|
||||
GL.BindTexture(TextureTarget.Texture2D, previousTextureBinding);
|
||||
|
||||
GL.ActiveTexture((TextureUnit)previousUnit);
|
||||
}
|
||||
}
|
||||
}
|
@@ -18,7 +18,7 @@ namespace Ryujinx.Graphics.OpenGL.Effects
|
||||
private int _srcY0Uniform;
|
||||
private int _scalingShaderProgram;
|
||||
private int _sharpeningShaderProgram;
|
||||
private float _scale = 1;
|
||||
private float _sharpeningLevel = 1;
|
||||
private int _srcY1Uniform;
|
||||
private int _dstX0Uniform;
|
||||
private int _dstX1Uniform;
|
||||
@@ -30,10 +30,10 @@ namespace Ryujinx.Graphics.OpenGL.Effects
|
||||
|
||||
public float Level
|
||||
{
|
||||
get => _scale;
|
||||
get => _sharpeningLevel;
|
||||
set
|
||||
{
|
||||
_scale = MathF.Max(0.01f, value);
|
||||
_sharpeningLevel = MathF.Max(0.01f, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
using Ryujinx.Common.Logging;
|
||||
|
||||
namespace Ryujinx.Graphics.OpenGL.Effects
|
||||
{
|
||||
@@ -6,18 +7,7 @@ namespace Ryujinx.Graphics.OpenGL.Effects
|
||||
{
|
||||
public static int CompileProgram(string shaderCode, ShaderType shaderType)
|
||||
{
|
||||
var shader = GL.CreateShader(shaderType);
|
||||
GL.ShaderSource(shader, shaderCode);
|
||||
GL.CompileShader(shader);
|
||||
|
||||
var program = GL.CreateProgram();
|
||||
GL.AttachShader(program, shader);
|
||||
GL.LinkProgram(program);
|
||||
|
||||
GL.DetachShader(program, shader);
|
||||
GL.DeleteShader(shader);
|
||||
|
||||
return program;
|
||||
return CompileProgram(new string[] { shaderCode }, shaderType);
|
||||
}
|
||||
|
||||
public static int CompileProgram(string[] shaders, ShaderType shaderType)
|
||||
@@ -26,6 +16,15 @@ namespace Ryujinx.Graphics.OpenGL.Effects
|
||||
GL.ShaderSource(shader, shaders.Length, shaders, (int[])null);
|
||||
GL.CompileShader(shader);
|
||||
|
||||
GL.GetShader(shader, ShaderParameter.CompileStatus, out int isCompiled);
|
||||
if (isCompiled == 0)
|
||||
{
|
||||
string log = GL.GetShaderInfoLog(shader);
|
||||
Logger.Error?.Print(LogClass.Gpu, $"Failed to compile effect shader:\n\n{log}\n");
|
||||
GL.DeleteShader(shader);
|
||||
return 0;
|
||||
}
|
||||
|
||||
var program = GL.CreateProgram();
|
||||
GL.AttachShader(program, shader);
|
||||
GL.LinkProgram(program);
|
||||
|
@@ -0,0 +1,119 @@
|
||||
#version 430 core
|
||||
precision mediump float;
|
||||
layout (local_size_x = 16, local_size_y = 16) in;
|
||||
layout(rgba8, binding = 0, location=0) uniform image2D imgOutput;
|
||||
layout( location=1 ) uniform sampler2D Source;
|
||||
layout( location=2 ) uniform float srcX0;
|
||||
layout( location=3 ) uniform float srcX1;
|
||||
layout( location=4 ) uniform float srcY0;
|
||||
layout( location=5 ) uniform float srcY1;
|
||||
layout( location=6 ) uniform float dstX0;
|
||||
layout( location=7 ) uniform float dstX1;
|
||||
layout( location=8 ) uniform float dstY0;
|
||||
layout( location=9 ) uniform float dstY1;
|
||||
|
||||
/***** Area Sampling *****/
|
||||
|
||||
// By Sam Belliveau and Filippo Tarpini. Public Domain license.
|
||||
// Effectively a more accurate sharp bilinear filter when upscaling,
|
||||
// that also works as a mathematically perfect downscale filter.
|
||||
// https://entropymine.com/imageworsener/pixelmixing/
|
||||
// https://github.com/obsproject/obs-studio/pull/1715
|
||||
// https://legacy.imagemagick.org/Usage/filter/
|
||||
vec4 AreaSampling(vec2 xy)
|
||||
{
|
||||
// Determine the sizes of the source and target images.
|
||||
vec2 source_size = vec2(abs(srcX1 - srcX0), abs(srcY1 - srcY0));
|
||||
vec2 target_size = vec2(abs(dstX1 - dstX0), abs(dstY1 - dstY0));
|
||||
vec2 inverted_target_size = vec2(1.0) / target_size;
|
||||
|
||||
// Compute the top-left and bottom-right corners of the target pixel box.
|
||||
vec2 t_beg = floor(xy - vec2(dstX0 < dstX1 ? dstX0 : dstX1, dstY0 < dstY1 ? dstY0 : dstY1));
|
||||
vec2 t_end = t_beg + vec2(1.0, 1.0);
|
||||
|
||||
// Convert the target pixel box to source pixel box.
|
||||
vec2 beg = t_beg * inverted_target_size * source_size;
|
||||
vec2 end = t_end * inverted_target_size * source_size;
|
||||
|
||||
// Compute the top-left and bottom-right corners of the pixel box.
|
||||
ivec2 f_beg = ivec2(beg);
|
||||
ivec2 f_end = ivec2(end);
|
||||
|
||||
// Compute how much of the start and end pixels are covered horizontally & vertically.
|
||||
float area_w = 1.0 - fract(beg.x);
|
||||
float area_n = 1.0 - fract(beg.y);
|
||||
float area_e = fract(end.x);
|
||||
float area_s = fract(end.y);
|
||||
|
||||
// Compute the areas of the corner pixels in the pixel box.
|
||||
float area_nw = area_n * area_w;
|
||||
float area_ne = area_n * area_e;
|
||||
float area_sw = area_s * area_w;
|
||||
float area_se = area_s * area_e;
|
||||
|
||||
// Initialize the color accumulator.
|
||||
vec4 avg_color = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
|
||||
// Accumulate corner pixels.
|
||||
avg_color += area_nw * texelFetch(Source, ivec2(f_beg.x, f_beg.y), 0);
|
||||
avg_color += area_ne * texelFetch(Source, ivec2(f_end.x, f_beg.y), 0);
|
||||
avg_color += area_sw * texelFetch(Source, ivec2(f_beg.x, f_end.y), 0);
|
||||
avg_color += area_se * texelFetch(Source, ivec2(f_end.x, f_end.y), 0);
|
||||
|
||||
// Determine the size of the pixel box.
|
||||
int x_range = int(f_end.x - f_beg.x - 0.5);
|
||||
int y_range = int(f_end.y - f_beg.y - 0.5);
|
||||
|
||||
// Accumulate top and bottom edge pixels.
|
||||
for (int x = f_beg.x + 1; x <= f_beg.x + x_range; ++x)
|
||||
{
|
||||
avg_color += area_n * texelFetch(Source, ivec2(x, f_beg.y), 0);
|
||||
avg_color += area_s * texelFetch(Source, ivec2(x, f_end.y), 0);
|
||||
}
|
||||
|
||||
// Accumulate left and right edge pixels and all the pixels in between.
|
||||
for (int y = f_beg.y + 1; y <= f_beg.y + y_range; ++y)
|
||||
{
|
||||
avg_color += area_w * texelFetch(Source, ivec2(f_beg.x, y), 0);
|
||||
avg_color += area_e * texelFetch(Source, ivec2(f_end.x, y), 0);
|
||||
|
||||
for (int x = f_beg.x + 1; x <= f_beg.x + x_range; ++x)
|
||||
{
|
||||
avg_color += texelFetch(Source, ivec2(x, y), 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the area of the pixel box that was sampled.
|
||||
float area_corners = area_nw + area_ne + area_sw + area_se;
|
||||
float area_edges = float(x_range) * (area_n + area_s) + float(y_range) * (area_w + area_e);
|
||||
float area_center = float(x_range) * float(y_range);
|
||||
|
||||
// Return the normalized average color.
|
||||
return avg_color / (area_corners + area_edges + area_center);
|
||||
}
|
||||
|
||||
float insideBox(vec2 v, vec2 bLeft, vec2 tRight) {
|
||||
vec2 s = step(bLeft, v) - step(tRight, v);
|
||||
return s.x * s.y;
|
||||
}
|
||||
|
||||
vec2 translateDest(vec2 pos) {
|
||||
vec2 translatedPos = vec2(pos.x, pos.y);
|
||||
translatedPos.x = dstX1 < dstX0 ? dstX1 - translatedPos.x : translatedPos.x;
|
||||
translatedPos.y = dstY0 > dstY1 ? dstY0 + dstY1 - translatedPos.y - 1 : translatedPos.y;
|
||||
return translatedPos;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 bLeft = vec2(dstX0 < dstX1 ? dstX0 : dstX1, dstY0 < dstY1 ? dstY0 : dstY1);
|
||||
vec2 tRight = vec2(dstX1 > dstX0 ? dstX1 : dstX0, dstY1 > dstY0 ? dstY1 : dstY0);
|
||||
ivec2 loc = ivec2(gl_GlobalInvocationID.x, gl_GlobalInvocationID.y);
|
||||
if (insideBox(loc, bLeft, tRight) == 0) {
|
||||
imageStore(imgOutput, loc, vec4(0, 0, 0, 1));
|
||||
return;
|
||||
}
|
||||
|
||||
vec4 outColor = AreaSampling(loc);
|
||||
imageStore(imgOutput, ivec2(translateDest(loc)), vec4(outColor.rgb, 1));
|
||||
}
|
@@ -21,6 +21,7 @@
|
||||
<EmbeddedResource Include="Effects\Shaders\ffx_fsr1.h" />
|
||||
<EmbeddedResource Include="Effects\Shaders\ffx_a.h" />
|
||||
<EmbeddedResource Include="Effects\Shaders\fsr_scaling.glsl" />
|
||||
<EmbeddedResource Include="Effects\Shaders\area_scaling.glsl" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@@ -373,6 +373,16 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
_isLinear = false;
|
||||
_scalingFilter.Level = _scalingFilterLevel;
|
||||
|
||||
RecreateUpscalingTexture();
|
||||
break;
|
||||
case ScalingFilter.Area:
|
||||
if (_scalingFilter is not AreaScalingFilter)
|
||||
{
|
||||
_scalingFilter?.Dispose();
|
||||
_scalingFilter = new AreaScalingFilter(_renderer);
|
||||
}
|
||||
_isLinear = false;
|
||||
|
||||
RecreateUpscalingTexture();
|
||||
break;
|
||||
}
|
||||
|
101
ryujinx/src/Ryujinx.Graphics.Vulkan/Effects/AreaScalingFilter.cs
Normal file
101
ryujinx/src/Ryujinx.Graphics.Vulkan/Effects/AreaScalingFilter.cs
Normal file
@@ -0,0 +1,101 @@
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Shader;
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
using Silk.NET.Vulkan;
|
||||
using System;
|
||||
using Extent2D = Ryujinx.Graphics.GAL.Extents2D;
|
||||
using Format = Silk.NET.Vulkan.Format;
|
||||
using SamplerCreateInfo = Ryujinx.Graphics.GAL.SamplerCreateInfo;
|
||||
|
||||
namespace Ryujinx.Graphics.Vulkan.Effects
|
||||
{
|
||||
internal class AreaScalingFilter : IScalingFilter
|
||||
{
|
||||
private readonly VulkanRenderer _renderer;
|
||||
private PipelineHelperShader _pipeline;
|
||||
private ISampler _sampler;
|
||||
private ShaderCollection _scalingProgram;
|
||||
private Device _device;
|
||||
|
||||
public float Level { get; set; }
|
||||
|
||||
public AreaScalingFilter(VulkanRenderer renderer, Device device)
|
||||
{
|
||||
_device = device;
|
||||
_renderer = renderer;
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_pipeline.Dispose();
|
||||
_scalingProgram.Dispose();
|
||||
_sampler.Dispose();
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_pipeline = new PipelineHelperShader(_renderer, _device);
|
||||
|
||||
_pipeline.Initialize();
|
||||
|
||||
var scalingShader = EmbeddedResources.Read("Ryujinx.Graphics.Vulkan/Effects/Shaders/AreaScaling.spv");
|
||||
|
||||
var scalingResourceLayout = new ResourceLayoutBuilder()
|
||||
.Add(ResourceStages.Compute, ResourceType.UniformBuffer, 2)
|
||||
.Add(ResourceStages.Compute, ResourceType.TextureAndSampler, 1)
|
||||
.Add(ResourceStages.Compute, ResourceType.Image, 0, true).Build();
|
||||
|
||||
_sampler = _renderer.CreateSampler(SamplerCreateInfo.Create(MinFilter.Linear, MagFilter.Linear));
|
||||
|
||||
_scalingProgram = _renderer.CreateProgramWithMinimalLayout(new[]
|
||||
{
|
||||
new ShaderSource(scalingShader, ShaderStage.Compute, TargetLanguage.Spirv),
|
||||
}, scalingResourceLayout);
|
||||
}
|
||||
|
||||
public void Run(
|
||||
TextureView view,
|
||||
CommandBufferScoped cbs,
|
||||
Auto<DisposableImageView> destinationTexture,
|
||||
Format format,
|
||||
int width,
|
||||
int height,
|
||||
Extent2D source,
|
||||
Extent2D destination)
|
||||
{
|
||||
_pipeline.SetCommandBuffer(cbs);
|
||||
_pipeline.SetProgram(_scalingProgram);
|
||||
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, view, _sampler);
|
||||
|
||||
ReadOnlySpan<float> dimensionsBuffer = stackalloc float[]
|
||||
{
|
||||
source.X1,
|
||||
source.X2,
|
||||
source.Y1,
|
||||
source.Y2,
|
||||
destination.X1,
|
||||
destination.X2,
|
||||
destination.Y1,
|
||||
destination.Y2,
|
||||
};
|
||||
|
||||
int rangeSize = dimensionsBuffer.Length * sizeof(float);
|
||||
using var buffer = _renderer.BufferManager.ReserveOrCreate(_renderer, cbs, rangeSize);
|
||||
buffer.Holder.SetDataUnchecked(buffer.Offset, dimensionsBuffer);
|
||||
|
||||
int threadGroupWorkRegionDim = 16;
|
||||
int dispatchX = (width + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
|
||||
int dispatchY = (height + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
|
||||
|
||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, buffer.Range) });
|
||||
_pipeline.SetImage(0, destinationTexture);
|
||||
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
||||
_pipeline.ComputeBarrier();
|
||||
|
||||
_pipeline.Finish();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,122 @@
|
||||
// Scaling
|
||||
|
||||
#version 430 core
|
||||
layout (local_size_x = 16, local_size_y = 16) in;
|
||||
layout( rgba8, binding = 0, set = 3) uniform image2D imgOutput;
|
||||
layout( binding = 1, set = 2) uniform sampler2D Source;
|
||||
layout( binding = 2 ) uniform dimensions{
|
||||
float srcX0;
|
||||
float srcX1;
|
||||
float srcY0;
|
||||
float srcY1;
|
||||
float dstX0;
|
||||
float dstX1;
|
||||
float dstY0;
|
||||
float dstY1;
|
||||
};
|
||||
|
||||
/***** Area Sampling *****/
|
||||
|
||||
// By Sam Belliveau and Filippo Tarpini. Public Domain license.
|
||||
// Effectively a more accurate sharp bilinear filter when upscaling,
|
||||
// that also works as a mathematically perfect downscale filter.
|
||||
// https://entropymine.com/imageworsener/pixelmixing/
|
||||
// https://github.com/obsproject/obs-studio/pull/1715
|
||||
// https://legacy.imagemagick.org/Usage/filter/
|
||||
vec4 AreaSampling(vec2 xy)
|
||||
{
|
||||
// Determine the sizes of the source and target images.
|
||||
vec2 source_size = vec2(abs(srcX1 - srcX0), abs(srcY1 - srcY0));
|
||||
vec2 target_size = vec2(abs(dstX1 - dstX0), abs(dstY1 - dstY0));
|
||||
vec2 inverted_target_size = vec2(1.0) / target_size;
|
||||
|
||||
// Compute the top-left and bottom-right corners of the target pixel box.
|
||||
vec2 t_beg = floor(xy - vec2(dstX0 < dstX1 ? dstX0 : dstX1, dstY0 < dstY1 ? dstY0 : dstY1));
|
||||
vec2 t_end = t_beg + vec2(1.0, 1.0);
|
||||
|
||||
// Convert the target pixel box to source pixel box.
|
||||
vec2 beg = t_beg * inverted_target_size * source_size;
|
||||
vec2 end = t_end * inverted_target_size * source_size;
|
||||
|
||||
// Compute the top-left and bottom-right corners of the pixel box.
|
||||
ivec2 f_beg = ivec2(beg);
|
||||
ivec2 f_end = ivec2(end);
|
||||
|
||||
// Compute how much of the start and end pixels are covered horizontally & vertically.
|
||||
float area_w = 1.0 - fract(beg.x);
|
||||
float area_n = 1.0 - fract(beg.y);
|
||||
float area_e = fract(end.x);
|
||||
float area_s = fract(end.y);
|
||||
|
||||
// Compute the areas of the corner pixels in the pixel box.
|
||||
float area_nw = area_n * area_w;
|
||||
float area_ne = area_n * area_e;
|
||||
float area_sw = area_s * area_w;
|
||||
float area_se = area_s * area_e;
|
||||
|
||||
// Initialize the color accumulator.
|
||||
vec4 avg_color = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
|
||||
// Accumulate corner pixels.
|
||||
avg_color += area_nw * texelFetch(Source, ivec2(f_beg.x, f_beg.y), 0);
|
||||
avg_color += area_ne * texelFetch(Source, ivec2(f_end.x, f_beg.y), 0);
|
||||
avg_color += area_sw * texelFetch(Source, ivec2(f_beg.x, f_end.y), 0);
|
||||
avg_color += area_se * texelFetch(Source, ivec2(f_end.x, f_end.y), 0);
|
||||
|
||||
// Determine the size of the pixel box.
|
||||
int x_range = int(f_end.x - f_beg.x - 0.5);
|
||||
int y_range = int(f_end.y - f_beg.y - 0.5);
|
||||
|
||||
// Accumulate top and bottom edge pixels.
|
||||
for (int x = f_beg.x + 1; x <= f_beg.x + x_range; ++x)
|
||||
{
|
||||
avg_color += area_n * texelFetch(Source, ivec2(x, f_beg.y), 0);
|
||||
avg_color += area_s * texelFetch(Source, ivec2(x, f_end.y), 0);
|
||||
}
|
||||
|
||||
// Accumulate left and right edge pixels and all the pixels in between.
|
||||
for (int y = f_beg.y + 1; y <= f_beg.y + y_range; ++y)
|
||||
{
|
||||
avg_color += area_w * texelFetch(Source, ivec2(f_beg.x, y), 0);
|
||||
avg_color += area_e * texelFetch(Source, ivec2(f_end.x, y), 0);
|
||||
|
||||
for (int x = f_beg.x + 1; x <= f_beg.x + x_range; ++x)
|
||||
{
|
||||
avg_color += texelFetch(Source, ivec2(x, y), 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the area of the pixel box that was sampled.
|
||||
float area_corners = area_nw + area_ne + area_sw + area_se;
|
||||
float area_edges = float(x_range) * (area_n + area_s) + float(y_range) * (area_w + area_e);
|
||||
float area_center = float(x_range) * float(y_range);
|
||||
|
||||
// Return the normalized average color.
|
||||
return avg_color / (area_corners + area_edges + area_center);
|
||||
}
|
||||
|
||||
float insideBox(vec2 v, vec2 bLeft, vec2 tRight) {
|
||||
vec2 s = step(bLeft, v) - step(tRight, v);
|
||||
return s.x * s.y;
|
||||
}
|
||||
|
||||
vec2 translateDest(vec2 pos) {
|
||||
vec2 translatedPos = vec2(pos.x, pos.y);
|
||||
translatedPos.x = dstX1 < dstX0 ? dstX1 - translatedPos.x : translatedPos.x;
|
||||
translatedPos.y = dstY0 < dstY1 ? dstY1 + dstY0 - translatedPos.y - 1 : translatedPos.y;
|
||||
return translatedPos;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 bLeft = vec2(dstX0 < dstX1 ? dstX0 : dstX1, dstY0 < dstY1 ? dstY0 : dstY1);
|
||||
vec2 tRight = vec2(dstX1 > dstX0 ? dstX1 : dstX0, dstY1 > dstY0 ? dstY1 : dstY0);
|
||||
ivec2 loc = ivec2(gl_GlobalInvocationID.x, gl_GlobalInvocationID.y);
|
||||
if (insideBox(loc, bLeft, tRight) == 0) {
|
||||
imageStore(imgOutput, loc, vec4(0, 0, 0, 1));
|
||||
return;
|
||||
}
|
||||
|
||||
vec4 outColor = AreaSampling(loc);
|
||||
imageStore(imgOutput, ivec2(translateDest(loc)), vec4(outColor.rgb, 1));
|
||||
}
|
Binary file not shown.
@@ -15,6 +15,7 @@
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Effects\Textures\SmaaAreaTexture.bin" />
|
||||
<EmbeddedResource Include="Effects\Textures\SmaaSearchTexture.bin" />
|
||||
<EmbeddedResource Include="Effects\Shaders\AreaScaling.spv" />
|
||||
<EmbeddedResource Include="Effects\Shaders\FsrScaling.spv" />
|
||||
<EmbeddedResource Include="Effects\Shaders\FsrSharpening.spv" />
|
||||
<EmbeddedResource Include="Effects\Shaders\Fxaa.spv" />
|
||||
|
@@ -568,6 +568,13 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
_scalingFilter.Level = _scalingFilterLevel;
|
||||
break;
|
||||
case ScalingFilter.Area:
|
||||
if (_scalingFilter is not AreaScalingFilter)
|
||||
{
|
||||
_scalingFilter?.Dispose();
|
||||
_scalingFilter = new AreaScalingFilter(_gd, _device);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -647,7 +647,7 @@ namespace Ryujinx.UI
|
||||
}
|
||||
|
||||
var memoryConfiguration = ConfigurationState.Instance.System.ExpandRam.Value
|
||||
? HLE.MemoryConfiguration.MemoryConfiguration6GiB
|
||||
? HLE.MemoryConfiguration.MemoryConfiguration8GiB
|
||||
: HLE.MemoryConfiguration.MemoryConfiguration4GiB;
|
||||
|
||||
IntegrityCheckLevel fsIntegrityCheckLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None;
|
||||
|
@@ -28,8 +28,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Common
|
||||
MemoryArrange.MemoryArrange4GiBSystemDev or
|
||||
MemoryArrange.MemoryArrange6GiBAppletDev => 3285 * MiB,
|
||||
MemoryArrange.MemoryArrange4GiBAppletDev => 2048 * MiB,
|
||||
MemoryArrange.MemoryArrange6GiB or
|
||||
MemoryArrange.MemoryArrange8GiB => 4916 * MiB,
|
||||
MemoryArrange.MemoryArrange6GiB => 4916 * MiB,
|
||||
MemoryArrange.MemoryArrange8GiB => 6964 * MiB,
|
||||
_ => throw new ArgumentException($"Invalid memory arrange \"{arrange}\"."),
|
||||
};
|
||||
}
|
||||
@@ -42,8 +42,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Common
|
||||
MemoryArrange.MemoryArrange4GiBAppletDev => 1554 * MiB,
|
||||
MemoryArrange.MemoryArrange4GiBSystemDev => 448 * MiB,
|
||||
MemoryArrange.MemoryArrange6GiB => 562 * MiB,
|
||||
MemoryArrange.MemoryArrange6GiBAppletDev or
|
||||
MemoryArrange.MemoryArrange8GiB => 2193 * MiB,
|
||||
MemoryArrange.MemoryArrange6GiBAppletDev => 2193 * MiB,
|
||||
MemoryArrange.MemoryArrange8GiB => 562 * MiB,
|
||||
_ => throw new ArgumentException($"Invalid memory arrange \"{arrange}\"."),
|
||||
};
|
||||
}
|
||||
|
@@ -219,7 +219,7 @@ namespace Ryujinx.Headless.SDL2
|
||||
|
||||
// Hacks
|
||||
|
||||
[Option("expand-ram", Required = false, Default = false, HelpText = "Expands the RAM amount on the emulated system from 4GiB to 6GiB.")]
|
||||
[Option("expand-ram", Required = false, Default = false, HelpText = "Expands the RAM amount on the emulated system from 4GiB to 8GiB.")]
|
||||
public bool ExpandRAM { get; set; }
|
||||
|
||||
[Option("ignore-missing-services", Required = false, Default = false, HelpText = "Enable ignoring missing services.")]
|
||||
|
@@ -562,7 +562,7 @@ namespace Ryujinx.Headless.SDL2
|
||||
_userChannelPersistence,
|
||||
renderer,
|
||||
new SDL2HardwareDeviceDriver(),
|
||||
options.ExpandRAM ? MemoryConfiguration.MemoryConfiguration6GiB : MemoryConfiguration.MemoryConfiguration4GiB,
|
||||
options.ExpandRAM ? MemoryConfiguration.MemoryConfiguration8GiB : MemoryConfiguration.MemoryConfiguration4GiB,
|
||||
window,
|
||||
options.SystemLanguage,
|
||||
options.SystemRegion,
|
||||
|
@@ -238,7 +238,7 @@ namespace Ryujinx.UI.Common.Configuration
|
||||
public MemoryManagerMode MemoryManagerMode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Expands the RAM amount on the emulated system from 4GiB to 6GiB
|
||||
/// Expands the RAM amount on the emulated system from 4GiB to 8GiB
|
||||
/// </summary>
|
||||
public bool ExpandRam { get; set; }
|
||||
|
||||
|
@@ -845,7 +845,7 @@ namespace Ryujinx.Ava
|
||||
Logger.Info?.PrintMsg(LogClass.Gpu, $"Backend Threading ({threadingMode}): {isGALThreaded}");
|
||||
|
||||
// Initialize Configuration.
|
||||
var memoryConfiguration = ConfigurationState.Instance.System.ExpandRam.Value ? MemoryConfiguration.MemoryConfiguration6GiB : MemoryConfiguration.MemoryConfiguration4GiB;
|
||||
var memoryConfiguration = ConfigurationState.Instance.System.ExpandRam.Value ? MemoryConfiguration.MemoryConfiguration8GiB : MemoryConfiguration.MemoryConfiguration4GiB;
|
||||
|
||||
HLEConfiguration configuration = new(VirtualFileSystem,
|
||||
_viewModel.LibHacHorizonManager,
|
||||
|
@@ -145,7 +145,7 @@
|
||||
"SettingsTabSystemAudioBackendSDL2": "SDL2",
|
||||
"SettingsTabSystemHacks": "Hacks",
|
||||
"SettingsTabSystemHacksNote": "May cause instability",
|
||||
"SettingsTabSystemExpandDramSize": "Use alternative memory layout (Developers)",
|
||||
"SettingsTabSystemExpandDramSize": "Expand DRAM to 8GiB",
|
||||
"SettingsTabSystemIgnoreMissingServices": "Ignore Missing Services",
|
||||
"SettingsTabGraphics": "Graphics",
|
||||
"SettingsTabGraphicsAPI": "Graphics API",
|
||||
@@ -575,7 +575,7 @@
|
||||
"MemoryManagerHostTooltip": "Directly map memory in the host address space. Much faster JIT compilation and execution.",
|
||||
"MemoryManagerUnsafeTooltip": "Directly map memory, but do not mask the address within the guest address space before access. Faster, but at the cost of safety. The guest application can access memory from anywhere in Ryujinx, so only run programs you trust with this mode.",
|
||||
"UseHypervisorTooltip": "Use Hypervisor instead of JIT. Greatly improves performance when available, but can be unstable in its current state.",
|
||||
"DRamTooltip": "Utilizes an alternative MemoryMode layout to mimic a Switch development model.\n\nThis is only useful for higher-resolution texture packs or 4k resolution mods. Does NOT improve performance.\n\nLeave OFF if unsure.",
|
||||
"DRamTooltip": "Utilizes an alternative memory mode with 8GiB of DRAM to mimic a Switch development model.\n\nThis is only useful for higher-resolution texture packs or 4k resolution mods. Does NOT improve performance.\n\nLeave OFF if unsure.",
|
||||
"IgnoreMissingServicesTooltip": "Ignores unimplemented Horizon OS services. This may help in bypassing crashes when booting certain games.\n\nLeave OFF if unsure.",
|
||||
"GraphicsBackendThreadingTooltip": "Executes graphics backend commands on a second thread.\n\nSpeeds up shader compilation, reduces stuttering, and improves performance on GPU drivers without multithreading support of their own. Slightly better performance on drivers with multithreading.\n\nSet to AUTO if unsure.",
|
||||
"GalThreadingTooltip": "Executes graphics backend commands on a second thread.\n\nSpeeds up shader compilation, reduces stuttering, and improves performance on GPU drivers without multithreading support of their own. Slightly better performance on drivers with multithreading.\n\nSet to AUTO if unsure.",
|
||||
@@ -758,10 +758,11 @@
|
||||
"GraphicsAATooltip": "Applies anti-aliasing to the game render.\n\nFXAA will blur most of the image, while SMAA will attempt to find jagged edges and smooth them out.\n\nNot recommended to use in conjunction with the FSR scaling filter.\n\nThis option can be changed while a game is running by clicking \"Apply\" below; you can simply move the settings window aside and experiment until you find your preferred look for a game.\n\nLeave on NONE if unsure.",
|
||||
"GraphicsAALabel": "Anti-Aliasing:",
|
||||
"GraphicsScalingFilterLabel": "Scaling Filter:",
|
||||
"GraphicsScalingFilterTooltip": "Choose the scaling filter that will be applied when using resolution scale.\n\nBilinear works well for 3D games and is a safe default option.\n\nNearest is recommended for pixel art games.\n\nFSR 1.0 is merely a sharpening filter, not recommended for use with FXAA or SMAA.\n\nThis option can be changed while a game is running by clicking \"Apply\" below; you can simply move the settings window aside and experiment until you find your preferred look for a game.\n\nLeave on BILINEAR if unsure.",
|
||||
"GraphicsScalingFilterTooltip": "Choose the scaling filter that will be applied when using resolution scale.\n\nBilinear works well for 3D games and is a safe default option.\n\nNearest is recommended for pixel art games.\n\nFSR 1.0 is merely a sharpening filter, not recommended for use with FXAA or SMAA.\n\nArea scaling is recommended when downscaling resolutions that are larger than the output window. It can be used to achieve a supersampled anti-aliasing effect when downscaling by more than 2x.\n\nThis option can be changed while a game is running by clicking \"Apply\" below; you can simply move the settings window aside and experiment until you find your preferred look for a game.\n\nLeave on BILINEAR if unsure.",
|
||||
"GraphicsScalingFilterBilinear": "Bilinear",
|
||||
"GraphicsScalingFilterNearest": "Nearest",
|
||||
"GraphicsScalingFilterFsr": "FSR",
|
||||
"GraphicsScalingFilterArea": "Area",
|
||||
"GraphicsScalingFilterLevelLabel": "Level",
|
||||
"GraphicsScalingFilterLevelTooltip": "Set FSR 1.0 sharpening level. Higher is sharper.",
|
||||
"SmaaLow": "SMAA Low",
|
||||
|
@@ -1,4 +1,4 @@
|
||||
<UserControl
|
||||
<UserControl
|
||||
x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsGraphicsView"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -173,6 +173,9 @@
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale GraphicsScalingFilterFsr}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale GraphicsScalingFilterArea}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
<controls:SliderScroll Value="{Binding ScalingFilterLevel}"
|
||||
ToolTip.Tip="{locale:Locale GraphicsScalingFilterLevelTooltip}"
|
||||
|
@@ -13,6 +13,7 @@ use crate::{
|
||||
};
|
||||
|
||||
/// Service context
|
||||
#[derive(Debug)]
|
||||
pub struct Context {
|
||||
// Protector against replay attack
|
||||
// The actual replay detection behavior is implemented in ReplayProtector
|
||||
|
@@ -38,6 +38,7 @@ pub trait DnsResolve {
|
||||
}
|
||||
|
||||
#[cfg(feature = "hickory-dns")]
|
||||
#[derive(Debug)]
|
||||
pub struct HickoryDnsSystemResolver {
|
||||
resolver: ArcSwap<HickoryDnsResolver>,
|
||||
#[cfg_attr(any(windows, target_os = "android"), allow(dead_code))]
|
||||
|
@@ -46,6 +46,7 @@ impl fmt::Display for ManagerSocketAddr {
|
||||
/// Datagram socket for manager
|
||||
///
|
||||
/// For *nix system, this is a wrapper for both UDP socket and Unix socket
|
||||
#[derive(Debug)]
|
||||
pub enum ManagerDatagram {
|
||||
UdpDatagram(UdpSocket),
|
||||
#[cfg(unix)]
|
||||
|
@@ -13,6 +13,7 @@ use super::{
|
||||
};
|
||||
|
||||
/// Manager server Listener
|
||||
#[derive(Debug)]
|
||||
pub struct ManagerListener {
|
||||
socket: ManagerDatagram,
|
||||
}
|
||||
|
@@ -121,6 +121,7 @@ impl AsyncWrite for TcpStream {
|
||||
}
|
||||
|
||||
/// `TcpListener` for accepting inbound connections
|
||||
#[derive(Debug)]
|
||||
pub struct TcpListener {
|
||||
inner: TokioTcpListener,
|
||||
accept_opts: AcceptOpts,
|
||||
|
@@ -85,6 +85,7 @@ fn make_mtu_error(packet_size: usize, mtu: usize) -> io::Error {
|
||||
}
|
||||
|
||||
/// Wrappers for outbound `UdpSocket`
|
||||
#[derive(Debug)]
|
||||
#[pin_project]
|
||||
pub struct UdpSocket {
|
||||
#[pin]
|
||||
|
@@ -58,6 +58,7 @@ pub enum PluginMode {
|
||||
}
|
||||
|
||||
/// A shadowsocks SIP004 Plugin
|
||||
#[derive(Debug)]
|
||||
pub struct Plugin {
|
||||
process: Child,
|
||||
local_addr: SocketAddr,
|
||||
|
@@ -80,6 +80,7 @@ impl From<ProtocolError> for io::Error {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum DecryptReadState {
|
||||
WaitSalt { key: Bytes },
|
||||
ReadLength,
|
||||
@@ -320,6 +321,7 @@ impl DecryptedReader {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum EncryptWriteState {
|
||||
AssemblePacket,
|
||||
Writing { pos: usize },
|
||||
|
@@ -1,7 +1,7 @@
|
||||
//! IO facilities for TCP relay
|
||||
|
||||
use std::{
|
||||
io,
|
||||
fmt, io,
|
||||
marker::Unpin,
|
||||
pin::Pin,
|
||||
sync::Arc,
|
||||
@@ -313,6 +313,15 @@ pub struct CryptoStream<S> {
|
||||
has_handshaked: bool,
|
||||
}
|
||||
|
||||
impl<S> fmt::Debug for CryptoStream<S> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("CryptoStream")
|
||||
.field("method", &self.method)
|
||||
.field("has_handshaked", &self.has_handshaked)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> CryptoStream<S> {
|
||||
/// Create a new CryptoStream with the underlying stream connection
|
||||
pub fn from_stream(
|
||||
|
@@ -17,6 +17,7 @@ use crate::{
|
||||
};
|
||||
|
||||
/// A TCP listener for accepting shadowsocks' client connection
|
||||
#[derive(Debug)]
|
||||
pub struct ProxyListener {
|
||||
listener: TcpListener,
|
||||
method: CipherKind,
|
||||
|
@@ -30,12 +30,14 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ProxyClientStreamWriteState {
|
||||
Connect(Address),
|
||||
Connecting(BytesMut),
|
||||
Connected,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ProxyClientStreamReadState {
|
||||
#[cfg(feature = "aead-cipher-2022")]
|
||||
CheckRequestNonce,
|
||||
@@ -43,6 +45,7 @@ enum ProxyClientStreamReadState {
|
||||
}
|
||||
|
||||
/// A stream for sending / receiving data stream from remote server via shadowsocks' proxy server
|
||||
#[derive(Debug)]
|
||||
#[pin_project]
|
||||
pub struct ProxyClientStream<S> {
|
||||
#[pin]
|
||||
|
@@ -18,6 +18,7 @@ pub mod v1;
|
||||
#[cfg(feature = "aead-cipher-2022")]
|
||||
pub mod v2;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum TcpRequestHeader {
|
||||
Stream(StreamTcpRequestHeader),
|
||||
#[cfg(feature = "aead-cipher-2022")]
|
||||
@@ -74,6 +75,7 @@ impl TcpRequestHeader {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum TcpRequestHeaderRef<'a> {
|
||||
Stream(StreamTcpRequestHeaderRef<'a>),
|
||||
#[cfg(feature = "aead-cipher-2022")]
|
||||
|
@@ -7,6 +7,7 @@ use tokio::io::AsyncRead;
|
||||
|
||||
use crate::relay::socks5::Address;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct StreamTcpRequestHeader {
|
||||
pub addr: Address,
|
||||
}
|
||||
@@ -27,6 +28,7 @@ impl StreamTcpRequestHeader {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct StreamTcpRequestHeaderRef<'a> {
|
||||
pub addr: &'a Address,
|
||||
}
|
||||
|
@@ -66,6 +66,7 @@ impl Aead2022TcpRequestHeader {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Aead2022TcpRequestHeaderRef<'a> {
|
||||
pub addr: &'a Address,
|
||||
pub padding_size: u16,
|
||||
|
@@ -25,6 +25,7 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ProxyServerStreamWriteState {
|
||||
#[cfg(feature = "aead-cipher-2022")]
|
||||
PrepareHeader(Option<std::task::Waker>),
|
||||
@@ -32,6 +33,7 @@ enum ProxyServerStreamWriteState {
|
||||
}
|
||||
|
||||
/// A stream for communicating with shadowsocks' proxy client
|
||||
#[derive(Debug)]
|
||||
#[pin_project]
|
||||
pub struct ProxyServerStream<S> {
|
||||
#[pin]
|
||||
|
@@ -69,6 +69,7 @@ impl From<ProxySocketError> for io::Error {
|
||||
pub type ProxySocketResult<T> = Result<T, ProxySocketError>;
|
||||
|
||||
/// UDP client for communicating with ShadowSocks' server
|
||||
#[derive(Debug)]
|
||||
pub struct ProxySocket {
|
||||
socket_type: UdpSocketType,
|
||||
socket: ShadowUdpSocket,
|
||||
|
@@ -1,3 +1,5 @@
|
||||
use std::fmt;
|
||||
|
||||
#[cfg(feature = "aead-cipher-2022")]
|
||||
use std::time::Duration;
|
||||
|
||||
@@ -29,6 +31,12 @@ pub struct ReplayProtector {
|
||||
nonce_set: spin::Mutex<LruCache<Vec<u8>, ()>>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for ReplayProtector {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("ReplayProtector").finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl ReplayProtector {
|
||||
/// Create a new ReplayProtector
|
||||
#[allow(unused_variables)]
|
||||
|
@@ -27,6 +27,7 @@ const BF_ERROR_RATE_FOR_CLIENT: f64 = 1e-15;
|
||||
//
|
||||
// It contains 2 bloom filters and each one holds 1/2 entries.
|
||||
// Use them as a ring buffer.
|
||||
#[derive(Debug)]
|
||||
pub struct PingPongBloom {
|
||||
blooms: [Bloom<[u8]>; 2],
|
||||
bloom_count: [usize; 2],
|
||||
|
@@ -619,23 +619,27 @@ function gen_config_server(node)
|
||||
end
|
||||
|
||||
if node.protocol == "tuic" then
|
||||
if node.uuid then
|
||||
local users = {}
|
||||
for i = 1, #node.uuid do
|
||||
users[i] = {
|
||||
name = node.uuid[i],
|
||||
uuid = node.uuid[i],
|
||||
password = node.password
|
||||
}
|
||||
end
|
||||
tls.alpn = (node.tuic_alpn and node.tuic_alpn ~= "") and {
|
||||
node.tuic_alpn
|
||||
} or nil
|
||||
protocol_table = {
|
||||
users = {
|
||||
{
|
||||
name = "user1",
|
||||
uuid = node.uuid,
|
||||
password = node.password
|
||||
}
|
||||
},
|
||||
users = users,
|
||||
congestion_control = node.tuic_congestion_control or "cubic",
|
||||
zero_rtt_handshake = (node.tuic_zero_rtt_handshake == "1") and true or false,
|
||||
heartbeat = node.tuic_heartbeat .. "s",
|
||||
tls = tls
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
if node.protocol == "hysteria2" then
|
||||
protocol_table = {
|
||||
|
BIN
suyu/img/need to fix bugs.png
Normal file
BIN
suyu/img/need to fix bugs.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 249 KiB |
@@ -18,7 +18,7 @@ namespace ServiceLib.Common
|
||||
Uri uri = new(url);
|
||||
//Authorization Header
|
||||
var headers = new WebHeaderCollection();
|
||||
if (!Utils.IsNullOrEmpty(uri.UserInfo))
|
||||
if (Utils.IsNotEmpty(uri.UserInfo))
|
||||
{
|
||||
headers.Add(HttpRequestHeader.Authorization, "Basic " + Utils.Base64Encode(uri.UserInfo));
|
||||
}
|
||||
|
@@ -82,7 +82,7 @@ namespace ServiceLib.Common
|
||||
}
|
||||
try
|
||||
{
|
||||
if (!Utils.IsNullOrEmpty(ignoredName) && entry.Name.Contains(ignoredName))
|
||||
if (Utils.IsNotEmpty(ignoredName) && entry.Name.Contains(ignoredName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -157,7 +157,7 @@ namespace ServiceLib.Common
|
||||
// Get the files in the source directory and copy to the destination directory
|
||||
foreach (FileInfo file in dir.GetFiles())
|
||||
{
|
||||
if (!Utils.IsNullOrEmpty(ignoredName) && file.Name.Contains(ignoredName))
|
||||
if (Utils.IsNotEmpty(ignoredName) && file.Name.Contains(ignoredName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@@ -22,7 +22,7 @@ namespace ServiceLib.Common
|
||||
|
||||
public async Task<string?> TryGetAsync(string url)
|
||||
{
|
||||
if (string.IsNullOrEmpty(url))
|
||||
if (Utils.IsNullOrEmpty(url))
|
||||
return null;
|
||||
|
||||
try
|
||||
|
@@ -14,6 +14,11 @@ namespace ServiceLib.Common
|
||||
return string.IsNullOrWhiteSpace(value);
|
||||
}
|
||||
|
||||
public static bool IsNotEmpty([NotNullWhen(false)] this string? value)
|
||||
{
|
||||
return !string.IsNullOrEmpty(value);
|
||||
}
|
||||
|
||||
public static bool BeginWithAny(this string s, IEnumerable<char> chars)
|
||||
{
|
||||
if (s.IsNullOrEmpty()) return false;
|
||||
|
@@ -417,6 +417,11 @@ namespace ServiceLib.Common
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IsNotEmpty(string? text)
|
||||
{
|
||||
return !string.IsNullOrEmpty(text);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证IP地址是否合法
|
||||
/// </summary>
|
||||
|
@@ -23,7 +23,7 @@ namespace ServiceLib.Handler
|
||||
{
|
||||
//载入配置文件
|
||||
var result = Utils.LoadResource(Utils.GetConfigPath(configRes));
|
||||
if (!Utils.IsNullOrEmpty(result))
|
||||
if (Utils.IsNotEmpty(result))
|
||||
{
|
||||
//转成Json
|
||||
config = JsonUtils.Deserialize<Config>(result);
|
||||
@@ -1007,7 +1007,7 @@ namespace ServiceLib.Handler
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(profileItem.security) && profileItem.security != Global.None)
|
||||
if (Utils.IsNotEmpty(profileItem.security) && profileItem.security != Global.None)
|
||||
{
|
||||
profileItem.security = Global.None;
|
||||
}
|
||||
@@ -1045,7 +1045,7 @@ namespace ServiceLib.Handler
|
||||
{
|
||||
profileItem.configVersion = 2;
|
||||
|
||||
if (!Utils.IsNullOrEmpty(profileItem.streamSecurity))
|
||||
if (Utils.IsNotEmpty(profileItem.streamSecurity))
|
||||
{
|
||||
if (profileItem.streamSecurity != Global.StreamSecurity
|
||||
&& profileItem.streamSecurity != Global.StreamSecurityReality)
|
||||
@@ -1065,7 +1065,7 @@ namespace ServiceLib.Handler
|
||||
}
|
||||
}
|
||||
|
||||
if (!Utils.IsNullOrEmpty(profileItem.network) && !Global.Networks.Contains(profileItem.network))
|
||||
if (Utils.IsNotEmpty(profileItem.network) && !Global.Networks.Contains(profileItem.network))
|
||||
{
|
||||
profileItem.network = Global.DefaultNetwork;
|
||||
}
|
||||
@@ -1186,7 +1186,7 @@ namespace ServiceLib.Handler
|
||||
|
||||
string subFilter = string.Empty;
|
||||
//remove sub items
|
||||
if (isSub && !Utils.IsNullOrEmpty(subid))
|
||||
if (isSub && Utils.IsNotEmpty(subid))
|
||||
{
|
||||
RemoveServerViaSubid(config, subid, isSub);
|
||||
subFilter = LazyConfig.Instance.GetSubItem(subid)?.filter ?? "";
|
||||
@@ -1219,7 +1219,7 @@ namespace ServiceLib.Handler
|
||||
}
|
||||
|
||||
//exist sub items
|
||||
if (isSub && !Utils.IsNullOrEmpty(subid))
|
||||
if (isSub && Utils.IsNotEmpty(subid))
|
||||
{
|
||||
var existItem = lstOriSub?.FirstOrDefault(t => t.isSub == isSub
|
||||
&& config.uiItem.enableUpdateSubOnlyRemarksExist ? t.remarks == profileItem.remarks : CompareProfileItem(t, profileItem, true));
|
||||
@@ -1241,7 +1241,7 @@ namespace ServiceLib.Handler
|
||||
}
|
||||
}
|
||||
//filter
|
||||
if (!Utils.IsNullOrEmpty(subFilter))
|
||||
if (Utils.IsNotEmpty(subFilter))
|
||||
{
|
||||
if (!Regex.IsMatch(profileItem.remarks, subFilter))
|
||||
{
|
||||
@@ -1305,7 +1305,7 @@ namespace ServiceLib.Handler
|
||||
}
|
||||
if (lstProfiles != null && lstProfiles.Count > 0)
|
||||
{
|
||||
if (isSub && !Utils.IsNullOrEmpty(subid))
|
||||
if (isSub && Utils.IsNotEmpty(subid))
|
||||
{
|
||||
RemoveServerViaSubid(config, subid, isSub);
|
||||
}
|
||||
@@ -1361,7 +1361,7 @@ namespace ServiceLib.Handler
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (isSub && !Utils.IsNullOrEmpty(subid))
|
||||
if (isSub && Utils.IsNotEmpty(subid))
|
||||
{
|
||||
RemoveServerViaSubid(config, subid, isSub);
|
||||
}
|
||||
@@ -1389,7 +1389,7 @@ namespace ServiceLib.Handler
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (isSub && !Utils.IsNullOrEmpty(subid))
|
||||
if (isSub && Utils.IsNotEmpty(subid))
|
||||
{
|
||||
RemoveServerViaSubid(config, subid, isSub);
|
||||
}
|
||||
@@ -1421,7 +1421,7 @@ namespace ServiceLib.Handler
|
||||
return -1;
|
||||
}
|
||||
List<ProfileItem>? lstOriSub = null;
|
||||
if (isSub && !Utils.IsNullOrEmpty(subid))
|
||||
if (isSub && Utils.IsNotEmpty(subid))
|
||||
{
|
||||
lstOriSub = LazyConfig.Instance.ProfileItems(subid);
|
||||
}
|
||||
|
@@ -43,7 +43,7 @@
|
||||
}
|
||||
|
||||
string addressFileName = node.address;
|
||||
if (string.IsNullOrEmpty(addressFileName))
|
||||
if (Utils.IsNullOrEmpty(addressFileName))
|
||||
{
|
||||
msg = ResUI.FailedGetDefaultConfiguration;
|
||||
return -1;
|
||||
@@ -117,7 +117,7 @@
|
||||
if (_config.tunModeItem.enableTun)
|
||||
{
|
||||
string tun = Utils.GetEmbedText(Global.ClashTunYaml);
|
||||
if (!string.IsNullOrEmpty(tun))
|
||||
if (Utils.IsNotEmpty(tun))
|
||||
{
|
||||
var tunContent = YamlUtils.FromYaml<Dictionary<string, object>>(tun);
|
||||
if (tunContent != null)
|
||||
|
@@ -370,7 +370,7 @@ namespace ServiceLib.Handler.CoreConfig
|
||||
}
|
||||
|
||||
string addressFileName = node.address;
|
||||
if (string.IsNullOrEmpty(addressFileName))
|
||||
if (Utils.IsNullOrEmpty(addressFileName))
|
||||
{
|
||||
msg = ResUI.FailedGetDefaultConfiguration;
|
||||
return -1;
|
||||
@@ -489,7 +489,7 @@ namespace ServiceLib.Handler.CoreConfig
|
||||
if (_config.routingBasicItem.enableRoutingAdvanced)
|
||||
{
|
||||
var routing = ConfigHandler.GetDefaultRouting(_config);
|
||||
if (!Utils.IsNullOrEmpty(routing.domainStrategy4Singbox))
|
||||
if (Utils.IsNotEmpty(routing.domainStrategy4Singbox))
|
||||
{
|
||||
inbound.domain_strategy = routing.domainStrategy4Singbox;
|
||||
}
|
||||
@@ -512,7 +512,7 @@ namespace ServiceLib.Handler.CoreConfig
|
||||
singboxConfig.inbounds.Add(inbound4);
|
||||
|
||||
//auth
|
||||
if (!Utils.IsNullOrEmpty(_config.inbound[0].user) && !Utils.IsNullOrEmpty(_config.inbound[0].pass))
|
||||
if (Utils.IsNotEmpty(_config.inbound[0].user) && Utils.IsNotEmpty(_config.inbound[0].pass))
|
||||
{
|
||||
inbound3.users = new() { new() { username = _config.inbound[0].user, password = _config.inbound[0].pass } };
|
||||
inbound4.users = new() { new() { username = _config.inbound[0].user, password = _config.inbound[0].pass } };
|
||||
@@ -604,8 +604,8 @@ namespace ServiceLib.Handler.CoreConfig
|
||||
case EConfigType.Socks:
|
||||
{
|
||||
outbound.version = "5";
|
||||
if (!Utils.IsNullOrEmpty(node.security)
|
||||
&& !Utils.IsNullOrEmpty(node.id))
|
||||
if (Utils.IsNotEmpty(node.security)
|
||||
&& Utils.IsNotEmpty(node.id))
|
||||
{
|
||||
outbound.username = node.security;
|
||||
outbound.password = node.id;
|
||||
@@ -614,8 +614,8 @@ namespace ServiceLib.Handler.CoreConfig
|
||||
}
|
||||
case EConfigType.Http:
|
||||
{
|
||||
if (!Utils.IsNullOrEmpty(node.security)
|
||||
&& !Utils.IsNullOrEmpty(node.id))
|
||||
if (Utils.IsNotEmpty(node.security)
|
||||
&& Utils.IsNotEmpty(node.id))
|
||||
{
|
||||
outbound.username = node.security;
|
||||
outbound.password = node.id;
|
||||
@@ -649,7 +649,7 @@ namespace ServiceLib.Handler.CoreConfig
|
||||
{
|
||||
outbound.password = node.id;
|
||||
|
||||
if (!Utils.IsNullOrEmpty(node.path))
|
||||
if (Utils.IsNotEmpty(node.path))
|
||||
{
|
||||
outbound.obfs = new()
|
||||
{
|
||||
@@ -695,7 +695,7 @@ namespace ServiceLib.Handler.CoreConfig
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_config.coreBasicItem.muxEnabled && !Utils.IsNullOrEmpty(_config.mux4SboxItem.protocol))
|
||||
if (_config.coreBasicItem.muxEnabled && Utils.IsNotEmpty(_config.mux4SboxItem.protocol))
|
||||
{
|
||||
var mux = new Multiplex4Sbox()
|
||||
{
|
||||
@@ -721,11 +721,11 @@ namespace ServiceLib.Handler.CoreConfig
|
||||
if (node.streamSecurity == Global.StreamSecurityReality || node.streamSecurity == Global.StreamSecurity)
|
||||
{
|
||||
var server_name = string.Empty;
|
||||
if (!Utils.IsNullOrEmpty(node.sni))
|
||||
if (Utils.IsNotEmpty(node.sni))
|
||||
{
|
||||
server_name = node.sni;
|
||||
}
|
||||
else if (!Utils.IsNullOrEmpty(node.requestHost))
|
||||
else if (Utils.IsNotEmpty(node.requestHost))
|
||||
{
|
||||
server_name = Utils.String2List(node.requestHost)[0];
|
||||
}
|
||||
@@ -736,7 +736,7 @@ namespace ServiceLib.Handler.CoreConfig
|
||||
insecure = Utils.ToBool(node.allowInsecure.IsNullOrEmpty() ? _config.coreBasicItem.defAllowInsecure.ToString().ToLower() : node.allowInsecure),
|
||||
alpn = node.GetAlpn(),
|
||||
};
|
||||
if (!Utils.IsNullOrEmpty(node.fingerprint))
|
||||
if (Utils.IsNotEmpty(node.fingerprint))
|
||||
{
|
||||
tls.utls = new Utls4Sbox()
|
||||
{
|
||||
@@ -798,7 +798,7 @@ namespace ServiceLib.Handler.CoreConfig
|
||||
case nameof(ETransport.ws):
|
||||
transport.type = nameof(ETransport.ws);
|
||||
transport.path = Utils.IsNullOrEmpty(node.path) ? null : node.path;
|
||||
if (!Utils.IsNullOrEmpty(node.requestHost))
|
||||
if (Utils.IsNotEmpty(node.requestHost))
|
||||
{
|
||||
transport.headers = new()
|
||||
{
|
||||
@@ -1020,7 +1020,7 @@ namespace ServiceLib.Handler.CoreConfig
|
||||
outbound = item.outboundTag,
|
||||
};
|
||||
|
||||
if (!Utils.IsNullOrEmpty(item.port))
|
||||
if (Utils.IsNotEmpty(item.port))
|
||||
{
|
||||
if (item.port.Contains("-"))
|
||||
{
|
||||
@@ -1031,7 +1031,7 @@ namespace ServiceLib.Handler.CoreConfig
|
||||
rule.port = new List<int> { Utils.ToInt(item.port) };
|
||||
}
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(item.network))
|
||||
if (Utils.IsNotEmpty(item.network))
|
||||
{
|
||||
rule.network = Utils.String2List(item.network);
|
||||
}
|
||||
@@ -1221,7 +1221,7 @@ namespace ServiceLib.Handler.CoreConfig
|
||||
});
|
||||
|
||||
var lstDomain = singboxConfig.outbounds
|
||||
.Where(t => !Utils.IsNullOrEmpty(t.server) && Utils.IsDomain(t.server))
|
||||
.Where(t => Utils.IsNotEmpty(t.server) && Utils.IsDomain(t.server))
|
||||
.Select(t => t.server)
|
||||
.Distinct()
|
||||
.ToList();
|
||||
@@ -1324,10 +1324,10 @@ namespace ServiceLib.Handler.CoreConfig
|
||||
if (_config.routingBasicItem.enableRoutingAdvanced)
|
||||
{
|
||||
var routing = ConfigHandler.GetDefaultRouting(_config);
|
||||
if (!Utils.IsNullOrEmpty(routing.customRulesetPath4Singbox))
|
||||
if (Utils.IsNotEmpty(routing.customRulesetPath4Singbox))
|
||||
{
|
||||
var result = Utils.LoadResource(routing.customRulesetPath4Singbox);
|
||||
if (!Utils.IsNullOrEmpty(result))
|
||||
if (Utils.IsNotEmpty(result))
|
||||
{
|
||||
customRulesets = (JsonUtils.Deserialize<List<Ruleset4Sbox>>(result) ?? [])
|
||||
.Where(t => t.tag != null)
|
||||
|
@@ -392,7 +392,7 @@ namespace ServiceLib.Handler.CoreConfig
|
||||
v2rayConfig.inbounds.Add(inbound4);
|
||||
|
||||
//auth
|
||||
if (!Utils.IsNullOrEmpty(_config.inbound[0].user) && !Utils.IsNullOrEmpty(_config.inbound[0].pass))
|
||||
if (Utils.IsNotEmpty(_config.inbound[0].user) && Utils.IsNotEmpty(_config.inbound[0].pass))
|
||||
{
|
||||
inbound3.settings.auth = "password";
|
||||
inbound3.settings.accounts = new List<AccountsItem4Ray> { new AccountsItem4Ray() { user = _config.inbound[0].user, pass = _config.inbound[0].pass } };
|
||||
@@ -453,7 +453,7 @@ namespace ServiceLib.Handler.CoreConfig
|
||||
var routing = ConfigHandler.GetDefaultRouting(_config);
|
||||
if (routing != null)
|
||||
{
|
||||
if (!Utils.IsNullOrEmpty(routing.domainStrategy))
|
||||
if (Utils.IsNotEmpty(routing.domainStrategy))
|
||||
{
|
||||
v2rayConfig.routing.domainStrategy = routing.domainStrategy;
|
||||
}
|
||||
@@ -550,7 +550,7 @@ namespace ServiceLib.Handler.CoreConfig
|
||||
}
|
||||
if (!hasDomainIp)
|
||||
{
|
||||
if (!Utils.IsNullOrEmpty(rule.port)
|
||||
if (Utils.IsNotEmpty(rule.port)
|
||||
|| rule.protocol?.Count > 0
|
||||
|| rule.inboundTag?.Count > 0
|
||||
)
|
||||
@@ -660,8 +660,8 @@ namespace ServiceLib.Handler.CoreConfig
|
||||
serversItem.method = null;
|
||||
serversItem.password = null;
|
||||
|
||||
if (!Utils.IsNullOrEmpty(node.security)
|
||||
&& !Utils.IsNullOrEmpty(node.id))
|
||||
if (Utils.IsNotEmpty(node.security)
|
||||
&& Utils.IsNotEmpty(node.id))
|
||||
{
|
||||
SocksUsersItem4Ray socksUsersItem = new()
|
||||
{
|
||||
@@ -712,7 +712,7 @@ namespace ServiceLib.Handler.CoreConfig
|
||||
if (node.streamSecurity == Global.StreamSecurityReality
|
||||
|| node.streamSecurity == Global.StreamSecurity)
|
||||
{
|
||||
if (!Utils.IsNullOrEmpty(node.flow))
|
||||
if (Utils.IsNotEmpty(node.flow))
|
||||
{
|
||||
usersItem.flow = node.flow;
|
||||
|
||||
@@ -818,11 +818,11 @@ namespace ServiceLib.Handler.CoreConfig
|
||||
alpn = node.GetAlpn(),
|
||||
fingerprint = node.fingerprint.IsNullOrEmpty() ? _config.coreBasicItem.defFingerprint : node.fingerprint
|
||||
};
|
||||
if (!Utils.IsNullOrEmpty(sni))
|
||||
if (Utils.IsNotEmpty(sni))
|
||||
{
|
||||
tlsSettings.serverName = sni;
|
||||
}
|
||||
else if (!Utils.IsNullOrEmpty(host))
|
||||
else if (Utils.IsNotEmpty(host))
|
||||
{
|
||||
tlsSettings.serverName = Utils.String2List(host)[0];
|
||||
}
|
||||
@@ -867,7 +867,7 @@ namespace ServiceLib.Handler.CoreConfig
|
||||
{
|
||||
type = node.headerType
|
||||
};
|
||||
if (!Utils.IsNullOrEmpty(node.path))
|
||||
if (Utils.IsNotEmpty(node.path))
|
||||
{
|
||||
kcpSettings.seed = node.path;
|
||||
}
|
||||
@@ -878,15 +878,15 @@ namespace ServiceLib.Handler.CoreConfig
|
||||
WsSettings4Ray wsSettings = new();
|
||||
wsSettings.headers = new Headers4Ray();
|
||||
string path = node.path;
|
||||
if (!Utils.IsNullOrEmpty(host))
|
||||
if (Utils.IsNotEmpty(host))
|
||||
{
|
||||
wsSettings.headers.Host = host;
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(path))
|
||||
if (Utils.IsNotEmpty(path))
|
||||
{
|
||||
wsSettings.path = path;
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(useragent))
|
||||
if (Utils.IsNotEmpty(useragent))
|
||||
{
|
||||
wsSettings.headers.UserAgent = useragent;
|
||||
}
|
||||
@@ -897,11 +897,11 @@ namespace ServiceLib.Handler.CoreConfig
|
||||
case nameof(ETransport.httpupgrade):
|
||||
HttpupgradeSettings4Ray httpupgradeSettings = new();
|
||||
|
||||
if (!Utils.IsNullOrEmpty(node.path))
|
||||
if (Utils.IsNotEmpty(node.path))
|
||||
{
|
||||
httpupgradeSettings.path = node.path;
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(host))
|
||||
if (Utils.IsNotEmpty(host))
|
||||
{
|
||||
httpupgradeSettings.host = host;
|
||||
}
|
||||
@@ -916,11 +916,11 @@ namespace ServiceLib.Handler.CoreConfig
|
||||
maxConcurrentUploads = 10
|
||||
};
|
||||
|
||||
if (!Utils.IsNullOrEmpty(node.path))
|
||||
if (Utils.IsNotEmpty(node.path))
|
||||
{
|
||||
splithttpSettings.path = node.path;
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(host))
|
||||
if (Utils.IsNotEmpty(host))
|
||||
{
|
||||
splithttpSettings.host = host;
|
||||
}
|
||||
@@ -931,7 +931,7 @@ namespace ServiceLib.Handler.CoreConfig
|
||||
case nameof(ETransport.h2):
|
||||
HttpSettings4Ray httpSettings = new();
|
||||
|
||||
if (!Utils.IsNullOrEmpty(host))
|
||||
if (Utils.IsNotEmpty(host))
|
||||
{
|
||||
httpSettings.host = Utils.String2List(host);
|
||||
}
|
||||
@@ -954,7 +954,7 @@ namespace ServiceLib.Handler.CoreConfig
|
||||
streamSettings.quicSettings = quicsettings;
|
||||
if (node.streamSecurity == Global.StreamSecurity)
|
||||
{
|
||||
if (!Utils.IsNullOrEmpty(sni))
|
||||
if (Utils.IsNotEmpty(sni))
|
||||
{
|
||||
streamSettings.tlsSettings.serverName = sni;
|
||||
}
|
||||
@@ -1000,7 +1000,7 @@ namespace ServiceLib.Handler.CoreConfig
|
||||
request = request.Replace("$requestUserAgent$", $"\"{useragent}\"");
|
||||
//Path
|
||||
string pathHttp = @"/";
|
||||
if (!Utils.IsNullOrEmpty(node.path))
|
||||
if (Utils.IsNotEmpty(node.path))
|
||||
{
|
||||
string[] arrPath = node.path.Split(',');
|
||||
pathHttp = string.Join("\",\"", arrPath);
|
||||
@@ -1033,7 +1033,7 @@ namespace ServiceLib.Handler.CoreConfig
|
||||
}
|
||||
|
||||
//Outbound Freedom domainStrategy
|
||||
if (!Utils.IsNullOrEmpty(domainStrategy4Freedom))
|
||||
if (Utils.IsNotEmpty(domainStrategy4Freedom))
|
||||
{
|
||||
var outbound = v2rayConfig.outbounds[1];
|
||||
outbound.settings.domainStrategy = domainStrategy4Freedom;
|
||||
@@ -1157,7 +1157,7 @@ namespace ServiceLib.Handler.CoreConfig
|
||||
{
|
||||
//fragment proxy
|
||||
if (_config.coreBasicItem.enableFragment
|
||||
&& !Utils.IsNullOrEmpty(v2rayConfig.outbounds[0].streamSettings?.security))
|
||||
&& Utils.IsNotEmpty(v2rayConfig.outbounds[0].streamSettings?.security))
|
||||
{
|
||||
var fragmentOutbound = new Outbounds4Ray
|
||||
{
|
||||
|
@@ -302,7 +302,7 @@ namespace ServiceLib.Handler
|
||||
{
|
||||
proc.OutputDataReceived += (sender, e) =>
|
||||
{
|
||||
if (!Utils.IsNullOrEmpty(e.Data))
|
||||
if (Utils.IsNotEmpty(e.Data))
|
||||
{
|
||||
string msg = e.Data + Environment.NewLine;
|
||||
ShowMsg(false, msg);
|
||||
@@ -310,7 +310,7 @@ namespace ServiceLib.Handler
|
||||
};
|
||||
proc.ErrorDataReceived += (sender, e) =>
|
||||
{
|
||||
if (!Utils.IsNullOrEmpty(e.Data))
|
||||
if (Utils.IsNotEmpty(e.Data))
|
||||
{
|
||||
string msg = e.Data + Environment.NewLine;
|
||||
ShowMsg(false, msg);
|
||||
|
@@ -117,7 +117,7 @@ namespace ServiceLib.Handler
|
||||
try
|
||||
{
|
||||
var result1 = await DownloadStringAsync(url, blProxy, userAgent);
|
||||
if (!Utils.IsNullOrEmpty(result1))
|
||||
if (Utils.IsNotEmpty(result1))
|
||||
{
|
||||
return result1;
|
||||
}
|
||||
@@ -135,7 +135,7 @@ namespace ServiceLib.Handler
|
||||
try
|
||||
{
|
||||
var result2 = await DownloadStringViaDownloader(url, blProxy, userAgent);
|
||||
if (!Utils.IsNullOrEmpty(result2))
|
||||
if (Utils.IsNotEmpty(result2))
|
||||
{
|
||||
return result2;
|
||||
}
|
||||
@@ -155,7 +155,7 @@ namespace ServiceLib.Handler
|
||||
using var wc = new WebClient();
|
||||
wc.Proxy = GetWebProxy(blProxy);
|
||||
var result3 = await wc.DownloadStringTaskAsync(url);
|
||||
if (!Utils.IsNullOrEmpty(result3))
|
||||
if (Utils.IsNotEmpty(result3))
|
||||
{
|
||||
return result3;
|
||||
}
|
||||
@@ -197,7 +197,7 @@ namespace ServiceLib.Handler
|
||||
|
||||
Uri uri = new(url);
|
||||
//Authorization Header
|
||||
if (!Utils.IsNullOrEmpty(uri.UserInfo))
|
||||
if (Utils.IsNotEmpty(uri.UserInfo))
|
||||
{
|
||||
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Utils.Base64Encode(uri.UserInfo));
|
||||
}
|
||||
|
@@ -16,12 +16,12 @@ namespace ServiceLib.Handler.Fmt
|
||||
|
||||
protected static int GetStdTransport(ProfileItem item, string? securityDef, ref Dictionary<string, string> dicQuery)
|
||||
{
|
||||
if (!Utils.IsNullOrEmpty(item.flow))
|
||||
if (Utils.IsNotEmpty(item.flow))
|
||||
{
|
||||
dicQuery.Add("flow", item.flow);
|
||||
}
|
||||
|
||||
if (!Utils.IsNullOrEmpty(item.streamSecurity))
|
||||
if (Utils.IsNotEmpty(item.streamSecurity))
|
||||
{
|
||||
dicQuery.Add("security", item.streamSecurity);
|
||||
}
|
||||
@@ -32,27 +32,27 @@ namespace ServiceLib.Handler.Fmt
|
||||
dicQuery.Add("security", securityDef);
|
||||
}
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(item.sni))
|
||||
if (Utils.IsNotEmpty(item.sni))
|
||||
{
|
||||
dicQuery.Add("sni", item.sni);
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(item.alpn))
|
||||
if (Utils.IsNotEmpty(item.alpn))
|
||||
{
|
||||
dicQuery.Add("alpn", Utils.UrlEncode(item.alpn));
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(item.fingerprint))
|
||||
if (Utils.IsNotEmpty(item.fingerprint))
|
||||
{
|
||||
dicQuery.Add("fp", Utils.UrlEncode(item.fingerprint));
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(item.publicKey))
|
||||
if (Utils.IsNotEmpty(item.publicKey))
|
||||
{
|
||||
dicQuery.Add("pbk", Utils.UrlEncode(item.publicKey));
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(item.shortId))
|
||||
if (Utils.IsNotEmpty(item.shortId))
|
||||
{
|
||||
dicQuery.Add("sid", Utils.UrlEncode(item.shortId));
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(item.spiderX))
|
||||
if (Utils.IsNotEmpty(item.spiderX))
|
||||
{
|
||||
dicQuery.Add("spx", Utils.UrlEncode(item.spiderX));
|
||||
}
|
||||
@@ -61,21 +61,21 @@ namespace ServiceLib.Handler.Fmt
|
||||
dicQuery.Add("allowInsecure", "1");
|
||||
}
|
||||
|
||||
dicQuery.Add("type", !Utils.IsNullOrEmpty(item.network) ? item.network : nameof(ETransport.tcp));
|
||||
dicQuery.Add("type", Utils.IsNotEmpty(item.network) ? item.network : nameof(ETransport.tcp));
|
||||
|
||||
switch (item.network)
|
||||
{
|
||||
case nameof(ETransport.tcp):
|
||||
dicQuery.Add("headerType", !Utils.IsNullOrEmpty(item.headerType) ? item.headerType : Global.None);
|
||||
if (!Utils.IsNullOrEmpty(item.requestHost))
|
||||
dicQuery.Add("headerType", Utils.IsNotEmpty(item.headerType) ? item.headerType : Global.None);
|
||||
if (Utils.IsNotEmpty(item.requestHost))
|
||||
{
|
||||
dicQuery.Add("host", Utils.UrlEncode(item.requestHost));
|
||||
}
|
||||
break;
|
||||
|
||||
case nameof(ETransport.kcp):
|
||||
dicQuery.Add("headerType", !Utils.IsNullOrEmpty(item.headerType) ? item.headerType : Global.None);
|
||||
if (!Utils.IsNullOrEmpty(item.path))
|
||||
dicQuery.Add("headerType", Utils.IsNotEmpty(item.headerType) ? item.headerType : Global.None);
|
||||
if (Utils.IsNotEmpty(item.path))
|
||||
{
|
||||
dicQuery.Add("seed", Utils.UrlEncode(item.path));
|
||||
}
|
||||
@@ -84,11 +84,11 @@ namespace ServiceLib.Handler.Fmt
|
||||
case nameof(ETransport.ws):
|
||||
case nameof(ETransport.httpupgrade):
|
||||
case nameof(ETransport.splithttp):
|
||||
if (!Utils.IsNullOrEmpty(item.requestHost))
|
||||
if (Utils.IsNotEmpty(item.requestHost))
|
||||
{
|
||||
dicQuery.Add("host", Utils.UrlEncode(item.requestHost));
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(item.path))
|
||||
if (Utils.IsNotEmpty(item.path))
|
||||
{
|
||||
dicQuery.Add("path", Utils.UrlEncode(item.path));
|
||||
}
|
||||
@@ -97,24 +97,24 @@ namespace ServiceLib.Handler.Fmt
|
||||
case nameof(ETransport.http):
|
||||
case nameof(ETransport.h2):
|
||||
dicQuery["type"] = nameof(ETransport.http);
|
||||
if (!Utils.IsNullOrEmpty(item.requestHost))
|
||||
if (Utils.IsNotEmpty(item.requestHost))
|
||||
{
|
||||
dicQuery.Add("host", Utils.UrlEncode(item.requestHost));
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(item.path))
|
||||
if (Utils.IsNotEmpty(item.path))
|
||||
{
|
||||
dicQuery.Add("path", Utils.UrlEncode(item.path));
|
||||
}
|
||||
break;
|
||||
|
||||
case nameof(ETransport.quic):
|
||||
dicQuery.Add("headerType", !Utils.IsNullOrEmpty(item.headerType) ? item.headerType : Global.None);
|
||||
dicQuery.Add("headerType", Utils.IsNotEmpty(item.headerType) ? item.headerType : Global.None);
|
||||
dicQuery.Add("quicSecurity", Utils.UrlEncode(item.requestHost));
|
||||
dicQuery.Add("key", Utils.UrlEncode(item.path));
|
||||
break;
|
||||
|
||||
case nameof(ETransport.grpc):
|
||||
if (!Utils.IsNullOrEmpty(item.path))
|
||||
if (Utils.IsNotEmpty(item.path))
|
||||
{
|
||||
dicQuery.Add("authority", Utils.UrlEncode(item.requestHost));
|
||||
dicQuery.Add("serviceName", Utils.UrlEncode(item.path));
|
||||
|
@@ -31,20 +31,20 @@
|
||||
string url = string.Empty;
|
||||
|
||||
string remark = string.Empty;
|
||||
if (!Utils.IsNullOrEmpty(item.remarks))
|
||||
if (Utils.IsNotEmpty(item.remarks))
|
||||
{
|
||||
remark = "#" + Utils.UrlEncode(item.remarks);
|
||||
}
|
||||
var dicQuery = new Dictionary<string, string>();
|
||||
if (!Utils.IsNullOrEmpty(item.sni))
|
||||
if (Utils.IsNotEmpty(item.sni))
|
||||
{
|
||||
dicQuery.Add("sni", item.sni);
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(item.alpn))
|
||||
if (Utils.IsNotEmpty(item.alpn))
|
||||
{
|
||||
dicQuery.Add("alpn", Utils.UrlEncode(item.alpn));
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(item.path))
|
||||
if (Utils.IsNotEmpty(item.path))
|
||||
{
|
||||
dicQuery.Add("obfs", "salamander");
|
||||
dicQuery.Add("obfs-password", Utils.UrlEncode(item.path));
|
||||
|
@@ -30,7 +30,7 @@ namespace ServiceLib.Handler.Fmt
|
||||
string url = string.Empty;
|
||||
|
||||
string remark = string.Empty;
|
||||
if (!Utils.IsNullOrEmpty(item.remarks))
|
||||
if (Utils.IsNotEmpty(item.remarks))
|
||||
{
|
||||
remark = "#" + Utils.UrlEncode(item.remarks);
|
||||
}
|
||||
@@ -59,7 +59,7 @@ namespace ServiceLib.Handler.Fmt
|
||||
ProfileItem item = new();
|
||||
var base64 = match.Groups["base64"].Value.TrimEnd('/');
|
||||
var tag = match.Groups["tag"].Value;
|
||||
if (!Utils.IsNullOrEmpty(tag))
|
||||
if (Utils.IsNotEmpty(tag))
|
||||
{
|
||||
item.remarks = Utils.UrlDecode(tag);
|
||||
}
|
||||
@@ -128,7 +128,7 @@ namespace ServiceLib.Handler.Fmt
|
||||
{
|
||||
//obfs-host exists
|
||||
var obfsHost = queryParameters["plugin"]?.Split(';').FirstOrDefault(t => t.Contains("obfs-host"));
|
||||
if (queryParameters["plugin"].Contains("obfs=http") && !Utils.IsNullOrEmpty(obfsHost))
|
||||
if (queryParameters["plugin"].Contains("obfs=http") && Utils.IsNotEmpty(obfsHost))
|
||||
{
|
||||
obfsHost = obfsHost?.Replace("obfs-host=", "");
|
||||
item.network = Global.DefaultNetwork;
|
||||
|
@@ -28,7 +28,7 @@
|
||||
string url = string.Empty;
|
||||
|
||||
string remark = string.Empty;
|
||||
if (!Utils.IsNullOrEmpty(item.remarks))
|
||||
if (Utils.IsNotEmpty(item.remarks))
|
||||
{
|
||||
remark = "#" + Utils.UrlEncode(item.remarks);
|
||||
}
|
||||
|
@@ -30,7 +30,7 @@
|
||||
string url = string.Empty;
|
||||
|
||||
string remark = string.Empty;
|
||||
if (!Utils.IsNullOrEmpty(item.remarks))
|
||||
if (Utils.IsNotEmpty(item.remarks))
|
||||
{
|
||||
remark = "#" + Utils.UrlEncode(item.remarks);
|
||||
}
|
||||
|
@@ -36,16 +36,16 @@
|
||||
string url = string.Empty;
|
||||
|
||||
string remark = string.Empty;
|
||||
if (!Utils.IsNullOrEmpty(item.remarks))
|
||||
if (Utils.IsNotEmpty(item.remarks))
|
||||
{
|
||||
remark = "#" + Utils.UrlEncode(item.remarks);
|
||||
}
|
||||
var dicQuery = new Dictionary<string, string>();
|
||||
if (!Utils.IsNullOrEmpty(item.sni))
|
||||
if (Utils.IsNotEmpty(item.sni))
|
||||
{
|
||||
dicQuery.Add("sni", item.sni);
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(item.alpn))
|
||||
if (Utils.IsNotEmpty(item.alpn))
|
||||
{
|
||||
dicQuery.Add("alpn", Utils.UrlEncode(item.alpn));
|
||||
}
|
||||
|
@@ -33,12 +33,12 @@
|
||||
string url = string.Empty;
|
||||
|
||||
string remark = string.Empty;
|
||||
if (!Utils.IsNullOrEmpty(item.remarks))
|
||||
if (Utils.IsNotEmpty(item.remarks))
|
||||
{
|
||||
remark = "#" + Utils.UrlEncode(item.remarks);
|
||||
}
|
||||
var dicQuery = new Dictionary<string, string>();
|
||||
if (!Utils.IsNullOrEmpty(item.security))
|
||||
if (Utils.IsNotEmpty(item.security))
|
||||
{
|
||||
dicQuery.Add("encryption", item.security);
|
||||
}
|
||||
|
@@ -78,12 +78,12 @@
|
||||
item.alterId = Utils.ToInt(vmessQRCode.aid);
|
||||
item.security = Utils.ToString(vmessQRCode.scy);
|
||||
|
||||
item.security = !Utils.IsNullOrEmpty(vmessQRCode.scy) ? vmessQRCode.scy : Global.DefaultSecurity;
|
||||
if (!Utils.IsNullOrEmpty(vmessQRCode.net))
|
||||
item.security = Utils.IsNotEmpty(vmessQRCode.scy) ? vmessQRCode.scy : Global.DefaultSecurity;
|
||||
if (Utils.IsNotEmpty(vmessQRCode.net))
|
||||
{
|
||||
item.network = vmessQRCode.net;
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(vmessQRCode.type))
|
||||
if (Utils.IsNotEmpty(vmessQRCode.type))
|
||||
{
|
||||
item.headerType = vmessQRCode.type;
|
||||
}
|
||||
|
@@ -34,25 +34,25 @@
|
||||
string url = string.Empty;
|
||||
|
||||
string remark = string.Empty;
|
||||
if (!Utils.IsNullOrEmpty(item.remarks))
|
||||
if (Utils.IsNotEmpty(item.remarks))
|
||||
{
|
||||
remark = "#" + Utils.UrlEncode(item.remarks);
|
||||
}
|
||||
|
||||
var dicQuery = new Dictionary<string, string>();
|
||||
if (!Utils.IsNullOrEmpty(item.publicKey))
|
||||
if (Utils.IsNotEmpty(item.publicKey))
|
||||
{
|
||||
dicQuery.Add("publickey", Utils.UrlEncode(item.publicKey));
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(item.path))
|
||||
if (Utils.IsNotEmpty(item.path))
|
||||
{
|
||||
dicQuery.Add("reserved", Utils.UrlEncode(item.path));
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(item.requestHost))
|
||||
if (Utils.IsNotEmpty(item.requestHost))
|
||||
{
|
||||
dicQuery.Add("address", Utils.UrlEncode(item.requestHost));
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(item.shortId))
|
||||
if (Utils.IsNotEmpty(item.shortId))
|
||||
{
|
||||
dicQuery.Add("mtu", Utils.UrlEncode(item.shortId));
|
||||
}
|
||||
|
@@ -104,11 +104,11 @@
|
||||
from ProfileItem a
|
||||
left join SubItem b on a.subid = b.id
|
||||
where 1=1 ";
|
||||
if (!Utils.IsNullOrEmpty(subid))
|
||||
if (Utils.IsNotEmpty(subid))
|
||||
{
|
||||
sql += $" and a.subid = '{subid}'";
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(filter))
|
||||
if (Utils.IsNotEmpty(filter))
|
||||
{
|
||||
if (filter.Contains('\''))
|
||||
{
|
||||
|
@@ -35,7 +35,7 @@ namespace ServiceLib.Handler
|
||||
|
||||
private void IndexIdEnqueue(string indexId)
|
||||
{
|
||||
if (!Utils.IsNullOrEmpty(indexId) && !_queIndexIds.Contains(indexId))
|
||||
if (Utils.IsNotEmpty(indexId) && !_queIndexIds.Contains(indexId))
|
||||
{
|
||||
_queIndexIds.Enqueue(indexId);
|
||||
}
|
||||
|
@@ -88,7 +88,7 @@ namespace ServiceLib.Handler.Statistics
|
||||
while (!res.CloseStatus.HasValue)
|
||||
{
|
||||
var result = Encoding.UTF8.GetString(buffer, 0, res.Count);
|
||||
if (!Utils.IsNullOrEmpty(result))
|
||||
if (Utils.IsNotEmpty(result))
|
||||
{
|
||||
ParseOutput(result, out ulong up, out ulong down);
|
||||
|
||||
|
@@ -143,7 +143,7 @@ namespace ServiceLib.Handler
|
||||
string url = item.url.TrimEx();
|
||||
string userAgent = item.userAgent.TrimEx();
|
||||
string hashCode = $"{item.remarks}->";
|
||||
if (Utils.IsNullOrEmpty(id) || Utils.IsNullOrEmpty(url) || (!Utils.IsNullOrEmpty(subId) && item.id != subId))
|
||||
if (Utils.IsNullOrEmpty(id) || Utils.IsNullOrEmpty(url) || (Utils.IsNotEmpty(subId) && item.id != subId))
|
||||
{
|
||||
//_updateFunc(false, $"{hashCode}{ResUI.MsgNoValidSubscription}");
|
||||
continue;
|
||||
@@ -169,7 +169,7 @@ namespace ServiceLib.Handler
|
||||
//one url
|
||||
url = Utils.GetPunycode(url);
|
||||
//convert
|
||||
if (!Utils.IsNullOrEmpty(item.convertTarget))
|
||||
if (Utils.IsNotEmpty(item.convertTarget))
|
||||
{
|
||||
var subConvertUrl = Utils.IsNullOrEmpty(config.constItem.subConvertUrl) ? Global.SubConvertUrls.FirstOrDefault() : config.constItem.subConvertUrl;
|
||||
url = string.Format(subConvertUrl!, Utils.UrlEncode(url));
|
||||
@@ -189,9 +189,9 @@ namespace ServiceLib.Handler
|
||||
}
|
||||
|
||||
//more url
|
||||
if (Utils.IsNullOrEmpty(item.convertTarget) && !Utils.IsNullOrEmpty(item.moreUrl.TrimEx()))
|
||||
if (Utils.IsNullOrEmpty(item.convertTarget) && Utils.IsNotEmpty(item.moreUrl.TrimEx()))
|
||||
{
|
||||
if (!Utils.IsNullOrEmpty(result) && Utils.IsBase64String(result!))
|
||||
if (Utils.IsNotEmpty(result) && Utils.IsBase64String(result!))
|
||||
{
|
||||
result = Utils.Base64Decode(result);
|
||||
}
|
||||
@@ -210,7 +210,7 @@ namespace ServiceLib.Handler
|
||||
{
|
||||
result2 = await downloadHandle.TryDownloadString(url2, false, userAgent);
|
||||
}
|
||||
if (!Utils.IsNullOrEmpty(result2))
|
||||
if (Utils.IsNotEmpty(result2))
|
||||
{
|
||||
if (Utils.IsBase64String(result2!))
|
||||
{
|
||||
@@ -277,7 +277,7 @@ namespace ServiceLib.Handler
|
||||
var url = coreInfo?.coreReleaseApiUrl;
|
||||
|
||||
var result = await downloadHandle.DownloadStringAsync(url, true, Global.AppName);
|
||||
if (!Utils.IsNullOrEmpty(result))
|
||||
if (Utils.IsNotEmpty(result))
|
||||
{
|
||||
return await ParseDownloadUrl(type, result, preRelease);
|
||||
}
|
||||
|
9
v2rayn/v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
9
v2rayn/v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
@@ -105,6 +105,15 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Host filter 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string ConnectionsHostFilterTitle {
|
||||
get {
|
||||
return ResourceManager.GetString("ConnectionsHostFilterTitle", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Note that custom configuration relies entirely on your own configuration and does not work with all settings. If you want to use the system proxy, please modify the listening port manually. 的本地化字符串。
|
||||
/// </summary>
|
||||
|
@@ -1318,4 +1318,7 @@
|
||||
<data name="LocalRestoreInvalidZipTips" xml:space="preserve">
|
||||
<value>Invalid backup file</value>
|
||||
</data>
|
||||
<data name="ConnectionsHostFilterTitle" xml:space="preserve">
|
||||
<value>Host filter</value>
|
||||
</data>
|
||||
</root>
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user