Darien Raymond 8 лет назад
Родитель
Сommit
b11d48d73f

+ 0 - 8
app/api/api.go

@@ -1,12 +1,4 @@
 package api
 
-import (
-	"v2ray.com/core/app"
-)
-
-const (
-	APP_ID = app.ID(5)
-)
-
 type ApiServer struct {
 }

+ 8 - 4
app/dispatcher/dispatcher.go

@@ -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
app/dispatcher/impl/default.go

@@ -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 {

+ 0 - 44
app/dispatcher/testing/dispatcher.go

@@ -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
app/dns/dns.go

@@ -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
app/dns/server/server.go

@@ -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 - 0
app/proxy/config.pb.go

@@ -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 - 0
app/proxy/config.proto

@@ -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
app/proxy/proxy.go

@@ -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
app/proxy/proxy_test.go

@@ -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
app/proxyman/outbound/outbound.go

@@ -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
app/proxyman/proxyman.go

@@ -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
app/router/router.go

@@ -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
app/router/router_test.go

@@ -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
app/space.go

@@ -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
+}

+ 0 - 6
app/web/web.go

@@ -1,11 +1,5 @@
 package web
 
-import "v2ray.com/core/app"
-
-const (
-	APP_ID = app.ID(8)
-)
-
 type WebServer interface {
 	Handle()
 }

+ 4 - 3
common/serial/typed_message.go

@@ -30,13 +30,14 @@ func GetInstance(messageType string) (interface{}, error) {
 	return reflect.New(mType.Elem()).Interface(), nil
 }
 
