Liu Song’s Projects


~/Projects/clash-pro

git clone https://code.lsong.org/clash-pro

Commit

Commit
3b96d54369b3d7f750bfb1491056292b10ab4795
Author
wwqgtxx <[email protected]>
Date
2022-12-05 23:51:38 +0800 +0800
Diffstat
 rules/logic/and.go | 68 ---------
 rules/logic/common.go | 139 --------------------
 rules/logic/logic.go | 289 ++++++++++++++++++++++++++++++++++++++++++
 rules/logic/not.go | 63 ---------
 rules/logic/or.go | 67 ---------
 rules/logic/sub_rules.go | 91 -------------

chore: cleanup rules/logic code


diff --git a/rules/logic/and.go b/rules/logic/and.go
deleted file mode 100644
index ffd7c26263bd2c699c8ad1cb580706aa086ccfaa..0000000000000000000000000000000000000000
--- a/rules/logic/and.go
+++ /dev/null
@@ -1,68 +0,0 @@
-package logic
-
-import (
-	"fmt"
-	C "github.com/Dreamacro/clash/constant"
-	"github.com/Dreamacro/clash/rules/common"
-	"strings"
-)
-
-type AND struct {
-	*common.Base
-	rules   []C.Rule
-	payload string
-	adapter string
-	needIP  bool
-}
-
-func (A *AND) ShouldFindProcess() bool {
-	return false
-}
-
-func NewAND(payload string, adapter string,
-	parse func(tp, payload, target string, params []string, subRules map[string][]C.Rule) (parsed C.Rule, parseErr error)) (*AND, error) {
-	and := &AND{Base: &common.Base{}, payload: payload, adapter: adapter}
-	rules, err := ParseRuleByPayload(payload, parse)
-	if err != nil {
-		return nil, err
-	}
-
-	and.rules = rules
-	payloads := make([]string, 0, len(rules))
-	for _, rule := range rules {
-		payloads = append(payloads, fmt.Sprintf("(%s,%s)", rule.RuleType().String(), rule.Payload()))
-		if rule.ShouldResolveIP() {
-			and.needIP = true
-			break
-		}
-	}
-
-	and.payload = fmt.Sprintf("(%s)", strings.Join(payloads, " && "))
-	return and, nil
-}
-
-func (A *AND) RuleType() C.RuleType {
-	return C.AND
-}
-
-func (A *AND) Match(metadata *C.Metadata) (bool, string) {
-	for _, rule := range A.rules {
-		if m, _ := rule.Match(metadata); !m {
-			return false, ""
-		}
-	}
-
-	return true, A.adapter
-}
-
-func (A *AND) Adapter() string {
-	return A.adapter
-}
-
-func (A *AND) Payload() string {
-	return A.payload
-}
-
-func (A *AND) ShouldResolveIP() bool {
-	return A.needIP
-}




