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