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
}