diff --git a/rules/logic/common.go b/rules/logic/common.go
deleted file mode 100644
index 1385463b4c9b1690d2fe54d61739a967613ba665..0000000000000000000000000000000000000000
--- a/rules/logic/common.go
+++ /dev/null
@@ -1,139 +0,0 @@
-package logic
-
-import (
-	"fmt"
-	"github.com/Dreamacro/clash/common/collections"
-	C "github.com/Dreamacro/clash/constant"
-	"regexp"
-	"strings"
-	_ "unsafe"
-)
-
-func ParseRuleByPayload(payload string, parseRule func(tp, payload, target string, params []string, subRules map[string][]C.Rule) (parsed C.Rule, parseErr error)) ([]C.Rule, error) {
-	regex, err := regexp.Compile("\\(.*\\)")
-	if err != nil {
-		return nil, err
-	}
-
-	if regex.MatchString(payload) {
-		subAllRanges, err := format(payload)
-		if err != nil {
-			return nil, err
-		}
-		rules := make([]C.Rule, 0, len(subAllRanges))
-
-		subRanges := findSubRuleRange(payload, subAllRanges)
-		for _, subRange := range subRanges {
-			subPayload := payload[subRange.start+1 : subRange.end]
-
-			rule, err := payloadToRule(subPayload, parseLogicSubRule(parseRule))
-			if err != nil {
-				return nil, err
-			}
-
-			rules = append(rules, rule)
-		}
-
-		return rules, nil
-	}
-
-	return nil, fmt.Errorf("payload format error")
-}
-
-func containRange(r Range, preStart, preEnd int) bool {
-	return preStart < r.start && preEnd > r.end
-}
-
-func payloadToRule(subPayload string, parseRule func(tp, payload, target string, params []string) (parsed C.Rule, parseErr error)) (C.Rule, error) {
-	splitStr := strings.SplitN(subPayload, ",", 2)
-	if len(splitStr) < 2 {
-		return nil, fmt.Errorf("[%s] format is error", subPayload)
-	}
-
-	tp := splitStr[0]
-	payload := splitStr[1]
-	if tp == "NOT" || tp == "OR" || tp == "AND" {
-		return parseRule(tp, payload, "", nil)
-	}
-	param := strings.Split(payload, ",")
-	return parseRule(tp, param[0], "", param[1:])
-}
-
-func parseLogicSubRule(parseRule func(tp, payload, target string, params []string, subRules map[string][]C.Rule) (parsed C.Rule, parseErr error)) func(tp, payload, target string, params []string) (parsed C.Rule, parseErr error) {
-	return func(tp, payload, target string, params []string) (parsed C.Rule, parseErr error) {
-		switch tp {
-		case "MATCH", "SUB-RULE":
-			return nil, fmt.Errorf("unsupported rule type [%s] on logic rule", tp)
-		default:
-			return parseRule(tp, payload, target, params, nil)
-		}
-	}
-}
-
-type Range struct {
-	start int
-	end   int
-	index int
-}
-
-func format(payload string) ([]Range, error) {
-	stack := collections.NewStack()
-	num := 0
-	subRanges := make([]Range, 0)
-	for i, c := range payload {
-		if c == '(' {
-			sr := Range{
-				start: i,
-				index: num,
-			}
-
-			num++
-			stack.Push(sr)
-		} else if c == ')' {
-			if stack.Len() == 0 {
-				return nil, fmt.Errorf("missing '('")
-			}
-
-			sr := stack.Pop().(Range)
-			sr.end = i
-			subRanges = append(subRanges, sr)
-		}
-	}
-
-	if stack.Len() != 0 {
-		return nil, fmt.Errorf("format error is missing )")
-	}
-
-	sortResult := make([]Range, len(subRanges))
-	for _, sr := range subRanges {
-		sortResult[sr.index] = sr
-	}
-
-	return sortResult, nil
-}
-
-func findSubRuleRange(payload string, ruleRanges []Range) []Range {
-	payloadLen := len(payload)
-	subRuleRange := make([]Range, 0)
-	for _, rr := range ruleRanges {
-		if rr.start == 0 && rr.end == payloadLen-1 {
-			// 最大范围跳过
-			continue
-		}
-
-		containInSub := false
-		for _, r := range subRuleRange {
-			if containRange(rr, r.start, r.end) {
-				// The subRuleRange contains a range of rr, which is the next level node of the tree
-				containInSub = true
-				break
-			}
-		}
-
-		if !containInSub {
-			subRuleRange = append(subRuleRange, rr)
-		}
-	}
-
-	return subRuleRange
-}




