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  }