Ver Fonte

leverage global object creator in proxies.

Darien Raymond há 8 anos atrás
pai
commit
148e4832eb

+ 6 - 2
app/proxy/proxy_test.go

@@ -1,6 +1,7 @@
 package proxy_test
 
 import (
+	"context"
 	"testing"
 
 	"v2ray.com/core/app"
@@ -21,14 +22,17 @@ func TestProxyDial(t *testing.T) {
 	assert := assert.On(t)
 
 	space := app.NewSpace()
+	ctx := app.ContextWithSpace(context.Background(), space)
 	assert.Error(space.AddApp(new(proxyman.OutboundConfig)))
 	outboundManager := proxyman.OutboundHandlerManagerFromSpace(space)
-	common.Must(outboundManager.SetHandler("tag", freedom.New(&freedom.Config{}, space, &proxy.OutboundHandlerMeta{
+	freedom, err := freedom.New(proxy.ContextWithOutboundMeta(ctx, &proxy.OutboundHandlerMeta{
 		Tag: "tag",
 		StreamSettings: &internet.StreamConfig{
 			Protocol: internet.TransportProtocol_TCP,
 		},
-	})))
+	}), &freedom.Config{})
+	assert.Error(err).IsNil()
+	common.Must(outboundManager.SetHandler("tag", freedom))
 
 	assert.Error(space.AddApp(new(Config))).IsNil()
 	proxy := OutboundProxyFromSpace(space)

+ 16 - 0
app/space.go

@@ -1,6 +1,8 @@
 package app
 
 import (
+	"context"
+
 	"github.com/golang/protobuf/proto"
 	"v2ray.com/core/common/errors"
 	"v2ray.com/core/common/log"
@@ -104,3 +106,17 @@ func (v *spaceImpl) AddApp(config proto.Message) error {
 func (v *spaceImpl) AddAppLegacy(name string, application Application) {
 	v.cache[name] = application
 }
+
+type contextKey int
+
+const (
+	spaceKey = contextKey(0)
+)
+
+func SpaceFromContext(ctx context.Context) Space {
+	return ctx.Value(spaceKey).(Space)
+}
+
+func ContextWithSpace(ctx context.Context, space Space) context.Context {
+	return context.WithValue(ctx, spaceKey, space)
+}

+ 7 - 3
inbound_detour_always.go

@@ -1,6 +1,8 @@
 package core
 
 import (
+	"context"
+
 	"v2ray.com/core/app"
 	"v2ray.com/core/common/dice"
 	"v2ray.com/core/common/log"
@@ -15,7 +17,8 @@ type InboundDetourHandlerAlways struct {
 	ich    []proxy.InboundHandler
 }
 
-func NewInboundDetourHandlerAlways(space app.Space, config *InboundConnectionConfig) (*InboundDetourHandlerAlways, error) {
+func NewInboundDetourHandlerAlways(ctx context.Context, config *InboundConnectionConfig) (*InboundDetourHandlerAlways, error) {
+	space := app.SpaceFromContext(ctx)
 	handler := &InboundDetourHandlerAlways{
 		space:  space,
 		config: config,
@@ -27,13 +30,14 @@ func NewInboundDetourHandlerAlways(space app.Space, config *InboundConnectionCon
 		if err != nil {
 			return nil, err
 		}
-		ich, err := proxy.CreateInboundHandler(config.Settings.Type, space, ichConfig, &proxy.InboundHandlerMeta{
+		ich, err := proxy.CreateInboundHandler(proxy.ContextWithInboundMeta(ctx, &proxy.InboundHandlerMeta{
 			Address:                config.GetListenOnValue(),
 			Port:                   i,
 			Tag:                    config.Tag,
 			StreamSettings:         config.StreamSettings,
 			AllowPassiveConnection: config.AllowPassiveConnection,
-		})
+		}), ichConfig)
+
 		if err != nil {
 			log.Error("Failed to create inbound connection handler: ", err)
 			return nil, err

+ 12 - 5
inbound_detour_dynamic.go

@@ -4,6 +4,8 @@ import (
 	"sync"
 	"time"
 
+	"context"
+
 	"v2ray.com/core/app"
 	"v2ray.com/core/common/dice"
 	"v2ray.com/core/common/log"
@@ -20,13 +22,16 @@ type InboundDetourHandlerDynamic struct {
 	ichs        []proxy.InboundHandler
 	ich2Recyle  []proxy.InboundHandler
 	lastRefresh time.Time
+	ctx         context.Context
 }
 
-func NewInboundDetourHandlerDynamic(space app.Space, config *InboundConnectionConfig) (*InboundDetourHandlerDynamic, error) {
+func NewInboundDetourHandlerDynamic(ctx context.Context, config *InboundConnectionConfig) (*InboundDetourHandlerDynamic, error) {
+	space := app.SpaceFromContext(ctx)
 	handler := &InboundDetourHandlerDynamic{
 		space:      space,
 		config:     config,
 		portsInUse: make(map[v2net.Port]bool),
+		ctx:        ctx,
 	}
 	handler.ichs = make([]proxy.InboundHandler, config.GetAllocationStrategyValue().GetConcurrencyValue())
 
@@ -35,13 +40,13 @@ func NewInboundDetourHandlerDynamic(space app.Space, config *InboundConnectionCo
 	if err != nil {
 		return nil, err
 	}
-	ich, err := proxy.CreateInboundHandler(config.Settings.Type, space, ichConfig, &proxy.InboundHandlerMeta{
+	ich, err := proxy.CreateInboundHandler(proxy.ContextWithInboundMeta(ctx, &proxy.InboundHandlerMeta{
 		Address:                config.GetListenOnValue(),
 		Port:                   0,
 		Tag:                    config.Tag,
 		StreamSettings:         config.StreamSettings,
 		AllowPassiveConnection: config.AllowPassiveConnection,
-	})
+	}), ichConfig)
 	if err != nil {
 		log.Error("Point: Failed to create inbound connection handler: ", err)
 		return nil, err
@@ -107,8 +112,10 @@ func (v *InboundDetourHandlerDynamic) refresh() error {
 		err := retry.Timed(5, 100).On(func() error {
 			port := v.pickUnusedPort()
 			ichConfig, _ := config.GetTypedSettings()
-			ich, err := proxy.CreateInboundHandler(config.Settings.Type, v.space, ichConfig, &proxy.InboundHandlerMeta{
-				Address: config.GetListenOnValue(), Port: port, Tag: config.Tag, StreamSettings: config.StreamSettings})
+			ich, err := proxy.CreateInboundHandler(proxy.ContextWithInboundMeta(v.ctx, &proxy.InboundHandlerMeta{
+				Address: config.GetListenOnValue(),
+				Port:    port, Tag: config.Tag,
+				StreamSettings: config.StreamSettings}), ichConfig)
 			if err != nil {
 				delete(v.portsInUse, port)
 				return err

+ 7 - 11
proxy/blackhole/blackhole.go

@@ -2,28 +2,26 @@
 package blackhole
 
 import (
+	"context"
 	"time"
 
-	"v2ray.com/core/app"
+	"v2ray.com/core/common"
 	v2net "v2ray.com/core/common/net"
-	"v2ray.com/core/proxy"
 	"v2ray.com/core/transport/ray"
 )
 
 // Handler is an outbound connection that sliently swallow the entire payload.
 type Handler struct {
-	meta     *proxy.OutboundHandlerMeta
 	response ResponseConfig
 }
 
 // New creates a new blackhole handler.
-func New(space app.Space, config *Config, meta *proxy.OutboundHandlerMeta) (proxy.OutboundHandler, error) {
+func New(ctx context.Context, config *Config) (*Handler, error) {
 	response, err := config.GetInternalResponse()
 	if err != nil {
 		return nil, err
 	}
 	return &Handler{
-		meta:     meta,
 		response: response,
 	}, nil
 }
@@ -38,10 +36,8 @@ func (v *Handler) Dispatch(destination v2net.Destination, ray ray.OutboundRay) {
 	ray.OutboundOutput().CloseError()
 }
 
-// Factory is an utility for creating blackhole handlers.
-type Factory struct{}
-
-// Create implements OutboundHandlerFactory.Create().
-func (v *Factory) Create(space app.Space, config interface{}, meta *proxy.OutboundHandlerMeta) (proxy.OutboundHandler, error) {
-	return New(space, config.(*Config), meta)
+func init() {
+	common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
+		return New(ctx, config.(*Config))
+	}))
 }

+ 0 - 12
proxy/blackhole/init.go

@@ -1,12 +0,0 @@
-package blackhole
-
-import (
-	"v2ray.com/core/common"
-	"v2ray.com/core/common/serial"
-	"v2ray.com/core/proxy"
-)
-
-func init() {
-	// Must listed after config.pb.go
-	common.Must(proxy.RegisterOutboundHandlerCreator(serial.GetMessageType(new(Config)), new(Factory)))
-}

+ 36 - 0
proxy/context.go

@@ -0,0 +1,36 @@
+package proxy
+
+import (
+	"context"
+)
+
+type key int
+
+const (
+	inboundMetaKey  = key(0)
+	outboundMetaKey = key(1)
+)
+
+func ContextWithInboundMeta(ctx context.Context, meta *InboundHandlerMeta) context.Context {
+	return context.WithValue(ctx, inboundMetaKey, meta)
+}
+
+func InboundMetaFromContext(ctx context.Context) *InboundHandlerMeta {
+	v := ctx.Value(inboundMetaKey)
+	if v == nil {
+		return nil
+	}
+	return v.(*InboundHandlerMeta)
+}
+
+func ContextWithOutboundMeta(ctx context.Context, meta *OutboundHandlerMeta) context.Context {
+	return context.WithValue(ctx, outboundMetaKey, meta)
+}
+
+func OutboundMetaFromContext(ctx context.Context) *OutboundHandlerMeta {
+	v := ctx.Value(outboundMetaKey)
+	if v == nil {
+		return nil
+	}
+	return v.(*OutboundHandlerMeta)
+}

+ 0 - 11
proxy/creator.go

@@ -1,11 +0,0 @@
-package proxy
-
-import "v2ray.com/core/app"
-
-type InboundHandlerFactory interface {
-	Create(space app.Space, config interface{}, meta *InboundHandlerMeta) (InboundHandler, error)
-}
-
-type OutboundHandlerFactory interface {
-	Create(space app.Space, config interface{}, meta *OutboundHandlerMeta) (OutboundHandler, error)
-}

+ 14 - 10
proxy/dokodemo/dokodemo.go

@@ -1,6 +1,7 @@
 package dokodemo
 
 import (
+	"context"
 	"sync"
 
 	"v2ray.com/core/app"
@@ -10,7 +11,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/common/signal"
 	"v2ray.com/core/proxy"
 	"v2ray.com/core/transport/internet"
@@ -31,7 +31,15 @@ type DokodemoDoor struct {
 	meta             *proxy.InboundHandlerMeta
 }
 
-func NewDokodemoDoor(config *Config, space app.Space, meta *proxy.InboundHandlerMeta) *DokodemoDoor {
+func NewDokodemoDoor(ctx context.Context, config *Config) (*DokodemoDoor, error) {
+	space := app.SpaceFromContext(ctx)
+	if space == nil {
+		return nil, errors.New("Dokodemo: No space in context.")
+	}
+	meta := proxy.InboundMetaFromContext(ctx)
+	if meta == nil {
+		return nil, errors.New("Dokodemo: No outbound meta in context.")
+	}
 	d := &DokodemoDoor{
 		config:  config,
 		address: config.GetPredefinedAddress(),
@@ -45,7 +53,7 @@ func NewDokodemoDoor(config *Config, space app.Space, meta *proxy.InboundHandler
 		}
 		return nil
 	})
-	return d
+	return d, nil
 }
 
 func (v *DokodemoDoor) Port() v2net.Port {
@@ -205,12 +213,8 @@ func (v *DokodemoDoor) HandleTCPConnection(conn internet.Connection) {
 	}
 }
 
-type Factory struct{}
-
-func (v *Factory) Create(space app.Space, rawConfig interface{}, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error) {
-	return NewDokodemoDoor(rawConfig.(*Config), space, meta), nil
-}
-
 func init() {
-	common.Must(proxy.RegisterInboundHandlerCreator(serial.GetMessageType(new(Config)), new(Factory)))
+	common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
+		return NewDokodemoDoor(ctx, config.(*Config))
+	}))
 }

+ 44 - 31
proxy/dokodemo/dokodemo_test.go

@@ -4,6 +4,8 @@ import (
 	"net"
 	"testing"
 
+	"context"
+
 	"v2ray.com/core/app"
 	"v2ray.com/core/app/dispatcher"
 	_ "v2ray.com/core/app/dispatcher/impl"
@@ -42,31 +44,36 @@ func TestDokodemoTCP(t *testing.T) {
 	space.AddApp(new(proxyman.OutboundConfig))
 
 	ohm := proxyman.OutboundHandlerManagerFromSpace(space)
-	ohm.SetDefaultHandler(
-		freedom.New(
-			&freedom.Config{},
-			space,
-			&proxy.OutboundHandlerMeta{
-				Address: v2net.LocalHostIP,
-				StreamSettings: &internet.StreamConfig{
-					Protocol: internet.TransportProtocol_TCP,
-				},
-			}))
+	ctx := context.Background()
+	ctx = app.ContextWithSpace(ctx, space)
+
+	freedom, err := freedom.New(proxy.ContextWithOutboundMeta(ctx, &proxy.OutboundHandlerMeta{
+		Address: v2net.LocalHostIP,
+		StreamSettings: &internet.StreamConfig{
+			Protocol: internet.TransportProtocol_TCP,
+		},
+	}), &freedom.Config{})
+	assert.Error(err).IsNil()
+	ohm.SetDefaultHandler(freedom)
 
 	data2Send := "Data to be sent to remote."
 
 	port := v2net.Port(dice.Roll(20000) + 10000)
-	dokodemo := NewDokodemoDoor(&Config{
-		Address:     v2net.NewIPOrDomain(v2net.LocalHostIP),
-		Port:        uint32(tcpServer.Port),
-		NetworkList: v2net.Network_TCP.AsList(),
-		Timeout:     600,
-	}, space, &proxy.InboundHandlerMeta{
+
+	ctx = proxy.ContextWithInboundMeta(ctx, &proxy.InboundHandlerMeta{
 		Address: v2net.LocalHostIP,
 		Port:    port,
 		StreamSettings: &internet.StreamConfig{
 			Protocol: internet.TransportProtocol_TCP,
 		}})
+
+	dokodemo, err := NewDokodemoDoor(ctx, &Config{
+		Address:     v2net.NewIPOrDomain(v2net.LocalHostIP),
+		Port:        uint32(tcpServer.Port),
+		NetworkList: v2net.Network_TCP.AsList(),
+		Timeout:     600,
+	})
+	assert.Error(err).IsNil()
 	defer dokodemo.Close()
 
 	assert.Error(space.Initialize()).IsNil()
@@ -114,30 +121,36 @@ func TestDokodemoUDP(t *testing.T) {
 	space.AddApp(new(proxyman.OutboundConfig))
 
 	ohm := proxyman.OutboundHandlerManagerFromSpace(space)
-	ohm.SetDefaultHandler(
-		freedom.New(
-			&freedom.Config{},
-			space,
-			&proxy.OutboundHandlerMeta{
-				Address: v2net.AnyIP,
-				StreamSettings: &internet.StreamConfig{
-					Protocol: internet.TransportProtocol_TCP,
-				}}))
+
+	ctx := context.Background()
+	ctx = app.ContextWithSpace(ctx, space)
+	freedom, err := freedom.New(proxy.ContextWithOutboundMeta(ctx, &proxy.OutboundHandlerMeta{
+		Address: v2net.AnyIP,
+		StreamSettings: &internet.StreamConfig{
+			Protocol: internet.TransportProtocol_TCP,
+		},
+	}), &freedom.Config{})
+	assert.Error(err).IsNil()
+	ohm.SetDefaultHandler(freedom)
 
 	data2Send := "Data to be sent to remote."
 
 	port := v2net.Port(dice.Roll(20000) + 10000)
-	dokodemo := NewDokodemoDoor(&Config{
-		Address:     v2net.NewIPOrDomain(v2net.LocalHostIP),
-		Port:        uint32(udpServer.Port),
-		NetworkList: v2net.Network_UDP.AsList(),
-		Timeout:     600,
-	}, space, &proxy.InboundHandlerMeta{
+
+	ctx = proxy.ContextWithInboundMeta(ctx, &proxy.InboundHandlerMeta{
 		Address: v2net.LocalHostIP,
 		Port:    port,
 		StreamSettings: &internet.StreamConfig{
 			Protocol: internet.TransportProtocol_TCP,
 		}})
+
+	dokodemo, err := NewDokodemoDoor(ctx, &Config{
+		Address:     v2net.NewIPOrDomain(v2net.LocalHostIP),
+		Port:        uint32(udpServer.Port),
+		NetworkList: v2net.Network_UDP.AsList(),
+		Timeout:     600,
+	})
+	assert.Error(err).IsNil()
 	defer dokodemo.Close()
 
 	assert.Error(space.Initialize()).IsNil()

+ 14 - 10
proxy/freedom/freedom.go

@@ -1,6 +1,7 @@
 package freedom
 
 import (
+	"context"
 	"io"
 
 	"v2ray.com/core/app"
@@ -12,7 +13,6 @@ import (
 	"v2ray.com/core/common/log"
 	v2net "v2ray.com/core/common/net"
 	"v2ray.com/core/common/retry"
-	"v2ray.com/core/common/serial"
 	"v2ray.com/core/common/signal"
 	"v2ray.com/core/proxy"
 	"v2ray.com/core/transport/internet"
@@ -26,7 +26,15 @@ type Handler struct {
 	meta           *proxy.OutboundHandlerMeta
 }
 
-func New(config *Config, space app.Space, meta *proxy.OutboundHandlerMeta) *Handler {
+func New(ctx context.Context, config *Config) (*Handler, error) {
+	space := app.SpaceFromContext(ctx)
+	if space == nil {
+		return nil, errors.New("Freedom: No space in context.")
+	}
+	meta := proxy.OutboundMetaFromContext(ctx)
+	if meta == nil {
+		return nil, errors.New("Freedom: No outbound meta in context.")
+	}
 	f := &Handler{
 		domainStrategy: config.DomainStrategy,
 		timeout:        config.Timeout,
@@ -41,7 +49,7 @@ func New(config *Config, space app.Space, meta *proxy.OutboundHandlerMeta) *Hand
 		}
 		return nil
 	})
-	return f
+	return f, nil
 }
 
 // Private: Visible for testing.
@@ -128,12 +136,8 @@ func (v *Handler) Dispatch(destination v2net.Destination, ray ray.OutboundRay) {
 	}
 }
 
-type Factory struct{}
-
-func (v *Factory) Create(space app.Space, config interface{}, meta *proxy.OutboundHandlerMeta) (proxy.OutboundHandler, error) {
-	return New(config.(*Config), space, meta), nil
-}
-
 func init() {
-	common.Must(proxy.RegisterOutboundHandlerCreator(serial.GetMessageType(new(Config)), new(Factory)))
+	common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
+		return New(ctx, config.(*Config))
+	}))
 }

+ 20 - 18
proxy/freedom/freedom_test.go

@@ -3,6 +3,8 @@ package freedom_test
 import (
 	"testing"
 
+	"context"
+
 	"v2ray.com/core/app"
 	"v2ray.com/core/app/dispatcher"
 	_ "v2ray.com/core/app/dispatcher/impl"
@@ -37,15 +39,15 @@ func TestSinglePacket(t *testing.T) {
 	assert.Error(err).IsNil()
 
 	space := app.NewSpace()
-	freedom := New(
-		&Config{},
-		space,
-		&proxy.OutboundHandlerMeta{
-			Address: v2net.AnyIP,
-			StreamSettings: &internet.StreamConfig{
-				Protocol: internet.TransportProtocol_TCP,
-			},
-		})
+	ctx := app.ContextWithSpace(context.Background(), space)
+	ctx = proxy.ContextWithOutboundMeta(ctx, &proxy.OutboundHandlerMeta{
+		Address: v2net.AnyIP,
+		StreamSettings: &internet.StreamConfig{
+			Protocol: internet.TransportProtocol_TCP,
+		},
+	})
+	freedom, err := New(ctx, &Config{})
+	assert.Error(err).IsNil()
 	assert.Error(space.Initialize()).IsNil()
 
 	traffic := ray.NewRay()
@@ -77,15 +79,15 @@ func TestIPResolution(t *testing.T) {
 		},
 	})).IsNil()
 
-	freedom := New(
-		&Config{DomainStrategy: Config_USE_IP},
-		space,
-		&proxy.OutboundHandlerMeta{
-			Address: v2net.AnyIP,
-			StreamSettings: &internet.StreamConfig{
-				Protocol: internet.TransportProtocol_TCP,
-			},
-		})
+	ctx := app.ContextWithSpace(context.Background(), space)
+	ctx = proxy.ContextWithOutboundMeta(ctx, &proxy.OutboundHandlerMeta{
+		Address: v2net.AnyIP,
+		StreamSettings: &internet.StreamConfig{
+			Protocol: internet.TransportProtocol_TCP,
+		},
+	})
+	freedom, err := New(ctx, &Config{DomainStrategy: Config_USE_IP})
+	assert.Error(err).IsNil()
 
 	assert.Error(space.Initialize()).IsNil()
 

+ 20 - 31
proxy/handler_cache.go

@@ -1,45 +1,34 @@
 package proxy
 
 import (
-	"v2ray.com/core/app"
+	"context"
+
 	"v2ray.com/core/common"
 	"v2ray.com/core/common/errors"
 )
 
-var (
-	inboundFactories  = make(map[string]InboundHandlerFactory)
-	outboundFactories = make(map[string]OutboundHandlerFactory)
-)
-
-func RegisterInboundHandlerCreator(name string, creator InboundHandlerFactory) error {
-	if _, found := inboundFactories[name]; found {
-		return common.ErrDuplicatedName
+func CreateInboundHandler(ctx context.Context, config interface{}) (InboundHandler, error) {
+	handler, err := common.CreateObject(ctx, config)
+	if err != nil {
+		return nil, err
 	}
-	inboundFactories[name] = creator
-	return nil
-}
-
-func RegisterOutboundHandlerCreator(name string, creator OutboundHandlerFactory) error {
-	if _, found := outboundFactories[name]; found {
-		return common.ErrDuplicatedName
+	switch h := handler.(type) {
+	case InboundHandler:
+		return h, nil
+	default:
+		return nil, errors.New("Proxy: Not a InboundHandler.")
 	}
-	outboundFactories[name] = creator
-	return nil
 }
 
-func CreateInboundHandler(name string, space app.Space, config interface{}, meta *InboundHandlerMeta) (InboundHandler, error) {
-	creator, found := inboundFactories[name]
-	if !found {
-		return nil, errors.New("Proxy: Unknown inbound name: " + name)
+func CreateOutboundHandler(ctx context.Context, config interface{}) (OutboundHandler, error) {
+	handler, err := common.CreateObject(ctx, config)
+	if err != nil {
+		return nil, err
 	}
-	return creator.Create(space, config, meta)
-}
-
-func CreateOutboundHandler(name string, space app.Space, config interface{}, meta *OutboundHandlerMeta) (OutboundHandler, error) {
-	creator, found := outboundFactories[name]
-	if !found {
-		return nil, errors.New("Proxy: Unknown outbound name: " + name)
+	switch h := handler.(type) {
+	case OutboundHandler:
+		return h, nil
+	default:
+		return nil, errors.New("Proxy: Not a OutboundHandler.")
 	}
-
-	return creator.Create(space, config, meta)
 }

+ 15 - 12
proxy/http/server.go

@@ -8,6 +8,8 @@ import (
 	"strings"
 	"sync"
 
+	"context"
+
 	"v2ray.com/core/app"
 	"v2ray.com/core/app/dispatcher"
 	"v2ray.com/core/common"
@@ -16,7 +18,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/common/signal"
 	"v2ray.com/core/proxy"
 	"v2ray.com/core/transport/internet"
@@ -33,7 +34,15 @@ type Server struct {
 }
 
 // NewServer creates a new HTTP inbound handler.
-func NewServer(config *ServerConfig, space app.Space, meta *proxy.InboundHandlerMeta) *Server {
+func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
+	space := app.SpaceFromContext(ctx)
+	if space == nil {
+		return nil, errors.New("HTTP|Server: No space in context.")
+	}
+	meta := proxy.InboundMetaFromContext(ctx)
+	if meta == nil {
+		return nil, errors.New("HTTP|Server: No inbound meta from context.")
+	}
 	s := &Server{
 		config: config,
 		meta:   meta,
@@ -45,7 +54,7 @@ func NewServer(config *ServerConfig, space app.Space, meta *proxy.InboundHandler
 		}
 		return nil
 	})
-	return s
+	return s, nil
 }
 
 // Port implements InboundHandler.Port().
@@ -285,14 +294,8 @@ func (v *Server) handlePlainHTTP(request *http.Request, session *proxy.SessionIn
 	}
 }
 
-// ServerFactory is a InboundHandlerFactory.
-type ServerFactory struct{}
-
-// Create implements InboundHandlerFactory.Create().
-func (v *ServerFactory) Create(space app.Space, rawConfig interface{}, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error) {
-	return NewServer(rawConfig.(*ServerConfig), space, meta), nil
-}
-
 func init() {
-	common.Must(proxy.RegisterInboundHandlerCreator(serial.GetMessageType(new(ServerConfig)), new(ServerFactory)))
+	common.Must(common.RegisterConfig((*ServerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
+		return NewServer(ctx, config.(*ServerConfig))
+	}))
 }

+ 13 - 8
proxy/shadowsocks/client.go

@@ -1,7 +1,10 @@
 package shadowsocks
 
 import (
-	"v2ray.com/core/app"
+	"context"
+	"errors"
+
+	"v2ray.com/core/common"
 	"v2ray.com/core/common/buf"
 	"v2ray.com/core/common/bufio"
 	"v2ray.com/core/common/log"
@@ -21,7 +24,11 @@ type Client struct {
 }
 
 // NewClient create a new Shadowsocks client.
-func NewClient(config *ClientConfig, space app.Space, meta *proxy.OutboundHandlerMeta) (*Client, error) {
+func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
+	meta := proxy.OutboundMetaFromContext(ctx)
+	if meta == nil {
+		return nil, errors.New("Shadowsocks|Client: No outbound meta in context.")
+	}
 	serverList := protocol.NewServerList()
 	for _, rec := range config.Server {
 		serverList.AddServer(protocol.NewServerSpecFromPB(*rec))
@@ -164,10 +171,8 @@ func (v *Client) Dispatch(destination v2net.Destination, ray ray.OutboundRay) {
 	}
 }
 
-// ClientFactory is a OutboundHandlerFactory.
-type ClientFactory struct{}
-
-// Create implements OutboundHandlerFactory.Create().
-func (ClientFactory) Create(space app.Space, rawConfig interface{}, meta *proxy.OutboundHandlerMeta) (proxy.OutboundHandler, error) {
-	return NewClient(rawConfig.(*ClientConfig), space, meta)
+func init() {
+	common.Must(common.RegisterConfig((*ClientConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
+		return NewClient(ctx, config.(*ClientConfig))
+	}))
 }

+ 0 - 13
proxy/shadowsocks/init.go

@@ -1,13 +0,0 @@
-package shadowsocks
-
-import (
-	"v2ray.com/core/common"
-	"v2ray.com/core/common/serial"
-	"v2ray.com/core/proxy"
-)
-
-func init() {
-	// Must happen after config is initialized
-	common.Must(proxy.RegisterOutboundHandlerCreator(serial.GetMessageType(new(ClientConfig)), new(ClientFactory)))
-	common.Must(proxy.RegisterInboundHandlerCreator(serial.GetMessageType(new(ServerConfig)), new(ServerFactory)))
-}

+ 16 - 5
proxy/shadowsocks/server.go

@@ -1,8 +1,11 @@
 package shadowsocks
 
 import (
+	"context"
+
 	"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"
@@ -27,7 +30,15 @@ type Server struct {
 	udpServer        *udp.Server
 }
 
-func NewServer(config *ServerConfig, space app.Space, meta *proxy.InboundHandlerMeta) (*Server, error) {
+func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
+	space := app.SpaceFromContext(ctx)
+	if space == nil {
+		return nil, errors.New("Shadowsocks|Server: No space in context.")
+	}
+	meta := proxy.InboundMetaFromContext(ctx)
+	if meta == nil {
+		return nil, errors.New("Shadowsocks|Server: No inbound meta in context.")
+	}
 	if config.GetUser() == nil {
 		return nil, protocol.ErrUserMissing
 	}
@@ -216,8 +227,8 @@ func (v *Server) handleConnection(conn internet.Connection) {
 	}
 }
 
-type ServerFactory struct{}
-
-func (v *ServerFactory) Create(space app.Space, rawConfig interface{}, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error) {
-	return NewServer(rawConfig.(*ServerConfig), space, meta)
+func init() {
+	common.Must(common.RegisterConfig((*ServerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
+		return NewServer(ctx, config.(*ServerConfig))
+	}))
 }

+ 13 - 6
proxy/socks/client.go

@@ -1,7 +1,10 @@
 package socks
 
 import (
-	"v2ray.com/core/app"
+	"context"
+	"errors"
+
+	"v2ray.com/core/common"
 	"v2ray.com/core/common/buf"
 	"v2ray.com/core/common/log"
 	"v2ray.com/core/common/net"
@@ -18,7 +21,11 @@ type Client struct {
 	meta         *proxy.OutboundHandlerMeta
 }
 
-func NewClient(config *ClientConfig, space app.Space, meta *proxy.OutboundHandlerMeta) (*Client, error) {
+func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
+	meta := proxy.OutboundMetaFromContext(ctx)
+	if meta == nil {
+		return nil, errors.New("Socks|Client: No outbound meta in context.")
+	}
 	serverList := protocol.NewServerList()
 	for _, rec := range config.Server {
 		serverList.AddServer(protocol.NewServerSpecFromPB(*rec))
@@ -112,8 +119,8 @@ func (c *Client) Dispatch(destination net.Destination, ray ray.OutboundRay) {
 	}
 }
 
-type ClientFactory struct{}
-
-func (ClientFactory) Create(space app.Space, rawConfig interface{}, meta *proxy.OutboundHandlerMeta) (proxy.OutboundHandler, error) {
-	return NewClient(rawConfig.(*ClientConfig), space, meta)
+func init() {
+	common.Must(common.RegisterConfig((*ClientConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
+		return NewClient(ctx, config.(*ClientConfig))
+	}))
 }

+ 16 - 6
proxy/socks/server.go

@@ -1,12 +1,14 @@
 package socks
 
 import (
+	"context"
 	"io"
 	"sync"
 	"time"
 
 	"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"
@@ -34,7 +36,15 @@ type Server struct {
 }
 
 // NewServer creates a new Server object.
-func NewServer(config *ServerConfig, space app.Space, meta *proxy.InboundHandlerMeta) *Server {
+func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
+	space := app.SpaceFromContext(ctx)
+	if space == nil {
+		return nil, errors.New("Socks|Server: No space in context.")
+	}
+	meta := proxy.InboundMetaFromContext(ctx)
+	if meta == nil {
+		return nil, errors.New("Socks|Server: No inbound meta in context.")
+	}
 	s := &Server{
 		config: config,
 		meta:   meta,
@@ -46,7 +56,7 @@ func NewServer(config *ServerConfig, space app.Space, meta *proxy.InboundHandler
 		}
 		return nil
 	})
-	return s
+	return s, nil
 }
 
 // Port implements InboundHandler.Port().
@@ -181,8 +191,8 @@ func (v *Server) transport(reader io.Reader, writer io.Writer, session *proxy.Se
 	}
 }
 
-type ServerFactory struct{}
-
-func (v *ServerFactory) Create(space app.Space, rawConfig interface{}, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error) {
-	return NewServer(rawConfig.(*ServerConfig), space, meta), nil
+func init() {
+	common.Must(common.RegisterConfig((*ServerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
+		return NewServer(ctx, config.(*ServerConfig))
+	}))
 }

+ 1 - 11
proxy/socks/socks.go

@@ -1,12 +1,2 @@
+// Package socks provides implements of Socks protocol 4, 4a and 5.
 package socks
-
-import (
-	"v2ray.com/core/common"
-	"v2ray.com/core/common/serial"
-	"v2ray.com/core/proxy"
-)
-
-func init() {
-	common.Must(proxy.RegisterOutboundHandlerCreator(serial.GetMessageType((*ClientConfig)(nil)), new(ClientFactory)))
-	common.Must(proxy.RegisterInboundHandlerCreator(serial.GetMessageType((*ServerConfig)(nil)), new(ServerFactory)))
-}

+ 42 - 33
proxy/vmess/inbound/inbound.go

@@ -4,6 +4,8 @@ import (
 	"io"
 	"sync"
 
+	"context"
+
 	"v2ray.com/core/app"
 	"v2ray.com/core/app/dispatcher"
 	"v2ray.com/core/app/proxyman"
@@ -82,6 +84,43 @@ type VMessInboundHandler struct {
 	meta                  *proxy.InboundHandlerMeta
 }
 
+func New(ctx context.Context, config *Config) (*VMessInboundHandler, error) {
+	space := app.SpaceFromContext(ctx)
+	if space == nil {
+		return nil, errors.New("VMess|Inbound: No space in context.")
+	}
+	meta := proxy.InboundMetaFromContext(ctx)
+	if meta == nil {
+		return nil, errors.New("VMess|Inbound: No inbound meta in context.")
+	}
+
+	allowedClients := vmess.NewTimedUserValidator(protocol.DefaultIDHash)
+	for _, user := range config.User {
+		allowedClients.Add(user)
+	}
+
+	handler := &VMessInboundHandler{
+		clients:      allowedClients,
+		detours:      config.Detour,
+		usersByEmail: NewUserByEmail(config.User, config.GetDefaultValue()),
+		meta:         meta,
+	}
+
+	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
+}
+
 func (v *VMessInboundHandler) Port() v2net.Port {
 	return v.meta.Port
 }
@@ -251,38 +290,8 @@ func (v *VMessInboundHandler) HandleConnection(connection internet.Connection) {
 	}
 }
 
-type Factory struct{}
-
-func (v *Factory) Create(space app.Space, rawConfig interface{}, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error) {
-	config := rawConfig.(*Config)
-
-	allowedClients := vmess.NewTimedUserValidator(protocol.DefaultIDHash)
-	for _, user := range config.User {
-		allowedClients.Add(user)
-	}
-
-	handler := &VMessInboundHandler{
-		clients:      allowedClients,
-		detours:      config.Detour,
-		usersByEmail: NewUserByEmail(config.User, config.GetDefaultValue()),
-		meta:         meta,
-	}
-
-	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
-}
-
 func init() {
-	common.Must(proxy.RegisterInboundHandlerCreator(serial.GetMessageType(new(Config)), new(Factory)))
+	common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
+		return New(ctx, config.(*Config))
+	}))
 }

+ 28 - 21
proxy/vmess/outbound/outbound.go

@@ -3,6 +3,8 @@ package outbound
 import (
 	"time"
 
+	"context"
+
 	"v2ray.com/core/app"
 	"v2ray.com/core/common"
 	"v2ray.com/core/common/buf"
@@ -12,7 +14,6 @@ import (
 	v2net "v2ray.com/core/common/net"
 	"v2ray.com/core/common/protocol"
 	"v2ray.com/core/common/retry"
-	"v2ray.com/core/common/serial"
 	"v2ray.com/core/common/signal"
 	"v2ray.com/core/proxy"
 	"v2ray.com/core/proxy/vmess"
@@ -28,6 +29,29 @@ type VMessOutboundHandler struct {
 	meta         *proxy.OutboundHandlerMeta
 }
 
+func New(ctx context.Context, config *Config) (*VMessOutboundHandler, error) {
+	space := app.SpaceFromContext(ctx)
+	if space == nil {
+		return nil, errors.New("VMess|Outbound: No space in context.")
+	}
+	meta := proxy.OutboundMetaFromContext(ctx)
+	if meta == nil {
+		return nil, errors.New("VMess|Outbound: No outbound meta in context.")
+	}
+
+	serverList := protocol.NewServerList()
+	for _, rec := range config.Receiver {
+		serverList.AddServer(protocol.NewServerSpecFromPB(*rec))
+	}
+	handler := &VMessOutboundHandler{
+		serverList:   serverList,
+		serverPicker: protocol.NewRoundRobinServerPicker(serverList),
+		meta:         meta,
+	}
+
+	return handler, nil
+}
+
 // Dispatch implements OutboundHandler.Dispatch().
 func (v *VMessOutboundHandler) Dispatch(target v2net.Destination, outboundRay ray.OutboundRay) {
 	var rec *protocol.ServerSpec
@@ -142,25 +166,8 @@ func (v *VMessOutboundHandler) Dispatch(target v2net.Destination, outboundRay ra
 	return
 }
 
-// Factory is a proxy factory for VMess outbound.
-type Factory struct{}
-
-func (v *Factory) Create(space app.Space, rawConfig interface{}, meta *proxy.OutboundHandlerMeta) (proxy.OutboundHandler, error) {
-	vOutConfig := rawConfig.(*Config)
-
-	serverList := protocol.NewServerList()
-	for _, rec := range vOutConfig.Receiver {
-		serverList.AddServer(protocol.NewServerSpecFromPB(*rec))
-	}
-	handler := &VMessOutboundHandler{
-		serverList:   serverList,
-		serverPicker: protocol.NewRoundRobinServerPicker(serverList),
-		meta:         meta,
-	}
-
-	return handler, nil
-}
-
 func init() {
-	common.Must(proxy.RegisterOutboundHandlerCreator(serial.GetMessageType(new(Config)), new(Factory)))
+	common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
+		return New(ctx, config.(*Config))
+	}))
 }

+ 12 - 9
v2ray.go

@@ -1,6 +1,8 @@
 package core
 
 import (
+	"context"
+
 	"v2ray.com/core/app"
 	"v2ray.com/core/app/dispatcher"
 	"v2ray.com/core/app/dns"
@@ -38,6 +40,8 @@ func NewPoint(pConfig *Config) (*Point, error) {
 	}
 
 	space := app.NewSpace()
+	ctx := app.ContextWithSpace(context.Background(), space)
+
 	vpoint.space = space
 	vpoint.space.AddAppLegacy(serial.GetMessageType((*proxyman.InboundConfig)(nil)), vpoint)
 
@@ -94,14 +98,14 @@ func NewPoint(pConfig *Config) (*Point, error) {
 		var inboundHandler InboundDetourHandler
 		switch allocConfig.Type {
 		case AllocationStrategy_Always:
-			dh, err := NewInboundDetourHandlerAlways(vpoint.space, inbound)
+			dh, err := NewInboundDetourHandlerAlways(ctx, inbound)
 			if err != nil {
 				log.Error("V2Ray: Failed to create detour handler: ", err)
 				return nil, common.ErrBadConfiguration
 			}
 			inboundHandler = dh
 		case AllocationStrategy_Random:
-			dh, err := NewInboundDetourHandlerDynamic(vpoint.space, inbound)
+			dh, err := NewInboundDetourHandlerDynamic(ctx, inbound)
 			if err != nil {
 				log.Error("V2Ray: Failed to create detour handler: ", err)
 				return nil, common.ErrBadConfiguration
@@ -124,13 +128,12 @@ func NewPoint(pConfig *Config) (*Point, error) {
 		if err != nil {
 			return nil, err
 		}
-		outboundHandler, err := proxy.CreateOutboundHandler(
-			outbound.Settings.Type, vpoint.space, outboundSettings, &proxy.OutboundHandlerMeta{
-				Tag:            outbound.Tag,
-				Address:        outbound.GetSendThroughValue(),
-				StreamSettings: outbound.StreamSettings,
-				ProxySettings:  outbound.ProxySettings,
-			})
+		outboundHandler, err := proxy.CreateOutboundHandler(proxy.ContextWithOutboundMeta(ctx, &proxy.OutboundHandlerMeta{
+			Tag:            outbound.Tag,
+			Address:        outbound.GetSendThroughValue(),
+			StreamSettings: outbound.StreamSettings,
+			ProxySettings:  outbound.ProxySettings,
+		}), outboundSettings)
 		if err != nil {
 			log.Error("V2Ray: Failed to create detour outbound connection handler: ", err)
 			return nil, err