mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2025-01-03 16:13:30 +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
|
File VehicleType = iota
|
||||||
HTTP
|
HTTP
|
||||||
Compatible
|
Compatible
|
||||||
|
Inline
|
||||||
)
|
)
|
||||||
|
|
||||||
// VehicleType defined
|
// VehicleType defined
|
||||||
@ -26,6 +27,8 @@ func (v VehicleType) String() string {
|
|||||||
return "HTTP"
|
return "HTTP"
|
||||||
case Compatible:
|
case Compatible:
|
||||||
return "Compatible"
|
return "Compatible"
|
||||||
|
case Inline:
|
||||||
|
return "Inline"
|
||||||
default:
|
default:
|
||||||
return "Unknown"
|
return "Unknown"
|
||||||
}
|
}
|
||||||
|
@ -1014,6 +1014,14 @@ rule-providers:
|
|||||||
format: mrs
|
format: mrs
|
||||||
behavior: domain
|
behavior: domain
|
||||||
path: /path/to/save/file.mrs
|
path: /path/to/save/file.mrs
|
||||||
|
rule4:
|
||||||
|
type: inline
|
||||||
|
behavior: domain # classical / ipcidr
|
||||||
|
payload:
|
||||||
|
- '.blogger.com'
|
||||||
|
- '*.*.microsoft.com'
|
||||||
|
- 'books.itunes.apple.com'
|
||||||
|
|
||||||
rules:
|
rules:
|
||||||
- RULE-SET,rule1,REJECT
|
- RULE-SET,rule1,REJECT
|
||||||
- IP-ASN,1,PROXY
|
- IP-ASN,1,PROXY
|
||||||
|
@ -24,9 +24,12 @@ type ruleProviderSchema struct {
|
|||||||
Format string `provider:"format,omitempty"`
|
Format string `provider:"format,omitempty"`
|
||||||
Interval int `provider:"interval,omitempty"`
|
Interval int `provider:"interval,omitempty"`
|
||||||
SizeLimit int64 `provider:"size-limit,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{}
|
schema := &ruleProviderSchema{}
|
||||||
decoder := structure.NewDecoder(structure.Option{TagName: "provider", WeaklyTypedInput: true})
|
decoder := structure.NewDecoder(structure.Option{TagName: "provider", WeaklyTypedInput: true})
|
||||||
if err := decoder.Decode(mapping, schema); err != nil {
|
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)
|
vehicle = resource.NewHTTPVehicle(schema.URL, path, schema.Proxy, nil, resource.DefaultHttpTimeout, schema.SizeLimit)
|
||||||
|
case "inline":
|
||||||
|
return newInlineProvider(name, behavior, schema.Payload, parse), nil
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unsupported vehicle type: %s", schema.Type)
|
return nil, fmt.Errorf("unsupported vehicle type: %s", schema.Type)
|
||||||
}
|
}
|
||||||
|
@ -24,9 +24,13 @@ func SetTunnel(t P.Tunnel) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ruleSetProvider struct {
|
type ruleSetProvider struct {
|
||||||
|
ruleSetProviderBase
|
||||||
*resource.Fetcher[ruleStrategy]
|
*resource.Fetcher[ruleStrategy]
|
||||||
behavior P.RuleBehavior
|
|
||||||
format P.RuleFormat
|
format P.RuleFormat
|
||||||
|
}
|
||||||
|
|
||||||
|
type ruleSetProviderBase struct {
|
||||||
|
behavior P.RuleBehavior
|
||||||
strategy ruleStrategy
|
strategy ruleStrategy
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +65,7 @@ type mrsRuleStrategy interface {
|
|||||||
DumpMrs(f func(key string) bool)
|
DumpMrs(f func(key string) bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rp *ruleSetProvider) Type() P.ProviderType {
|
func (rp *ruleSetProviderBase) Type() P.ProviderType {
|
||||||
return P.Rule
|
return P.Rule
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,40 +79,51 @@ func (rp *ruleSetProvider) Update() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rp *ruleSetProvider) Behavior() P.RuleBehavior {
|
func (rp *ruleSetProviderBase) Behavior() P.RuleBehavior {
|
||||||
return rp.behavior
|
return rp.behavior
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rp *ruleSetProvider) Count() int {
|
func (rp *ruleSetProviderBase) Count() int {
|
||||||
return rp.strategy.Count()
|
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)
|
return rp.strategy != nil && rp.strategy.Match(metadata)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rp *ruleSetProvider) ShouldResolveIP() bool {
|
func (rp *ruleSetProviderBase) ShouldResolveIP() bool {
|
||||||
return rp.strategy.ShouldResolveIP()
|
return rp.strategy.ShouldResolveIP()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rp *ruleSetProvider) ShouldFindProcess() bool {
|
func (rp *ruleSetProviderBase) ShouldFindProcess() bool {
|
||||||
return rp.strategy.ShouldFindProcess()
|
return rp.strategy.ShouldFindProcess()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rp *ruleSetProvider) Strategy() any {
|
func (rp *ruleSetProviderBase) Strategy() any {
|
||||||
return rp.strategy
|
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) {
|
func (rp *ruleSetProvider) MarshalJSON() ([]byte, error) {
|
||||||
return json.Marshal(
|
return json.Marshal(
|
||||||
map[string]interface{}{
|
providerForApi{
|
||||||
"behavior": rp.behavior.String(),
|
Behavior: rp.behavior.String(),
|
||||||
"format": rp.format.String(),
|
Format: rp.format.String(),
|
||||||
"name": rp.Name(),
|
Name: rp.Fetcher.Name(),
|
||||||
"ruleCount": rp.strategy.Count(),
|
RuleCount: rp.strategy.Count(),
|
||||||
"type": rp.Type().String(),
|
Type: rp.Type().String(),
|
||||||
"updatedAt": rp.UpdatedAt(),
|
UpdatedAt: rp.UpdatedAt(),
|
||||||
"vehicleType": rp.VehicleType().String(),
|
VehicleType: rp.VehicleType().String(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,9 +133,12 @@ func (rp *RuleSetProvider) Close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewRuleSetProvider(name string, behavior P.RuleBehavior, format P.RuleFormat, interval time.Duration, vehicle P.Vehicle,
|
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{
|
rp := &ruleSetProvider{
|
||||||
|
ruleSetProviderBase: ruleSetProviderBase{
|
||||||
behavior: behavior,
|
behavior: behavior,
|
||||||
|
},
|
||||||
format: format,
|
format: format,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,7 +160,7 @@ func NewRuleSetProvider(name string, behavior P.RuleBehavior, format P.RuleForma
|
|||||||
return wrapper
|
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 {
|
switch behavior {
|
||||||
case P.Domain:
|
case P.Domain:
|
||||||
strategy := NewDomainStrategy()
|
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 (
|
||||||
var ErrInvalidFormat = errors.New("invalid format")
|
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) {
|
func rulesParse(buf []byte, strategy ruleStrategy, format P.RuleFormat) (ruleStrategy, error) {
|
||||||
strategy.Reset()
|
strategy.Reset()
|
||||||
@ -254,3 +274,71 @@ func rulesParse(buf []byte, strategy ruleStrategy, format P.RuleFormat) (ruleStr
|
|||||||
|
|
||||||
return strategy, nil
|
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…
x
Reference in New Issue
Block a user