فهرست منبع

context'ize apps

Darien Raymond 8 سال پیش
والد
کامیت
17504d2aac

+ 1 - 2
app/dispatcher/dispatcher.go

@@ -2,7 +2,6 @@ package dispatcher
 
 import (
 	"v2ray.com/core/app"
-	"v2ray.com/core/common/serial"
 	"v2ray.com/core/proxy"
 	"v2ray.com/core/transport/ray"
 )
@@ -13,7 +12,7 @@ type PacketDispatcher interface {
 }
 
 func FromSpace(space app.Space) PacketDispatcher {
-	if app := space.(app.AppGetter).GetApp(serial.GetMessageType((*Config)(nil))); app != nil {
+	if app := space.GetApplication((*PacketDispatcher)(nil)); app != nil {
 		return app.(PacketDispatcher)
 	}
 	return nil

+ 14 - 9
app/dispatcher/impl/default.go

@@ -1,6 +1,7 @@
 package impl
 
 import (
+	"context"
 	"time"
 
 	"v2ray.com/core/app"
@@ -21,7 +22,11 @@ type DefaultDispatcher struct {
 	router *router.Router
 }
 
-func NewDefaultDispatcher(space app.Space) *DefaultDispatcher {
+func NewDefaultDispatcher(ctx context.Context, config *dispatcher.Config) (*DefaultDispatcher, error) {
+	space := app.SpaceFromContext(ctx)
+	if space == nil {
+		return nil, errors.New("DefaultDispatcher: No space in context.")
+	}
 	d := &DefaultDispatcher{}
 	space.OnInitialize(func() error {
 		d.ohm = proxyman.OutboundHandlerManagerFromSpace(space)
@@ -31,7 +36,11 @@ func NewDefaultDispatcher(space app.Space) *DefaultDispatcher {
 		d.router = router.FromSpace(space)
 		return nil
 	})
-	return d
+	return d, nil
+}
+
+func (DefaultDispatcher) Interface() interface{} {
+	return (*dispatcher.PacketDispatcher)(nil)
 }
 
 func (v *DefaultDispatcher) DispatchToOutbound(session *proxy.SessionInfo) ray.InboundRay {
@@ -79,14 +88,10 @@ func (v *DefaultDispatcher) waitAndDispatch(wait func() error, destination v2net
 	dispatcher.Dispatch(destination, link)
 }
 
-type DefaultDispatcherFactory struct{}
-
-func (v DefaultDispatcherFactory) Create(space app.Space, config interface{}) (app.Application, error) {
-	return NewDefaultDispatcher(space), nil
-}
-
 func init() {
-	common.Must(app.RegisterApplicationFactory((*dispatcher.Config)(nil), DefaultDispatcherFactory{}))
+	common.Must(common.RegisterConfig((*dispatcher.Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
+		return NewDefaultDispatcher(ctx, config.(*dispatcher.Config))
+	}))
 }
 
 type waitDataInspector struct {

+ 1 - 2
app/dns/dns.go

@@ -4,7 +4,6 @@ import (
 	"net"
 
 	"v2ray.com/core/app"
-	"v2ray.com/core/common/serial"
 )
 
 // A DnsCache is an internal cache of DNS resolutions.
@@ -13,7 +12,7 @@ type Server interface {
 }
 
 func FromSpace(space app.Space) Server {
-	app := space.(app.AppGetter).GetApp(serial.GetMessageType((*Config)(nil)))
+	app := space.GetApplication((*Server)(nil))
 	if app == nil {
 		return nil
 	}

+ 15 - 12
app/dns/server/server.go

@@ -1,10 +1,12 @@
 package server
 
 import (
+	"context"
 	"net"
 	"sync"
 	"time"
 
+	dnsmsg "github.com/miekg/dns"
 	"v2ray.com/core/app"
 	"v2ray.com/core/app/dispatcher"
 	"v2ray.com/core/app/dns"
@@ -12,8 +14,6 @@ import (
 	"v2ray.com/core/common/errors"
 	"v2ray.com/core/common/log"
 	v2net "v2ray.com/core/common/net"
-
-	dnsmsg "github.com/miekg/dns"
 )
 
 const (
@@ -32,7 +32,11 @@ type CacheServer struct {
 	servers []NameServer
 }
 
-func NewCacheServer(space app.Space, config *dns.Config) *CacheServer {
+func NewCacheServer(ctx context.Context, config *dns.Config) (*CacheServer, error) {
+	space := app.SpaceFromContext(ctx)
+	if space == nil {
+		return nil, errors.New("DNSCacheServer: No space in context.")
+	}
 	server := &CacheServer{
 		records: make(map[string]*DomainRecord),
 		servers: make([]NameServer, len(config.NameServers)),
@@ -62,7 +66,11 @@ func NewCacheServer(space app.Space, config *dns.Config) *CacheServer {
 		}
 		return nil
 	})
-	return server
+	return server, nil
+}
+
+func (CacheServer) Interface() interface{} {
+	return (*dns.Server)(nil)
 }
 
 // Private: Visible for testing.
@@ -109,13 +117,8 @@ func (v *CacheServer) Get(domain string) []net.IP {
 	return nil
 }
 
-type CacheServerFactory struct{}
-
-func (v CacheServerFactory) Create(space app.Space, config interface{}) (app.Application, error) {
-	server := NewCacheServer(space, config.(*dns.Config))
-	return server, nil
-}
-
 func init() {
-	common.Must(app.RegisterApplicationFactory((*dns.Config)(nil), CacheServerFactory{}))
+	common.Must(common.RegisterConfig((*dns.Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
+		return NewCacheServer(ctx, config.(*dns.Config))
+	}))
 }

+ 16 - 11
app/proxy/proxy.go

@@ -5,6 +5,8 @@ import (
 	"net"
 	"time"
 
+	"context"
+
 	"v2ray.com/core/app"
 	"v2ray.com/core/app/proxyman"
 	"v2ray.com/core/common"
@@ -12,7 +14,6 @@ import (
 	"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"
 )
@@ -21,7 +22,11 @@ type OutboundProxy struct {
 	outboundManager proxyman.OutboundHandlerManager
 }
 
-func NewOutboundProxy(space app.Space) *OutboundProxy {
+func NewOutboundProxy(ctx context.Context, config *Config) (*OutboundProxy, error) {
+	space := app.SpaceFromContext(ctx)
+	if space == nil {
+		return nil, errors.New("OutboundProxy: No space in context.")
+	}
 	proxy := new(OutboundProxy)
 	space.OnInitialize(func() error {
 		proxy.outboundManager = proxyman.OutboundHandlerManagerFromSpace(space)
@@ -30,7 +35,11 @@ func NewOutboundProxy(space app.Space) *OutboundProxy {
 		}
 		return nil
 	})
-	return proxy
+	return proxy, nil
+}
+
+func (OutboundProxy) Interface() interface{} {
+	return (*OutboundProxy)(nil)
 }
 
 func (v *OutboundProxy) RegisterDialer() {
@@ -132,14 +141,8 @@ 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)))
+	app := space.GetApplication((*OutboundProxy)(nil))
 	if app == nil {
 		return nil
 	}
@@ -147,5 +150,7 @@ func OutboundProxyFromSpace(space app.Space) *OutboundProxy {
 }
 
 func init() {
-	common.Must(app.RegisterApplicationFactory((*Config)(nil), OutboundProxyFactory{}))
+	common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
+		return NewOutboundProxy(ctx, config.(*Config))
+	}))
 }

+ 2 - 3
app/proxy/proxy_test.go

@@ -23,7 +23,7 @@ func TestProxyDial(t *testing.T) {
 
 	space := app.NewSpace()
 	ctx := app.ContextWithSpace(context.Background(), space)
-	assert.Error(space.AddApp(new(proxyman.OutboundConfig)))
+	assert.Error(app.AddApplicationToSpace(ctx, new(proxyman.OutboundConfig))).IsNil()
 	outboundManager := proxyman.OutboundHandlerManagerFromSpace(space)
 	freedom, err := freedom.New(proxy.ContextWithOutboundMeta(ctx, &proxy.OutboundHandlerMeta{
 		Tag: "tag",
@@ -34,9 +34,8 @@ func TestProxyDial(t *testing.T) {
 	assert.Error(err).IsNil()
 	common.Must(outboundManager.SetHandler("tag", freedom))
 
-	assert.Error(space.AddApp(new(Config))).IsNil()
+	assert.Error(app.AddApplicationToSpace(ctx, new(Config))).IsNil()
 	proxy := OutboundProxyFromSpace(space)
-
 	assert.Error(space.Initialize()).IsNil()
 
 	xor := func(b []byte) []byte {

+ 11 - 10
app/proxyman/outbound/outbound.go

@@ -3,7 +3,8 @@ package outbound
 import (
 	"sync"
 
-	"v2ray.com/core/app"
+	"context"
+
 	"v2ray.com/core/app/proxyman"
 	"v2ray.com/core/common"
 	"v2ray.com/core/proxy"
@@ -15,10 +16,14 @@ type DefaultOutboundHandlerManager struct {
 	taggedHandler  map[string]proxy.OutboundHandler
 }
 
-func New() *DefaultOutboundHandlerManager {
+func New(ctx context.Context, config *proxyman.OutboundConfig) (*DefaultOutboundHandlerManager, error) {
 	return &DefaultOutboundHandlerManager{
 		taggedHandler: make(map[string]proxy.OutboundHandler),
-	}
+	}, nil
+}
+
+func (DefaultOutboundHandlerManager) Interface() interface{} {
+	return (*proxyman.OutboundHandlerManager)(nil)
 }
 
 func (v *DefaultOutboundHandlerManager) GetDefaultHandler() proxy.OutboundHandler {
@@ -54,12 +59,8 @@ func (v *DefaultOutboundHandlerManager) SetHandler(tag string, handler proxy.Out
 	return nil
 }
 
-type OutboundHandlerManagerFactory struct{}
-
-func (v OutboundHandlerManagerFactory) Create(space app.Space, config interface{}) (app.Application, error) {
-	return New(), nil
-}
-
 func init() {
-	common.Must(app.RegisterApplicationFactory((*proxyman.OutboundConfig)(nil), OutboundHandlerManagerFactory{}))
+	common.Must(common.RegisterConfig((*proxyman.OutboundConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
+		return New(ctx, config.(*proxyman.OutboundConfig))
+	}))
 }

+ 2 - 3
app/proxyman/proxyman.go

@@ -3,7 +3,6 @@ package proxyman
 
 import (
 	"v2ray.com/core/app"
-	"v2ray.com/core/common/serial"
 	"v2ray.com/core/proxy"
 )
 
@@ -19,7 +18,7 @@ type OutboundHandlerManager interface {
 }
 
 func InboundHandlerManagerFromSpace(space app.Space) InboundHandlerManager {
-	app := space.(app.AppGetter).GetApp(serial.GetMessageType((*InboundConfig)(nil)))
+	app := space.GetApplication((*InboundHandlerManager)(nil))
 	if app == nil {
 		return nil
 	}
@@ -27,7 +26,7 @@ func InboundHandlerManagerFromSpace(space app.Space) InboundHandlerManager {
 }
 
 func OutboundHandlerManagerFromSpace(space app.Space) OutboundHandlerManager {
-	app := space.(app.AppGetter).GetApp(serial.GetMessageType((*OutboundConfig)(nil)))
+	app := space.GetApplication((*OutboundHandlerManager)(nil))
 	if app == nil {
 		return nil
 	}

+ 16 - 10
app/router/router.go

@@ -1,13 +1,14 @@
 package router
 
 import (
+	"context"
+
 	"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"
-	"v2ray.com/core/common/serial"
 	"v2ray.com/core/proxy"
 )
 
@@ -23,7 +24,11 @@ type Router struct {
 	dnsServer dns.Server
 }
 
-func NewRouter(config *Config, space app.Space) *Router {
+func NewRouter(ctx context.Context, config *Config) (*Router, error) {
+	space := app.SpaceFromContext(ctx)
+	if space == nil {
+		return nil, errors.New("Router: No space in context.")
+	}
 	r := &Router{
 		domainStrategy: config.DomainStrategy,
 		//cache:          NewRoutingTable(),
@@ -46,7 +51,7 @@ func NewRouter(config *Config, space app.Space) *Router {
 		}
 		return nil
 	})
-	return r
+	return r, nil
 }
 
 // Private: Visible for testing.
@@ -106,15 +111,14 @@ func (v *Router) TakeDetour(session *proxy.SessionInfo) (string, error) {
 	//return tag, err
 }
 
-type RouterFactory struct{}
-
-func (RouterFactory) Create(space app.Space, config interface{}) (app.Application, error) {
-	router := NewRouter(config.(*Config), space)
-	return router, nil
+func (Router) Interface() interface{} {
+	return (*Router)(nil)
 }
 
+type RouterFactory struct{}
+
 func FromSpace(space app.Space) *Router {
-	app := space.(app.AppGetter).GetApp(serial.GetMessageType((*Config)(nil)))
+	app := space.GetApplication((*Router)(nil))
 	if app == nil {
 		return nil
 	}
@@ -122,5 +126,7 @@ func FromSpace(space app.Space) *Router {
 }
 
 func init() {
-	common.Must(app.RegisterApplicationFactory((*Config)(nil), RouterFactory{}))
+	common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
+		return NewRouter(ctx, config.(*Config))
+	}))
 }

+ 6 - 4
app/router/router_test.go

@@ -1,6 +1,7 @@
 package router_test
 
 import (
+	"context"
 	"testing"
 
 	"v2ray.com/core/app"
@@ -31,10 +32,11 @@ func TestSimpleRouter(t *testing.T) {
 	}
 
 	space := app.NewSpace()
-	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()
+	ctx := app.ContextWithSpace(context.Background(), space)
+	assert.Error(app.AddApplicationToSpace(ctx, new(dns.Config))).IsNil()
+	assert.Error(app.AddApplicationToSpace(ctx, new(dispatcher.Config))).IsNil()
+	assert.Error(app.AddApplicationToSpace(ctx, new(proxyman.OutboundConfig))).IsNil()
+	assert.Error(app.AddApplicationToSpace(ctx, config)).IsNil()
 	assert.Error(space.Initialize()).IsNil()
 
 	r := FromSpace(space)

+ 9 - 8
app/sender/sender.go

@@ -1,10 +1,11 @@
 package sender
 
 import (
+	"context"
+
 	"v2ray.com/core/app"
 	"v2ray.com/core/common"
 	"v2ray.com/core/common/net"
-	"v2ray.com/core/common/serial"
 	"v2ray.com/core/transport/internet"
 )
 
@@ -15,18 +16,16 @@ type Sender interface {
 type SenderManager struct {
 }
 
-func New(space app.Space, config *Config) (*SenderManager, error) {
+func New(ctx context.Context, config *Config) (*SenderManager, error) {
 	return &SenderManager{}, nil
 }
 
-type SenderManagerFactory struct{}
-
-func (SenderManagerFactory) Create(space app.Space, config interface{}) (app.Application, error) {
-	return New(space, config.(*Config))
+func (SenderManager) Interface() interface{} {
+	return (*SenderManager)(nil)
 }
 
 func FromSpace(space app.Space) *SenderManager {
-	app := space.(app.AppGetter).GetApp(serial.GetMessageType((*Config)(nil)))
+	app := space.GetApplication((*SenderManager)(nil))
 	if app == nil {
 		return nil
 	}
@@ -34,5 +33,7 @@ func FromSpace(space app.Space) *SenderManager {
 }
 
 func init() {
-	common.Must(app.RegisterApplicationFactory((*Config)(nil), SenderManagerFactory{}))
+	common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
+		return New(ctx, config.(*Config))
+	}))
 }

+ 34 - 47
app/space.go

@@ -2,60 +2,50 @@ package app
 
 import (
 	"context"
+	"reflect"
 
-	"github.com/golang/protobuf/proto"
+	"v2ray.com/core/common"
 	"v2ray.com/core/common/errors"
 	"v2ray.com/core/common/log"
-	"v2ray.com/core/common/serial"
 )
 
 type Application interface {
+	Interface() interface{}
 }
 
 type InitializationCallback func() error
 
-type ApplicationFactory interface {
-	Create(space Space, config interface{}) (Application, error)
-}
-
-type AppGetter interface {
-	GetApp(name string) Application
-}
-
-var (
-	applicationFactoryCache = make(map[string]ApplicationFactory)
-)
-
-func RegisterApplicationFactory(defaultConfig proto.Message, factory ApplicationFactory) error {
-	if defaultConfig == nil {
-		return errors.New("Space: config is nil.")
+func CreateAppFromConfig(ctx context.Context, config interface{}) (Application, error) {
+	application, err := common.CreateObject(ctx, config)
+	if err != nil {
+		return nil, err
 	}
-	name := serial.GetMessageType(defaultConfig)
-	if len(name) == 0 {
-		return errors.New("Space: cannot get config type.")
+	switch a := application.(type) {
+	case Application:
+		return a, nil
+	default:
+		return nil, errors.New("App: Not an application.")
 	}
-	applicationFactoryCache[name] = factory
-	return nil
 }
 
 // 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)
+	GetApplication(appInterface interface{}) Application
+	AddApplication(application Application) error
 	Initialize() error
 	OnInitialize(InitializationCallback)
 }
 
 type spaceImpl struct {
 	initialized bool
-	cache       map[string]Application
+	cache       map[reflect.Type]Application
 	appInit     []InitializationCallback
 }
 
 func NewSpace() Space {
 	return &spaceImpl{
-		cache:   make(map[string]Application),
+		cache:   make(map[reflect.Type]Application),
 		appInit: make([]InitializationCallback, 0, 32),
 	}
 }
@@ -81,38 +71,35 @@ func (v *spaceImpl) Initialize() error {
 	return nil
 }
 
-func (v *spaceImpl) GetApp(configType string) Application {
-	obj, found := v.cache[configType]
-	if !found {
-		return nil
-	}
-	return obj
+func (v *spaceImpl) GetApplication(appInterface interface{}) Application {
+	appType := reflect.TypeOf(appInterface)
+	return v.cache[appType]
 }
 
-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: ", configName)
-	}
-	app, err := factory.Create(v, config)
-	if err != nil {
-		return err
-	}
-	v.cache[configName] = app
+func (v *spaceImpl) AddApplication(app Application) error {
+	appType := reflect.TypeOf(app.Interface())
+	v.cache[appType] = app
 	return nil
 }
 
-func (v *spaceImpl) AddAppLegacy(name string, application Application) {
-	v.cache[name] = application
-}
-
 type contextKey int
 
 const (
 	spaceKey = contextKey(0)
 )
 
+func AddApplicationToSpace(ctx context.Context, appConfig interface{}) error {
+	space := SpaceFromContext(ctx)
+	if space == nil {
+		return errors.New("App: No space in context.")
+	}
+	application, err := CreateAppFromConfig(ctx, appConfig)
+	if err != nil {
+		return err
+	}
+	return space.AddApplication(application)
+}
+
 func SpaceFromContext(ctx context.Context) Space {
 	return ctx.Value(spaceKey).(Space)
 }

+ 6 - 10
proxy/dokodemo/dokodemo_test.go

@@ -40,13 +40,11 @@ func TestDokodemoTCP(t *testing.T) {
 	defer tcpServer.Close()
 
 	space := app.NewSpace()
-	space.AddApp(new(dispatcher.Config))
-	space.AddApp(new(proxyman.OutboundConfig))
+	ctx := app.ContextWithSpace(context.Background(), space)
+	app.AddApplicationToSpace(ctx, new(dispatcher.Config))
+	app.AddApplicationToSpace(ctx, new(proxyman.OutboundConfig))
 
 	ohm := proxyman.OutboundHandlerManagerFromSpace(space)
-	ctx := context.Background()
-	ctx = app.ContextWithSpace(ctx, space)
-
 	freedom, err := freedom.New(proxy.ContextWithOutboundMeta(ctx, &proxy.OutboundHandlerMeta{
 		Address: v2net.LocalHostIP,
 		StreamSettings: &internet.StreamConfig{
@@ -117,13 +115,11 @@ func TestDokodemoUDP(t *testing.T) {
 	defer udpServer.Close()
 
 	space := app.NewSpace()
-	space.AddApp(new(dispatcher.Config))
-	space.AddApp(new(proxyman.OutboundConfig))
+	ctx := app.ContextWithSpace(context.Background(), space)
+	app.AddApplicationToSpace(ctx, new(dispatcher.Config))
+	app.AddApplicationToSpace(ctx, new(proxyman.OutboundConfig))
 
 	ohm := proxyman.OutboundHandlerManagerFromSpace(space)
-
-	ctx := context.Background()
-	ctx = app.ContextWithSpace(ctx, space)
 	freedom, err := freedom.New(proxy.ContextWithOutboundMeta(ctx, &proxy.OutboundHandlerMeta{
 		Address: v2net.AnyIP,
 		StreamSettings: &internet.StreamConfig{

+ 5 - 5
proxy/freedom/freedom_test.go

@@ -70,16 +70,16 @@ func TestIPResolution(t *testing.T) {
 	assert := assert.On(t)
 
 	space := app.NewSpace()
-	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{
+	ctx := app.ContextWithSpace(context.Background(), space)
+	assert.Error(app.AddApplicationToSpace(ctx, new(proxyman.OutboundConfig))).IsNil()
+	assert.Error(app.AddApplicationToSpace(ctx, new(dispatcher.Config))).IsNil()
+	assert.Error(app.AddApplicationToSpace(ctx, new(router.Config))).IsNil()
+	assert.Error(app.AddApplicationToSpace(ctx, &dns.Config{
 		Hosts: map[string]*v2net.IPOrDomain{
 			"v2ray.com": v2net.NewIPOrDomain(v2net.LocalHostIP),
 		},
 	})).IsNil()
 
-	ctx := app.ContextWithSpace(context.Background(), space)
 	ctx = proxy.ContextWithOutboundMeta(ctx, &proxy.OutboundHandlerMeta{
 		Address: v2net.AnyIP,
 		StreamSettings: &internet.StreamConfig{

+ 30 - 13
v2ray.go

@@ -11,7 +11,6 @@ import (
 	"v2ray.com/core/common"
 	"v2ray.com/core/common/log"
 	v2net "v2ray.com/core/common/net"
-	"v2ray.com/core/common/serial"
 	"v2ray.com/core/proxy"
 )
 
@@ -43,29 +42,39 @@ func NewPoint(pConfig *Config) (*Point, error) {
 	ctx := app.ContextWithSpace(context.Background(), space)
 
 	vpoint.space = space
-	vpoint.space.AddAppLegacy(serial.GetMessageType((*proxyman.InboundConfig)(nil)), vpoint)
+	vpoint.space.AddApplication(vpoint)
 
 	outboundHandlerManager := proxyman.OutboundHandlerManagerFromSpace(space)
 	if outboundHandlerManager == nil {
-		if err := space.AddApp(new(proxyman.OutboundConfig)); err != nil {
+		o, err := app.CreateAppFromConfig(ctx, new(proxyman.OutboundConfig))
+		if err != nil {
 			return nil, err
 		}
-		outboundHandlerManager = proxyman.OutboundHandlerManagerFromSpace(space)
+		space.AddApplication(o)
+		outboundHandlerManager = o.(proxyman.OutboundHandlerManager)
 	}
 
 	proxyDialer := proxydialer.OutboundProxyFromSpace(space)
 	if proxyDialer == nil {
-		space.AddApp(new(proxydialer.Config))
-		proxyDialer = proxydialer.OutboundProxyFromSpace(space)
+		p, err := app.CreateAppFromConfig(ctx, new(proxydialer.Config))
+		if err != nil {
+			return nil, err
+		}
+		space.AddApplication(p)
+		proxyDialer = p.(*proxydialer.OutboundProxy)
 	}
 	proxyDialer.RegisterDialer()
 
-	for _, app := range pConfig.App {
-		settings, err := app.GetInstance()
+	for _, appSettings := range pConfig.App {
+		settings, err := appSettings.GetInstance()
 		if err != nil {
 			return nil, err
 		}
-		if err := space.AddApp(settings); err != nil {
+		application, err := app.CreateAppFromConfig(ctx, settings)
+		if err != nil {
+			return nil, err
+		}
+		if err := space.AddApplication(application); err != nil {
 			return nil, err
 		}
 	}
@@ -77,18 +86,22 @@ func NewPoint(pConfig *Config) (*Point, error) {
 				Address: v2net.NewIPOrDomain(v2net.LocalHostDomain),
 			}},
 		}
-		if err := space.AddApp(dnsConfig); err != nil {
+		d, err := app.CreateAppFromConfig(ctx, dnsConfig)
+		if err != nil {
 			return nil, err
 		}
+		space.AddApplication(d)
+		dnsServer = d.(dns.Server)
 	}
 
 	disp := dispatcher.FromSpace(space)
 	if disp == nil {
-		dispatcherConfig := new(dispatcher.Config)
-		if err := vpoint.space.AddApp(dispatcherConfig); err != nil {
+		d, err := app.CreateAppFromConfig(ctx, new(dispatcher.Config))
+		if err != nil {
 			return nil, err
 		}
-		disp = dispatcher.FromSpace(space)
+		space.AddApplication(d)
+		disp = d.(dispatcher.PacketDispatcher)
 	}
 
 	vpoint.inboundHandlers = make([]InboundDetourHandler, 0, 8)
@@ -156,6 +169,10 @@ func NewPoint(pConfig *Config) (*Point, error) {
 	return vpoint, nil
 }
 
+func (Point) Interface() interface{} {
+	return (*proxyman.InboundHandlerManager)(nil)
+}
+
 func (v *Point) Close() {
 	for _, inbound := range v.inboundHandlers {
 		inbound.Close()