github.com/inazumav/sing-box@v0.0.0-20230926072359-ab51429a14f1/box_outbound.go (about) 1 package box 2 3 import ( 4 "strings" 5 6 "github.com/inazumav/sing-box/adapter" 7 "github.com/sagernet/sing/common" 8 E "github.com/sagernet/sing/common/exceptions" 9 F "github.com/sagernet/sing/common/format" 10 ) 11 12 func (s *Box) startOutbounds() error { 13 outboundTags := make(map[adapter.Outbound]string) 14 outbounds := make(map[string]adapter.Outbound) 15 for i, outboundToStart := range s.outbounds { 16 var outboundTag string 17 if outboundToStart.Tag() == "" { 18 outboundTag = F.ToString(i) 19 } else { 20 outboundTag = outboundToStart.Tag() 21 } 22 if _, exists := outbounds[outboundTag]; exists { 23 return E.New("outbound tag ", outboundTag, " duplicated") 24 } 25 outboundTags[outboundToStart] = outboundTag 26 outbounds[outboundTag] = outboundToStart 27 } 28 started := make(map[string]bool) 29 for { 30 canContinue := false 31 startOne: 32 for _, outboundToStart := range s.outbounds { 33 outboundTag := outboundTags[outboundToStart] 34 if started[outboundTag] { 35 continue 36 } 37 dependencies := outboundToStart.Dependencies() 38 for _, dependency := range dependencies { 39 if !started[dependency] { 40 continue startOne 41 } 42 } 43 started[outboundTag] = true 44 canContinue = true 45 if starter, isStarter := outboundToStart.(common.Starter); isStarter { 46 s.logger.Trace("initializing outbound/", outboundToStart.Type(), "[", outboundTag, "]") 47 err := starter.Start() 48 if err != nil { 49 return E.Cause(err, "initialize outbound/", outboundToStart.Type(), "[", outboundTag, "]") 50 } 51 } 52 } 53 if len(started) == len(s.outbounds) { 54 break 55 } 56 if canContinue { 57 continue 58 } 59 currentOutbound := common.Find(s.outbounds, func(it adapter.Outbound) bool { 60 return !started[outboundTags[it]] 61 }) 62 var lintOutbound func(oTree []string, oCurrent adapter.Outbound) error 63 lintOutbound = func(oTree []string, oCurrent adapter.Outbound) error { 64 problemOutboundTag := common.Find(oCurrent.Dependencies(), func(it string) bool { 65 return !started[it] 66 }) 67 if common.Contains(oTree, problemOutboundTag) { 68 return E.New("circular outbound dependency: ", strings.Join(oTree, " -> "), " -> ", problemOutboundTag) 69 } 70 problemOutbound := outbounds[problemOutboundTag] 71 if problemOutbound == nil { 72 return E.New("dependency[", problemOutbound, "] not found for outbound[", outboundTags[oCurrent], "]") 73 } 74 return lintOutbound(append(oTree, problemOutboundTag), problemOutbound) 75 } 76 return lintOutbound([]string{outboundTags[currentOutbound]}, currentOutbound) 77 } 78 return nil 79 }