feat: 尝试实现脚本rule

This commit is contained in:
Skyxim 2022-06-05 17:28:19 +08:00
parent 20cb4d0643
commit 55c7c4edb3
4 changed files with 91 additions and 5 deletions

View File

@ -3,17 +3,22 @@
package js package js
import ( import (
"github.com/Dreamacro/clash/log"
"github.com/dop251/goja" "github.com/dop251/goja"
"github.com/dop251/goja_nodejs/console" "github.com/dop251/goja_nodejs/console"
"github.com/dop251/goja_nodejs/eventloop" "github.com/dop251/goja_nodejs/eventloop"
"github.com/dop251/goja_nodejs/require" "github.com/dop251/goja_nodejs/require"
) )
func init() {
logPrinter := console.RequireWithPrinter(&JsLog{})
require.RegisterNativeModule("console", logPrinter)
}
func preSetting(rt *goja.Runtime) { func preSetting(rt *goja.Runtime) {
registry := new(require.Registry) registry := new(require.Registry)
registry.Enable(rt) registry.Enable(rt)
logPrinter := console.RequireWithPrinter(&JsLog{})
require.RegisterNativeModule("console", logPrinter)
console.Enable(rt) console.Enable(rt)
eventloop.EnableConsole(true) eventloop.EnableConsole(true)
} }
@ -33,12 +38,20 @@ func compiler(name, code string) (*goja.Program, error) {
} }
func run(loop *eventloop.EventLoop, program *goja.Program, args map[string]any, callback func(any, error)) { func run(loop *eventloop.EventLoop, program *goja.Program, args map[string]any, callback func(any, error)) {
loop.RunOnLoop(func(runtime *goja.Runtime) { loop.Run(func(runtime *goja.Runtime) {
for k, v := range args { for k, v := range args {
runtime.Set(k, v) runtime.SetFieldNameMapper(goja.TagFieldNameMapper("json", true))
err := runtime.Set(k, v)
if err != nil {
log.Errorln("Args to script failed, %s", err.Error())
}
} }
v, err := runtime.RunProgram(program) v, err := runtime.RunProgram(program)
callback(v, err) if v == nil {
callback(nil, err)
} else {
callback(v.Export(), err)
}
}) })
} }

View File

@ -14,6 +14,7 @@ const (
SrcPort SrcPort
DstPort DstPort
Process Process
Script
ProcessPath ProcessPath
RuleSet RuleSet
Network Network
@ -61,6 +62,8 @@ func (rt RuleType) String() string {
return "RuleSet" return "RuleSet"
case Network: case Network:
return "Network" return "Network"
case Script:
return "Script"
case Uid: case Uid:
return "Uid" return "Uid"
case INTYPE: case INTYPE:

68
rule/common/script.go Normal file
View File

@ -0,0 +1,68 @@
package common
import (
"github.com/Dreamacro/clash/component/js"
C "github.com/Dreamacro/clash/constant"
"github.com/gofrs/uuid"
)
type Script struct {
*Base
adapter string
name string
}
func (s *Script) RuleType() C.RuleType {
return C.Script
}
func (s *Script) Match(metadata *C.Metadata) bool {
res := false
js.Run(s.name, map[string]any{
"metadata": metadata,
}, func(a any, err error) {
if err != nil {
res = false
}
r, ok := a.(bool)
if !ok {
res = false
}
res = r
})
return res
}
func (s *Script) Adapter() string {
return s.adapter
}
func (s *Script) Payload() string {
return s.adapter
}
func (s *Script) ShouldResolveIP() bool {
return true
}
func NewScript(script string, adapter string) (*Script, error) {
name, err := uuid.NewV4()
if err != nil {
return nil, err
}
if err := js.NewJS(name.String(), script); err != nil {
return nil, err
}
return &Script{
Base: &Base{},
adapter: adapter,
name: name.String(),
}, nil
}
var _ C.Rule = (*Script)(nil)

View File

@ -43,6 +43,8 @@ func ParseSameRule(tp, payload, target string, params []string) (parsed C.Rule,
parsed, parseErr = RC.NewUid(payload, target) parsed, parseErr = RC.NewUid(payload, target)
case "IN-TYPE": case "IN-TYPE":
parsed, parseErr = RC.NewInType(payload, target) parsed, parseErr = RC.NewInType(payload, target)
case "SCRIPT":
parsed, parseErr = RC.NewScript(payload, target)
default: default:
parseErr = fmt.Errorf("unsupported rule type %s", tp) parseErr = fmt.Errorf("unsupported rule type %s", tp)
} }