mirror of
				https://github.com/v2fly/v2ray-core.git
				synced 2025-10-31 01:39:16 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			132 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			132 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package core
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"sync"
 | |
| 
 | |
| 	"v2ray.com/core/common"
 | |
| 	"v2ray.com/core/common/buf"
 | |
| 	"v2ray.com/core/common/errors"
 | |
| 	"v2ray.com/core/common/net"
 | |
| )
 | |
| 
 | |
| // Link is a utility for connecting between an inbound and an outbound proxy handler.
 | |
| type Link struct {
 | |
| 	Reader buf.Reader
 | |
| 	Writer buf.Writer
 | |
| }
 | |
| 
 | |
| // Dispatcher is a feature that dispatches inbound requests to outbound handlers based on rules.
 | |
| // Dispatcher is required to be registered in a V2Ray instance to make V2Ray function properly.
 | |
| type Dispatcher interface {
 | |
| 	Feature
 | |
| 
 | |
| 	// Dispatch returns a Ray for transporting data for the given request.
 | |
| 	Dispatch(ctx context.Context, dest net.Destination) (*Link, error)
 | |
| }
 | |
| 
 | |
| type syncDispatcher struct {
 | |
| 	sync.RWMutex
 | |
| 	Dispatcher
 | |
| }
 | |
| 
 | |
| func (d *syncDispatcher) Dispatch(ctx context.Context, dest net.Destination) (*Link, error) {
 | |
| 	d.RLock()
 | |
| 	defer d.RUnlock()
 | |
| 
 | |
| 	if d.Dispatcher == nil {
 | |
| 		return nil, newError("Dispatcher not set.").AtError()
 | |
| 	}
 | |
| 
 | |
| 	return d.Dispatcher.Dispatch(ctx, dest)
 | |
| }
 | |
| 
 | |
| func (d *syncDispatcher) Start() error {
 | |
| 	d.RLock()
 | |
| 	defer d.RUnlock()
 | |
| 
 | |
| 	if d.Dispatcher == nil {
 | |
| 		return newError("Dispatcher not set.").AtError()
 | |
| 	}
 | |
| 
 | |
| 	return d.Dispatcher.Start()
 | |
| }
 | |
| 
 | |
| func (d *syncDispatcher) Close() error {
 | |
| 	d.RLock()
 | |
| 	defer d.RUnlock()
 | |
| 
 | |
| 	return common.Close(d.Dispatcher)
 | |
| }
 | |
| 
 | |
| func (d *syncDispatcher) Set(disp Dispatcher) {
 | |
| 	if disp == nil {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	d.Lock()
 | |
| 	defer d.Unlock()
 | |
| 
 | |
| 	common.Close(d.Dispatcher) // nolint: errorcheck
 | |
| 	d.Dispatcher = disp
 | |
| }
 | |
| 
 | |
| var (
 | |
| 	// ErrNoClue is for the situation that existing information is not enough to make a decision. For example, Router may return this error when there is no suitable route.
 | |
| 	ErrNoClue = errors.New("not enough information for making a decision")
 | |
| )
 | |
| 
 | |
| // Router is a feature to choose an outbound tag for the given request.
 | |
| type Router interface {
 | |
| 	Feature
 | |
| 
 | |
| 	// PickRoute returns a tag of an OutboundHandler based on the given context.
 | |
| 	PickRoute(ctx context.Context) (string, error)
 | |
| }
 | |
| 
 | |
| type syncRouter struct {
 | |
| 	sync.RWMutex
 | |
| 	Router
 | |
| }
 | |
| 
 | |
| func (r *syncRouter) PickRoute(ctx context.Context) (string, error) {
 | |
| 	r.RLock()
 | |
| 	defer r.RUnlock()
 | |
| 
 | |
| 	if r.Router == nil {
 | |
| 		return "", ErrNoClue
 | |
| 	}
 | |
| 
 | |
| 	return r.Router.PickRoute(ctx)
 | |
| }
 | |
| 
 | |
| func (r *syncRouter) Start() error {
 | |
| 	r.RLock()
 | |
| 	defer r.RUnlock()
 | |
| 
 | |
| 	if r.Router == nil {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	return r.Router.Start()
 | |
| }
 | |
| 
 | |
| func (r *syncRouter) Close() error {
 | |
| 	r.RLock()
 | |
| 	defer r.RUnlock()
 | |
| 
 | |
| 	return common.Close(r.Router)
 | |
| }
 | |
| 
 | |
| func (r *syncRouter) Set(router Router) {
 | |
| 	if router == nil {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	r.Lock()
 | |
| 	defer r.Unlock()
 | |
| 
 | |
| 	common.Close(r.Router) // nolint: errcheck
 | |
| 	r.Router = router
 | |
| }
 | 
