github.com/imannamdari/v2ray-core/v5@v5.0.5/app/proxyman/outbound/outbound.go (about)

     1  package outbound
     2  
     3  //go:generate go run github.com/imannamdari/v2ray-core/v5/common/errors/errorgen
     4  
     5  import (
     6  	"context"
     7  	"strings"
     8  	"sync"
     9  
    10  	core "github.com/imannamdari/v2ray-core/v5"
    11  	"github.com/imannamdari/v2ray-core/v5/app/proxyman"
    12  	"github.com/imannamdari/v2ray-core/v5/common"
    13  	"github.com/imannamdari/v2ray-core/v5/common/errors"
    14  	"github.com/imannamdari/v2ray-core/v5/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  	tag := handler.Tag()
   106  
   107  	if m.defaultHandler == nil ||
   108  		(len(tag) > 0 && tag == m.defaultHandler.Tag()) {
   109  		m.defaultHandler = handler
   110  	}
   111  
   112  	if len(tag) > 0 {
   113  		if oldHandler, found := m.taggedHandler[tag]; found {
   114  			errors.New("will replace the existed outbound with the tag: " + tag).AtWarning().WriteToLog()
   115  			_ = oldHandler.Close()
   116  		}
   117  		m.taggedHandler[tag] = handler
   118  	} else {
   119  		m.untaggedHandlers = append(m.untaggedHandlers, handler)
   120  	}
   121  
   122  	if m.running {
   123  		return handler.Start()
   124  	}
   125  
   126  	return nil
   127  }
   128  
   129  // RemoveHandler implements outbound.Manager.
   130  func (m *Manager) RemoveHandler(ctx context.Context, tag string) error {
   131  	if tag == "" {
   132  		return common.ErrNoClue
   133  	}
   134  	m.access.Lock()
   135  	defer m.access.Unlock()
   136  
   137  	delete(m.taggedHandler, tag)
   138  	if m.defaultHandler != nil && m.defaultHandler.Tag() == tag {
   139  		m.defaultHandler = nil
   140  	}
   141  
   142  	return nil
   143  }
   144  
   145  // Select implements outbound.HandlerSelector.
   146  func (m *Manager) Select(selectors []string) []string {
   147  	m.access.RLock()
   148  	defer m.access.RUnlock()
   149  
   150  	tags := make([]string, 0, len(selectors))
   151  
   152  	for tag := range m.taggedHandler {
   153  		match := false
   154  		for _, selector := range selectors {
   155  			if strings.HasPrefix(tag, selector) {
   156  				match = true
   157  				break
   158  			}
   159  		}
   160  		if match {
   161  			tags = append(tags, tag)
   162  		}
   163  	}
   164  
   165  	return tags
   166  }
   167  
   168  func init() {
   169  	common.Must(common.RegisterConfig((*proxyman.OutboundConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
   170  		return New(ctx, config.(*proxyman.OutboundConfig))
   171  	}))
   172  	common.Must(common.RegisterConfig((*core.OutboundHandlerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
   173  		return NewHandler(ctx, config.(*core.OutboundHandlerConfig))
   174  	}))
   175  }