Skip to content

Commit 300eb8b

Browse files
committed
chore: rebuild rule parsing code
1 parent 2b84dd3 commit 300eb8b

File tree

6 files changed

+65
-70
lines changed

6 files changed

+65
-70
lines changed

config/config.go

Lines changed: 6 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,46 +1035,20 @@ func parseRules(rulesConfig []string, proxies map[string]C.Proxy, ruleProviders
10351035

10361036
// parse rules
10371037
for idx, line := range rulesConfig {
1038-
rule := trimArr(strings.Split(line, ","))
1039-
var (
1040-
payload string
1041-
target string
1042-
params []string
1043-
ruleName = strings.ToUpper(rule[0])
1044-
)
1045-
1046-
l := len(rule)
1047-
1048-
if ruleName == "NOT" || ruleName == "OR" || ruleName == "AND" || ruleName == "SUB-RULE" || ruleName == "DOMAIN-REGEX" || ruleName == "PROCESS-NAME-REGEX" || ruleName == "PROCESS-PATH-REGEX" {
1049-
target = rule[l-1]
1050-
payload = strings.Join(rule[1:l-1], ",")
1051-
} else {
1052-
if l < 2 {
1053-
return nil, fmt.Errorf("%s[%d] [%s] error: format invalid", format, idx, line)
1054-
}
1055-
if l < 4 {
1056-
rule = append(rule, make([]string, 4-l)...)
1057-
}
1058-
if ruleName == "MATCH" {
1059-
l = 2
1060-
}
1061-
if l >= 3 {
1062-
l = 3
1063-
payload = rule[1]
1064-
}
1065-
target = rule[l-1]
1066-
params = rule[l:]
1038+
tp, payload, target, params := RC.ParseRulePayload(line, true)
1039+
if target == "" {
1040+
return nil, fmt.Errorf("%s[%d] [%s] error: format invalid", format, idx, line)
10671041
}
1042+
10681043
if _, ok := proxies[target]; !ok {
1069-
if ruleName != "SUB-RULE" {
1044+
if tp != "SUB-RULE" {
10701045
return nil, fmt.Errorf("%s[%d] [%s] error: proxy [%s] not found", format, idx, line, target)
10711046
} else if _, ok = subRules[target]; !ok {
10721047
return nil, fmt.Errorf("%s[%d] [%s] error: sub-rule [%s] not found", format, idx, line, target)
10731048
}
10741049
}
10751050

1076-
params = trimArr(params)
1077-
parsed, parseErr := R.ParseRule(ruleName, payload, target, params, subRules)
1051+
parsed, parseErr := R.ParseRule(tp, payload, target, params, subRules)
10781052
if parseErr != nil {
10791053
return nil, fmt.Errorf("%s[%d] [%s] error: %s", format, idx, line, parseErr.Error())
10801054
}

config/utils.go

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,11 @@ import (
66
"net/netip"
77
"os"
88
"strconv"
9-
"strings"
109

1110
"github.com/metacubex/mihomo/adapter/outboundgroup"
1211
"github.com/metacubex/mihomo/common/structure"
1312
)
1413

15-
func trimArr(arr []string) (r []string) {
16-
for _, e := range arr {
17-
r = append(r, strings.Trim(e, " "))
18-
}
19-
return
20-
}
21-
2214
// Check if ProxyGroups form DAG(Directed Acyclic Graph), and sort all ProxyGroups by dependency order.
2315
// Meanwhile, record the original index in the config file.
2416
// If loop is detected, return an error with location of loop.

rules/common/base.go

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,22 +34,48 @@ func ParseParams(params []string) (isSrc bool, noResolve bool) {
3434
return
3535
}
3636

37-
func ParseRulePayload(ruleRaw string) (string, string, []string) {
38-
item := strings.Split(ruleRaw, ",")
39-
if len(item) == 1 {
40-
return "", item[0], nil
41-
} else if len(item) == 2 {
42-
return item[0], item[1], nil
43-
} else if len(item) > 2 {
44-
// keep in sync with config/config.go [parseRules]
45-
if item[0] == "NOT" || item[0] == "OR" || item[0] == "AND" || item[0] == "SUB-RULE" || item[0] == "DOMAIN-REGEX" || item[0] == "PROCESS-NAME-REGEX" || item[0] == "PROCESS-PATH-REGEX" {
46-
return item[0], strings.Join(item[1:], ","), nil
47-
} else {
48-
return item[0], item[1], item[2:]
37+
func trimArr(arr []string) (r []string) {
38+
for _, e := range arr {
39+
r = append(r, strings.Trim(e, " "))
40+
}
41+
return
42+
}
43+
44+
// ParseRulePayload parse rule format like:
45+
// `tp,payload,target(,params...)` or `tp,payload(,params...)`
46+
// needTarget control the format contains `target` in string
47+
func ParseRulePayload(ruleRaw string, needTarget bool) (tp, payload, target string, params []string) {
48+
item := trimArr(strings.Split(ruleRaw, ","))
49+
tp = strings.ToUpper(item[0])
50+
if len(item) > 1 {
51+
switch tp {
52+
case "MATCH":
53+
// MATCH doesn't contain payload and params
54+
target = item[1]
55+
case "NOT", "OR", "AND", "SUB-RULE", "DOMAIN-REGEX", "PROCESS-NAME-REGEX", "PROCESS-PATH-REGEX":
56+
// some type of rules that has comma in payload and don't need params
57+
if needTarget {
58+
l := len(item)
59+
target = item[l-1] // don't have params so target must at the end of slices
60+
item = item[:l-1] // remove the target from slices
61+
}
62+
payload = strings.Join(item[1:], ",")
63+
default:
64+
payload = item[1]
65+
if len(item) > 2 {
66+
if needTarget {
67+
target = item[2]
68+
if len(item) > 3 {
69+
params = item[3:]
70+
}
71+
} else {
72+
params = item[2:]
73+
}
74+
}
4975
}
5076
}
5177

52-
return "", "", nil
78+
return
5379
}
5480

5581
type ParseRuleFunc func(tp, payload, target string, params []string, subRules map[string][]C.Rule) (C.Rule, error)

rules/logic/logic.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,14 +78,14 @@ func (r Range) containRange(preStart, preEnd int) bool {
7878
}
7979

8080
func (logic *Logic) payloadToRule(subPayload string, parseRule common.ParseRuleFunc) (C.Rule, error) {
81-
tp, payload, param := common.ParseRulePayload(subPayload)
81+
tp, payload, target, param := common.ParseRulePayload(subPayload, false)
8282
switch tp {
8383
case "MATCH", "SUB-RULE":
8484
return nil, fmt.Errorf("unsupported rule type [%s] on logic rule", tp)
8585
case "":
8686
return nil, fmt.Errorf("[%s] format is error", subPayload)
8787
}
88-
return parseRule(tp, payload, "", param, nil)
88+
return parseRule(tp, payload, target, param, nil)
8989
}
9090

9191
func (logic *Logic) format(payload string) ([]Range, error) {

rules/parser.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ import (
1010
)
1111

1212
func ParseRule(tp, payload, target string, params []string, subRules map[string][]C.Rule) (parsed C.Rule, parseErr error) {
13+
if tp != "MATCH" && payload == "" { // only MATCH allowed doesn't contain payload
14+
return nil, fmt.Errorf("missing subsequent parameters: %s", tp)
15+
}
16+
1317
switch tp {
1418
case "DOMAIN":
1519
parsed = RC.NewDomain(payload, target)
@@ -83,8 +87,6 @@ func ParseRule(tp, payload, target string, params []string, subRules map[string]
8387
case "MATCH":
8488
parsed = RC.NewMatch(target)
8589
parseErr = nil
86-
case "":
87-
parseErr = fmt.Errorf("missing subsequent parameters: %s", payload)
8890
default:
8991
parseErr = fmt.Errorf("unsupported rule type: %s", tp)
9092
}

rules/provider/classical_strategy.go

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212
type classicalStrategy struct {
1313
rules []C.Rule
1414
count int
15-
parse func(tp, payload, target string, params []string) (parsed C.Rule, parseErr error)
15+
parse common.ParseRuleFunc
1616
}
1717

1818
func (c *classicalStrategy) Behavior() P.RuleBehavior {
@@ -39,25 +39,26 @@ func (c *classicalStrategy) Reset() {
3939
}
4040

4141
func (c *classicalStrategy) Insert(rule string) {
42-
ruleType, rule, params := common.ParseRulePayload(rule)
43-
r, err := c.parse(ruleType, rule, "", params)
42+
r, err := c.payloadToRule(rule)
4443
if err != nil {
45-
log.Warnln("parse classical rule error: %s", err.Error())
44+
log.Warnln("parse classical rule [%s] error: %s", rule, err.Error())
4645
} else {
4746
c.rules = append(c.rules, r)
4847
c.count++
4948
}
5049
}
5150

51+
func (c *classicalStrategy) payloadToRule(rule string) (C.Rule, error) {
52+
tp, payload, target, params := common.ParseRulePayload(rule, false)
53+
switch tp {
54+
case "MATCH", "RULE-SET", "SUB-RULE":
55+
return nil, fmt.Errorf("unsupported rule type on classical rule-set: %s", tp)
56+
}
57+
return c.parse(tp, payload, target, params, nil)
58+
}
59+
5260
func (c *classicalStrategy) FinishInsert() {}
5361

54-
func NewClassicalStrategy(parse func(tp, payload, target string, params []string, subRules map[string][]C.Rule) (parsed C.Rule, parseErr error)) *classicalStrategy {
55-
return &classicalStrategy{rules: []C.Rule{}, parse: func(tp, payload, target string, params []string) (parsed C.Rule, parseErr error) {
56-
switch tp {
57-
case "MATCH", "RULE-SET", "SUB-RULE":
58-
return nil, fmt.Errorf("unsupported rule type on classical rule-set: %s", tp)
59-
default:
60-
return parse(tp, payload, target, params, nil)
61-
}
62-
}}
62+
func NewClassicalStrategy(parse common.ParseRuleFunc) *classicalStrategy {
63+
return &classicalStrategy{rules: []C.Rule{}, parse: parse}
6364
}

0 commit comments

Comments
 (0)