diff --git a/rules/logic/logic.go b/rules/logic/logic.go
new file mode 100644
index 0000000000000000000000000000000000000000..4a0bd7e8d710860b538ac3747135466600dafd36
--- /dev/null
+++ b/rules/logic/logic.go
@@ -0,0 +1,289 @@
+package logic
+
+import (
+	"fmt"
+	"regexp"
+	"strings"
+
+	"github.com/Dreamacro/clash/common/collections"
+	C "github.com/Dreamacro/clash/constant"
+	"github.com/Dreamacro/clash/rules/common"
+)
+
+type Logic struct {
+	*common.Base
+	payload     string
+	adapter     string
+	ruleType    C.RuleType
+	rules       []C.Rule
+	subRules    map[string][]C.Rule
+	needIP      bool
+	needProcess bool
+}
+
+type ParseRuleFunc func(tp, payload, target string, params []string, subRules map[string][]C.Rule) (C.Rule, error)
+
+func NewSubRule(payload, adapter string, subRules map[string][]C.Rule, parseRule ParseRuleFunc) (*Logic, error) {
+	logic := &Logic{Base: &common.Base{}, payload: payload, adapter: adapter, ruleType: C.SubRules}
+	err := logic.parsePayload(fmt.Sprintf("(%s)", payload), parseRule)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(logic.rules) != 1 {
+		return nil, fmt.Errorf("Sub-Rule rule must contain one rule")
+	}
+	for _, rule := range subRules[adapter] {
+		if rule.ShouldResolveIP() {
+			logic.needIP = true
+		}
+		if rule.ShouldFindProcess() {
+			logic.needProcess = true
+		}
+	}
+	logic.subRules = subRules
+	return logic, nil
+}
+
+func NewNOT(payload string, adapter string, parseRule ParseRuleFunc) (*Logic, error) {
+	logic := &Logic{Base: &common.Base{}, payload: payload, adapter: adapter, ruleType: C.NOT}
+	err := logic.parsePayload(payload, parseRule)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(logic.rules) != 1 {
+		return nil, fmt.Errorf("not rule must contain one rule")
+	}
+	logic.needIP = logic.rules[0].ShouldResolveIP()
+	logic.needProcess = logic.rules[0].ShouldFindProcess()
+	logic.payload = fmt.Sprintf("(!(%s,%s))", logic.rules[0].RuleType(), logic.rules[0].Payload())
+	return logic, nil
+}
+
+func NewOR(payload string, adapter string, parseRule ParseRuleFunc) (*Logic, error) {
+	logic := &Logic{Base: &common.Base{}, payload: payload, adapter: adapter, ruleType: C.OR}
+	err := logic.parsePayload(payload, parseRule)
+	if err != nil {
+		return nil, err
+	}
+
+	payloads := make([]string, 0, len(logic.rules))
+	for _, rule := range logic.rules {
+		payloads = append(payloads, fmt.Sprintf("(%s,%s)", rule.RuleType().String(), rule.Payload()))
+		if rule.ShouldResolveIP() {
+			logic.needIP = true
+		}
+		if rule.ShouldFindProcess() {
+			logic.needProcess = true
+		}
+	}
+	logic.payload = fmt.Sprintf("(%s)", strings.Join(payloads, " || "))
+
+	return logic, nil
+}
+func NewAND(payload string, adapter string, parseRule ParseRuleFunc) (*Logic, error) {
+	logic := &Logic{Base: &common.Base{}, payload: payload, adapter: adapter, ruleType: C.AND}
+	err := logic.parsePayload(payload, parseRule)
+	if err != nil {
+		return nil, err
+	}
+
+	payloads := make([]string, 0, len(logic.rules))
+	for _, rule := range logic.rules {
+		payloads = append(payloads, fmt.Sprintf("(%s,%s)", rule.RuleType().String(), rule.Payload()))
+		if rule.ShouldResolveIP() {
+			logic.needIP = true
+		}
+		if rule.ShouldFindProcess() {
+			logic.needProcess = true
+		}
+	}
+	logic.payload = fmt.Sprintf("(%s)", strings.Join(payloads, " && "))
+
+	return logic, nil
+}
+
+type Range struct {
+	start int
+	end   int
+	index int
+}
+
+func (r Range) containRange(preStart, preEnd int) bool {
+	return preStart < r.start && preEnd > r.end
+}
+
+func (logic *Logic) payloadToRule(subPayload string, parseRule ParseRuleFunc) (C.Rule, error) {
+	splitStr := strings.SplitN(subPayload, ",", 2)
+	if len(splitStr) < 2 {
+		return nil, fmt.Errorf("[%s] format is error", subPayload)
+	}
+
+	tp := splitStr[0]
+	payload := splitStr[1]
+	switch tp {
+	case "MATCH", "SUB-RULE":
+		return nil, fmt.Errorf("unsupported rule type [%s] on logic rule", tp)
+	case "NOT", "OR", "AND":
+		return parseRule(tp, payload, "", nil, nil)
+	}
+	param := strings.Split(payload, ",")
+	return parseRule(tp, param[0], "", param[1:], nil)
+}
+
+func (logic *Logic) format(payload string) ([]Range, error) {
+	stack := collections.NewStack()
+	num := 0
+	subRanges := make([]Range, 0)
+	for i, c := range payload {
+		if c == '(' {
+			sr := Range{
+				start: i,
+				index: num,
+			}
+
+			num++
+			stack.Push(sr)
+		} else if c == ')' {
+			if stack.Len() == 0 {
+				return nil, fmt.Errorf("missing '('")
+			}
+
+			sr := stack.Pop().(Range)
+			sr.end = i
+			subRanges = append(subRanges, sr)
+		}
+	}
+
+	if stack.Len() != 0 {
+		return nil, fmt.Errorf("format error is missing )")
+	}
+
+	sortResult := make([]Range, len(subRanges))
+	for _, sr := range subRanges {
+		sortResult[sr.index] = sr
+	}
+
+	return sortResult, nil
+}
+
+func (logic *Logic) findSubRuleRange(payload string, ruleRanges []Range) []Range {
+	payloadLen := len(payload)
+	subRuleRange := make([]Range, 0)
+	for _, rr := range ruleRanges {
+		if rr.start == 0 && rr.end == payloadLen-1 {
+			// 最大范围跳过
+			continue
+		}
+
+		containInSub := false
+		for _, r := range subRuleRange {
+			if rr.containRange(r.start, r.end) {
+				// The subRuleRange contains a range of rr, which is the next level node of the tree
+				containInSub = true
+				break
+			}
+		}
+
+		if !containInSub {
+			subRuleRange = append(subRuleRange, rr)
+		}
+	}
+
+	return subRuleRange
+}
+
+func (logic *Logic) parsePayload(payload string, parseRule ParseRuleFunc) error {
+	regex, err := regexp.Compile("\\(.*\\)")
+	if err != nil {
+		return err
+	}
+
+	if regex.MatchString(payload) {
+		subAllRanges, err := logic.format(payload)
+		if err != nil {
+			return err
+		}
+		rules := make([]C.Rule, 0, len(subAllRanges))
+
+		subRanges := logic.findSubRuleRange(payload, subAllRanges)
+		for _, subRange := range subRanges {
+			subPayload := payload[subRange.start+1 : subRange.end]
+
+			rule, err := logic.payloadToRule(subPayload, parseRule)
+			if err != nil {
+				return err
+			}
+
+			rules = append(rules, rule)
+		}
+
+		logic.rules = rules
+
+		return nil
+	}
+
+	return fmt.Errorf("payload format error")
+}
+
+func (logic *Logic) RuleType() C.RuleType {
+	return logic.ruleType
+}
+
+func matchSubRules(metadata *C.Metadata, name string, subRules map[string][]C.Rule) (bool, string) {
+	for _, rule := range subRules[name] {
+		if m, a := rule.Match(metadata); m {
+			if rule.RuleType() == C.SubRules {
+				matchSubRules(metadata, rule.Adapter(), subRules)
+			} else {
+				return m, a
+			}
+		}
+	}
+	return false, ""
+}
+
+func (logic *Logic) Match(metadata *C.Metadata) (bool, string) {
+	switch logic.ruleType {
+	case C.SubRules:
+		return matchSubRules(metadata, logic.adapter, logic.subRules)
+	case C.NOT:
+		if m, _ := logic.rules[0].Match(metadata); !m {
+			return true, logic.adapter
+		}
+		return false, ""
+	case C.OR:
+		for _, rule := range logic.rules {
+			if m, _ := rule.Match(metadata); m {
+				return true, logic.adapter
+			}
+		}
+		return false, ""
+	case C.AND:
+		for _, rule := range logic.rules {
+			if m, _ := rule.Match(metadata); !m {
+				return false, logic.adapter
+			}
+		}
+		return true, logic.adapter
+	}
+
+	return false, ""
+}
+
+func (logic *Logic) Adapter() string {
+	return logic.adapter
+}
+
+func (logic *Logic) Payload() string {
+	return logic.payload
+}
+
+func (logic *Logic) ShouldResolveIP() bool {
+	return logic.needIP
+}
+
+func (logic *Logic) ShouldFindProcess() bool {
+	return logic.needProcess
+}




