mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2024-12-22 15:47:59 +08:00
feat: support inline rule provider (#1731)
This commit is contained in:
parent
3f6823ba49
commit
bb803249fa
@ -13,6 +13,7 @@ const (
|
||||
File VehicleType = iota
|
||||
HTTP
|
||||
Compatible
|
||||
Inline
|
||||
)
|
||||
|
||||
// VehicleType defined
|
||||
@ -26,6 +27,8 @@ func (v VehicleType) String() string {
|
||||
return "HTTP"
|
||||
case Compatible:
|
||||
return "Compatible"
|
||||
case Inline:
|
||||
return "Inline"
|
||||
default:
|
||||
return "Unknown"
|
||||
}
|
||||
|
@ -1014,6 +1014,14 @@ rule-providers:
|
||||
format: mrs
|
||||
behavior: domain
|
||||
path: /path/to/save/file.mrs
|
||||
rule4:
|
||||
type: inline
|
||||
behavior: domain # classical / ipcidr
|
||||
payload:
|
||||
- '.blogger.com'
|
||||
- '*.*.microsoft.com'
|
||||
- 'books.itunes.apple.com'
|
||||
|
||||
rules:
|
||||
- RULE-SET,rule1,REJECT
|
||||
- IP-ASN,1,PROXY
|
||||
|
@ -16,17 +16,20 @@ var (
|
||||
)
|
||||
|
||||
type ruleProviderSchema struct {
|
||||
Type string `provider:"type"`
|
||||
Behavior string `provider:"behavior"`
|
||||
Path string `provider:"path,omitempty"`
|
||||
URL string `provider:"url,omitempty"`
|
||||
Proxy string `provider:"proxy,omitempty"`
|
||||
Format string `provider:"format,omitempty"`
|
||||
Interval int `provider:"interval,omitempty"`
|
||||
SizeLimit int64 `provider:"size-limit,omitempty"`
|
||||
Type string `provider:"type"`
|
||||
Behavior string `provider:"behavior"`
|
||||
Path string `provider:"path,omitempty"`
|
||||
URL string `provider:"url,omitempty"`
|
||||
Proxy string `provider:"proxy,omitempty"`
|
||||
Format string `provider:"format,omitempty"`
|
||||
Interval int `provider:"interval,omitempty"`
|
||||
SizeLimit int64 `provider:"size-limit,omitempty"`
|
||||
Payload []string `provider:"payload,omitempty"`
|
||||
}
|
||||
|
||||
func ParseRuleProvider(name string, mapping map[string]interface{}, parse func(tp, payload, target string, params []string, subRules map[string][]C.Rule) (parsed C.Rule, parseErr error)) (P.RuleProvider, error) {
|
||||
type parseRuleFunc func(tp, payload, target string, params []string, subRules map[string][]C.Rule) (parsed C.Rule, parseErr error)
|
||||
|
||||
func ParseRuleProvider(name string, mapping map[string]any, parse parseRuleFunc) (P.RuleProvider, error) {
|
||||
schema := &ruleProviderSchema{}
|
||||
decoder := structure.NewDecoder(structure.Option{TagName: "provider", WeaklyTypedInput: true})
|
||||
if err := decoder.Decode(mapping, schema); err != nil {
|
||||
@ -55,6 +58,8 @@ func ParseRuleProvider(name string, mapping map[string]interface{}, parse func(t
|
||||
}
|
||||
}
|
||||
vehicle = resource.NewHTTPVehicle(schema.URL, path, schema.Proxy, nil, resource.DefaultHttpTimeout, schema.SizeLimit)
|
||||
case "inline":
|
||||
return newInlineProvider(name, behavior, schema.Payload, parse), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported vehicle type: %s", schema.Type)
|
||||
}
|
||||
|
@ -24,9 +24,13 @@ func SetTunnel(t P.Tunnel) {
|
||||
}
|
||||
|
||||
type ruleSetProvider struct {
|
||||
ruleSetProviderBase
|
||||
*resource.Fetcher[ruleStrategy]
|
||||
format P.RuleFormat
|
||||
}
|
||||
|
||||
type ruleSetProviderBase struct {
|
||||
behavior P.RuleBehavior
|
||||
format P.RuleFormat
|
||||
strategy ruleStrategy
|
||||
}
|
||||
|
||||
@ -61,7 +65,7 @@ type mrsRuleStrategy interface {
|
||||
DumpMrs(f func(key string) bool)
|
||||
}
|
||||
|
||||
func (rp *ruleSetProvider) Type() P.ProviderType {
|
||||
func (rp *ruleSetProviderBase) Type() P.ProviderType {
|
||||
return P.Rule
|
||||
}
|
||||
|
||||
@ -75,40 +79,51 @@ func (rp *ruleSetProvider) Update() error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (rp *ruleSetProvider) Behavior() P.RuleBehavior {
|
||||
func (rp *ruleSetProviderBase) Behavior() P.RuleBehavior {
|
||||
return rp.behavior
|
||||
}
|
||||
|
||||
func (rp *ruleSetProvider) Count() int {
|
||||
func (rp *ruleSetProviderBase) Count() int {
|
||||
return rp.strategy.Count()
|
||||
}
|
||||
|
||||
func (rp *ruleSetProvider) Match(metadata *C.Metadata) bool {
|
||||
func (rp *ruleSetProviderBase) Match(metadata *C.Metadata) bool {
|
||||
return rp.strategy != nil && rp.strategy.Match(metadata)
|
||||
}
|
||||
|
||||
func (rp *ruleSetProvider) ShouldResolveIP() bool {
|
||||
func (rp *ruleSetProviderBase) ShouldResolveIP() bool {
|
||||
return rp.strategy.ShouldResolveIP()
|
||||
}
|
||||
|
||||
func (rp *ruleSetProvider) ShouldFindProcess() bool {
|
||||
func (rp *ruleSetProviderBase) ShouldFindProcess() bool {
|
||||
return rp.strategy.ShouldFindProcess()
|
||||
}
|
||||
|
||||
func (rp *ruleSetProvider) Strategy() any {
|
||||
func (rp *ruleSetProviderBase) Strategy() any {
|
||||
return rp.strategy
|
||||
}
|
||||
|
||||
type providerForApi struct {
|
||||
Behavior string `json:"behavior"`
|
||||
Format string `json:"format"`
|
||||
Name string `json:"name"`
|
||||
RuleCount int `json:"ruleCount"`
|
||||
Type string `json:"type"`
|
||||
VehicleType string `json:"vehicleType"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
Payload []string `json:"payload,omitempty"`
|
||||
}
|
||||
|
||||
func (rp *ruleSetProvider) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(
|
||||
map[string]interface{}{
|
||||
"behavior": rp.behavior.String(),
|
||||
"format": rp.format.String(),
|
||||
"name": rp.Name(),
|
||||
"ruleCount": rp.strategy.Count(),
|
||||
"type": rp.Type().String(),
|
||||
"updatedAt": rp.UpdatedAt(),
|
||||
"vehicleType": rp.VehicleType().String(),
|
||||
providerForApi{
|
||||
Behavior: rp.behavior.String(),
|
||||
Format: rp.format.String(),
|
||||
Name: rp.Fetcher.Name(),
|
||||
RuleCount: rp.strategy.Count(),
|
||||
Type: rp.Type().String(),
|
||||
UpdatedAt: rp.UpdatedAt(),
|
||||
VehicleType: rp.VehicleType().String(),
|
||||
})
|
||||
}
|
||||
|
||||
@ -118,10 +133,13 @@ func (rp *RuleSetProvider) Close() error {
|
||||
}
|
||||
|
||||
func NewRuleSetProvider(name string, behavior P.RuleBehavior, format P.RuleFormat, interval time.Duration, vehicle P.Vehicle,
|
||||
parse func(tp, payload, target string, params []string, subRules map[string][]C.Rule) (parsed C.Rule, parseErr error)) P.RuleProvider {
|
||||
parse parseRuleFunc,
|
||||
) P.RuleProvider {
|
||||
rp := &ruleSetProvider{
|
||||
behavior: behavior,
|
||||
format: format,
|
||||
ruleSetProviderBase: ruleSetProviderBase{
|
||||
behavior: behavior,
|
||||
},
|
||||
format: format,
|
||||
}
|
||||
|
||||
onUpdate := func(strategy ruleStrategy) {
|
||||
@ -142,7 +160,7 @@ func NewRuleSetProvider(name string, behavior P.RuleBehavior, format P.RuleForma
|
||||
return wrapper
|
||||
}
|
||||
|
||||
func newStrategy(behavior P.RuleBehavior, parse func(tp, payload, target string, params []string, subRules map[string][]C.Rule) (parsed C.Rule, parseErr error)) ruleStrategy {
|
||||
func newStrategy(behavior P.RuleBehavior, parse parseRuleFunc) ruleStrategy {
|
||||
switch behavior {
|
||||
case P.Domain:
|
||||
strategy := NewDomainStrategy()
|
||||
@ -158,8 +176,10 @@ func newStrategy(behavior P.RuleBehavior, parse func(tp, payload, target string,
|
||||
}
|
||||
}
|
||||
|
||||
var ErrNoPayload = errors.New("file must have a `payload` field")
|
||||
var ErrInvalidFormat = errors.New("invalid format")
|
||||
var (
|
||||
ErrNoPayload = errors.New("file must have a `payload` field")
|
||||
ErrInvalidFormat = errors.New("invalid format")
|
||||
)
|
||||
|
||||
func rulesParse(buf []byte, strategy ruleStrategy, format P.RuleFormat) (ruleStrategy, error) {
|
||||
strategy.Reset()
|
||||
@ -254,3 +274,71 @@ func rulesParse(buf []byte, strategy ruleStrategy, format P.RuleFormat) (ruleStr
|
||||
|
||||
return strategy, nil
|
||||
}
|
||||
|
||||
func rulesParseInline(rs []string, strategy ruleStrategy) ruleStrategy {
|
||||
strategy.Reset()
|
||||
for _, r := range rs {
|
||||
if r != "" {
|
||||
strategy.Insert(r)
|
||||
}
|
||||
}
|
||||
strategy.FinishInsert()
|
||||
return strategy
|
||||
}
|
||||
|
||||
type inlineProvider struct {
|
||||
ruleSetProviderBase
|
||||
name string
|
||||
updateTime time.Time
|
||||
payload []string
|
||||
}
|
||||
|
||||
func (i *inlineProvider) Name() string {
|
||||
return i.name
|
||||
}
|
||||
|
||||
func (i *inlineProvider) Initial() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *inlineProvider) Update() error {
|
||||
// make api update happy
|
||||
i.updateTime = time.Now()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *inlineProvider) VehicleType() P.VehicleType {
|
||||
return P.Inline
|
||||
}
|
||||
|
||||
func (i *inlineProvider) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(
|
||||
providerForApi{
|
||||
Behavior: i.behavior.String(),
|
||||
Name: i.Name(),
|
||||
RuleCount: i.strategy.Count(),
|
||||
Type: i.Type().String(),
|
||||
VehicleType: i.VehicleType().String(),
|
||||
UpdatedAt: i.updateTime,
|
||||
Payload: i.payload,
|
||||
})
|
||||
}
|
||||
|
||||
func newInlineProvider(
|
||||
name string,
|
||||
behavior P.RuleBehavior,
|
||||
payload []string,
|
||||
parse parseRuleFunc,
|
||||
) P.RuleProvider {
|
||||
rp := &inlineProvider{
|
||||
ruleSetProviderBase: ruleSetProviderBase{
|
||||
behavior: behavior,
|
||||
strategy: newStrategy(behavior, parse),
|
||||
},
|
||||
payload: payload,
|
||||
name: name,
|
||||
updateTime: time.Now(),
|
||||
}
|
||||
rp.strategy = rulesParseInline(payload, rp.strategy)
|
||||
return rp
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user