diff --git a/box.go b/box.go index b9f04c87..e7813d95 100644 --- a/box.go +++ b/box.go @@ -15,6 +15,7 @@ import ( "github.com/sagernet/sing-box/common/dialer" "github.com/sagernet/sing-box/common/taskmonitor" "github.com/sagernet/sing-box/common/tls" + "github.com/sagernet/sing-box/common/urltest" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/experimental" "github.com/sagernet/sing-box/experimental/cachefile" @@ -114,6 +115,9 @@ func New(options Options) (*Box, error) { if experimentalOptions.V2RayAPI != nil && experimentalOptions.V2RayAPI.Listen != "" { needV2RayAPI = true } + if experimentalOptions.UnifiedDelay != nil && experimentalOptions.UnifiedDelay.Enabled { + ctx = urltest.ContextWithIsUnifiedDelay(ctx) + } platformInterface := service.FromContext[platform.Interface](ctx) var defaultLogWriter io.Writer if platformInterface != nil { diff --git a/common/urltest/context.go b/common/urltest/context.go new file mode 100644 index 00000000..002ff265 --- /dev/null +++ b/common/urltest/context.go @@ -0,0 +1,13 @@ +package urltest + +import "context" + +type contextKeyIsUnifiedDelay struct{} + +func ContextWithIsUnifiedDelay(ctx context.Context) context.Context { + return context.WithValue(ctx, contextKeyIsUnifiedDelay{}, true) +} + +func IsUnifiedDelayFromContext(ctx context.Context) bool { + return ctx.Value(contextKeyIsUnifiedDelay{}) != nil +} diff --git a/common/urltest/urltest.go b/common/urltest/urltest.go index 9efd0404..3ddb747e 100644 --- a/common/urltest/urltest.go +++ b/common/urltest/urltest.go @@ -122,6 +122,15 @@ func URLTest(ctx context.Context, link string, detour N.Dialer) (t uint16, err e return } resp.Body.Close() + if IsUnifiedDelayFromContext(ctx) { + second := time.Now() + resp, err = client.Do(req) + if err != nil { + return + } + resp.Body.Close() + start = second + } t = uint16(time.Since(start) / time.Millisecond) return } diff --git a/experimental/libbox/service.go b/experimental/libbox/service.go index 16c04a1f..d4ab3b75 100644 --- a/experimental/libbox/service.go +++ b/experimental/libbox/service.go @@ -69,6 +69,10 @@ func NewService(configContent string, platformInterface PlatformInterface) (*Box cancel() return nil, E.Cause(err, "create service") } + experimentalOptions := common.PtrValueOrDefault(options.Experimental) + if experimentalOptions.UnifiedDelay != nil && experimentalOptions.UnifiedDelay.Enabled { + ctx = urltest.ContextWithIsUnifiedDelay(ctx) + } runtimeDebug.FreeOSMemory() return &BoxService{ ctx: ctx, diff --git a/option/experimental.go b/option/experimental.go index 730740a4..0487881b 100644 --- a/option/experimental.go +++ b/option/experimental.go @@ -3,10 +3,11 @@ package option import "github.com/sagernet/sing/common/json/badoption" type ExperimentalOptions struct { - CacheFile *CacheFileOptions `json:"cache_file,omitempty"` - ClashAPI *ClashAPIOptions `json:"clash_api,omitempty"` - V2RayAPI *V2RayAPIOptions `json:"v2ray_api,omitempty"` - Debug *DebugOptions `json:"debug,omitempty"` + CacheFile *CacheFileOptions `json:"cache_file,omitempty"` + ClashAPI *ClashAPIOptions `json:"clash_api,omitempty"` + V2RayAPI *V2RayAPIOptions `json:"v2ray_api,omitempty"` + UnifiedDelay *UnifiedDelayOptions `json:"unified_delay,omitempty"` + Debug *DebugOptions `json:"debug,omitempty"` } type CacheFileOptions struct { @@ -53,3 +54,7 @@ type V2RayStatsServiceOptions struct { Outbounds []string `json:"outbounds,omitempty"` Users []string `json:"users,omitempty"` } + +type UnifiedDelayOptions struct { + Enabled bool `json:"enabled,omitempty"` +}