Files
Sillyv2/core/plugin_utils.go
T
cdle c1ff480349 x
2023-07-08 20:01:25 +08:00

402 lines
8.8 KiB
Go

package core
import (
"fmt"
"regexp"
"strings"
"sync"
"time"
"github.com/cdle/sillyplus/mongodb"
"github.com/cdle/sillyplus/utils"
"github.com/dop251/goja"
"github.com/dop251/goja_nodejs/require"
"github.com/robfig/cron/v3"
)
type ScriptUtils struct {
matched bool
ress [][]string
script string
}
func (su *ScriptUtils) match() {
su.ress = regexp.MustCompile(
`(\x20?\*[ ]?@([^\s]+)\s+([^\n]+?)\n)`,
).FindAllStringSubmatch(su.script, -1)
su.matched = true
}
func (su *ScriptUtils) GetValue(key string) string {
if !su.matched {
su.match()
}
value := ""
for _, res := range su.ress {
if res[2] == key {
value = res[3]
}
}
return value
}
// func Error(err error) interface{} {
// if err != nil {
// return map[string]string{"name": "Error", "message": err.Error()}
// }
// return nil
// }
func (su *ScriptUtils) SetValue(key, value string) {
if !su.matched {
su.match()
}
exists := []string{}
first := ""
for _, res := range su.ress {
if first == "" {
first = res[1]
}
if res[2] == key {
exists = append(exists, res[1])
}
}
if len(exists) != 0 {
for i := range exists {
if i == len(exists)-1 {
su.script = strings.Replace(su.script, exists[i], fmt.Sprintf(" * @%s %s\n", key, value), 1)
} else {
su.script = strings.Replace(su.script, exists[i], "", 1)
}
}
} else {
if first != "" {
su.script = strings.Replace(su.script, first, first+fmt.Sprintf(" * @%s %s\n", key, value), 1)
} else {
su.script = fmt.Sprintf("/**\n%s */\n", fmt.Sprintf(" * @%s %s\n", key, value)) + su.script
}
}
su.match()
}
func (su *ScriptUtils) DeleteValue(key string) {
if !su.matched {
su.match()
}
exists := []string{}
for _, res := range su.ress {
if res[2] == key {
exists = append(exists, res[1])
}
}
if len(exists) != 0 {
for i := range exists {
su.script = strings.Replace(su.script, exists[i], "", 1)
}
}
su.match()
}
var store sync.Map
var crons sync.Map
func CancelPluginCrons(uuid string) {
v, ok := crons.Load(uuid)
if ok {
for _, id := range *v.(*[]cron.EntryID) {
CRON.Remove(id)
}
}
}
func SetPluginMethod(vm *goja.Runtime, uuid string, on_start bool, running func() bool) {
vm.Set("Bucket", func(name string) interface{} {
return JsBucket(vm, name, uuid, on_start)
})
registry := require.NewRegistry(require.WithLoader(mapFileSystemSourceLoader(uuid)))
registry.RegisterNativeModule("crypto", cryptoModule)
registry.RegisterNativeModule("buffer", bufferModule)
if on_start {
var ids = &[]cron.EntryID{}
crons.Store(uuid, ids)
vm.Set("Cron", func() *goja.Object {
o := vm.NewObject()
o.Set("add", func(cron string, f func()) interface{} {
if f == nil {
return map[string]interface{}{
"id": 0,
"error": "未传入handler",
}
}
cron = strings.TrimSpace(cron)
if len(regexp.MustCompile(`\S+`).FindAllString(cron, -1)) == 5 {
cron = "0 " + cron
}
id, err := CRON.AddFunc(cron, func() {
// mutex := GetMutex(uuid)
// mutex.Lock()
// defer mutex.Unlock()
defer func() {
err := recover()
if err != nil {
pluginConsole(uuid).Error("C.AddFunc err: %v", err)
}
}()
f()
})
if err == nil {
*ids = append(*ids, id)
}
return map[string]interface{}{
"id": id,
"error": err,
}
})
o.Set("remove", func(id cron.EntryID) {
CRON.Remove(id)
})
return o
})
vm.Set("gofor", func(running func() bool, handle func()) {
go func() {
for {
if !func() bool {
defer func() {
err := recover()
if err != nil {
pluginConsole(uuid).Error("gofor running error:", err)
}
}()
return running()
}() {
return
}
func() {
defer func() {
err := recover()
if err != nil {
pluginConsole(uuid).Error("gofor error:", err)
}
}()
handle()
}()
}
}()
})
// func (f *Factory) Request(running func() bool, wt interface{}, handles ...func(error, map[string]interface{}, interface{}) interface{}) {
// go func() {
// for {
// if !running() {
// return
// }
// func() {
// defer func() {
// if debug_mode {
// return
// }
// err := recover()
// if err != nil {
// console.Error("Sender(\""+f.platform+"\").request error:", err)
// }
// }()
// request(wt, handles...)
// }()
// }
// }()
// }
}
vm.Set("Express", func() *goja.Object {
o := vm.NewObject()
methods := []string{"get", "post", "delete", "put", "fetch"}
for i := range methods {
method := methods[i]
o.Set(method, func(path string, handles ...func(*Request, *Response)) {
webs = append(webs, Web{
uuid: uuid,
method: strings.ToUpper(method),
path: path,
handles: handles,
})
})
}
o.Set("static", func(path string) {
addStatic(uuid, path)
})
return o
})
registry.Enable(vm)
vm.SetFieldNameMapper(myFieldNameMapper{})
// vm.Set("sleep", sleep)
vm.Set("md5", utils.Md5)
vm.Set("image", utils.ToImageQrcode)
vm.Set("video", utils.ToVideoQrcode)
vm.Set("console", &Console{UUID: uuid})
vm.Set("call", func(str string) interface{} {
return RegistFuncs[str]
})
vm.Set("fmt", &Fmt{})
vm.Set("strings", &Strings{
UUID: uuid,
})
// vm.Set("Bucket", BucketJsImpl)
vm.Set("time", &TimeJsImpl{
Second: time.Second,
Minute: time.Minute,
Hour: time.Hour,
Day: time.Hour * 24,
Month: 1,
})
vm.Set("Regexp", Regexp)
vm.Set("Form", func(...interface{}) {
})
vm.Set("url2Base64", Url2Base64)
// 字符串转Base64编码
vm.Set("stringToBase64", stringToBase64)
vm.Set("base64ToString", base64ToString)
vm.Set("Buffer", &BufferObj{vm: vm})
vm.Set("fetch", func(wts ...interface{}) interface{} {
promise, resolve, reject := vm.NewPromise()
go func() {
defer func() {
err := recover()
if err != nil {
o, ok := err.(*goja.Object)
if ok {
(&Console{
UUID: uuid,
}).Error(o.Get("value"))
}
}
}()
obj, err := fetch(vm, uuid, wts...)
if err != nil {
reject(err)
} else {
resolve(obj)
}
}()
return promise
})
vm.Set("request", func(wts ...interface{}) interface{} {
obj, err := fetch(vm, uuid, wts...)
if err != nil {
panic(Error(vm, err))
}
return obj
})
// for _, method := range []string{"get", "post", "delete", "put", "fetch"} {
// vm.Set(method, )
// }
vm.Set("HttpListen", func(method, api string) *goja.Promise {
promise, resolve, reject := vm.NewPromise()
go func() {
func() {
v := recover()
if v != nil {
if err, ok := v.(error); ok {
reject(Error(vm, err))
} else {
reject(Error(vm, fmt.Sprint(v)))
}
}
}()
AddHttpListen(api, strings.ToUpper(method), vm, uuid, resolve, reject)
}()
return promise
})
vm.Set("getReplyMessage", func(plt string, bots_id []string) *goja.Promise {
return GetReplyMessage(vm, plt, bots_id)
})
vm.Set("Script", func(str string) interface{} {
if str == "" {
str = uuid
}
return Script(str)
})
vm.Set("Temp", func(pre string, sec int) interface{} {
return map[string]interface{}{
"set": func(key string, value interface{}, num int) {
if sec != 0 && num == 0 {
num = sec
}
temp.Set(pre+"_"+key, value, num)
},
"get": func(key string, def interface{}) interface{} {
v := temp.Get(pre + "_" + key)
if v == nil {
v = def
}
return v
},
"delete": func(key string) {
temp.Delete(pre + "_" + key)
},
}
})
osjs := getJsOs(vm, running)
vm.Set("os", osjs)
vm.Set("fs", osjs)
vm.Set("forObject", ForeachObject)
vm.Set("MongoClient", func(uri string) interface{} {
return &mongodb.MongoClient{
Uri: uri,
Vm: vm,
}
})
vm.Set("importJs", func(file string) error {
file = strings.Replace(file, ".js", "", -1)
s, id, ok := getPaterner(uuid, file)
if !ok {
panic(Error(vm, "无法通过importJs导入"+file))
}
_, err := vm.RunString(s)
if err != nil {
pluginConsole(id).Error(err)
panic(Error(vm, "通过importJs导入"+file+"错误:"+err.Error()))
}
return nil
})
vm.Set("crypto", &Crypto{
vm: vm,
})
vm.Set("createNickName", CreateNickName)
}
func EncryptPlugin(script string) string {
res := strings.SplitN(script, "*/\n", 2)
if len(res) != 2 {
// logs.Info(len(res))
return script
}
str, err := EncryptByAes([]byte(res[1]))
if err != nil {
// logs.Info(err)
return script
}
su := ScriptUtils{script: res[0]}
if su.GetValue("encrypt_data") != "" {
return script
}
su.SetValue("encrypt_data", str)
return su.script + "*/\n"
}
func DecryptPlugin(script string) string {
su := ScriptUtils{script: script}
encrypt_data := su.GetValue("encrypt_data")
if encrypt_data == "" {
return script
}
su.DeleteValue("encrypt_data")
str, err := DecryptByAes(encrypt_data)
if err != nil {
return script
}
return fmt.Sprintf("%s%s", su.script, str)
}