136 lines
2.5 KiB
Go
136 lines
2.5 KiB
Go
package proxy
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/ivpusic/grpool"
|
|
|
|
"github.com/Dreamacro/clash/adapters/outbound"
|
|
)
|
|
|
|
const defaultURLTestTimeout = time.Second * 5
|
|
|
|
func testDelay(p Proxy) (delay uint16, err error) {
|
|
pmap := make(map[string]interface{})
|
|
err = json.Unmarshal([]byte(p.String()), &pmap)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
pmap["port"] = int(pmap["port"].(float64))
|
|
if p.TypeName() == "vmess" {
|
|
pmap["alterId"] = int(pmap["alterId"].(float64))
|
|
}
|
|
|
|
clashProxy, err := outbound.ParseProxy(pmap)
|
|
if err != nil {
|
|
fmt.Println(err.Error())
|
|
return
|
|
}
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), defaultURLTestTimeout)
|
|
delay, err = clashProxy.URLTest(ctx, "http://www.gstatic.com/generate_204")
|
|
cancel()
|
|
return delay, err
|
|
}
|
|
|
|
func CleanBadProxiesWithGrpool(proxies []Proxy) (cproxies []Proxy) {
|
|
pool := grpool.NewPool(500, 200)
|
|
|
|
c := make(chan checkResult)
|
|
defer close(c)
|
|
|
|
pool.WaitCount(len(proxies))
|
|
go func() {
|
|
for _, p := range proxies {
|
|
pp := p
|
|
pool.JobQueue <- func() {
|
|
defer pool.JobDone()
|
|
delay, err := testDelay(pp)
|
|
if err == nil {
|
|
c <- checkResult{
|
|
name: pp.Identifier(),
|
|
delay: delay,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}()
|
|
done := make(chan struct{})
|
|
defer close(done)
|
|
|
|
go func() {
|
|
pool.WaitAll()
|
|
pool.Release()
|
|
done <- struct{}{}
|
|
}()
|
|
|
|
okMap := make(map[string]struct{})
|
|
for {
|
|
select {
|
|
case r := <-c:
|
|
if r.delay > 0 {
|
|
okMap[r.name] = struct{}{}
|
|
}
|
|
case <-done:
|
|
cproxies = make(ProxyList, 0, 500)
|
|
for _, p := range proxies {
|
|
if _, ok := okMap[p.Identifier()]; ok {
|
|
cproxies = append(cproxies, p.Clone())
|
|
}
|
|
}
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func CleanBadProxies(proxies []Proxy) (cproxies []Proxy) {
|
|
c := make(chan checkResult, 40)
|
|
wg := &sync.WaitGroup{}
|
|
wg.Add(len(proxies))
|
|
for _, p := range proxies {
|
|
go testProxyDelayToChan(p, c, wg)
|
|
}
|
|
go func() {
|
|
wg.Wait()
|
|
close(c)
|
|
}()
|
|
|
|
okMap := make(map[string]struct{})
|
|
for r := range c {
|
|
if r.delay > 0 {
|
|
okMap[r.name] = struct{}{}
|
|
}
|
|
}
|
|
cproxies = make(ProxyList, 0, 500)
|
|
for _, p := range proxies {
|
|
if _, ok := okMap[p.Identifier()]; ok {
|
|
p.SetUseable(true)
|
|
cproxies = append(cproxies, p.Clone())
|
|
} else {
|
|
p.SetUseable(false)
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
type checkResult struct {
|
|
name string
|
|
delay uint16
|
|
}
|
|
|
|
func testProxyDelayToChan(p Proxy, c chan checkResult, wg *sync.WaitGroup) {
|
|
defer wg.Done()
|
|
delay, err := testDelay(p)
|
|
if err == nil {
|
|
c <- checkResult{
|
|
name: p.Identifier(),
|
|
delay: delay,
|
|
}
|
|
}
|
|
}
|