package route import ( "context" "os" "strings" "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/common/srs" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/option" E "github.com/sagernet/sing/common/exceptions" F "github.com/sagernet/sing/common/format" "github.com/sagernet/sing/common/json" "github.com/sagernet/sing/service/filemanager" ) var _ adapter.RuleSet = (*LocalRuleSet)(nil) type LocalRuleSet struct { rules []adapter.HeadlessRule metadata adapter.RuleSetMetadata } func NewLocalRuleSet(ctx context.Context, router adapter.Router, options option.RuleSet) (*LocalRuleSet, error) { var plainRuleSet option.PlainRuleSet switch options.Format { case C.RuleSetFormatSource, "": content, err := os.ReadFile(filemanager.BasePath(ctx, options.LocalOptions.Path)) if err != nil { return nil, err } compat, err := json.UnmarshalExtended[option.PlainRuleSetCompat](content) if err != nil { return nil, err } plainRuleSet = compat.Upgrade() case C.RuleSetFormatBinary: setFile, err := os.Open(filemanager.BasePath(ctx, options.LocalOptions.Path)) if err != nil { return nil, err } plainRuleSet, err = srs.Read(setFile, false) if err != nil { return nil, err } default: return nil, E.New("unknown rule set format: ", options.Format) } rules := make([]adapter.HeadlessRule, len(plainRuleSet.Rules)) var err error for i, ruleOptions := range plainRuleSet.Rules { rules[i], err = NewHeadlessRule(router, ruleOptions) if err != nil { return nil, E.Cause(err, "parse rule_set.rules.[", i, "]") } } var metadata adapter.RuleSetMetadata metadata.ContainsProcessRule = hasHeadlessRule(plainRuleSet.Rules, isProcessHeadlessRule) metadata.ContainsWIFIRule = hasHeadlessRule(plainRuleSet.Rules, isWIFIHeadlessRule) metadata.ContainsIPCIDRRule = hasHeadlessRule(plainRuleSet.Rules, isIPCIDRHeadlessRule) return &LocalRuleSet{rules, metadata}, nil } func (s *LocalRuleSet) Match(metadata *adapter.InboundContext) bool { for _, rule := range s.rules { if rule.Match(metadata) { return true } } return false } func (s *LocalRuleSet) String() string { return strings.Join(F.MapToString(s.rules), " ") } func (s *LocalRuleSet) StartContext(ctx context.Context, startContext adapter.RuleSetStartContext) error { return nil } func (s *LocalRuleSet) Metadata() adapter.RuleSetMetadata { return s.metadata } func (s *LocalRuleSet) Close() error { return nil }