diff --git a/rules/logic/not.go b/rules/logic/not.go
deleted file mode 100644
index c109a2c90597bd6d520179a6480c29f3f79f69de..0000000000000000000000000000000000000000
--- a/rules/logic/not.go
+++ /dev/null
@@ -1,63 +0,0 @@
-package logic
-
-import (
-	"fmt"
-	C "github.com/Dreamacro/clash/constant"
-	"github.com/Dreamacro/clash/rules/common"
-)
-
-type NOT struct {
-	*common.Base
-	rule    C.Rule
-	payload string
-	adapter string
-}
-
-func (not *NOT) ShouldFindProcess() bool {
-	return false
-}
-
-func NewNOT(payload string, adapter string, parse func(tp, payload, target string, params []string, subRules map[string][]C.Rule) (parsed C.Rule, parseErr error)) (*NOT, error) {
-	not := &NOT{Base: &common.Base{}, adapter: adapter}
-	rule, err := ParseRuleByPayload(payload, parse)
-	if err != nil {
-		return nil, err
-	}
-
-	if len(rule) != 1 {
-		return nil, fmt.Errorf("not rule must contain one rule")
-	}
-
-	not.rule = rule[0]
-	not.payload = fmt.Sprintf("(!(%s,%s))", rule[0].RuleType(), rule[0].Payload())
-
-	return not, nil
-}
-
-func (not *NOT) RuleType() C.RuleType {
-	return C.NOT
-}
-
-func (not *NOT) Match(metadata *C.Metadata) (bool, string) {
-	if not.rule == nil {
-		return true, not.adapter
-	}
-
-	if m, _ := not.rule.Match(metadata); !m {
-		return true, not.adapter
-	}
-
-	return false, ""
-}
-
-func (not *NOT) Adapter() string {
-	return not.adapter
-}
-
-func (not *NOT) Payload() string {
-	return not.payload
-}
-
-func (not *NOT) ShouldResolveIP() bool {
-	return not.rule != nil && not.rule.ShouldResolveIP()
-}




