Pārlūkot izejas kodu

Add format config support

世界 3 gadi atpakaļ
vecāks
revīzija
85a695caa1
10 mainītis faili ar 77 papildinājumiem un 60 dzēšanām
  1. 16 2
      cmd/sing-box/main.go
  2. 1 1
      go.mod
  3. 2 2
      go.sum
  4. 6 3
      option/address.go
  5. 1 1
      option/config.go
  6. 25 25
      option/inbound.go
  7. 9 9
      option/json.go
  8. 2 2
      option/listable.go
  9. 11 11
      option/outbound.go
  10. 4 4
      option/route.go

+ 16 - 2
cmd/sing-box/main.go

@@ -19,8 +19,9 @@ func init() {
 }
 }
 
 
 var (
 var (
-	configPath string
-	workingDir string
+	configPath   string
+	workingDir   string
+	formatConfig bool
 )
 )
 
 
 func main() {
 func main() {
@@ -30,6 +31,7 @@ func main() {
 	}
 	}
 	command.Flags().StringVarP(&configPath, "config", "c", "config.json", "set configuration file path")
 	command.Flags().StringVarP(&configPath, "config", "c", "config.json", "set configuration file path")
 	command.Flags().StringVarP(&workingDir, "directory", "D", "", "set working directory")
 	command.Flags().StringVarP(&workingDir, "directory", "D", "", "set working directory")
+	command.Flags().BoolVarP(&formatConfig, "format", "f", false, "print formatted configuration file")
 	if err := command.Execute(); err != nil {
 	if err := command.Execute(); err != nil {
 		logrus.Fatal(err)
 		logrus.Fatal(err)
 	}
 	}
@@ -57,6 +59,18 @@ func run(cmd *cobra.Command, args []string) {
 	if err != nil {
 	if err != nil {
 		logrus.Fatal("create service: ", err)
 		logrus.Fatal("create service: ", err)
 	}
 	}
+
+	if formatConfig {
+		cancel()
+		encoder := json.NewEncoder(os.Stdout)
+		encoder.SetIndent("", "  ")
+		err = encoder.Encode(options)
+		if err != nil {
+			logrus.Fatal("encode config: ", err)
+		}
+		return
+	}
+
 	err = service.Start()
 	err = service.Start()
 	if err != nil {
 	if err != nil {
 		logrus.Fatal("start service: ", err)
 		logrus.Fatal("start service: ", err)

+ 1 - 1
go.mod

@@ -6,7 +6,7 @@ require (
 	github.com/database64128/tfo-go v1.0.4
 	github.com/database64128/tfo-go v1.0.4
 	github.com/logrusorgru/aurora v2.0.3+incompatible
 	github.com/logrusorgru/aurora v2.0.3+incompatible
 	github.com/oschwald/geoip2-golang v1.7.0
 	github.com/oschwald/geoip2-golang v1.7.0
-	github.com/sagernet/sing v0.0.0-20220702174608-cb5bb5132de4
+	github.com/sagernet/sing v0.0.0-20220702193452-6a6c180cf77e
 	github.com/sagernet/sing-shadowsocks v0.0.0-20220701084835-2208da1d8649
 	github.com/sagernet/sing-shadowsocks v0.0.0-20220701084835-2208da1d8649
 	github.com/sirupsen/logrus v1.8.1
 	github.com/sirupsen/logrus v1.8.1
 	github.com/spf13/cobra v1.5.0
 	github.com/spf13/cobra v1.5.0

+ 2 - 2
go.sum

@@ -18,8 +18,8 @@ github.com/oschwald/maxminddb-golang v1.9.0/go.mod h1:TK+s/Z2oZq0rSl4PSeAEoP0bgm
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
-github.com/sagernet/sing v0.0.0-20220702174608-cb5bb5132de4 h1:Ce6nW9gV6g2hq/1K/nMtlVGiTtxh86EWs0/jOzMuNa4=
-github.com/sagernet/sing v0.0.0-20220702174608-cb5bb5132de4/go.mod h1:3ZmoGNg/nNJTyHAZFNRSPaXpNIwpDvyIiAUd0KIWV5c=
+github.com/sagernet/sing v0.0.0-20220702193452-6a6c180cf77e h1:GiH/gZcH8fupEfWJujaqGNBBaCkAouAJyVJy9Afxfvw=
+github.com/sagernet/sing v0.0.0-20220702193452-6a6c180cf77e/go.mod h1:3ZmoGNg/nNJTyHAZFNRSPaXpNIwpDvyIiAUd0KIWV5c=
 github.com/sagernet/sing-shadowsocks v0.0.0-20220701084835-2208da1d8649 h1:whNDUGOAX5GPZkSy4G3Gv9QyIgk5SXRyjkRuP7ohF8k=
 github.com/sagernet/sing-shadowsocks v0.0.0-20220701084835-2208da1d8649 h1:whNDUGOAX5GPZkSy4G3Gv9QyIgk5SXRyjkRuP7ohF8k=
 github.com/sagernet/sing-shadowsocks v0.0.0-20220701084835-2208da1d8649/go.mod h1:MuyT+9fEPjvauAv0fSE0a6Q+l0Tv2ZrAafTkYfnxBFw=
 github.com/sagernet/sing-shadowsocks v0.0.0-20220701084835-2208da1d8649/go.mod h1:MuyT+9fEPjvauAv0fSE0a6Q+l0Tv2ZrAafTkYfnxBFw=
 github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
 github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=

+ 6 - 3
option/address.go

@@ -7,9 +7,12 @@ import (
 
 
 type ListenAddress netip.Addr
 type ListenAddress netip.Addr
 
 
-func (a *ListenAddress) MarshalJSON() ([]byte, error) {
-	value := netip.Addr(*a).String()
-	return json.Marshal(value)
+func (a ListenAddress) MarshalJSON() ([]byte, error) {
+	addr := netip.Addr(a)
+	if !addr.IsValid() {
+		return json.Marshal("")
+	}
+	return json.Marshal(addr.String())
 }
 }
 
 
 func (a *ListenAddress) UnmarshalJSON(bytes []byte) error {
 func (a *ListenAddress) UnmarshalJSON(bytes []byte) error {

+ 1 - 1
option/config.go

@@ -3,7 +3,7 @@ package option
 import "github.com/sagernet/sing/common"
 import "github.com/sagernet/sing/common"
 
 
 type Options struct {
 type Options struct {
-	Log       *LogOption    `json:"log"`
+	Log       *LogOption    `json:"log,omitempty"`
 	Inbounds  []Inbound     `json:"inbounds,omitempty"`
 	Inbounds  []Inbound     `json:"inbounds,omitempty"`
 	Outbounds []Outbound    `json:"outbounds,omitempty"`
 	Outbounds []Outbound    `json:"outbounds,omitempty"`
 	Route     *RouteOptions `json:"route,omitempty"`
 	Route     *RouteOptions `json:"route,omitempty"`

+ 25 - 25
option/inbound.go

@@ -20,52 +20,52 @@ type _Inbound struct {
 
 
 type Inbound _Inbound
 type Inbound _Inbound
 
 
-func (i Inbound) Equals(other Inbound) bool {
-	return i.Type == other.Type &&
-		i.Tag == other.Tag &&
-		common.Equals(i.DirectOptions, other.DirectOptions) &&
-		common.Equals(i.SocksOptions, other.SocksOptions) &&
-		common.Equals(i.HTTPOptions, other.HTTPOptions) &&
-		common.Equals(i.MixedOptions, other.MixedOptions) &&
-		common.Equals(i.ShadowsocksOptions, other.ShadowsocksOptions)
+func (h Inbound) Equals(other Inbound) bool {
+	return h.Type == other.Type &&
+		h.Tag == other.Tag &&
+		common.Equals(h.DirectOptions, other.DirectOptions) &&
+		common.Equals(h.SocksOptions, other.SocksOptions) &&
+		common.Equals(h.HTTPOptions, other.HTTPOptions) &&
+		common.Equals(h.MixedOptions, other.MixedOptions) &&
+		common.Equals(h.ShadowsocksOptions, other.ShadowsocksOptions)
 }
 }
 
 
-func (i *Inbound) MarshalJSON() ([]byte, error) {
+func (h Inbound) MarshalJSON() ([]byte, error) {
 	var v any
 	var v any
-	switch i.Type {
+	switch h.Type {
 	case "direct":
 	case "direct":
-		v = i.DirectOptions
+		v = h.DirectOptions
 	case "socks":
 	case "socks":
-		v = i.SocksOptions
+		v = h.SocksOptions
 	case "http":
 	case "http":
-		v = i.HTTPOptions
+		v = h.HTTPOptions
 	case "mixed":
 	case "mixed":
-		v = i.MixedOptions
+		v = h.MixedOptions
 	case "shadowsocks":
 	case "shadowsocks":
-		v = i.ShadowsocksOptions
+		v = h.ShadowsocksOptions
 	default:
 	default:
-		return nil, E.New("unknown inbound type: ", i.Type)
+		return nil, E.New("unknown inbound type: ", h.Type)
 	}
 	}
-	return MarshallObjects(i, v)
+	return MarshallObjects((_Inbound)(h), v)
 }
 }
 
 
-func (i *Inbound) UnmarshalJSON(bytes []byte) error {
-	err := json.Unmarshal(bytes, (*_Inbound)(i))
+func (h *Inbound) UnmarshalJSON(bytes []byte) error {
+	err := json.Unmarshal(bytes, (*_Inbound)(h))
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 	var v any
 	var v any
-	switch i.Type {
+	switch h.Type {
 	case "direct":
 	case "direct":
-		v = &i.DirectOptions
+		v = &h.DirectOptions
 	case "socks":
 	case "socks":
-		v = &i.SocksOptions
+		v = &h.SocksOptions
 	case "http":
 	case "http":
-		v = &i.HTTPOptions
+		v = &h.HTTPOptions
 	case "mixed":
 	case "mixed":
-		v = &i.MixedOptions
+		v = &h.MixedOptions
 	case "shadowsocks":
 	case "shadowsocks":
-		v = &i.ShadowsocksOptions
+		v = &h.ShadowsocksOptions
 	default:
 	default:
 		return nil
 		return nil
 	}
 	}

+ 9 - 9
option/json.go

@@ -2,33 +2,33 @@ package option
 
 
 import (
 import (
 	"encoding/json"
 	"encoding/json"
+
+	"github.com/sagernet/sing/common/x/linkedhashmap"
 )
 )
 
 
-func ToMap(v any) (map[string]any, error) {
+func ToMap(v any) (*linkedhashmap.Map[string, any], error) {
 	bytes, err := json.Marshal(v)
 	bytes, err := json.Marshal(v)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-	var content map[string]any
+	var content linkedhashmap.Map[string, any]
 	err = json.Unmarshal(bytes, &content)
 	err = json.Unmarshal(bytes, &content)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-	return content, nil
+	return &content, nil
 }
 }
 
 
-func MergeObjects(objects ...any) (map[string]any, error) {
-	content := make(map[string]any)
+func MergeObjects(objects ...any) (*linkedhashmap.Map[string, any], error) {
+	var content linkedhashmap.Map[string, any]
 	for _, object := range objects {
 	for _, object := range objects {
 		objectMap, err := ToMap(object)
 		objectMap, err := ToMap(object)
 		if err != nil {
 		if err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
-		for k, v := range objectMap {
-			content[k] = v
-		}
+		content.PutAll(objectMap)
 	}
 	}
-	return content, nil
+	return &content, nil
 }
 }
 
 
 func MarshallObjects(objects ...any) ([]byte, error) {
 func MarshallObjects(objects ...any) ([]byte, error) {

+ 2 - 2
option/listable.go

@@ -4,8 +4,8 @@ import "encoding/json"
 
 
 type Listable[T comparable] []T
 type Listable[T comparable] []T
 
 
-func (l *Listable[T]) MarshalJSON() ([]byte, error) {
-	arrayList := []T(*l)
+func (l Listable[T]) MarshalJSON() ([]byte, error) {
+	arrayList := []T(l)
 	if len(arrayList) == 1 {
 	if len(arrayList) == 1 {
 		return json.Marshal(arrayList[0])
 		return json.Marshal(arrayList[0])
 	}
 	}

+ 11 - 11
option/outbound.go

@@ -16,30 +16,30 @@ type _Outbound struct {
 
 
 type Outbound _Outbound
 type Outbound _Outbound
 
 
-func (i *Outbound) MarshalJSON() ([]byte, error) {
+func (h Outbound) MarshalJSON() ([]byte, error) {
 	var v any
 	var v any
-	switch i.Type {
+	switch h.Type {
 	case "direct":
 	case "direct":
-		v = i.DirectOptions
+		v = h.DirectOptions
 	case "shadowsocks":
 	case "shadowsocks":
-		v = i.ShadowsocksOptions
+		v = h.ShadowsocksOptions
 	default:
 	default:
-		return nil, E.New("unknown outbound type: ", i.Type)
+		return nil, E.New("unknown outbound type: ", h.Type)
 	}
 	}
-	return MarshallObjects(i, v)
+	return MarshallObjects((_Outbound)(h), v)
 }
 }
 
 
-func (i *Outbound) UnmarshalJSON(bytes []byte) error {
-	err := json.Unmarshal(bytes, (*_Outbound)(i))
+func (h *Outbound) UnmarshalJSON(bytes []byte) error {
+	err := json.Unmarshal(bytes, (*_Outbound)(h))
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 	var v any
 	var v any
-	switch i.Type {
+	switch h.Type {
 	case "direct":
 	case "direct":
-		v = &i.DirectOptions
+		v = &h.DirectOptions
 	case "shadowsocks":
 	case "shadowsocks":
-		v = &i.ShadowsocksOptions
+		v = &h.ShadowsocksOptions
 	default:
 	default:
 		return nil
 		return nil
 	}
 	}

+ 4 - 4
option/route.go

@@ -26,8 +26,8 @@ type GeoIPOptions struct {
 
 
 type _Rule struct {
 type _Rule struct {
 	Type           string       `json:"type,omitempty"`
 	Type           string       `json:"type,omitempty"`
-	DefaultOptions *DefaultRule `json:"default_options,omitempty"`
-	LogicalOptions *LogicalRule `json:"logical_options,omitempty"`
+	DefaultOptions *DefaultRule `json:"-"`
+	LogicalOptions *LogicalRule `json:"-"`
 }
 }
 
 
 type Rule _Rule
 type Rule _Rule
@@ -38,7 +38,7 @@ func (r Rule) Equals(other Rule) bool {
 		common.PtrEquals(r.LogicalOptions, other.LogicalOptions)
 		common.PtrEquals(r.LogicalOptions, other.LogicalOptions)
 }
 }
 
 
-func (r *Rule) MarshalJSON() ([]byte, error) {
+func (r Rule) MarshalJSON() ([]byte, error) {
 	var v any
 	var v any
 	switch r.Type {
 	switch r.Type {
 	case C.RuleTypeDefault:
 	case C.RuleTypeDefault:
@@ -48,7 +48,7 @@ func (r *Rule) MarshalJSON() ([]byte, error) {
 	default:
 	default:
 		return nil, E.New("unknown rule type: " + r.Type)
 		return nil, E.New("unknown rule type: " + r.Type)
 	}
 	}
-	return MarshallObjects(r, v)
+	return MarshallObjects((_Rule)(r), v)
 }
 }
 
 
 func (r *Rule) UnmarshalJSON(bytes []byte) error {
 func (r *Rule) UnmarshalJSON(bytes []byte) error {