2fa2f7f816
Changelog: Share link import and mrs rule sets
101 lines
2.3 KiB
Go
101 lines
2.3 KiB
Go
package core
|
|
|
|
import (
|
|
"context"
|
|
"sync/atomic"
|
|
"time"
|
|
|
|
"github.com/metacubex/mihomo/common/utils"
|
|
"github.com/metacubex/mihomo/constant"
|
|
)
|
|
|
|
const (
|
|
delayTestConcurrency = 50
|
|
defaultTestURL = "https://www.gstatic.com/generate_204"
|
|
defaultDelayTestTimeout = 5 * time.Second
|
|
)
|
|
|
|
var (
|
|
delayTestSlots = make(slots, delayTestConcurrency)
|
|
anyDelayTestStatus utils.IntRanges[uint16]
|
|
|
|
testURL atomic.Pointer[string]
|
|
missingDelayTestProxyAt atomic.Int64
|
|
)
|
|
|
|
func setTestURL(url string) {
|
|
if url == "" {
|
|
return
|
|
}
|
|
constant.DefaultTestURL = url
|
|
testURL.Store(&url)
|
|
}
|
|
|
|
func currentTestURL() string {
|
|
if url := testURL.Load(); url != nil && *url != "" {
|
|
return *url
|
|
}
|
|
return defaultTestURL
|
|
}
|
|
|
|
const (
|
|
delayTimedOut int32 = -1
|
|
delayFailed int32 = -2
|
|
)
|
|
|
|
func delayValue(delay uint16, timedOut bool) int32 {
|
|
switch {
|
|
case delay > 0:
|
|
return int32(delay)
|
|
case timedOut:
|
|
return delayTimedOut
|
|
default:
|
|
return delayFailed
|
|
}
|
|
}
|
|
|
|
// A name the tunnel does not know is what an apply that fell back to the
|
|
// default config looks like: every node of the profile fails its test. Say so
|
|
// once a second, not once per node, so the log names the real failure.
|
|
func reportMissingDelayTestProxy(name string) {
|
|
now := time.Now().UnixNano()
|
|
last := missingDelayTestProxyAt.Load()
|
|
if last != 0 && now-last < int64(time.Second) {
|
|
return
|
|
}
|
|
if !missingDelayTestProxyAt.CompareAndSwap(last, now) {
|
|
return
|
|
}
|
|
logError("delay test: %q is not part of the applied config", name)
|
|
}
|
|
|
|
// A nil answer means the test never got a slot, which says nothing about the proxy.
|
|
func handleTestDelay(params *TestDelayParams) *Delay {
|
|
url := params.TestUrl
|
|
if url == "" {
|
|
url = currentTestURL()
|
|
}
|
|
result := &Delay{Name: params.ProxyName, Url: url, Value: delayFailed}
|
|
|
|
proxy := lookupProxy(params.ProxyName)
|
|
if proxy == nil {
|
|
reportMissingDelayTestProxy(params.ProxyName)
|
|
return result
|
|
}
|
|
|
|
timeout := timeoutFromMillis(params.Timeout, defaultDelayTestTimeout)
|
|
if !delayTestSlots.acquireWithin(context.Background(), timeout) {
|
|
return nil
|
|
}
|
|
defer delayTestSlots.release()
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
|
defer cancel()
|
|
delay, err := proxy.URLTest(ctx, url, anyDelayTestStatus)
|
|
if err != nil {
|
|
delay = 0
|
|
}
|
|
result.Value = delayValue(delay, ctx.Err() != nil)
|
|
return result
|
|
}
|