diff --git a/rules/logic/or.go b/rules/logic/or.go
deleted file mode 100644
index f63bae4bbc0087ef5b675cfc200edc71436447eb..0000000000000000000000000000000000000000
--- a/rules/logic/or.go
+++ /dev/null
@@ -1,67 +0,0 @@
-package logic
-
-import (
-	"fmt"
-	C "github.com/Dreamacro/clash/constant"
-	"github.com/Dreamacro/clash/rules/common"
-	"strings"
-)
-
-type OR struct {
-	*common.Base
-	rules   []C.Rule
-	payload string
-	adapter string
-	needIP  bool
-}
-
-func (or *OR) ShouldFindProcess() bool {
-	return false
-}
-
-func (or *OR) RuleType() C.RuleType {
-	return C.OR
-}
-
-func (or *OR) Match(metadata *C.Metadata) (bool, string) {
-	for _, rule := range or.rules {
-		if m, _ := rule.Match(metadata); m {
-			return true, or.adapter
-		}
-	}
-
-	return false, ""
-}
-
-func (or *OR) Adapter() string {
-	return or.adapter
-}
-
-func (or *OR) Payload() string {
-	return or.payload
-}
-
-func (or *OR) ShouldResolveIP() bool {
-	return or.needIP
-}
-
-func NewOR(payload string, adapter string, parse func(tp, payload, target string, params []string, subRules map[string][]C.Rule) (parsed C.Rule, parseErr error)) (*OR, error) {
-	or := &OR{Base: &common.Base{}, payload: payload, adapter: adapter}
-	rules, err := ParseRuleByPayload(payload, parse)
-	if err != nil {
-		return nil, err
-	}
-
-	or.rules = rules
-	payloads := make([]string, 0, len(rules))
-	for _, rule := range rules {
-		payloads = append(payloads, fmt.Sprintf("(%s,%s)", rule.RuleType(), rule.Payload()))
-		if rule.ShouldResolveIP() {
-			or.needIP = true
-			break
-		}
-	}
-
-	or.payload = fmt.Sprintf("(%s)", strings.Join(payloads, " || "))
-	return or, nil
-}




