From 85a695caa1c0c4b868130e36560cde71fd5d3f3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sun, 3 Jul 2022 03:42:57 +0800 Subject: [PATCH] Add format config support --- cmd/sing-box/main.go | 18 ++++++++++++++-- go.mod | 2 +- go.sum | 4 ++-- option/address.go | 9 +++++--- option/config.go | 2 +- option/inbound.go | 50 ++++++++++++++++++++++---------------------- option/json.go | 18 ++++++++-------- option/listable.go | 4 ++-- option/outbound.go | 22 +++++++++---------- option/route.go | 8 +++---- 10 files changed, 77 insertions(+), 60 deletions(-) diff --git a/cmd/sing-box/main.go b/cmd/sing-box/main.go index 5f456f87..082022db 100644 --- a/cmd/sing-box/main.go +++ b/cmd/sing-box/main.go @@ -19,8 +19,9 @@ func init() { } var ( - configPath string - workingDir string + configPath string + workingDir string + formatConfig bool ) func main() { @@ -30,6 +31,7 @@ func main() { } command.Flags().StringVarP(&configPath, "config", "c", "config.json", "set configuration file path") 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 { logrus.Fatal(err) } @@ -57,6 +59,18 @@ func run(cmd *cobra.Command, args []string) { if err != nil { 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() if err != nil { logrus.Fatal("start service: ", err) diff --git a/go.mod b/go.mod index e3c2c640..6b49831f 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/database64128/tfo-go v1.0.4 github.com/logrusorgru/aurora v2.0.3+incompatible 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/sirupsen/logrus v1.8.1 github.com/spf13/cobra v1.5.0 diff --git a/go.sum b/go.sum index f06ee00e..1beb0a55 100644 --- a/go.sum +++ b/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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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/go.mod h1:MuyT+9fEPjvauAv0fSE0a6Q+l0Tv2ZrAafTkYfnxBFw= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= diff --git a/option/address.go b/option/address.go index 7781482c..db179e2b 100644 --- a/option/address.go +++ b/option/address.go @@ -7,9 +7,12 @@ import ( 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 { diff --git a/option/config.go b/option/config.go index 7e4a0286..2b091714 100644 --- a/option/config.go +++ b/option/config.go @@ -3,7 +3,7 @@ package option import "github.com/sagernet/sing/common" type Options struct { - Log *LogOption `json:"log"` + Log *LogOption `json:"log,omitempty"` Inbounds []Inbound `json:"inbounds,omitempty"` Outbounds []Outbound `json:"outbounds,omitempty"` Route *RouteOptions `json:"route,omitempty"` diff --git a/option/inbound.go b/option/inbound.go index 0cf29e8c..f18948c3 100644 --- a/option/inbound.go +++ b/option/inbound.go @@ -20,52 +20,52 @@ type _Inbound struct { 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 - switch i.Type { + switch h.Type { case "direct": - v = i.DirectOptions + v = h.DirectOptions case "socks": - v = i.SocksOptions + v = h.SocksOptions case "http": - v = i.HTTPOptions + v = h.HTTPOptions case "mixed": - v = i.MixedOptions + v = h.MixedOptions case "shadowsocks": - v = i.ShadowsocksOptions + v = h.ShadowsocksOptions 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 { return err } var v any - switch i.Type { + switch h.Type { case "direct": - v = &i.DirectOptions + v = &h.DirectOptions case "socks": - v = &i.SocksOptions + v = &h.SocksOptions case "http": - v = &i.HTTPOptions + v = &h.HTTPOptions case "mixed": - v = &i.MixedOptions + v = &h.MixedOptions case "shadowsocks": - v = &i.ShadowsocksOptions + v = &h.ShadowsocksOptions default: return nil } diff --git a/option/json.go b/option/json.go index e17a33f2..c1f08dfc 100644 --- a/option/json.go +++ b/option/json.go @@ -2,33 +2,33 @@ package option import ( "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) if err != nil { return nil, err } - var content map[string]any + var content linkedhashmap.Map[string, any] err = json.Unmarshal(bytes, &content) if err != nil { 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 { objectMap, err := ToMap(object) if err != nil { 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) { diff --git a/option/listable.go b/option/listable.go index 877c06a4..d74a9511 100644 --- a/option/listable.go +++ b/option/listable.go @@ -4,8 +4,8 @@ import "encoding/json" 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 { return json.Marshal(arrayList[0]) } diff --git a/option/outbound.go b/option/outbound.go index 713f25c6..09d310c6 100644 --- a/option/outbound.go +++ b/option/outbound.go @@ -16,30 +16,30 @@ type _Outbound struct { type Outbound _Outbound -func (i *Outbound) MarshalJSON() ([]byte, error) { +func (h Outbound) MarshalJSON() ([]byte, error) { var v any - switch i.Type { + switch h.Type { case "direct": - v = i.DirectOptions + v = h.DirectOptions case "shadowsocks": - v = i.ShadowsocksOptions + v = h.ShadowsocksOptions 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 { return err } var v any - switch i.Type { + switch h.Type { case "direct": - v = &i.DirectOptions + v = &h.DirectOptions case "shadowsocks": - v = &i.ShadowsocksOptions + v = &h.ShadowsocksOptions default: return nil } diff --git a/option/route.go b/option/route.go index 51ab78ec..cb2d6c57 100644 --- a/option/route.go +++ b/option/route.go @@ -26,8 +26,8 @@ type GeoIPOptions struct { type _Rule struct { 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 @@ -38,7 +38,7 @@ func (r Rule) Equals(other Rule) bool { common.PtrEquals(r.LogicalOptions, other.LogicalOptions) } -func (r *Rule) MarshalJSON() ([]byte, error) { +func (r Rule) MarshalJSON() ([]byte, error) { var v any switch r.Type { case C.RuleTypeDefault: @@ -48,7 +48,7 @@ func (r *Rule) MarshalJSON() ([]byte, error) { default: 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 {