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