From a21eaa7de5ca5d8dd450e75ed77d8dbbe8da647c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Thu, 7 Nov 2024 12:02:36 +0800 Subject: [PATCH] Implement new deprecated warnings --- cmd/sing-box/cmd.go | 2 +- cmd/sing-box/cmd_check.go | 2 +- experimental/deprecated/constants.go | 27 +++++++++++++++++++ experimental/deprecated/manager.go | 2 ++ experimental/deprecated/{env.go => stderr.go} | 18 +++++++++---- experimental/libbox/deprecated.go | 3 ++- experimental/libbox/service.go | 4 +-- option/outbound.go | 11 ++++++++ option/rule_action.go | 15 ++++++----- option/rule_dns.go | 13 ++++----- 10 files changed, 74 insertions(+), 23 deletions(-) rename experimental/deprecated/{env.go => stderr.go} (59%) diff --git a/cmd/sing-box/cmd.go b/cmd/sing-box/cmd.go index b38d6518..dc7a8309 100644 --- a/cmd/sing-box/cmd.go +++ b/cmd/sing-box/cmd.go @@ -68,6 +68,6 @@ func preRun(cmd *cobra.Command, args []string) { if len(configPaths) == 0 && len(configDirectories) == 0 { configPaths = append(configPaths, "config.json") } - globalCtx = service.ContextWith(globalCtx, deprecated.NewEnvManager(log.StdLogger())) + globalCtx = service.ContextWith(globalCtx, deprecated.NewStderrManager(log.StdLogger())) globalCtx = box.Context(globalCtx, include.InboundRegistry(), include.OutboundRegistry()) } diff --git a/cmd/sing-box/cmd_check.go b/cmd/sing-box/cmd_check.go index 1beab954..29a39081 100644 --- a/cmd/sing-box/cmd_check.go +++ b/cmd/sing-box/cmd_check.go @@ -30,7 +30,7 @@ func check() error { if err != nil { return err } - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := context.WithCancel(globalCtx) instance, err := box.New(box.Options{ Context: ctx, Options: options, diff --git a/experimental/deprecated/constants.go b/experimental/deprecated/constants.go index 34ea5fc3..c830f49f 100644 --- a/experimental/deprecated/constants.go +++ b/experimental/deprecated/constants.go @@ -78,9 +78,36 @@ var OptionTUNAddressX = Note{ MigrationLink: "https://sing-box.sagernet.org/migration/#tun-address-fields-are-merged", } +var OptionSpecialOutbounds = Note{ + Name: "special-outbounds", + Description: "legacy special outbounds", + DeprecatedVersion: "1.11.0", + ScheduledVersion: "1.13.0", + MigrationLink: "https://sing-box.sagernet.org/migration/#migrate-legacy-special-outbounds-to-rule-actions", +} + +var OptionInboundOptions = Note{ + Name: "inbound-options", + Description: "legacy inbound fields", + DeprecatedVersion: "1.11.0", + ScheduledVersion: "1.13.0", + MigrationLink: "https://sing-box.sagernet.org/migration/#migrate-legacy-special-outbounds-to-rule-actions", +} + +var OptionLegacyDNSRouteOptions = Note{ + Name: "legacy-dns-route-options", + Description: "legacy dns route options", + DeprecatedVersion: "1.11.0", + ScheduledVersion: "1.12.0", + MigrationLink: "https://sing-box.sagernet.org/migration/#migrate-legacy-dns-route-options-to-rule-actions", +} + var Options = []Note{ OptionBadMatchSource, OptionGEOIP, OptionGEOSITE, OptionTUNAddressX, + OptionSpecialOutbounds, + OptionInboundOptions, + OptionLegacyDNSRouteOptions, } diff --git a/experimental/deprecated/manager.go b/experimental/deprecated/manager.go index d12acf48..48493589 100644 --- a/experimental/deprecated/manager.go +++ b/experimental/deprecated/manager.go @@ -2,6 +2,7 @@ package deprecated import ( "context" + "runtime/debug" "github.com/sagernet/sing/service" ) @@ -13,6 +14,7 @@ type Manager interface { func Report(ctx context.Context, feature Note) { manager := service.FromContext[Manager](ctx) if manager == nil { + debug.PrintStack() return } manager.ReportDeprecated(feature) diff --git a/experimental/deprecated/env.go b/experimental/deprecated/stderr.go similarity index 59% rename from experimental/deprecated/env.go rename to experimental/deprecated/stderr.go index 113b8717..0826baf9 100644 --- a/experimental/deprecated/env.go +++ b/experimental/deprecated/stderr.go @@ -7,15 +7,23 @@ import ( "github.com/sagernet/sing/common/logger" ) -type envManager struct { - logger logger.Logger +type stderrManager struct { + logger logger.Logger + reported map[string]bool } -func NewEnvManager(logger logger.Logger) Manager { - return &envManager{logger: logger} +func NewStderrManager(logger logger.Logger) Manager { + return &stderrManager{ + logger: logger, + reported: make(map[string]bool), + } } -func (f *envManager) ReportDeprecated(feature Note) { +func (f *stderrManager) ReportDeprecated(feature Note) { + if f.reported[feature.Name] { + return + } + f.reported[feature.Name] = true if !feature.Impending() { f.logger.Warn(feature.MessageWithLink()) return diff --git a/experimental/libbox/deprecated.go b/experimental/libbox/deprecated.go index b953014f..d27be576 100644 --- a/experimental/libbox/deprecated.go +++ b/experimental/libbox/deprecated.go @@ -4,6 +4,7 @@ import ( "sync" "github.com/sagernet/sing-box/experimental/deprecated" + "github.com/sagernet/sing/common" ) var _ deprecated.Manager = (*deprecatedManager)(nil) @@ -16,7 +17,7 @@ type deprecatedManager struct { func (m *deprecatedManager) ReportDeprecated(feature deprecated.Note) { m.access.Lock() defer m.access.Unlock() - m.features = append(m.features, feature) + m.features = common.Uniq(append(m.features, feature)) } func (m *deprecatedManager) Get() []deprecated.Note { diff --git a/experimental/libbox/service.go b/experimental/libbox/service.go index eadd4c27..dcb0370f 100644 --- a/experimental/libbox/service.go +++ b/experimental/libbox/service.go @@ -43,16 +43,16 @@ type BoxService struct { func NewService(configContent string, platformInterface PlatformInterface) (*BoxService, error) { ctx := box.Context(context.Background(), include.InboundRegistry(), include.OutboundRegistry()) + ctx = service.ContextWith[deprecated.Manager](ctx, new(deprecatedManager)) + ctx = filemanager.WithDefault(ctx, sWorkingPath, sTempPath, sUserID, sGroupID) options, err := parseConfig(ctx, configContent) if err != nil { return nil, err } runtimeDebug.FreeOSMemory() ctx, cancel := context.WithCancel(ctx) - ctx = filemanager.WithDefault(ctx, sWorkingPath, sTempPath, sUserID, sGroupID) urlTestHistoryStorage := urltest.NewHistoryStorage() ctx = service.ContextWithPtr(ctx, urlTestHistoryStorage) - ctx = service.ContextWith[deprecated.Manager](ctx, new(deprecatedManager)) platformWrapper := &platformInterfaceWrapper{iif: platformInterface, useProcFS: platformInterface.UseProcFS()} ctx = service.ContextWith[platform.Interface](ctx, platformWrapper) instance, err := box.New(box.Options{ diff --git a/option/outbound.go b/option/outbound.go index 00a20aa5..1dddb354 100644 --- a/option/outbound.go +++ b/option/outbound.go @@ -3,6 +3,8 @@ package option import ( "context" + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/experimental/deprecated" E "github.com/sagernet/sing/common/exceptions" "github.com/sagernet/sing/common/json" "github.com/sagernet/sing/common/json/badjson" @@ -35,6 +37,10 @@ func (h *Outbound) UnmarshalJSONContext(ctx context.Context, content []byte) err if registry == nil { return E.New("missing outbound options registry in context") } + switch h.Type { + case C.TypeBlock, C.TypeDNS: + deprecated.Report(ctx, deprecated.OptionSpecialOutbounds) + } options, loaded := registry.CreateOptions(h.Type) if !loaded { return E.New("unknown outbound type: ", h.Type) @@ -43,6 +49,11 @@ func (h *Outbound) UnmarshalJSONContext(ctx context.Context, content []byte) err if err != nil { return err } + if listenWrapper, isListen := options.(ListenOptionsWrapper); isListen { + if listenWrapper.TakeListenOptions().InboundOptions != (InboundOptions{}) { + deprecated.Report(ctx, deprecated.OptionInboundOptions) + } + } h.Options = options return nil } diff --git a/option/rule_action.go b/option/rule_action.go index f122f959..f95cd99d 100644 --- a/option/rule_action.go +++ b/option/rule_action.go @@ -1,10 +1,12 @@ package option import ( + "context" "fmt" "time" C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/experimental/deprecated" dns "github.com/sagernet/sing-dns" E "github.com/sagernet/sing/common/exceptions" "github.com/sagernet/sing/common/json" @@ -107,7 +109,7 @@ func (r DNSRuleAction) MarshalJSON() ([]byte, error) { return badjson.MarshallObjects((_DNSRuleAction)(r), v) } -func (r *DNSRuleAction) UnmarshalJSON(data []byte) error { +func (r *DNSRuleAction) UnmarshalJSONContext(ctx context.Context, data []byte) error { err := json.Unmarshal(data, (*_DNSRuleAction)(r)) if err != nil { return err @@ -124,11 +126,7 @@ func (r *DNSRuleAction) UnmarshalJSON(data []byte) error { default: return E.New("unknown DNS rule action: " + r.Action) } - if v == nil { - // check unknown fields - return json.UnmarshalDisallowUnknownFields(data, &_DNSRuleAction{}) - } - return badjson.UnmarshallExcluded(data, (*_DNSRuleAction)(r), v) + return badjson.UnmarshallExcludedContext(ctx, data, (*_DNSRuleAction)(r), v) } type _RouteActionOptions struct { @@ -178,7 +176,7 @@ type _DNSRouteActionOptions struct { type DNSRouteActionOptions _DNSRouteActionOptions -func (r *DNSRouteActionOptions) UnmarshalJSON(data []byte) error { +func (r *DNSRouteActionOptions) UnmarshalJSONContext(ctx context.Context, data []byte) error { err := json.Unmarshal(data, (*_DNSRouteActionOptions)(r)) if err != nil { return err @@ -186,6 +184,9 @@ func (r *DNSRouteActionOptions) UnmarshalJSON(data []byte) error { if r.Server == "" { return E.New("missing server") } + if r.DisableCache || r.RewriteTTL != nil || r.ClientSubnet != nil { + deprecated.Report(ctx, deprecated.OptionLegacyDNSRouteOptions) + } return nil } diff --git a/option/rule_dns.go b/option/rule_dns.go index b987fc02..88b8aa91 100644 --- a/option/rule_dns.go +++ b/option/rule_dns.go @@ -1,6 +1,7 @@ package option import ( + "context" "reflect" C "github.com/sagernet/sing-box/constant" @@ -32,7 +33,7 @@ func (r DNSRule) MarshalJSON() ([]byte, error) { return badjson.MarshallObjects((_DNSRule)(r), v) } -func (r *DNSRule) UnmarshalJSON(bytes []byte) error { +func (r *DNSRule) UnmarshalJSONContext(ctx context.Context, bytes []byte) error { err := json.Unmarshal(bytes, (*_DNSRule)(r)) if err != nil { return err @@ -47,7 +48,7 @@ func (r *DNSRule) UnmarshalJSON(bytes []byte) error { default: return E.New("unknown rule type: " + r.Type) } - err = badjson.UnmarshallExcluded(bytes, (*_DNSRule)(r), v) + err = badjson.UnmarshallExcludedContext(ctx, bytes, (*_DNSRule)(r), v) if err != nil { return err } @@ -115,12 +116,12 @@ func (r DefaultDNSRule) MarshalJSON() ([]byte, error) { return badjson.MarshallObjects(r.RawDefaultDNSRule, r.DNSRuleAction) } -func (r *DefaultDNSRule) UnmarshalJSON(data []byte) error { +func (r *DefaultDNSRule) UnmarshalJSONContext(ctx context.Context, data []byte) error { err := json.Unmarshal(data, &r.RawDefaultDNSRule) if err != nil { return err } - return badjson.UnmarshallExcluded(data, &r.RawDefaultDNSRule, &r.DNSRuleAction) + return badjson.UnmarshallExcludedContext(ctx, data, &r.RawDefaultDNSRule, &r.DNSRuleAction) } func (r DefaultDNSRule) IsValid() bool { @@ -145,12 +146,12 @@ func (r *LogicalDNSRule) MarshalJSON() ([]byte, error) { return badjson.MarshallObjects(r._LogicalDNSRule, r.DNSRuleAction) } -func (r *LogicalDNSRule) UnmarshalJSON(data []byte) error { +func (r *LogicalDNSRule) UnmarshalJSONContext(ctx context.Context, data []byte) error { err := json.Unmarshal(data, &r._LogicalDNSRule) if err != nil { return err } - return badjson.UnmarshallExcluded(data, &r._LogicalDNSRule, &r.DNSRuleAction) + return badjson.UnmarshallExcludedContext(ctx, data, &r._LogicalDNSRule, &r.DNSRuleAction) } func (r *LogicalDNSRule) IsValid() bool {