diff --git a/rules/logic/sub_rules.go b/rules/logic/sub_rules.go
deleted file mode 100644
index 7585297973e34e59dd4aa295c817c6e41d2b9f25..0000000000000000000000000000000000000000
--- a/rules/logic/sub_rules.go
+++ /dev/null
@@ -1,91 +0,0 @@
-package logic
-
-import (
-	"fmt"
-
-	C "github.com/Dreamacro/clash/constant"
-	"github.com/Dreamacro/clash/rules/common"
-)
-
-type SubRule struct {
-	*common.Base
-	payload           string
-	payloadRule       C.Rule
-	subName           string
-	subRules          map[string][]C.Rule
-	shouldFindProcess *bool
-	shouldResolveIP   *bool
-}
-
-func NewSubRule(payload, subName string, sub map[string][]C.Rule,
-	parse func(tp, payload, target string, params []string, subRules map[string][]C.Rule) (parsed C.Rule, parseErr error)) (*SubRule, error) {
-	payloadRule, err := ParseRuleByPayload(fmt.Sprintf("(%s)", payload), parse)
-	if err != nil {
-		return nil, err
-	}
-	if len(payloadRule) != 1 {
-		return nil, fmt.Errorf("Sub-Rule rule must contain one rule")
-	}
-
-	return &SubRule{
-		Base:        &common.Base{},
-		payload:     payload,
-		payloadRule: payloadRule[0],
-		subName:     subName,
-		subRules:    sub,
-	}, nil
-}
-
-func (r *SubRule) RuleType() C.RuleType {
-	return C.SubRules
-}
-
-func (r *SubRule) Match(metadata *C.Metadata) (bool, string) {
-
-	return match(metadata, r.subName, r.subRules)
-}
-
-func match(metadata *C.Metadata, name string, subRules map[string][]C.Rule) (bool, string) {
-	for _, rule := range subRules[name] {
-		if m, a := rule.Match(metadata); m {
-			if rule.RuleType() == C.SubRules {
-				match(metadata, rule.Adapter(), subRules)
-			} else {
-				return m, a
-			}
-		}
-	}
-	return false, ""
-}
-
-func (r *SubRule) ShouldResolveIP() bool {
-	if r.shouldResolveIP == nil {
-		s := false
-		for _, rule := range r.subRules[r.subName] {
-			s = s || rule.ShouldResolveIP()
-		}
-		r.shouldResolveIP = &s
-	}
-
-	return *r.shouldResolveIP
-}
-
-func (r *SubRule) ShouldFindProcess() bool {
-	if r.shouldFindProcess == nil {
-		s := false
-		for _, rule := range r.subRules[r.subName] {
-			s = s || rule.ShouldFindProcess()
-		}
-		r.shouldFindProcess = &s
-	}
-
-	return *r.shouldFindProcess
-}
-
-func (r *SubRule) Adapter() string {
-	return r.subName
-}
-
-func (r *SubRule) Payload() string {
-	return r.payload
-}