Преглед на файлове

Simpilify configuration files

V2Ray преди 10 години
родител
ревизия
72b4eeba8b

+ 9 - 2
config.go → config/config.go

@@ -1,8 +1,15 @@
-package core
+package config
+
+type Type string
+
+const (
+	TypeInbound  = Type("inbound")
+	TypeOutbound = Type("outbound")
+)
 
 type ConnectionConfig interface {
 	Protocol() string
-	Content() []byte
+	Settings(configType Type) interface{}
 }
 
 type PointConfig interface {

+ 20 - 0
config/json/config_cache.go

@@ -0,0 +1,20 @@
+package json
+
+import (
+	"github.com/v2ray/v2ray-core/config"
+)
+
+type ConfigObjectCreator func() interface{}
+
+var (
+	configCache = make(map[string]ConfigObjectCreator)
+)
+
+func getConfigKey(protocol string, cType config.Type) string {
+	return protocol + "_" + string(cType)
+}
+
+func RegisterConfigType(protocol string, cType config.Type, creator ConfigObjectCreator) {
+	// TODO: check name
+	configCache[getConfigKey(protocol, cType)] = creator
+}

+ 16 - 22
config/json/json.go

@@ -4,30 +4,32 @@ import (
 	"encoding/json"
 	"io/ioutil"
 	"os"
-	"path/filepath"
 
-	"github.com/v2ray/v2ray-core"
 	"github.com/v2ray/v2ray-core/common/log"
+	"github.com/v2ray/v2ray-core/config"
 )
 
 type ConnectionConfig struct {
-	ProtocolString string `json:"protocol"`
-	File           string `json:"file"`
+	ProtocolString  string          `json:"protocol"`
+	SettingsMessage json.RawMessage `json:"settings"`
 }
 
 func (config *ConnectionConfig) Protocol() string {
 	return config.ProtocolString
 }
 
-func (config *ConnectionConfig) Content() []byte {
-	if len(config.File) == 0 {
-		return nil
+func (config *ConnectionConfig) Settings(configType config.Type) interface{} {
+	creator, found := configCache[getConfigKey(config.Protocol(), configType)]
+	if !found {
+		panic("Unknown protocol " + config.Protocol())
 	}
-	content, err := ioutil.ReadFile(config.File)
+	configObj := creator()
+	err := json.Unmarshal(config.SettingsMessage, configObj)
 	if err != nil {
-		panic(log.Error("Failed to read config file (%s): %v", config.File, err))
+		log.Error("Unable to parse connection config: %v", err)
+		panic("Failed to parse connection config.")
 	}
-	return content
+	return configObj
 }
 
 // Config is the config for Point server.
@@ -41,11 +43,11 @@ func (config *Config) Port() uint16 {
 	return config.PortValue
 }
 
-func (config *Config) InboundConfig() core.ConnectionConfig {
+func (config *Config) InboundConfig() config.ConnectionConfig {
 	return config.InboundConfigValue
 }
 
-func (config *Config) OutboundConfig() core.ConnectionConfig {
+func (config *Config) OutboundConfig() config.ConnectionConfig {
 	return config.OutboundConfigValue
 }
 
@@ -53,24 +55,16 @@ func LoadConfig(file string) (*Config, error) {
 	fixedFile := os.ExpandEnv(file)
 	rawConfig, err := ioutil.ReadFile(fixedFile)
 	if err != nil {
-		log.Error("Failed to read point config file (%s): %v", file, err)
+		log.Error("Failed to read server config file (%s): %v", file, err)
 		return nil, err
 	}
 
 	config := &Config{}
 	err = json.Unmarshal(rawConfig, config)
 	if err != nil {
-		log.Error("Failed to load point config: %v", err)
+		log.Error("Failed to load server config: %v", err)
 		return nil, err
 	}
 
-	if !filepath.IsAbs(config.InboundConfigValue.File) && len(config.InboundConfigValue.File) > 0 {
-		config.InboundConfigValue.File = filepath.Join(filepath.Dir(fixedFile), config.InboundConfigValue.File)
-	}
-
-	if !filepath.IsAbs(config.OutboundConfigValue.File) && len(config.OutboundConfigValue.File) > 0 {
-		config.OutboundConfigValue.File = filepath.Join(filepath.Dir(fixedFile), config.OutboundConfigValue.File)
-	}
-
 	return config, err
 }

+ 23 - 17
config/json/json_test.go

@@ -1,9 +1,15 @@
-package json
+package json_test
 
 import (
 	"path/filepath"
 	"testing"
 
+	"github.com/v2ray/v2ray-core/config"
+	"github.com/v2ray/v2ray-core/config/json"
+	_ "github.com/v2ray/v2ray-core/proxy/freedom/config/json"
+	_ "github.com/v2ray/v2ray-core/proxy/socks/config/json"
+	_ "github.com/v2ray/v2ray-core/proxy/vmess"
+
 	"github.com/v2ray/v2ray-core/testing/unit"
 )
 
@@ -13,18 +19,18 @@ func TestClientSampleConfig(t *testing.T) {
 	// TODO: fix for Windows
 	baseDir := "$GOPATH/src/github.com/v2ray/v2ray-core/release/config"
 
-	config, err := LoadConfig(filepath.Join(baseDir, "vpoint_socks_vmess.json"))
+	pointConfig, err := json.LoadConfig(filepath.Join(baseDir, "vpoint_socks_vmess.json"))
 	assert.Error(err).IsNil()
 
-	assert.Uint16(config.Port()).Positive()
-	assert.Pointer(config.InboundConfig()).IsNotNil()
-	assert.Pointer(config.OutboundConfig()).IsNotNil()
+	assert.Uint16(pointConfig.Port()).Positive()
+	assert.Pointer(pointConfig.InboundConfig()).IsNotNil()
+	assert.Pointer(pointConfig.OutboundConfig()).IsNotNil()
 
-	assert.String(config.InboundConfig().Protocol()).Equals("socks")
-	assert.Int(len(config.InboundConfig().Content())).GreaterThan(0)
+	assert.String(pointConfig.InboundConfig().Protocol()).Equals("socks")
+	assert.Pointer(pointConfig.InboundConfig().Settings(config.TypeInbound)).IsNotNil()
 
-	assert.String(config.OutboundConfig().Protocol()).Equals("vmess")
-	assert.Int(len(config.OutboundConfig().Content())).GreaterThan(0)
+	assert.String(pointConfig.OutboundConfig().Protocol()).Equals("vmess")
+	assert.Pointer(pointConfig.OutboundConfig().Settings(config.TypeOutbound)).IsNotNil()
 }
 
 func TestServerSampleConfig(t *testing.T) {
@@ -33,16 +39,16 @@ func TestServerSampleConfig(t *testing.T) {
 	// TODO: fix for Windows
 	baseDir := "$GOPATH/src/github.com/v2ray/v2ray-core/release/config"
 
-	config, err := LoadConfig(filepath.Join(baseDir, "vpoint_vmess_freedom.json"))
+	pointConfig, err := json.LoadConfig(filepath.Join(baseDir, "vpoint_vmess_freedom.json"))
 	assert.Error(err).IsNil()
 
-	assert.Uint16(config.Port()).Positive()
-	assert.Pointer(config.InboundConfig()).IsNotNil()
-	assert.Pointer(config.OutboundConfig()).IsNotNil()
+	assert.Uint16(pointConfig.Port()).Positive()
+	assert.Pointer(pointConfig.InboundConfig()).IsNotNil()
+	assert.Pointer(pointConfig.OutboundConfig()).IsNotNil()
 
-	assert.String(config.InboundConfig().Protocol()).Equals("vmess")
-	assert.Int(len(config.InboundConfig().Content())).GreaterThan(0)
+	assert.String(pointConfig.InboundConfig().Protocol()).Equals("vmess")
+	assert.Pointer(pointConfig.InboundConfig().Settings(config.TypeInbound)).IsNotNil()
 
-	assert.String(config.OutboundConfig().Protocol()).Equals("freedom")
-	assert.Int(len(config.OutboundConfig().Content())).Equals(0)
+	assert.String(pointConfig.OutboundConfig().Protocol()).Equals("freedom")
+	assert.Pointer(pointConfig.OutboundConfig().Settings(config.TypeOutbound)).IsNotNil()
 }

+ 14 - 16
point.go

@@ -3,6 +3,7 @@ package core
 import (
 	"github.com/v2ray/v2ray-core/common/log"
 	v2net "github.com/v2ray/v2ray-core/common/net"
+	"github.com/v2ray/v2ray-core/config"
 )
 
 var (
@@ -26,37 +27,37 @@ func RegisterOutboundConnectionHandlerFactory(name string, factory OutboundConne
 type Point struct {
 	port       uint16
 	ichFactory InboundConnectionHandlerFactory
-	ichConfig  []byte
+	ichConfig  interface{}
 	ochFactory OutboundConnectionHandlerFactory
-	ochConfig  []byte
+	ochConfig  interface{}
 }
 
 // NewPoint returns a new Point server based on given configuration.
 // The server is not started at this point.
-func NewPoint(config PointConfig) (*Point, error) {
+func NewPoint(pConfig config.PointConfig) (*Point, error) {
 	var vpoint = new(Point)
-	vpoint.port = config.Port()
+	vpoint.port = pConfig.Port()
 
-	ichFactory, ok := inboundFactories[config.InboundConfig().Protocol()]
+	ichFactory, ok := inboundFactories[pConfig.InboundConfig().Protocol()]
 	if !ok {
-		panic(log.Error("Unknown inbound connection handler factory %s", config.InboundConfig().Protocol()))
+		panic(log.Error("Unknown inbound connection handler factory %s", pConfig.InboundConfig().Protocol()))
 	}
 	vpoint.ichFactory = ichFactory
-	vpoint.ichConfig = config.InboundConfig().Content()
+	vpoint.ichConfig = pConfig.InboundConfig().Settings(config.TypeInbound)
 
-	ochFactory, ok := outboundFactories[config.OutboundConfig().Protocol()]
+	ochFactory, ok := outboundFactories[pConfig.OutboundConfig().Protocol()]
 	if !ok {
-		panic(log.Error("Unknown outbound connection handler factory %s", config.OutboundConfig().Protocol))
+		panic(log.Error("Unknown outbound connection handler factory %s", pConfig.OutboundConfig().Protocol))
 	}
 
 	vpoint.ochFactory = ochFactory
-	vpoint.ochConfig = config.OutboundConfig().Content()
+	vpoint.ochConfig = pConfig.OutboundConfig().Settings(config.TypeOutbound)
 
 	return vpoint, nil
 }
 
 type InboundConnectionHandlerFactory interface {
-	Create(vp *Point, config []byte) (InboundConnectionHandler, error)
+	Create(vp *Point, config interface{}) (InboundConnectionHandler, error)
 }
 
 type InboundConnectionHandler interface {
@@ -64,8 +65,7 @@ type InboundConnectionHandler interface {
 }
 
 type OutboundConnectionHandlerFactory interface {
-	Initialize(config []byte) error
-	Create(VP *Point, firstPacket v2net.Packet) (OutboundConnectionHandler, error)
+	Create(VP *Point, config interface{}, firstPacket v2net.Packet) (OutboundConnectionHandler, error)
 }
 
 type OutboundConnectionHandler interface {
@@ -79,8 +79,6 @@ func (vp *Point) Start() error {
 		return log.Error("Invalid port %d", vp.port)
 	}
 
-	vp.ochFactory.Initialize(vp.ochConfig)
-
 	inboundConnectionHandler, err := vp.ichFactory.Create(vp, vp.ichConfig)
 	if err != nil {
 		return err
@@ -92,7 +90,7 @@ func (vp *Point) Start() error {
 func (p *Point) DispatchToOutbound(packet v2net.Packet) InboundRay {
 	ray := NewRay()
 	// TODO: handle error
-	och, _ := p.ochFactory.Create(p, packet)
+	och, _ := p.ochFactory.Create(p, p.ochConfig, packet)
 	_ = och.Start(ray)
 	return ray
 }

+ 15 - 0
proxy/freedom/config/json/json.go

@@ -0,0 +1,15 @@
+package json
+
+import (
+	"github.com/v2ray/v2ray-core/config"
+	"github.com/v2ray/v2ray-core/config/json"
+)
+
+type FreedomConfiguration struct {
+}
+
+func init() {
+	json.RegisterConfigType("freedom", config.TypeOutbound, func() interface{} {
+		return &FreedomConfiguration{}
+	})
+}

+ 7 - 4
proxy/freedom/freedom_test.go

@@ -11,6 +11,7 @@ import (
 	"github.com/v2ray/v2ray-core"
 	v2net "github.com/v2ray/v2ray-core/common/net"
 	_ "github.com/v2ray/v2ray-core/proxy/socks"
+	"github.com/v2ray/v2ray-core/proxy/socks/config/json"
 	"github.com/v2ray/v2ray-core/testing/mocks"
 	"github.com/v2ray/v2ray-core/testing/servers/tcp"
 	"github.com/v2ray/v2ray-core/testing/servers/udp"
@@ -47,11 +48,11 @@ func TestUDPSend(t *testing.T) {
 		PortValue: pointPort,
 		InboundConfigValue: &mocks.ConnectionConfig{
 			ProtocolValue: "mock_ich",
-			ContentValue:  nil,
+			SettingsValue: nil,
 		},
 		OutboundConfigValue: &mocks.ConnectionConfig{
 			ProtocolValue: "freedom",
-			ContentValue:  nil,
+			SettingsValue: nil,
 		},
 	}
 
@@ -89,11 +90,13 @@ func TestSocksTcpConnect(t *testing.T) {
 		PortValue: pointPort,
 		InboundConfigValue: &mocks.ConnectionConfig{
 			ProtocolValue: "socks",
-			ContentValue:  []byte("{\"auth\": \"noauth\"}"),
+			SettingsValue: &json.SocksConfig{
+				AuthMethod: "auth",
+			},
 		},
 		OutboundConfigValue: &mocks.ConnectionConfig{
 			ProtocolValue: "freedom",
-			ContentValue:  nil,
+			SettingsValue: nil,
 		},
 	}
 

+ 1 - 5
proxy/freedom/freedomfactory.go

@@ -8,11 +8,7 @@ import (
 type FreedomFactory struct {
 }
 
-func (factory FreedomFactory) Initialize(config []byte) error {
-	return nil
-}
-
-func (factory FreedomFactory) Create(vp *core.Point, firstPacket v2net.Packet) (core.OutboundConnectionHandler, error) {
+func (factory FreedomFactory) Create(vp *core.Point, config interface{}, firstPacket v2net.Packet) (core.OutboundConnectionHandler, error) {
 	return NewFreedomConnection(firstPacket), nil
 }
 

+ 6 - 5
proxy/socks/config/json/config.go

@@ -1,7 +1,8 @@
 package json
 
 import (
-	"encoding/json"
+	"github.com/v2ray/v2ray-core/config"
+	"github.com/v2ray/v2ray-core/config/json"
 )
 
 const (
@@ -24,8 +25,8 @@ func (config SocksConfig) IsPassword() bool {
 	return config.AuthMethod == AuthMethodUserPass
 }
 
-func Load(rawConfig []byte) (SocksConfig, error) {
-	config := SocksConfig{}
-	err := json.Unmarshal(rawConfig, &config)
-	return config, err
+func init() {
+	json.RegisterConfigType("socks", config.TypeInbound, func() interface{} {
+		return new(SocksConfig)
+	})
 }

+ 2 - 7
proxy/socks/socks.go

@@ -19,15 +19,10 @@ import (
 type SocksServer struct {
 	accepting bool
 	vPoint    *core.Point
-	config    jsonconfig.SocksConfig
+	config    *jsonconfig.SocksConfig
 }
 
-func NewSocksServer(vp *core.Point, rawConfig []byte) *SocksServer {
-	config, err := jsonconfig.Load(rawConfig)
-	if err != nil {
-		log.Error("Unable to load socks config: %v", err)
-		panic(errors.NewConfigurationError())
-	}
+func NewSocksServer(vp *core.Point, config *jsonconfig.SocksConfig) *SocksServer {
 	return &SocksServer{
 		vPoint: vp,
 		config: config,

+ 16 - 6
proxy/socks/socks_test.go

@@ -9,6 +9,7 @@ import (
 	"golang.org/x/net/proxy"
 
 	"github.com/v2ray/v2ray-core"
+	"github.com/v2ray/v2ray-core/proxy/socks/config/json"
 	"github.com/v2ray/v2ray-core/testing/mocks"
 	"github.com/v2ray/v2ray-core/testing/unit"
 )
@@ -28,11 +29,13 @@ func TestSocksTcpConnect(t *testing.T) {
 		PortValue: port,
 		InboundConfigValue: &mocks.ConnectionConfig{
 			ProtocolValue: "socks",
-			ContentValue:  []byte("{\"auth\": \"noauth\"}"),
+			SettingsValue: &json.SocksConfig{
+				AuthMethod: "noauth",
+			},
 		},
 		OutboundConfigValue: &mocks.ConnectionConfig{
 			ProtocolValue: "mock_och",
-			ContentValue:  nil,
+			SettingsValue: nil,
 		},
 	}
 
@@ -79,11 +82,15 @@ func TestSocksTcpConnectWithUserPass(t *testing.T) {
 		PortValue: port,
 		InboundConfigValue: &mocks.ConnectionConfig{
 			ProtocolValue: "socks",
-			ContentValue:  []byte("{\"auth\": \"password\",\"user\": \"userx\",\"pass\": \"passy\"}"),
+			SettingsValue: &json.SocksConfig{
+				AuthMethod: "noauth",
+				Username:   "userx",
+				Password:   "passy",
+			},
 		},
 		OutboundConfigValue: &mocks.ConnectionConfig{
 			ProtocolValue: "mock_och",
-			ContentValue:  nil,
+			SettingsValue: nil,
 		},
 	}
 
@@ -130,11 +137,14 @@ func TestSocksUdpSend(t *testing.T) {
 		PortValue: port,
 		InboundConfigValue: &mocks.ConnectionConfig{
 			ProtocolValue: "socks",
-			ContentValue:  []byte("{\"auth\": \"noauth\", \"udp\": true}"),
+			SettingsValue: &json.SocksConfig{
+				AuthMethod: "noauth",
+				UDPEnabled: true,
+			},
 		},
 		OutboundConfigValue: &mocks.ConnectionConfig{
 			ProtocolValue: "mock_och",
-			ContentValue:  nil,
+			SettingsValue: nil,
 		},
 	}
 

+ 3 - 2
proxy/socks/socksfactory.go

@@ -2,13 +2,14 @@ package socks
 
 import (
 	"github.com/v2ray/v2ray-core"
+	"github.com/v2ray/v2ray-core/proxy/socks/config/json"
 )
 
 type SocksServerFactory struct {
 }
 
-func (factory SocksServerFactory) Create(vp *core.Point, config []byte) (core.InboundConnectionHandler, error) {
-	return NewSocksServer(vp, config), nil
+func (factory SocksServerFactory) Create(vp *core.Point, config interface{}) (core.InboundConnectionHandler, error) {
+	return NewSocksServer(vp, config.(*json.SocksConfig)), nil
 }
 
 func init() {

+ 10 - 11
proxy/vmess/config.go

@@ -1,12 +1,13 @@
 package vmess
 
 import (
-	"encoding/json"
 	"net"
 	"strings"
 
 	"github.com/v2ray/v2ray-core/common/log"
 	v2net "github.com/v2ray/v2ray-core/common/net"
+	"github.com/v2ray/v2ray-core/config"
+	"github.com/v2ray/v2ray-core/config/json"
 	"github.com/v2ray/v2ray-core/proxy/vmess/protocol/user"
 )
 
@@ -29,12 +30,6 @@ type VMessInboundConfig struct {
 	UDPEnabled     bool        `json:"udp"`
 }
 
-func loadInboundConfig(rawConfig []byte) (VMessInboundConfig, error) {
-	config := VMessInboundConfig{}
-	err := json.Unmarshal(rawConfig, &config)
-	return config, err
-}
-
 type VNextConfig struct {
 	Address string      `json:"address"`
 	Port    uint16      `json:"port"`
@@ -76,8 +71,12 @@ type VMessOutboundConfig struct {
 	VNextList []VNextConfig `json:"vnext"`
 }
 
-func loadOutboundConfig(rawConfig []byte) (VMessOutboundConfig, error) {
-	config := VMessOutboundConfig{}
-	err := json.Unmarshal(rawConfig, &config)
-	return config, err
+func init() {
+	json.RegisterConfigType("vmess", config.TypeInbound, func() interface{} {
+		return new(VMessInboundConfig)
+	})
+
+	json.RegisterConfigType("vmess", config.TypeOutbound, func() interface{} {
+		return new(VMessOutboundConfig)
+	})
 }

+ 39 - 8
proxy/vmess/vmess_test.go

@@ -27,11 +27,22 @@ func TestVMessInAndOut(t *testing.T) {
 		PortValue: portA,
 		InboundConfigValue: &mocks.ConnectionConfig{
 			ProtocolValue: "mock_ich",
-			ContentValue:  nil,
+			SettingsValue: nil,
 		},
 		OutboundConfigValue: &mocks.ConnectionConfig{
 			ProtocolValue: "vmess",
-			ContentValue:  []byte("{\"vnext\":[{\"address\": \"127.0.0.1\", \"network\": \"tcp\", \"port\": 13829, \"users\":[{\"id\": \"ad937d9d-6e23-4a5a-ba23-bce5092a7c51\"}]}]}"),
+			SettingsValue: &VMessOutboundConfig{
+				[]VNextConfig{
+					VNextConfig{
+						Address: "127.0.0.1",
+						Port:    13829,
+						Network: "tcp",
+						Users: []VMessUser{
+							VMessUser{Id: "ad937d9d-6e23-4a5a-ba23-bce5092a7c51"},
+						},
+					},
+				},
+			},
 		},
 	}
 
@@ -54,11 +65,15 @@ func TestVMessInAndOut(t *testing.T) {
 		PortValue: portB,
 		InboundConfigValue: &mocks.ConnectionConfig{
 			ProtocolValue: "vmess",
-			ContentValue:  []byte("{\"clients\": [{\"id\": \"ad937d9d-6e23-4a5a-ba23-bce5092a7c51\"}]}"),
+			SettingsValue: &VMessInboundConfig{
+				AllowedClients: []VMessUser{
+					VMessUser{Id: "ad937d9d-6e23-4a5a-ba23-bce5092a7c51"},
+				},
+			},
 		},
 		OutboundConfigValue: &mocks.ConnectionConfig{
 			ProtocolValue: "mock_och",
-			ContentValue:  nil,
+			SettingsValue: nil,
 		},
 	}
 
@@ -91,11 +106,22 @@ func TestVMessInAndOutUDP(t *testing.T) {
 		PortValue: portA,
 		InboundConfigValue: &mocks.ConnectionConfig{
 			ProtocolValue: "mock_ich",
-			ContentValue:  nil,
+			SettingsValue: nil,
 		},
 		OutboundConfigValue: &mocks.ConnectionConfig{
 			ProtocolValue: "vmess",
-			ContentValue:  []byte("{\"vnext\":[{\"address\": \"127.0.0.1\", \"network\": \"udp\", \"port\": 13841, \"users\":[{\"id\": \"ad937d9d-6e23-4a5a-ba23-bce5092a7c51\"}]}]}"),
+			SettingsValue: &VMessOutboundConfig{
+				[]VNextConfig{
+					VNextConfig{
+						Address: "127.0.0.1",
+						Port:    13841,
+						Network: "udp",
+						Users: []VMessUser{
+							VMessUser{Id: "ad937d9d-6e23-4a5a-ba23-bce5092a7c51"},
+						},
+					},
+				},
+			},
 		},
 	}
 
@@ -118,11 +144,16 @@ func TestVMessInAndOutUDP(t *testing.T) {
 		PortValue: portB,
 		InboundConfigValue: &mocks.ConnectionConfig{
 			ProtocolValue: "vmess",
-			ContentValue:  []byte("{\"clients\": [{\"id\": \"ad937d9d-6e23-4a5a-ba23-bce5092a7c51\"}], \"udp\": true}"),
+			SettingsValue: &VMessInboundConfig{
+				AllowedClients: []VMessUser{
+					VMessUser{Id: "ad937d9d-6e23-4a5a-ba23-bce5092a7c51"},
+				},
+				UDPEnabled: true,
+			},
 		},
 		OutboundConfigValue: &mocks.ConnectionConfig{
 			ProtocolValue: "mock_och",
-			ContentValue:  nil,
+			SettingsValue: nil,
 		},
 	}
 

+ 3 - 5
proxy/vmess/vmessin.go

@@ -136,11 +136,9 @@ func handleOutput(request *protocol.VMessRequest, writer io.Writer, output <-cha
 type VMessInboundHandlerFactory struct {
 }
 
-func (factory *VMessInboundHandlerFactory) Create(vp *core.Point, rawConfig []byte) (core.InboundConnectionHandler, error) {
-	config, err := loadInboundConfig(rawConfig)
-	if err != nil {
-		panic(log.Error("VMessIn: Failed to load VMess inbound config: %v", err))
-	}
+func (factory *VMessInboundHandlerFactory) Create(vp *core.Point, rawConfig interface{}) (core.InboundConnectionHandler, error) {
+	config := rawConfig.(*VMessInboundConfig)
+
 	allowedClients := user.NewTimedUserSet()
 	for _, client := range config.AllowedClients {
 		user, err := client.ToUser()

+ 3 - 15
proxy/vmess/vmessout.go

@@ -193,16 +193,10 @@ func handleResponse(conn net.Conn, request *protocol.VMessRequest, output chan<-
 }
 
 type VMessOutboundHandlerFactory struct {
-	servers    []VNextServer
-	udpServers []VNextServer
 }
 
-func (factory *VMessOutboundHandlerFactory) Initialize(rawConfig []byte) error {
-	config, err := loadOutboundConfig(rawConfig)
-	if err != nil {
-		panic(log.Error("Failed to load VMess outbound config: %v", err))
-		return err
-	}
+func (factory *VMessOutboundHandlerFactory) Create(vp *core.Point, rawConfig interface{}, firstPacket v2net.Packet) (core.OutboundConnectionHandler, error) {
+	config := rawConfig.(*VMessOutboundConfig)
 	servers := make([]VNextServer, 0, len(config.VNextList))
 	udpServers := make([]VNextServer, 0, len(config.VNextList))
 	for _, server := range config.VNextList {
@@ -213,13 +207,7 @@ func (factory *VMessOutboundHandlerFactory) Initialize(rawConfig []byte) error {
 			udpServers = append(udpServers, server.ToVNextServer("udp"))
 		}
 	}
-	factory.servers = servers
-	factory.udpServers = udpServers
-	return nil
-}
-
-func (factory *VMessOutboundHandlerFactory) Create(vp *core.Point, firstPacket v2net.Packet) (core.OutboundConnectionHandler, error) {
-	return NewVMessOutboundHandler(vp, factory.servers, factory.udpServers, firstPacket), nil
+	return NewVMessOutboundHandler(vp, servers, udpServers, firstPacket), nil
 }
 
 func init() {

+ 0 - 4
release/config/in_socks.json

@@ -1,4 +0,0 @@
-{
-  "auth": "noauth",
-  "udp": false
-}

+ 0 - 6
release/config/in_vmess.json

@@ -1,6 +0,0 @@
-{
-  "clients": [
-    {"id": "ad937d9d-6e23-4a5a-ba23-bce5092a7c51"}
-  ],
-  "udp": false
-}

+ 0 - 12
release/config/out_vmess.json

@@ -1,12 +0,0 @@
-{
-  "vnext": [
-    {
-      "address": "127.0.0.1",
-      "port": 27183,
-      "users": [
-        {"id": "ad937d9d-6e23-4a5a-ba23-bce5092a7c51"}
-      ],
-      "network": "tcp"
-    }
-  ]
-}

+ 16 - 2
release/config/vpoint_socks_vmess.json

@@ -2,10 +2,24 @@
   "port": 1080,
   "inbound": {
     "protocol": "socks",
-    "file": "in_socks.json"
+    "settings": {
+      "auth": "noauth",
+      "udp": false
+    }
   },
   "outbound": {
     "protocol": "vmess",
-    "file": "out_vmess.json"
+    "settings": {
+      "vnext": [
+        {
+          "address": "127.0.0.1",
+          "port": 27183,
+          "users": [
+            {"id": "ad937d9d-6e23-4a5a-ba23-bce5092a7c51"}
+          ],
+          "network": "tcp"
+        }
+      ]
+    }
   }
 }

+ 7 - 2
release/config/vpoint_vmess_freedom.json

@@ -2,10 +2,15 @@
   "port": 27183,
   "inbound": {
     "protocol": "vmess",
-    "file": "in_vmess.json"
+    "settings": {
+      "clients": [
+        {"id": "ad937d9d-6e23-4a5a-ba23-bce5092a7c51"}
+      ],
+      "udp": false
+    }
   },
   "outbound": {
     "protocol": "freedom",
-    "file": ""
+    "settings": {}
   }
 }

+ 2 - 1
release/server/main.go

@@ -9,7 +9,8 @@ import (
 	jsonconf "github.com/v2ray/v2ray-core/config/json"
 
 	// The following are neccesary as they register handlers in their init functions.
-	_ "github.com/v2ray/v2ray-core/proxy/freedom"
+	_ "github.com/v2ray/v2ray-core/proxy/freedom/config/json"
+  _ "github.com/v2ray/v2ray-core/proxy/freedom"
 	_ "github.com/v2ray/v2ray-core/proxy/socks"
 	_ "github.com/v2ray/v2ray-core/proxy/vmess"
 )

+ 27 - 43
spec/guide.md

@@ -19,38 +19,27 @@
   "port": 1080, // 监听端口
   "inbound": {
     "protocol": "socks",  // 传入数据所用协议
-    "file": "in_socks.json" // socks 配置文件
+    "settings": {
+      "auth": "noauth", // 认证方式,暂时只支持匿名
+      "udp": false // 如果要使用 UDP 转发,请改成 true
+    }
   },
   "outbound": {
-    "protocol": "vmess", // 中继协议
-    "file": "out_vmess.json" // vmess 配置文件
-  }
-}
-```
-
-另外还需要两个文件,保存于同一文件夹下:
-
-```javascript
-// in_socks.json
-{
-  "auth": "noauth" // 认证方式,暂时只支持匿名
-  "udp": false // 如果要使用 UDP 转发,请改成 true
-}
-```
-
-```javascript
-// out_vmess.json
-{
-  "vnext": [
-    {
-      "address": "127.0.0.1", // Point B 的 IP 地址,IPv4 或 IPv6,不支持域名
-      "port": 27183, // Point B 的监听端口,请更换成其它的值
-      "users": [
-        {"id": "ad937d9d-6e23-4a5a-ba23-bce5092a7c51"}  // 用户 ID,必须包含在 Point B 的配置文件中。此 ID 将被用于通信的认证,请自行更换随机的 ID,可以使用 https://www.uuidgenerator.net/ 来生成新的 ID。
-      ],
-      "network": "tcp" // 如果要使用 UDP 转发,请改成 "tcp,udp"
+    "protocol": "vmess", // 中继协议,暂时只有这个
+    "settings": {
+      "vnext": [
+        {
+          "address": "127.0.0.1", // Point B 的 IP 地址,IPv4 或 IPv6,不支持域名
+          "port": 27183, // Point B 的监听端口,请更换成其它的值
+          "users": [
+            // 用户 ID,必须包含在 Point B 的配置文件中。此 ID 将被用于通信的认证,请自行更换随机的 ID,可以使用 https://www.uuidgenerator.net/ 来生成新的 ID。
+            {"id": "ad937d9d-6e23-4a5a-ba23-bce5092a7c51"}
+          ],
+          "network": "tcp" // 如果要使用 UDP 转发,请改成 "tcp,udp"
+        }
+      ]
     }
-  ]
+  }
 }
 ```
 
@@ -58,29 +47,24 @@
 示例配置保存于 vpoint_vmess_freedom.json 文件中,格式如下:
 ```javascript
 {
-  "port": 27183, // 监听端口,必须和 out_vmess.json 中指定的一致
+  "port": 27183, // 监听端口,必须和 Point A 中指定的一致
   "inbound": {
     "protocol": "vmess", // 中继协议,不用改
-    "file": "in_vmess.json" // vmess 配置文件
+    "settings": {
+      "clients": [
+          // 认可的用户 ID,必须包含 Point A 中的用户 ID
+        {"id": "ad937d9d-6e23-4a5a-ba23-bce5092a7c51"}
+      ],
+      "udp": false // 如果要使用 UDP 转发,请改成 true
+    }
   },
   "outbound": {
     "protocol": "freedom", // 出口协议,不用改
-    "file": "" // 暂无配置
+    "settings": {} // 暂无配置
   }
 }
 ```
 
-另外还需要 in_vmess.json:
-```javascript
-// in_vmess.json
-{
-  "clients": [
-    {"id": "ad937d9d-6e23-4a5a-ba23-bce5092a7c51"}  // 认可的用户 ID,必须包含 out_vmess.json 中的用户 ID
-  ],
-  "udp": false // 如果要使用 UDP 转发,请改成 true
-}
-```
-
 ### 其它
 * V2Ray 的用户验证基于时间,请确保 A 和 B 所在机器的系统时间误差在一分钟以内。
 * json 配置文件实际上不支持注释(即“//”之后的部分,在使用时请务必删去)。

+ 6 - 6
testing/mocks/config.go

@@ -1,20 +1,20 @@
 package mocks
 
 import (
-	"github.com/v2ray/v2ray-core"
+	"github.com/v2ray/v2ray-core/config"
 )
 
 type ConnectionConfig struct {
 	ProtocolValue string
-	ContentValue  []byte
+	SettingsValue interface{}
 }
 
 func (config *ConnectionConfig) Protocol() string {
 	return config.ProtocolValue
 }
 
-func (config *ConnectionConfig) Content() []byte {
-	return config.ContentValue
+func (config *ConnectionConfig) Settings(config.Type) interface{} {
+	return config.SettingsValue
 }
 
 type Config struct {
@@ -27,10 +27,10 @@ func (config *Config) Port() uint16 {
 	return config.PortValue
 }
 
-func (config *Config) InboundConfig() core.ConnectionConfig {
+func (config *Config) InboundConfig() config.ConnectionConfig {
 	return config.InboundConfigValue
 }
 
-func (config *Config) OutboundConfig() core.ConnectionConfig {
+func (config *Config) OutboundConfig() config.ConnectionConfig {
 	return config.OutboundConfigValue
 }

+ 1 - 1
testing/mocks/inboundhandler.go

@@ -32,7 +32,7 @@ func (handler *InboundConnectionHandler) Communicate(packet v2net.Packet) error
 	return nil
 }
 
-func (handler *InboundConnectionHandler) Create(point *core.Point, config []byte) (core.InboundConnectionHandler, error) {
+func (handler *InboundConnectionHandler) Create(point *core.Point, config interface{}) (core.InboundConnectionHandler, error) {
 	handler.Server = point
 	return handler, nil
 }

+ 1 - 5
testing/mocks/outboundhandler.go

@@ -34,11 +34,7 @@ func (handler *OutboundConnectionHandler) Start(ray core.OutboundRay) error {
 	return nil
 }
 
-func (handler *OutboundConnectionHandler) Initialize(config []byte) error {
-	return nil
-}
-
-func (handler *OutboundConnectionHandler) Create(point *core.Point, packet v2net.Packet) (core.OutboundConnectionHandler, error) {
+func (handler *OutboundConnectionHandler) Create(point *core.Point, config interface{}, packet v2net.Packet) (core.OutboundConnectionHandler, error) {
 	handler.Destination = packet.Destination()
 	if packet.Chunk() != nil {
 		handler.Data2Send.Write(packet.Chunk())

+ 4 - 1
testing/unit/subject.go

@@ -22,7 +22,10 @@ func NewSubject(assert *Assertion) *Subject {
 // decorate prefixes the string with the file and line of the call site
 // and inserts the final newline if needed and indentation tabs for formatting.
 func decorate(s string) string {
-	_, file, line, ok := runtime.Caller(4) // decorate + log + public function.
+	_, file, line, ok := runtime.Caller(3)
+	if strings.Contains(file, "testing") {
+		_, file, line, ok = runtime.Caller(4)
+	}
 	if ok {
 		// Truncate file name at last file name separator.
 		if index := strings.LastIndex(file, "/"); index >= 0 {