github.com/xraypb/xray-core@v1.6.6/app/proxyman/outbound/outbound.go (about) 1 package outbound 2 3 //go:generate go run github.com/xraypb/xray-core/common/errors/errorgen 4 5 import ( 6 "context" 7 "strings" 8 "sync" 9 10 "github.com/xraypb/xray-core/app/proxyman" 11 "github.com/xraypb/xray-core/common" 12 "github.com/xraypb/xray-core/common/errors" 13 "github.com/xraypb/xray-core/core" 14 "github.com/xraypb/xray-core/features/outbound" 15 ) 16 17 // Manager is to manage all outbound handlers. 18 type Manager struct { 19 access sync.RWMutex 20 defaultHandler outbound.Handler 21 taggedHandler map[string]outbound.Handler 22 untaggedHandlers []outbound.Handler 23 running bool 24 } 25 26 // New creates a new Manager. 27 func New(ctx context.Context, config *proxyman.OutboundConfig) (*Manager, error) { 28 m := &Manager{ 29 taggedHandler: make(map[string]outbound.Handler), 30 } 31 return m, nil 32 } 33 34 // Type implements common.HasType. 35 func (m *Manager) Type() interface{} { 36 return outbound.ManagerType() 37 } 38 39 // Start implements core.Feature 40 func (m *Manager) Start() error { 41 m.access.Lock() 42 defer m.access.Unlock() 43 44 m.running = true 45 46 for _, h := range m.taggedHandler { 47 if err := h.Start(); err != nil { 48 return err 49 } 50 } 51 52 for _, h := range m.untaggedHandlers { 53 if err := h.Start(); err != nil { 54 return err 55 } 56 } 57 58 return nil 59 } 60 61 // Close implements core.Feature 62 func (m *Manager) Close() error { 63 m.access.Lock() 64 defer m.access.Unlock() 65 66 m.running = false 67 68 var errs []error 69 for _, h := range m.taggedHandler { 70 errs = append(errs, h.Close()) 71 } 72 73 for _, h := range m.untaggedHandlers { 74 errs = append(errs, h.Close()) 75 } 76 77 return errors.Combine(errs...) 78 } 79 80 // GetDefaultHandler implements outbound.Manager. 81 func (m *Manager) GetDefaultHandler() outbound.Handler { 82 m.access.RLock() 83 defer m.access.RUnlock() 84 85 if m.defaultHandler == nil { 86 return nil 87 } 88 return m.defaultHandler 89 } 90 91 // GetHandler implements outbound.Manager. 92 func (m *Manager) GetHandler(tag string) outbound.Handler { 93 m.access.RLock() 94 defer m.access.RUnlock() 95 if handler, found := m.taggedHandler[tag]; found { 96 return handler 97 } 98 return nil 99 } 100 101 // AddHandler implements outbound.Manager. 102 func (m *Manager) AddHandler(ctx context.Context, handler outbound.Handler) error { 103 m.access.Lock() 104 defer m.access.Unlock() 105 106 if m.defaultHandler == nil { 107 m.defaultHandler = handler 108 } 109 110 tag := handler.Tag() 111 if len(tag) > 0 { 112 if _, found := m.taggedHandler[tag]; found { 113 return newError("existing tag found: " + tag) 114 } 115 m.taggedHandler[tag] = handler 116 } else { 117 m.untaggedHandlers = append(m.untaggedHandlers, handler) 118 } 119 120 if m.running { 121 return handler.Start() 122 } 123 124 return nil 125 } 126 127 // RemoveHandler implements outbound.Manager. 128 func (m *Manager) RemoveHandler(ctx context.Context, tag string) error { 129 if tag == "" { 130 return common.ErrNoClue 131 } 132 m.access.Lock() 133 defer m.access.Unlock() 134 135 delete(m.taggedHandler, tag) 136 if m.defaultHandler != nil && m.defaultHandler.Tag() == tag { 137 m.defaultHandler = nil 138 } 139 140 return nil 141 } 142 143 // Select implements outbound.HandlerSelector. 144 func (m *Manager) Select(selectors []string) []string { 145 m.access.RLock() 146 defer m.access.RUnlock() 147 148 tags := make([]string, 0, len(selectors)) 149 150 for tag := range m.taggedHandler { 151 match := false 152 for _, selector := range selectors { 153 if strings.HasPrefix(tag, selector) { 154 match = true 155 break 156 } 157 } 158 if match { 159 tags = append(tags, tag) 160 } 161 } 162 163 return tags 164 } 165 166 func init() { 167 common.Must(common.RegisterConfig((*proxyman.OutboundConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { 168 return New(ctx, config.(*proxyman.OutboundConfig)) 169 })) 170 common.Must(common.RegisterConfig((*core.OutboundHandlerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { 171 return NewHandler(ctx, config.(*core.OutboundHandlerConfig)) 172 })) 173 }