box_outbound.go 2.3 KB

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