1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283 |
- package box
- import (
- "strings"
- "github.com/sagernet/sing-box/adapter"
- "github.com/sagernet/sing-box/common/taskmonitor"
- C "github.com/sagernet/sing-box/constant"
- "github.com/sagernet/sing/common"
- E "github.com/sagernet/sing/common/exceptions"
- F "github.com/sagernet/sing/common/format"
- )
- func (s *Box) startOutbounds() error {
- monitor := taskmonitor.New(s.logger, C.DefaultStartTimeout)
- outboundTags := make(map[adapter.Outbound]string)
- outbounds := make(map[string]adapter.Outbound)
- for i, outboundToStart := range s.outbounds {
- var outboundTag string
- if outboundToStart.Tag() == "" {
- outboundTag = F.ToString(i)
- } else {
- outboundTag = outboundToStart.Tag()
- }
- if _, exists := outbounds[outboundTag]; exists {
- return E.New("outbound tag ", outboundTag, " duplicated")
- }
- outboundTags[outboundToStart] = outboundTag
- outbounds[outboundTag] = outboundToStart
- }
- started := make(map[string]bool)
- for {
- canContinue := false
- startOne:
- for _, outboundToStart := range s.outbounds {
- outboundTag := outboundTags[outboundToStart]
- if started[outboundTag] {
- continue
- }
- dependencies := outboundToStart.Dependencies()
- for _, dependency := range dependencies {
- if !started[dependency] {
- continue startOne
- }
- }
- started[outboundTag] = true
- canContinue = true
- if starter, isStarter := outboundToStart.(common.Starter); isStarter {
- monitor.Start("initialize outbound/", outboundToStart.Type(), "[", outboundTag, "]")
- err := starter.Start()
- monitor.Finish()
- if err != nil {
- return E.Cause(err, "initialize outbound/", outboundToStart.Type(), "[", outboundTag, "]")
- }
- }
- }
- if len(started) == len(s.outbounds) {
- break
- }
- if canContinue {
- continue
- }
- currentOutbound := common.Find(s.outbounds, func(it adapter.Outbound) bool {
- return !started[outboundTags[it]]
- })
- var lintOutbound func(oTree []string, oCurrent adapter.Outbound) error
- lintOutbound = func(oTree []string, oCurrent adapter.Outbound) error {
- problemOutboundTag := common.Find(oCurrent.Dependencies(), func(it string) bool {
- return !started[it]
- })
- if common.Contains(oTree, problemOutboundTag) {
- return E.New("circular outbound dependency: ", strings.Join(oTree, " -> "), " -> ", problemOutboundTag)
- }
- problemOutbound := outbounds[problemOutboundTag]
- if problemOutbound == nil {
- return E.New("dependency[", problemOutboundTag, "] not found for outbound[", outboundTags[oCurrent], "]")
- }
- return lintOutbound(append(oTree, problemOutboundTag), problemOutbound)
- }
- return lintOutbound([]string{outboundTags[currentOutbound]}, currentOutbound)
- }
- return nil
- }
|