mirror of https://github.com/v2ray/v2ray-core
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
131 lines
2.5 KiB
131 lines
2.5 KiB
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 |
|
}
|
|
|