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  }