Invalid config check

This commit is contained in:
世界 2022-07-03 01:57:04 +08:00
parent 6eae8e361f
commit 30444057bd
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
16 changed files with 276 additions and 162 deletions

View file

@ -8,10 +8,14 @@ import (
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format"
)
func New(ctx context.Context, router adapter.Router, logger log.Logger, index int, options option.Inbound) (adapter.Inbound, error) {
if common.IsEmptyByEquals(options) {
return nil, E.New("empty inbound config")
}
var tag string
if options.Tag != "" {
tag = options.Tag
@ -21,16 +25,16 @@ func New(ctx context.Context, router adapter.Router, logger log.Logger, index in
inboundLogger := logger.WithPrefix(F.ToString("inbound/", options.Type, "[", tag, "]: "))
switch options.Type {
case C.TypeDirect:
return NewDirect(ctx, router, inboundLogger, options.Tag, common.PtrValueOrDefault(options.DirectOptions)), nil
return NewDirect(ctx, router, inboundLogger, options.Tag, options.DirectOptions), nil
case C.TypeSocks:
return NewSocks(ctx, router, inboundLogger, options.Tag, common.PtrValueOrDefault(options.SocksOptions)), nil
return NewSocks(ctx, router, inboundLogger, options.Tag, options.SocksOptions), nil
case C.TypeHTTP:
return NewHTTP(ctx, router, inboundLogger, options.Tag, common.PtrValueOrDefault(options.HTTPOptions)), nil
return NewHTTP(ctx, router, inboundLogger, options.Tag, options.HTTPOptions), nil
case C.TypeMixed:
return NewMixed(ctx, router, inboundLogger, options.Tag, common.PtrValueOrDefault(options.MixedOptions)), nil
return NewMixed(ctx, router, inboundLogger, options.Tag, options.MixedOptions), nil
case C.TypeShadowsocks:
return NewShadowsocks(ctx, router, inboundLogger, options.Tag, common.PtrValueOrDefault(options.ShadowsocksOptions))
return NewShadowsocks(ctx, router, inboundLogger, options.Tag, options.ShadowsocksOptions)
default:
panic(F.ToString("unknown inbound type: ", options.Type))
return nil, E.New("unknown inbound type: ", options.Type)
}
}

View file

@ -6,10 +6,14 @@ import (
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format"
)
func New(router adapter.Router, logger log.Logger, index int, options option.Outbound) (adapter.Outbound, error) {
if common.IsEmpty(options) {
return nil, E.New("empty outbound config")
}
var tag string
if options.Tag != "" {
tag = options.Tag
@ -19,10 +23,10 @@ func New(router adapter.Router, logger log.Logger, index int, options option.Out
outboundLogger := logger.WithPrefix(F.ToString("outbound/", options.Type, "[", tag, "]: "))
switch options.Type {
case C.TypeDirect:
return NewDirect(router, outboundLogger, options.Tag, common.PtrValueOrDefault(options.DirectOptions)), nil
return NewDirect(router, outboundLogger, options.Tag, options.DirectOptions), nil
case C.TypeShadowsocks:
return NewShadowsocks(router, outboundLogger, options.Tag, common.PtrValueOrDefault(options.ShadowsocksOptions))
return NewShadowsocks(router, outboundLogger, options.Tag, options.ShadowsocksOptions)
default:
panic(F.ToString("unknown outbound type: ", options.Type))
return nil, E.New("unknown outbound type: ", options.Type)
}
}

View file

@ -13,10 +13,25 @@ import (
)
func NewRule(router adapter.Router, logger log.Logger, options option.Rule) (adapter.Rule, error) {
if common.IsEmptyByEquals(options) {
return nil, E.New("empty rule config")
}
switch options.Type {
case "", C.RuleTypeDefault:
if !options.DefaultOptions.IsValid() {
return nil, E.New("missing conditions")
}
if options.DefaultOptions.Outbound == "" {
return nil, E.New("missing outbound field")
}
return NewDefaultRule(router, logger, common.PtrValueOrDefault(options.DefaultOptions))
case C.RuleTypeLogical:
if !options.LogicalOptions.IsValid() {
return nil, E.New("missing conditions")
}
if options.LogicalOptions.Outbound == "" {
return nil, E.New("missing outbound field")
}
return NewLogicalRule(router, logger, common.PtrValueOrDefault(options.LogicalOptions))
default:
return nil, E.New("unknown rule type: ", options.Type)

View file

@ -18,7 +18,10 @@ func init() {
logrus.StandardLogger().Formatter.(*logrus.TextFormatter).ForceColors = true
}
var configPath string
var (
configPath string
workingDir string
)
func main() {
command := &cobra.Command{
@ -26,12 +29,19 @@ func main() {
Run: run,
}
command.Flags().StringVarP(&configPath, "config", "c", "config.json", "set configuration file path")
command.Flags().StringVarP(&workingDir, "directory", "D", "", "set working directory")
if err := command.Execute(); err != nil {
logrus.Fatal(err)
}
}
func run(cmd *cobra.Command, args []string) {
if workingDir != "" {
if err := os.Chdir(workingDir); err != nil {
logrus.Fatal(err)
}
}
configContent, err := os.ReadFile(configPath)
if err != nil {
logrus.Fatal("read config: ", err)

2
go.mod
View file

@ -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-20220702141141-b3923d54845b
github.com/sagernet/sing v0.0.0-20220702174608-cb5bb5132de4
github.com/sagernet/sing-shadowsocks v0.0.0-20220701084835-2208da1d8649
github.com/sirupsen/logrus v1.8.1
github.com/spf13/cobra v1.5.0

4
go.sum
View file

@ -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-20220702141141-b3923d54845b h1:oK5RglZ0s4oXNSrIsLJkBiHbYoAUMOGLN3a0JgDNzVM=
github.com/sagernet/sing v0.0.0-20220702141141-b3923d54845b/go.mod h1:3ZmoGNg/nNJTyHAZFNRSPaXpNIwpDvyIiAUd0KIWV5c=
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-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=

View file

@ -7,6 +7,8 @@ import (
)
type Logger interface {
Start() error
Close() error
Trace(args ...interface{})
Debug(args ...interface{})
Info(args ...interface{})
@ -18,7 +20,6 @@ type Logger interface {
Panic(args ...interface{})
WithContext(ctx context.Context) Logger
WithPrefix(prefix string) Logger
Close() error
}
func NewLogger(options option.LogOption) (Logger, error) {

View file

@ -15,6 +15,7 @@ var _ Logger = (*logrusLogger)(nil)
type logrusLogger struct {
abstractLogrusLogger
outputPath string
output *os.File
}
@ -28,7 +29,6 @@ func NewLogrusLogger(options option.LogOption) (*logrusLogger, error) {
logger.SetLevel(logrus.TraceLevel)
logger.Formatter.(*logrus.TextFormatter).ForceColors = true
logger.AddHook(new(logrusHook))
var output *os.File
var err error
if options.Level != "" {
logger.Level, err = logrus.ParseLevel(options.Level)
@ -36,18 +36,26 @@ func NewLogrusLogger(options option.LogOption) (*logrusLogger, error) {
return nil, err
}
}
if options.Output != "" {
output, err = os.OpenFile(options.Output, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)
return &logrusLogger{logger, options.Output, nil}, nil
}
func (l *logrusLogger) Start() error {
if l.outputPath != "" {
output, err := os.OpenFile(l.outputPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)
if err != nil {
return nil, E.Extend(err, "open log output")
return E.Cause(err, "open log output")
}
logger.SetOutput(output)
l.abstractLogrusLogger.(*logrus.Logger).SetOutput(output)
}
return &logrusLogger{logger, output}, nil
return nil
}
func (l *logrusLogger) Close() error {
return common.Close(common.PtrOrNil(l.output))
}
func (l *logrusLogger) WithContext(ctx context.Context) Logger {
return &logrusLogger{l.abstractLogrusLogger.WithContext(ctx), nil}
return &logrusLogger{abstractLogrusLogger: l.abstractLogrusLogger.WithContext(ctx)}
}
func (l *logrusLogger) WithPrefix(prefix string) Logger {
@ -57,9 +65,5 @@ func (l *logrusLogger) WithPrefix(prefix string) Logger {
prefix = F.ToString(loadedPrefix, prefix)
}
}
return &logrusLogger{l.WithField("prefix", prefix), nil}
}
func (l *logrusLogger) Close() error {
return common.Close(common.PtrOrNil(l.output))
return &logrusLogger{abstractLogrusLogger: l.WithField("prefix", prefix)}
}

View file

@ -10,6 +10,14 @@ func NewNopLogger() Logger {
return (*nopLogger)(nil)
}
func (l *nopLogger) Start() error {
return nil
}
func (l *nopLogger) Close() error {
return nil
}
func (l *nopLogger) Trace(args ...interface{}) {
}
@ -44,7 +52,3 @@ func (l *nopLogger) WithContext(ctx context.Context) Logger {
func (l *nopLogger) WithPrefix(prefix string) Logger {
return l
}
func (l *nopLogger) Close() error {
return nil
}

View file

@ -1,5 +1,7 @@
package option
import "github.com/sagernet/sing/common"
type Options struct {
Log *LogOption `json:"log"`
Inbounds []Inbound `json:"inbounds,omitempty"`
@ -7,6 +9,13 @@ type Options struct {
Route *RouteOptions `json:"route,omitempty"`
}
func (o Options) Equals(other Options) bool {
return common.ComparablePtrEquals(o.Log, other.Log) &&
common.SliceEquals(o.Inbounds, other.Inbounds) &&
common.ComparableSliceEquals(o.Outbounds, other.Outbounds) &&
common.PtrEquals(o.Route, other.Route)
}
type LogOption struct {
Disabled bool `json:"disabled,omitempty"`
Level string `json:"level,omitempty"`

View file

@ -3,52 +3,50 @@ package option
import (
"encoding/json"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/auth"
E "github.com/sagernet/sing/common/exceptions"
)
var ErrUnknownInboundType = E.New("unknown inbound type")
type _Inbound struct {
Tag string `json:"tag,omitempty"`
Type string `json:"type,omitempty"`
DirectOptions *DirectInboundOptions `json:"directOptions,omitempty"`
SocksOptions *SimpleInboundOptions `json:"socksOptions,omitempty"`
HTTPOptions *SimpleInboundOptions `json:"httpOptions,omitempty"`
MixedOptions *SimpleInboundOptions `json:"mixedOptions,omitempty"`
ShadowsocksOptions *ShadowsocksInboundOptions `json:"shadowsocksOptions,omitempty"`
Type string `json:"type"`
DirectOptions DirectInboundOptions `json:"-"`
SocksOptions SimpleInboundOptions `json:"-"`
HTTPOptions SimpleInboundOptions `json:"-"`
MixedOptions SimpleInboundOptions `json:"-"`
ShadowsocksOptions ShadowsocksInboundOptions `json:"-"`
}
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 (i *Inbound) MarshalJSON() ([]byte, error) {
var options []byte
var err error
var v any
switch i.Type {
case "direct":
options, err = json.Marshal(i.DirectOptions)
v = i.DirectOptions
case "socks":
options, err = json.Marshal(i.SocksOptions)
v = i.SocksOptions
case "http":
options, err = json.Marshal(i.HTTPOptions)
v = i.HTTPOptions
case "mixed":
options, err = json.Marshal(i.MixedOptions)
v = i.MixedOptions
case "shadowsocks":
options, err = json.Marshal(i.ShadowsocksOptions)
v = i.ShadowsocksOptions
default:
return nil, E.Extend(ErrUnknownInboundType, i.Type)
return nil, E.New("unknown inbound type: ", i.Type)
}
if err != nil {
return nil, err
}
var content map[string]any
err = json.Unmarshal(options, &content)
if err != nil {
return nil, err
}
content["tag"] = i.Tag
content["type"] = i.Type
return json.Marshal(content)
return MarshallObjects(i, v)
}
func (i *Inbound) UnmarshalJSON(bytes []byte) error {
@ -56,43 +54,29 @@ func (i *Inbound) UnmarshalJSON(bytes []byte) error {
if err != nil {
return err
}
var v any
switch i.Type {
case "direct":
if i.DirectOptions != nil {
break
}
err = json.Unmarshal(bytes, &i.DirectOptions)
v = &i.DirectOptions
case "socks":
if i.SocksOptions != nil {
break
}
err = json.Unmarshal(bytes, &i.SocksOptions)
v = &i.SocksOptions
case "http":
if i.HTTPOptions != nil {
break
}
err = json.Unmarshal(bytes, &i.HTTPOptions)
v = &i.HTTPOptions
case "mixed":
if i.MixedOptions != nil {
break
}
err = json.Unmarshal(bytes, &i.MixedOptions)
v = &i.MixedOptions
case "shadowsocks":
if i.ShadowsocksOptions != nil {
break
}
err = json.Unmarshal(bytes, &i.ShadowsocksOptions)
v = &i.ShadowsocksOptions
default:
return E.Extend(ErrUnknownInboundType, i.Type)
return nil
}
return err
return json.Unmarshal(bytes, v)
}
type ListenOptions struct {
Listen ListenAddress `json:"listen"`
Port uint16 `json:"listen_port"`
TCPFastOpen bool `json:"tcpFastOpen,omitempty"`
UDPTimeout int64 `json:"udpTimeout,omitempty"`
TCPFastOpen bool `json:"tcp_fast_open,omitempty"`
UDPTimeout int64 `json:"udp_timeout,omitempty"`
}
type SimpleInboundOptions struct {
@ -100,11 +84,23 @@ type SimpleInboundOptions struct {
Users []auth.User `json:"users,omitempty"`
}
func (o SimpleInboundOptions) Equals(other SimpleInboundOptions) bool {
return o.ListenOptions == other.ListenOptions &&
common.ComparableSliceEquals(o.Users, other.Users)
}
type DirectInboundOptions struct {
ListenOptions
Network NetworkList `json:"network,omitempty"`
OverrideAddress string `json:"overrideAddress,omitempty"`
OverridePort uint16 `json:"overridePort,omitempty"`
OverrideAddress string `json:"override_address,omitempty"`
OverridePort uint16 `json:"override_port,omitempty"`
}
func (o DirectInboundOptions) Equals(other DirectInboundOptions) bool {
return o.ListenOptions == other.ListenOptions &&
common.ComparableSliceEquals(o.Network, other.Network) &&
o.OverrideAddress == other.OverrideAddress &&
o.OverridePort == other.OverridePort
}
type ShadowsocksInboundOptions struct {
@ -113,3 +109,10 @@ type ShadowsocksInboundOptions struct {
Method string `json:"method"`
Password string `json:"password"`
}
func (o ShadowsocksInboundOptions) Equals(other ShadowsocksInboundOptions) bool {
return o.ListenOptions == other.ListenOptions &&
common.ComparableSliceEquals(o.Network, other.Network) &&
o.Method == other.Method &&
o.Password == other.Password
}

40
option/json.go Normal file
View file

@ -0,0 +1,40 @@
package option
import (
"encoding/json"
)
func ToMap(v any) (map[string]any, error) {
bytes, err := json.Marshal(v)
if err != nil {
return nil, err
}
var content map[string]any
err = json.Unmarshal(bytes, &content)
if err != nil {
return nil, err
}
return content, nil
}
func MergeObjects(objects ...any) (map[string]any, error) {
content := make(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
}
}
return content, nil
}
func MarshallObjects(objects ...any) ([]byte, error) {
content, err := MergeObjects(objects...)
if err != nil {
return nil, err
}
return json.Marshal(content)
}

View file

@ -2,7 +2,7 @@ package option
import "encoding/json"
type Listable[T any] []T
type Listable[T comparable] []T
func (l *Listable[T]) MarshalJSON() ([]byte, error) {
arrayList := []T(*l)

View file

@ -7,65 +7,44 @@ import (
M "github.com/sagernet/sing/common/metadata"
)
var ErrUnknownOutboundType = E.New("unknown outbound type")
type _Outbound struct {
Tag string `json:"tag,omitempty"`
Type string `json:"type,omitempty"`
DirectOptions *DirectOutboundOptions `json:"directOptions,omitempty"`
ShadowsocksOptions *ShadowsocksOutboundOptions `json:"shadowsocksOptions,omitempty"`
DirectOptions DirectOutboundOptions `json:"-"`
ShadowsocksOptions ShadowsocksOutboundOptions `json:"-"`
}
type Outbound _Outbound
func (i *Outbound) MarshalJSON() ([]byte, error) {
var options []byte
var err error
var v any
switch i.Type {
case "direct":
options, err = json.Marshal(i.DirectOptions)
v = i.DirectOptions
case "shadowsocks":
options, err = json.Marshal(i.ShadowsocksOptions)
v = i.ShadowsocksOptions
default:
return nil, E.Extend(ErrUnknownOutboundType, i.Type)
return nil, E.New("unknown outbound type: ", i.Type)
}
if err != nil {
return nil, err
}
var content map[string]any
err = json.Unmarshal(options, &content)
if err != nil {
return nil, err
}
content["tag"] = i.Tag
content["type"] = i.Type
return json.Marshal(content)
return MarshallObjects(i, v)
}
func (i *Outbound) UnmarshalJSON(bytes []byte) error {
if err := json.Unmarshal(bytes, (*_Outbound)(i)); err != nil {
err := json.Unmarshal(bytes, (*_Outbound)(i))
if err != nil {
return err
}
var v any
switch i.Type {
case "direct":
if i.DirectOptions != nil {
break
}
if err := json.Unmarshal(bytes, &i.DirectOptions); err != nil {
return err
}
v = &i.DirectOptions
case "shadowsocks":
if i.ShadowsocksOptions != nil {
break
}
if err := json.Unmarshal(bytes, &i.ShadowsocksOptions); err != nil {
return err
}
v = &i.ShadowsocksOptions
default:
return E.Extend(ErrUnknownOutboundType, i.Type)
}
return nil
}
return json.Unmarshal(bytes, v)
}
type DialerOptions struct {
Detour string `json:"detour,omitempty"`

View file

@ -4,16 +4,20 @@ import (
"encoding/json"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
)
var ErrUnknownRuleType = E.New("unknown rule type")
type RouteOptions struct {
GeoIP *GeoIPOptions `json:"geoip,omitempty"`
Rules []Rule `json:"rules,omitempty"`
}
func (o RouteOptions) Equals(other RouteOptions) bool {
return common.ComparablePtrEquals(o.GeoIP, other.GeoIP) &&
common.SliceEquals(o.Rules, other.Rules)
}
type GeoIPOptions struct {
Path string `json:"path,omitempty"`
DownloadURL string `json:"download_url,omitempty"`
@ -28,25 +32,23 @@ type _Rule struct {
type Rule _Rule
func (r Rule) Equals(other Rule) bool {
return r.Type == other.Type &&
common.PtrEquals(r.DefaultOptions, other.DefaultOptions) &&
common.PtrEquals(r.LogicalOptions, other.LogicalOptions)
}
func (r *Rule) MarshalJSON() ([]byte, error) {
var content map[string]any
var v any
switch r.Type {
case "", C.RuleTypeDefault:
return json.Marshal(r.DefaultOptions)
case C.RuleTypeDefault:
v = r.DefaultOptions
case C.RuleTypeLogical:
options, err := json.Marshal(r.LogicalOptions)
if err != nil {
return nil, err
}
err = json.Unmarshal(options, &content)
if err != nil {
return nil, err
}
content["type"] = r.Type
return json.Marshal(content)
v = r.LogicalOptions
default:
return nil, E.Extend(ErrUnknownRuleType, r.Type)
return nil, E.New("unknown rule type: " + r.Type)
}
return MarshallObjects(r, v)
}
func (r *Rule) UnmarshalJSON(bytes []byte) error {
@ -54,21 +56,19 @@ func (r *Rule) UnmarshalJSON(bytes []byte) error {
if err != nil {
return err
}
if r.Type == "" {
r.Type = C.RuleTypeDefault
}
var v any
switch r.Type {
case "", C.RuleTypeDefault:
if r.DefaultOptions == nil {
break
}
err = json.Unmarshal(bytes, r.DefaultOptions)
case C.RuleTypeDefault:
v = &r.DefaultOptions
case C.RuleTypeLogical:
if r.LogicalOptions == nil {
break
}
err = json.Unmarshal(bytes, r.LogicalOptions)
v = &r.LogicalOptions
default:
err = E.Extend(ErrUnknownRuleType, r.Type)
return E.New("unknown rule type: " + r.Type)
}
return err
return json.Unmarshal(bytes, v)
}
type DefaultRule struct {
@ -90,8 +90,41 @@ type DefaultRule struct {
Outbound string `json:"outbound,omitempty"`
}
func (r DefaultRule) IsValid() bool {
var defaultValue DefaultRule
defaultValue.Outbound = r.Outbound
return !r.Equals(defaultValue)
}
func (r DefaultRule) Equals(other DefaultRule) bool {
return common.ComparableSliceEquals(r.Inbound, other.Inbound) &&
r.IPVersion == other.IPVersion &&
r.Network == other.Network &&
common.ComparableSliceEquals(r.Protocol, other.Protocol) &&
common.ComparableSliceEquals(r.Domain, other.Domain) &&
common.ComparableSliceEquals(r.DomainSuffix, other.DomainSuffix) &&
common.ComparableSliceEquals(r.DomainKeyword, other.DomainKeyword) &&
common.ComparableSliceEquals(r.SourceGeoIP, other.SourceGeoIP) &&
common.ComparableSliceEquals(r.GeoIP, other.GeoIP) &&
common.ComparableSliceEquals(r.SourceIPCIDR, other.SourceIPCIDR) &&
common.ComparableSliceEquals(r.IPCIDR, other.IPCIDR) &&
common.ComparableSliceEquals(r.SourcePort, other.SourcePort) &&
common.ComparableSliceEquals(r.Port, other.Port) &&
r.Outbound == other.Outbound
}
type LogicalRule struct {
Mode string `json:"mode"`
Rules []DefaultRule `json:"rules,omitempty"`
Outbound string `json:"outbound,omitempty"`
}
func (r LogicalRule) IsValid() bool {
return len(r.Rules) > 0 && common.All(r.Rules, DefaultRule.IsValid)
}
func (r LogicalRule) Equals(other LogicalRule) bool {
return r.Mode == other.Mode &&
common.SliceEquals(r.Rules, other.Rules) &&
r.Outbound == other.Outbound
}

View file

@ -10,6 +10,7 @@ import (
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
)
var _ adapter.Service = (*Service)(nil)
@ -24,11 +25,11 @@ type Service struct {
func NewService(ctx context.Context, options option.Options) (*Service, error) {
logger, err := log.NewLogger(common.PtrValueOrDefault(options.Log))
if err != nil {
return nil, err
return nil, E.Cause(err, "parse log options")
}
router, err := route.NewRouter(ctx, logger, common.PtrValueOrDefault(options.Route))
if err != nil {
return nil, err
return nil, E.Cause(err, "parse route options")
}
inbounds := make([]adapter.Inbound, 0, len(options.Inbounds))
outbounds := make([]adapter.Outbound, 0, len(options.Outbounds))
@ -36,7 +37,7 @@ func NewService(ctx context.Context, options option.Options) (*Service, error) {
var inboundService adapter.Inbound
inboundService, err = inbound.New(ctx, router, logger, i, inboundOptions)
if err != nil {
return nil, err
return nil, E.Cause(err, "parse inbound[", i, "]")
}
inbounds = append(inbounds, inboundService)
}
@ -44,7 +45,7 @@ func NewService(ctx context.Context, options option.Options) (*Service, error) {
var outboundService adapter.Outbound
outboundService, err = outbound.New(router, logger, i, outboundOptions)
if err != nil {
return nil, err
return nil, E.Cause(err, "parse outbound[", i, "]")
}
outbounds = append(outbounds, outboundService)
}
@ -61,13 +62,19 @@ func NewService(ctx context.Context, options option.Options) (*Service, error) {
}
func (s *Service) Start() error {
err := s.logger.Start()
if err != nil {
return err
}
for _, in := range s.inbounds {
err := in.Start()
err = in.Start()
if err != nil {
return err
}
}
return nil
return common.AnyError(
s.router.Start(),
)
}
func (s *Service) Close() error {
@ -77,7 +84,8 @@ func (s *Service) Close() error {
for _, out := range s.outbounds {
common.Close(out)
}
s.logger.Close()
s.router.Close()
return nil
return common.Close(
s.router,
s.logger,
)
}