-func (v *TypedMessage) GetInstance() (interface{}, error) {
+func (v *TypedMessage) GetInstance() (proto.Message, error) {
 	instance, err := GetInstance(v.Type)
 	if err != nil {
 		return nil, err
 	}
-	if err := proto.Unmarshal(v.Value, instance.(proto.Message)); err != nil {
+	protoMessage := instance.(proto.Message)
+	if err := proto.Unmarshal(v.Value, protoMessage); err != nil {
 		return nil, err
 	}
-	return instance, nil
+	return protoMessage, nil
 }

+ 3 - 3
proxy/dokodemo/dokodemo.go

@@ -38,11 +38,11 @@ func NewDokodemoDoor(config *Config, space app.Space, meta *proxy.InboundHandler
 		port:    v2net.Port(config.Port),
 		meta:    meta,
 	}
-	space.InitializeApplication(func() error {
-		if !space.HasApp(dispatcher.APP_ID) {
+	space.OnInitialize(func() error {
+		d.packetDispatcher = dispatcher.FromSpace(space)
+		if d.packetDispatcher == nil {
 			return errors.New("Dokodemo: Dispatcher is not found in the space.")
 		}
-		d.packetDispatcher = space.GetApp(dispatcher.APP_ID).(dispatcher.PacketDispatcher)
 		return nil
 	})
 	return d

+ 10 - 8
proxy/dokodemo/dokodemo_test.go

@@ -6,9 +6,9 @@ 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/proxyman"
-	"v2ray.com/core/app/proxyman/outbound"
+	_ "v2ray.com/core/app/proxyman/outbound"
 	"v2ray.com/core/common/dice"
 	v2net "v2ray.com/core/common/net"
 	"v2ray.com/core/proxy"
@@ -38,8 +38,10 @@ func TestDokodemoTCP(t *testing.T) {
 	defer tcpServer.Close()
 
 	space := app.NewSpace()
-	space.BindApp(dispatcher.APP_ID, dispatchers.NewDefaultDispatcher(space))
-	ohm := outbound.New()
+	space.AddApp(new(dispatcher.Config))
+	space.AddApp(new(proxyman.OutboundConfig))
+
+	ohm := proxyman.OutboundHandlerManagerFromSpace(space)
 	ohm.SetDefaultHandler(
 		freedom.New(
 			&freedom.Config{},
@@ -50,7 +52,6 @@ func TestDokodemoTCP(t *testing.T) {
 					Network: v2net.Network_TCP,
 				},
 			}))
-	space.BindApp(proxyman.APP_ID_OUTBOUND_MANAGER, ohm)
 
 	data2Send := "Data to be sent to remote."
 
@@ -109,8 +110,10 @@ func TestDokodemoUDP(t *testing.T) {
 	defer udpServer.Close()
 
 	space := app.NewSpace()
-	space.BindApp(dispatcher.APP_ID, dispatchers.NewDefaultDispatcher(space))
-	ohm := outbound.New()
+	space.AddApp(new(dispatcher.Config))
+	space.AddApp(new(proxyman.OutboundConfig))
+
+	ohm := proxyman.OutboundHandlerManagerFromSpace(space)
 	ohm.SetDefaultHandler(
 		freedom.New(
 			&freedom.Config{},
@@ -120,7 +123,6 @@ func TestDokodemoUDP(t *testing.T) {
 				StreamSettings: &internet.StreamConfig{
 					Network: v2net.Network_TCP,
 				}}))
-	space.BindApp(proxyman.APP_ID_OUTBOUND_MANAGER, ohm)
 
 	data2Send := "Data to be sent to remote."
 

+ 3 - 3
proxy/freedom/freedom.go

@@ -32,12 +32,12 @@ func New(config *Config, space app.Space, meta *proxy.OutboundHandlerMeta) *Hand
 		timeout:        config.Timeout,
 		meta:           meta,
 	}
-	space.InitializeApplication(func() error {
+	space.OnInitialize(func() error {
 		if config.DomainStrategy == Config_USE_IP {
-			if !space.HasApp(dns.APP_ID) {
+			f.dns = dns.FromSpace(space)
+			if f.dns == nil {
 				return errors.New("Freedom: DNS server is not found in the space.")
 			}
-			f.dns = space.GetApp(dns.APP_ID).(dns.Server)
 		}
 		return nil
 	})

+ 8 - 10
proxy/freedom/freedom_test.go

@@ -6,11 +6,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"
 	"v2ray.com/core/common/buf"
 	v2net "v2ray.com/core/common/net"
@@ -70,16 +70,14 @@ func TestIPResolution(t *testing.T) {
 	assert := assert.On(t)
 
 	space := app.NewSpace()
-	space.BindApp(proxyman.APP_ID_OUTBOUND_MANAGER, outbound.New())
-	space.BindApp(dispatcher.APP_ID, dispatchers.NewDefaultDispatcher(space))
-	r := router.NewRouter(&router.Config{}, space)
-	space.BindApp(router.APP_ID, r)
-	dnsServer := dnsserver.NewCacheServer(space, &dns.Config{
+	assert.Error(space.AddApp(new(proxyman.OutboundConfig))).IsNil()
+	assert.Error(space.AddApp(new(dispatcher.Config))).IsNil()
+	assert.Error(space.AddApp(new(router.Config))).IsNil()
+	assert.Error(space.AddApp(&dns.Config{
 		Hosts: map[string]*v2net.IPOrDomain{
 			"v2ray.com": v2net.NewIPOrDomain(v2net.LocalHostIP),
 		},
-	})
-	space.BindApp(dns.APP_ID, dnsServer)
+	})).IsNil()
 
 	freedom := New(
 		&Config{DomainStrategy: Config_USE_IP},

+ 13 - 12
proxy/http/server.go

@@ -33,12 +33,19 @@ type Server struct {
 }
 
 // NewServer creates a new HTTP inbound handler.
-func NewServer(config *ServerConfig, packetDispatcher dispatcher.PacketDispatcher, meta *proxy.InboundHandlerMeta) *Server {
-	return &Server{
-		packetDispatcher: packetDispatcher,
-		config:           config,
-		meta:             meta,
+func NewServer(config *ServerConfig, space app.Space, meta *proxy.InboundHandlerMeta) *Server {
+	s := &Server{
+		config: config,
+		meta:   meta,
 	}
+	space.OnInitialize(func() error {
+		s.packetDispatcher = dispatcher.FromSpace(space)
+		if s.packetDispatcher == nil {
+			return errors.New("HTTP|Server: Dispatcher not found in space.")
+		}
+		return nil
+	})
+	return s
 }
 
 // Port implements InboundHandler.Port().
@@ -291,13 +298,7 @@ func (v *ServerFactory) StreamCapability() v2net.NetworkList {
 
 // Create implements InboundHandlerFactory.Create().
 func (v *ServerFactory) Create(space app.Space, rawConfig interface{}, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error) {
-	if !space.HasApp(dispatcher.APP_ID) {
-		return nil, common.ErrBadConfiguration
-	}
-	return NewServer(
-		rawConfig.(*ServerConfig),
-		space.GetApp(dispatcher.APP_ID).(dispatcher.PacketDispatcher),
-		meta), nil
+	return NewServer(rawConfig.(*ServerConfig), space, meta), nil
 }
 
 func init() {

+ 0 - 32
proxy/http/server_test.go

@@ -6,13 +6,8 @@ import (
 	"strings"
 	"testing"
 
-	testdispatcher "v2ray.com/core/app/dispatcher/testing"
-	"v2ray.com/core/common/dice"
-	v2net "v2ray.com/core/common/net"
-	"v2ray.com/core/proxy"
 	. "v2ray.com/core/proxy/http"
 	"v2ray.com/core/testing/assert"
-	"v2ray.com/core/transport/internet"
 
 	_ "v2ray.com/core/transport/internet/tcp"
 )
@@ -50,30 +45,3 @@ Accept-Language: de,en;q=0.7,en-us;q=0.3
 	assert.String(req.Header.Get("Proxy-Connection")).Equals("")
 	assert.String(req.Header.Get("Proxy-Authenticate")).Equals("")
 }
-
-func TestNormalGetRequest(t *testing.T) {
-	assert := assert.On(t)
-
-	testPacketDispatcher := testdispatcher.NewTestPacketDispatcher(nil)
-
-	port := v2net.Port(dice.Roll(20000) + 10000)
-	httpProxy := NewServer(
-		&ServerConfig{},
-		testPacketDispatcher,
-		&proxy.InboundHandlerMeta{
-			Address: v2net.LocalHostIP,
-			Port:    port,
-			StreamSettings: &internet.StreamConfig{
-				Network: v2net.Network_TCP,
-			}})
-	defer httpProxy.Close()
-
-	err := httpProxy.Start()
-	assert.Error(err).IsNil()
-	assert.Port(port).Equals(httpProxy.Port())
-
-	httpClient := &http.Client{}
-	resp, err := httpClient.Get("http://127.0.0.1:" + port.String() + "/")
-	assert.Error(err).IsNil()
-	assert.Int(resp.StatusCode).Equals(400)
-}

+ 3 - 7
proxy/shadowsocks/server.go

@@ -3,7 +3,6 @@ package shadowsocks
 import (
 	"v2ray.com/core/app"
 	"v2ray.com/core/app/dispatcher"
-	"v2ray.com/core/common"
 	"v2ray.com/core/common/buf"
 	"v2ray.com/core/common/bufio"
 	"v2ray.com/core/common/errors"
@@ -46,11 +45,11 @@ func NewServer(config *ServerConfig, space app.Space, meta *proxy.InboundHandler
 		account: account,
 	}
 
-	space.InitializeApplication(func() error {
-		if !space.HasApp(dispatcher.APP_ID) {
+	space.OnInitialize(func() error {
+		s.packetDispatcher = dispatcher.FromSpace(space)
+		if s.packetDispatcher == nil {
 			return errors.New("Shadowsocks|Server: Dispatcher is not found in space.")
 		}
-		s.packetDispatcher = space.GetApp(dispatcher.APP_ID).(dispatcher.PacketDispatcher)
 		return nil
 	})
 
@@ -228,8 +227,5 @@ func (v *ServerFactory) StreamCapability() v2net.NetworkList {
 }
 
 func (v *ServerFactory) Create(space app.Space, rawConfig interface{}, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error) {
-	if !space.HasApp(dispatcher.APP_ID) {
-		return nil, common.ErrBadConfiguration
-	}
 	return NewServer(rawConfig.(*ServerConfig), space, meta)
 }

+ 3 - 3
proxy/socks/server.go

@@ -41,11 +41,11 @@ func NewServer(config *ServerConfig, space app.Space, meta *proxy.InboundHandler
 		config: config,
 		meta:   meta,
 	}
-	space.InitializeApplication(func() error {
-		if !space.HasApp(dispatcher.APP_ID) {
+	space.OnInitialize(func() error {
+		s.packetDispatcher = dispatcher.FromSpace(space)
+		if s.packetDispatcher == nil {
 			return errors.New("Socks|Server: Dispatcher is not found in the space.")
 		}
-		s.packetDispatcher = space.GetApp(dispatcher.APP_ID).(dispatcher.PacketDispatcher)
 		return nil
 	})
 	return s

+ 15 - 11
proxy/vmess/inbound/inbound.go

@@ -261,9 +261,6 @@ func (v *Factory) StreamCapability() v2net.NetworkList {
 }
 
 func (v *Factory) Create(space app.Space, rawConfig interface{}, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error) {
-	if !space.HasApp(dispatcher.APP_ID) {
-		return nil, common.ErrBadConfiguration
-	}
 	config := rawConfig.(*Config)
 
 	allowedClients := vmess.NewTimedUserValidator(protocol.DefaultIDHash)
@@ -272,16 +269,23 @@ func (v *Factory) Create(space app.Space, rawConfig interface{}, meta *proxy.Inb
 	}
 
 	handler := &VMessInboundHandler{
-		packetDispatcher: space.GetApp(dispatcher.APP_ID).(dispatcher.PacketDispatcher),
-		clients:          allowedClients,
-		detours:          config.Detour,
-		usersByEmail:     NewUserByEmail(config.User, config.GetDefaultValue()),
-		meta:             meta,
+		clients:      allowedClients,
+		detours:      config.Detour,
+		usersByEmail: NewUserByEmail(config.User, config.GetDefaultValue()),
+		meta:         meta,
 	}
 
-	if space.HasApp(proxyman.APP_ID_INBOUND_MANAGER) {
-		handler.inboundHandlerManager = space.GetApp(proxyman.APP_ID_INBOUND_MANAGER).(proxyman.InboundHandlerManager)
-	}
+	space.OnInitialize(func() error {
+		handler.packetDispatcher = dispatcher.FromSpace(space)
+		if handler.packetDispatcher == nil {
+			return errors.New("VMess|Inbound: Dispatcher is not found in space.")
+		}
+		handler.inboundHandlerManager = proxyman.InboundHandlerManagerFromSpace(space)
+		if handler.inboundHandlerManager == nil {
+			return errors.New("VMess|Inbound: InboundHandlerManager is not found is space.")
+		}
+		return nil
+	})
 
 	return handler, nil
 }

+ 23 - 14
v2ray.go

@@ -39,43 +39,52 @@ func NewPoint(pConfig *Config) (*Point, error) {
 
 	space := app.NewSpace()
 	vpoint.space = space
-	vpoint.space.BindApp(proxyman.APP_ID_INBOUND_MANAGER, vpoint)
+	vpoint.space.AddAppLegacy(serial.GetMessageType((*proxyman.InboundConfig)(nil)), vpoint)
 
-	outboundManagerConfig := new(proxyman.OutboundConfig)
-	if err := space.BindFromConfig(serial.GetMessageType(outboundManagerConfig), outboundManagerConfig); err != nil {
-		return nil, err
+	outboundHandlerManager := proxyman.OutboundHandlerManagerFromSpace(space)
+	if outboundHandlerManager == nil {
+		if err := space.AddApp(new(proxyman.OutboundConfig)); err != nil {
+			return nil, err
+		}
+		outboundHandlerManager = proxyman.OutboundHandlerManagerFromSpace(space)
 	}
 
-	outboundHandlerManager := space.GetApp(proxyman.APP_ID_OUTBOUND_MANAGER).(proxyman.OutboundHandlerManager)
-
-	proxyDialer := proxydialer.NewOutboundProxy(space)
+	proxyDialer := proxydialer.OutboundProxyFromSpace(space)
+	if proxyDialer == nil {
+		space.AddApp(new(proxydialer.Config))
+		proxyDialer = proxydialer.OutboundProxyFromSpace(space)
+	}
 	proxyDialer.RegisterDialer()
-	space.BindApp(proxydialer.APP_ID, proxyDialer)
 
 	for _, app := range pConfig.App {
 		settings, err := app.GetInstance()
 		if err != nil {
 			return nil, err
 		}
-		if err := space.BindFromConfig(app.Type, settings); err != nil {
+		if err := space.AddApp(settings); err != nil {
 			return nil, err
 		}
 	}
 
-	if !space.HasApp(dns.APP_ID) {
+	dnsServer := dns.FromSpace(space)
+	if dnsServer == nil {
 		dnsConfig := &dns.Config{
 			NameServers: []*v2net.Endpoint{{
 				Address: v2net.NewIPOrDomain(v2net.LocalHostDomain),
 			}},
 		}
-		if err := space.BindFromConfig(serial.GetMessageType(dnsConfig), dnsConfig); err != nil {
+		if err := space.AddApp(dnsConfig); err != nil {
 			return nil, err
 		}
 	}
 
-	dispatcherConfig := new(dispatcher.Config)
-	if err := vpoint.space.BindFromConfig(serial.GetMessageType(dispatcherConfig), dispatcherConfig); err != nil {
-		return nil, err
+	disp := dispatcher.FromSpace(space)
+	if disp == nil {
+		dispatcherConfig := new(dispatcher.Config)
+		if err := vpoint.space.AddApp(dispatcherConfig); err != nil {
+			return nil, err
+		}
+		disp = dispatcher.FromSpace(space)
 	}
 
 	vpoint.inboundHandlers = make([]InboundDetourHandler, 0, 8)