simplify app design

This commit is contained in:
Darien Raymond
2017-01-06 15:32:36 +01:00
parent 13e4506781
commit b11d48d73f
27 changed files with 286 additions and 283 deletions
-8
View File
@@ -1,12 +1,4 @@
package api
import (
"v2ray.com/core/app"
)
const (
APP_ID = app.ID(5)
)
type ApiServer struct {
}
+8 -4
View File
@@ -2,15 +2,19 @@ package dispatcher
import (
"v2ray.com/core/app"
"v2ray.com/core/common/serial"
"v2ray.com/core/proxy"
"v2ray.com/core/transport/ray"
)
const (
APP_ID = app.ID(1)
)
// PacketDispatcher dispatch a packet and possibly further network payload to its destination.
type PacketDispatcher interface {
DispatchToOutbound(session *proxy.SessionInfo) ray.InboundRay
}
func FromSpace(space app.Space) PacketDispatcher {
if app := space.(app.AppGetter).GetApp(serial.GetMessageType((*Config)(nil))); app != nil {
return app.(PacketDispatcher)
}
return nil
}
+9 -23
View File
@@ -7,11 +7,11 @@ import (
"v2ray.com/core/app/dispatcher"
"v2ray.com/core/app/proxyman"
"v2ray.com/core/app/router"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/errors"
"v2ray.com/core/common/log"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/common/serial"
"v2ray.com/core/proxy"
"v2ray.com/core/transport/ray"
)
@@ -23,27 +23,17 @@ type DefaultDispatcher struct {
func NewDefaultDispatcher(space app.Space) *DefaultDispatcher {
d := &DefaultDispatcher{}
space.InitializeApplication(func() error {
return d.Initialize(space)
space.OnInitialize(func() error {
d.ohm = proxyman.OutboundHandlerManagerFromSpace(space)
if d.ohm == nil {
return errors.New("DefaultDispatcher: OutboundHandlerManager is not found in the space.")
}
d.router = router.FromSpace(space)
return nil
})
return d
}
// Initialize initializes the dispatcher.
// Private: Used by app.Space only.
func (v *DefaultDispatcher) Initialize(space app.Space) error {
if !space.HasApp(proxyman.APP_ID_OUTBOUND_MANAGER) {
return errors.New("DefaultDispatcher: OutboundHandlerManager is not found in the space.")
}
v.ohm = space.GetApp(proxyman.APP_ID_OUTBOUND_MANAGER).(proxyman.OutboundHandlerManager)
if space.HasApp(router.APP_ID) {
v.router = space.GetApp(router.APP_ID).(*router.Router)
}
return nil
}
func (v *DefaultDispatcher) DispatchToOutbound(session *proxy.SessionInfo) ray.InboundRay {
dispatcher := v.ohm.GetDefaultHandler()
destination := session.Destination
@@ -95,12 +85,8 @@ func (v DefaultDispatcherFactory) Create(space app.Space, config interface{}) (a
return NewDefaultDispatcher(space), nil
}
func (v DefaultDispatcherFactory) AppId() app.ID {
return dispatcher.APP_ID
}
func init() {
app.RegisterApplicationFactory(serial.GetMessageType(new(dispatcher.Config)), DefaultDispatcherFactory{})
common.Must(app.RegisterApplicationFactory((*dispatcher.Config)(nil), DefaultDispatcherFactory{}))
}
type waitDataInspector struct {
-44
View File
@@ -1,44 +0,0 @@
package testing
import (
"v2ray.com/core/common/buf"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/proxy"
"v2ray.com/core/transport/ray"
)
type TestPacketDispatcher struct {
Destination chan v2net.Destination
Handler func(destination v2net.Destination, traffic ray.OutboundRay)
}
func NewTestPacketDispatcher(handler func(destination v2net.Destination, traffic ray.OutboundRay)) *TestPacketDispatcher {
if handler == nil {
handler = func(destination v2net.Destination, traffic ray.OutboundRay) {
for {
payload, err := traffic.OutboundInput().Read()
if err != nil {
break
}
output := buf.New()
output.Append([]byte("Processed: "))
output.Append(payload.Bytes())
payload.Release()
traffic.OutboundOutput().Write(output)
}
traffic.OutboundOutput().Close()
}
}
return &TestPacketDispatcher{
Destination: make(chan v2net.Destination),
Handler: handler,
}
}
func (v *TestPacketDispatcher) DispatchToOutbound(session *proxy.SessionInfo) ray.InboundRay {
traffic := ray.NewRay()
v.Destination <- session.Destination
go v.Handler(session.Destination, traffic)
return traffic
}
+9 -4
View File
@@ -4,13 +4,18 @@ import (
"net"
"v2ray.com/core/app"
)
const (
APP_ID = app.ID(2)
"v2ray.com/core/common/serial"
)
// A DnsCache is an internal cache of DNS resolutions.
type Server interface {
Get(domain string) []net.IP
}
func FromSpace(space app.Space) Server {
app := space.(app.AppGetter).GetApp(serial.GetMessageType((*Config)(nil)))
if app == nil {
return nil
}
return app.(Server)
}
+6 -11
View File
@@ -8,10 +8,10 @@ import (
"v2ray.com/core/app"
"v2ray.com/core/app/dispatcher"
"v2ray.com/core/app/dns"
"v2ray.com/core/common"
"v2ray.com/core/common/errors"
"v2ray.com/core/common/log"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/common/serial"
dnsmsg "github.com/miekg/dns"
)
@@ -38,12 +38,11 @@ func NewCacheServer(space app.Space, config *dns.Config) *CacheServer {
servers: make([]NameServer, len(config.NameServers)),
hosts: config.GetInternalHosts(),
}
space.InitializeApplication(func() error {
if !space.HasApp(dispatcher.APP_ID) {
space.OnInitialize(func() error {
disp := dispatcher.FromSpace(space)
if disp == nil {
return errors.New("DNS: Dispatcher is not found in the space.")
}
dispatcher := space.GetApp(dispatcher.APP_ID).(dispatcher.PacketDispatcher)
for idx, destPB := range config.NameServers {
address := destPB.Address.AsAddress()
if address.Family().IsDomain() && address.Domain() == "localhost" {
@@ -54,7 +53,7 @@ func NewCacheServer(space app.Space, config *dns.Config) *CacheServer {
dest.Network = v2net.Network_UDP
}
if dest.Network == v2net.Network_UDP {
server.servers[idx] = NewUDPNameServer(dest, dispatcher)
server.servers[idx] = NewUDPNameServer(dest, disp)
}
}
}
@@ -117,10 +116,6 @@ func (v CacheServerFactory) Create(space app.Space, config interface{}) (app.App
return server, nil
}
func (v CacheServerFactory) AppId() app.ID {
return dns.APP_ID
}
func init() {
app.RegisterApplicationFactory(serial.GetMessageType(new(dns.Config)), CacheServerFactory{})
common.Must(app.RegisterApplicationFactory((*dns.Config)(nil), CacheServerFactory{}))
}
+42
View File
@@ -0,0 +1,42 @@
package proxy
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type Config struct {
}
func (m *Config) Reset() { *m = Config{} }
func (m *Config) String() string { return proto.CompactTextString(m) }
func (*Config) ProtoMessage() {}
func (*Config) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func init() {
proto.RegisterType((*Config)(nil), "v2ray.core.app.proxy.Config")
}
func init() { proto.RegisterFile("v2ray.com/core/app/proxy/config.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 128 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x52, 0x2d, 0x33, 0x2a, 0x4a,
0xac, 0xd4, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0x2f, 0x4a, 0xd5, 0x4f, 0x2c, 0x28, 0xd0, 0x2f,
0x28, 0xca, 0xaf, 0xa8, 0xd4, 0x4f, 0xce, 0xcf, 0x4b, 0xcb, 0x4c, 0xd7, 0x2b, 0x28, 0xca, 0x2f,
0xc9, 0x17, 0x12, 0x81, 0x29, 0x2b, 0x4a, 0xd5, 0x4b, 0x2c, 0x28, 0xd0, 0x03, 0x2b, 0x51, 0xe2,
0xe0, 0x62, 0x73, 0x06, 0xab, 0x72, 0x72, 0xe5, 0x92, 0x48, 0xce, 0xcf, 0xd5, 0xc3, 0xa6, 0xca,
0x89, 0x1b, 0xa2, 0x26, 0x00, 0x64, 0x50, 0x14, 0x2b, 0x58, 0x6c, 0x15, 0x93, 0x48, 0x98, 0x51,
0x50, 0x62, 0xa5, 0x9e, 0x33, 0x48, 0xa9, 0x63, 0x41, 0x81, 0x5e, 0x00, 0x48, 0x38, 0x89, 0x0d,
0x6c, 0x9b, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0x16, 0xbe, 0x54, 0x50, 0x96, 0x00, 0x00, 0x00,
}
+10
View File
@@ -0,0 +1,10 @@
syntax = "proto3";
package v2ray.core.app.proxy;
option csharp_namespace = "V2Ray.Core.App.Proxy";
option go_package = "proxy";
option java_package = "com.v2ray.core.app.proxy";
option java_outer_classname = "ConfigProto";
message Config {
}
+24 -8
View File
@@ -7,29 +7,27 @@ import (
"v2ray.com/core/app"
"v2ray.com/core/app/proxyman"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/errors"
"v2ray.com/core/common/log"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/common/serial"
"v2ray.com/core/transport/internet"
"v2ray.com/core/transport/ray"
)
const (
APP_ID = 7
)
type OutboundProxy struct {
outboundManager proxyman.OutboundHandlerManager
}
func NewOutboundProxy(space app.Space) *OutboundProxy {
proxy := new(OutboundProxy)
space.InitializeApplication(func() error {
if !space.HasApp(proxyman.APP_ID_OUTBOUND_MANAGER) {
return errors.New("Proxy: Outbound handler manager not found.")
space.OnInitialize(func() error {
proxy.outboundManager = proxyman.OutboundHandlerManagerFromSpace(space)
if proxy.outboundManager == nil {
return errors.New("Proxy: Outbound handler manager not found in space.")
}
proxy.outboundManager = space.GetApp(proxyman.APP_ID_OUTBOUND_MANAGER).(proxyman.OutboundHandlerManager)
return nil
})
return proxy
@@ -133,3 +131,21 @@ func (v *Connection) Reusable() bool {
func (v *Connection) SetReusable(bool) {
}
type OutboundProxyFactory struct{}
func (OutboundProxyFactory) Create(space app.Space, config interface{}) (app.Application, error) {
return NewOutboundProxy(space), nil
}
func OutboundProxyFromSpace(space app.Space) *OutboundProxy {
app := space.(app.AppGetter).GetApp(serial.GetMessageType((*Config)(nil)))
if app == nil {
return nil
}
return app.(*OutboundProxy)
}
func init() {
common.Must(app.RegisterApplicationFactory((*Config)(nil), OutboundProxyFactory{}))
}
+5 -5
View File
@@ -6,7 +6,7 @@ import (
"v2ray.com/core/app"
. "v2ray.com/core/app/proxy"
"v2ray.com/core/app/proxyman"
"v2ray.com/core/app/proxyman/outbound"
_ "v2ray.com/core/app/proxyman/outbound"
"v2ray.com/core/common"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/proxy"
@@ -21,17 +21,17 @@ func TestProxyDial(t *testing.T) {
assert := assert.On(t)
space := app.NewSpace()
outboundManager := outbound.New()
assert.Error(space.AddApp(new(proxyman.OutboundConfig)))
outboundManager := proxyman.OutboundHandlerManagerFromSpace(space)
common.Must(outboundManager.SetHandler("tag", freedom.New(&freedom.Config{}, space, &proxy.OutboundHandlerMeta{
Tag: "tag",
StreamSettings: &internet.StreamConfig{
Network: v2net.Network_TCP,
},
})))
space.BindApp(proxyman.APP_ID_OUTBOUND_MANAGER, outboundManager)
proxy := NewOutboundProxy(space)
space.BindApp(APP_ID, proxy)
assert.Error(space.AddApp(new(Config))).IsNil()
proxy := OutboundProxyFromSpace(space)
assert.Error(space.Initialize()).IsNil()
+2 -6
View File
@@ -5,7 +5,7 @@ import (
"v2ray.com/core/app"
"v2ray.com/core/app/proxyman"
"v2ray.com/core/common/serial"
"v2ray.com/core/common"
"v2ray.com/core/proxy"
)
@@ -60,10 +60,6 @@ func (v OutboundHandlerManagerFactory) Create(space app.Space, config interface{
return New(), nil
}
func (v OutboundHandlerManagerFactory) AppId() app.ID {
return proxyman.APP_ID_OUTBOUND_MANAGER
}
func init() {
app.RegisterApplicationFactory(serial.GetMessageType(new(proxyman.OutboundConfig)), OutboundHandlerManagerFactory{})
common.Must(app.RegisterApplicationFactory((*proxyman.OutboundConfig)(nil), OutboundHandlerManagerFactory{}))
}
+17 -5
View File
@@ -3,14 +3,10 @@ package proxyman
import (
"v2ray.com/core/app"
"v2ray.com/core/common/serial"
"v2ray.com/core/proxy"
)
const (
APP_ID_INBOUND_MANAGER = app.ID(4)
APP_ID_OUTBOUND_MANAGER = app.ID(6)
)
type InboundHandlerManager interface {
GetHandler(tag string) (proxy.InboundHandler, int)
}
@@ -21,3 +17,19 @@ type OutboundHandlerManager interface {
SetDefaultHandler(handler proxy.OutboundHandler) error
SetHandler(tag string, handler proxy.OutboundHandler) error
}
func InboundHandlerManagerFromSpace(space app.Space) InboundHandlerManager {
app := space.(app.AppGetter).GetApp(serial.GetMessageType((*InboundConfig)(nil)))
if app == nil {
return nil
}
return app.(InboundHandlerManager)
}
func OutboundHandlerManagerFromSpace(space app.Space) OutboundHandlerManager {
app := space.(app.AppGetter).GetApp(serial.GetMessageType((*OutboundConfig)(nil)))
if app == nil {
return nil
}
return app.(OutboundHandlerManager)
}
+11 -10
View File
@@ -3,6 +3,7 @@ package router
import (
"v2ray.com/core/app"
"v2ray.com/core/app/dns"
"v2ray.com/core/common"
"v2ray.com/core/common/errors"
"v2ray.com/core/common/log"
v2net "v2ray.com/core/common/net"
@@ -10,10 +11,6 @@ import (
"v2ray.com/core/proxy"
)
const (
APP_ID = app.ID(3)
)
var (
ErrInvalidRule = errors.New("Invalid Rule")
ErrNoRuleApplicable = errors.New("No rule applicable")
@@ -33,7 +30,7 @@ func NewRouter(config *Config, space app.Space) *Router {
rules: make([]Rule, len(config.Rule)),
}
space.InitializeApplication(func() error {
space.OnInitialize(func() error {
for idx, rule := range config.Rule {
r.rules[idx].Tag = rule.Tag
cond, err := rule.BuildCondition()
@@ -43,10 +40,10 @@ func NewRouter(config *Config, space app.Space) *Router {
r.rules[idx].Condition = cond
}
if !space.HasApp(dns.APP_ID) {
r.dnsServer = dns.FromSpace(space)
if r.dnsServer == nil {
return errors.New("Router: DNS is not found in the space.")
}
r.dnsServer = space.GetApp(dns.APP_ID).(dns.Server)
return nil
})
return r
@@ -116,10 +113,14 @@ func (RouterFactory) Create(space app.Space, config interface{}) (app.Applicatio
return router, nil
}
func (RouterFactory) AppId() app.ID {
return APP_ID
func FromSpace(space app.Space) *Router {
app := space.(app.AppGetter).GetApp(serial.GetMessageType((*Config)(nil)))
if app == nil {
return nil
}
return app.(*Router)
}
func init() {
app.RegisterApplicationFactory(serial.GetMessageType(new(Config)), RouterFactory{})
common.Must(app.RegisterApplicationFactory((*Config)(nil), RouterFactory{}))
}
+9 -8
View File
@@ -5,11 +5,11 @@ import (
"v2ray.com/core/app"
"v2ray.com/core/app/dispatcher"
dispatchers "v2ray.com/core/app/dispatcher/impl"
_ "v2ray.com/core/app/dispatcher/impl"
"v2ray.com/core/app/dns"
dnsserver "v2ray.com/core/app/dns/server"
_ "v2ray.com/core/app/dns/server"
"v2ray.com/core/app/proxyman"
"v2ray.com/core/app/proxyman/outbound"
_ "v2ray.com/core/app/proxyman/outbound"
. "v2ray.com/core/app/router"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/proxy"
@@ -31,13 +31,14 @@ func TestSimpleRouter(t *testing.T) {
}
space := app.NewSpace()
space.BindApp(dns.APP_ID, dnsserver.NewCacheServer(space, &dns.Config{}))
space.BindApp(dispatcher.APP_ID, dispatchers.NewDefaultDispatcher(space))
space.BindApp(proxyman.APP_ID_OUTBOUND_MANAGER, outbound.New())
r := NewRouter(config, space)
space.BindApp(APP_ID, r)
assert.Error(space.AddApp(new(dns.Config))).IsNil()
assert.Error(space.AddApp(new(dispatcher.Config))).IsNil()
assert.Error(space.AddApp(new(proxyman.OutboundConfig))).IsNil()
assert.Error(space.AddApp(config)).IsNil()
assert.Error(space.Initialize()).IsNil()
r := FromSpace(space)
tag, err := r.TakeDetour(&proxy.SessionInfo{Destination: v2net.TCPDestination(v2net.DomainAddress("v2ray.com"), 80)})
assert.Error(err).IsNil()
assert.String(tag).Equals("test")
+49 -35
View File
@@ -1,23 +1,37 @@
package app
import "v2ray.com/core/common/errors"
type ID int
import (
"github.com/golang/protobuf/proto"
"v2ray.com/core/common/errors"
"v2ray.com/core/common/log"
"v2ray.com/core/common/serial"
)
type Application interface {
}
type ApplicationInitializer func() error
type InitializationCallback func() error
type ApplicationFactory interface {
Create(space Space, config interface{}) (Application, error)
AppId() ID
}
type AppGetter interface {
GetApp(name string) Application
}
var (
applicationFactoryCache = make(map[string]ApplicationFactory)
)
func RegisterApplicationFactory(name string, factory ApplicationFactory) error {
func RegisterApplicationFactory(defaultConfig proto.Message, factory ApplicationFactory) error {
if defaultConfig == nil {
return errors.New("Space: config is nil.")
}
name := serial.GetMessageType(defaultConfig)
if len(name) == 0 {
return errors.New("Space: cannot get config type.")
}
applicationFactoryCache[name] = factory
return nil
}
@@ -25,67 +39,67 @@ func RegisterApplicationFactory(name string, factory ApplicationFactory) error {
// A Space contains all apps that may be available in a V2Ray runtime.
// Caller must check the availability of an app by calling HasXXX before getting its instance.
type Space interface {
AddApp(config proto.Message) error
AddAppLegacy(name string, app Application)
Initialize() error
InitializeApplication(ApplicationInitializer)
HasApp(ID) bool
GetApp(ID) Application
BindApp(ID, Application)
BindFromConfig(name string, config interface{}) error
OnInitialize(InitializationCallback)
}
type spaceImpl struct {
cache map[ID]Application
appInit []ApplicationInitializer
initialized bool
cache map[string]Application
appInit []InitializationCallback
}
func NewSpace() Space {
return &spaceImpl{
cache: make(map[ID]Application),
appInit: make([]ApplicationInitializer, 0, 32),
cache: make(map[string]Application),
appInit: make([]InitializationCallback, 0, 32),
}
}
func (v *spaceImpl) InitializeApplication(f ApplicationInitializer) {
v.appInit = append(v.appInit, f)
func (v *spaceImpl) OnInitialize(f InitializationCallback) {
if v.initialized {
if err := f(); err != nil {
log.Error("Space: error after space initialization: ", err)
}
} else {
v.appInit = append(v.appInit, f)
}
}
func (v *spaceImpl) Initialize() error {
for _, f := range v.appInit {
err := f()
if err != nil {
if err := f(); err != nil {
return err
}
}
v.initialized = true
return nil
}
func (v *spaceImpl) HasApp(id ID) bool {
_, found := v.cache[id]
return found
}
func (v *spaceImpl) GetApp(id ID) Application {
obj, found := v.cache[id]
func (v *spaceImpl) GetApp(configType string) Application {
obj, found := v.cache[configType]
if !found {
return nil
}
return obj
}
func (v *spaceImpl) BindApp(id ID, application Application) {
v.cache[id] = application
}
func (v *spaceImpl) BindFromConfig(name string, config interface{}) error {
factory, found := applicationFactoryCache[name]
func (v *spaceImpl) AddApp(config proto.Message) error {
configName := serial.GetMessageType(config)
factory, found := applicationFactoryCache[configName]
if !found {
return errors.New("Space: app not registered: ", name)
return errors.New("Space: app not registered: ", configName)
}
app, err := factory.Create(v, config)
if err != nil {
return err
}
v.BindApp(factory.AppId(), app)
v.cache[configName] = app
return nil
}
func (v *spaceImpl) AddAppLegacy(name string, application Application) {
v.cache[name] = application
}
-6
View File
@@ -1,11 +1,5 @@
package web
import "v2ray.com/core/app"
const (
APP_ID = app.ID(8)
)
type WebServer interface {
Handle()
}