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  }