github.com/sagernet/sing-box@v1.9.0-rc.20/experimental/libbox/command_urltest.go (about) 1 package libbox 2 3 import ( 4 "encoding/binary" 5 "net" 6 "time" 7 8 "github.com/sagernet/sing-box/adapter" 9 "github.com/sagernet/sing-box/common/urltest" 10 "github.com/sagernet/sing-box/outbound" 11 "github.com/sagernet/sing/common" 12 "github.com/sagernet/sing/common/batch" 13 E "github.com/sagernet/sing/common/exceptions" 14 "github.com/sagernet/sing/common/rw" 15 "github.com/sagernet/sing/service" 16 ) 17 18 func (c *CommandClient) URLTest(groupTag string) error { 19 conn, err := c.directConnect() 20 if err != nil { 21 return err 22 } 23 defer conn.Close() 24 err = binary.Write(conn, binary.BigEndian, uint8(CommandURLTest)) 25 if err != nil { 26 return err 27 } 28 err = rw.WriteVString(conn, groupTag) 29 if err != nil { 30 return err 31 } 32 return readError(conn) 33 } 34 35 func (s *CommandServer) handleURLTest(conn net.Conn) error { 36 groupTag, err := rw.ReadVString(conn) 37 if err != nil { 38 return err 39 } 40 serviceNow := s.service 41 if serviceNow == nil { 42 return nil 43 } 44 abstractOutboundGroup, isLoaded := serviceNow.instance.Router().Outbound(groupTag) 45 if !isLoaded { 46 return writeError(conn, E.New("outbound group not found: ", groupTag)) 47 } 48 outboundGroup, isOutboundGroup := abstractOutboundGroup.(adapter.OutboundGroup) 49 if !isOutboundGroup { 50 return writeError(conn, E.New("outbound is not a group: ", groupTag)) 51 } 52 urlTest, isURLTest := abstractOutboundGroup.(*outbound.URLTest) 53 if isURLTest { 54 go urlTest.CheckOutbounds() 55 } else { 56 historyStorage := service.PtrFromContext[urltest.HistoryStorage](serviceNow.ctx) 57 outbounds := common.Filter(common.Map(outboundGroup.All(), func(it string) adapter.Outbound { 58 itOutbound, _ := serviceNow.instance.Router().Outbound(it) 59 return itOutbound 60 }), func(it adapter.Outbound) bool { 61 if it == nil { 62 return false 63 } 64 _, isGroup := it.(adapter.OutboundGroup) 65 if isGroup { 66 return false 67 } 68 return true 69 }) 70 b, _ := batch.New(serviceNow.ctx, batch.WithConcurrencyNum[any](10)) 71 for _, detour := range outbounds { 72 outboundToTest := detour 73 outboundTag := outboundToTest.Tag() 74 b.Go(outboundTag, func() (any, error) { 75 t, err := urltest.URLTest(serviceNow.ctx, "", outboundToTest) 76 if err != nil { 77 historyStorage.DeleteURLTestHistory(outboundTag) 78 } else { 79 historyStorage.StoreURLTestHistory(outboundTag, &urltest.History{ 80 Time: time.Now(), 81 Delay: t, 82 }) 83 } 84 return nil, nil 85 }) 86 } 87 } 88 return writeError(conn, nil) 89 }