474 lines
11 KiB
Go
474 lines
11 KiB
Go
package core
|
|
|
|
import (
|
|
"fmt"
|
|
"math/rand"
|
|
"regexp"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"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) {
|
|
C.Remove(id)
|
|
}
|
|
}
|
|
}
|
|
|
|
func SetPluginMethod(vm *goja.Runtime, uuid string, on_start bool, running func() bool) {
|
|
vm.Set("Bucket", func(name string) interface{} {
|
|
return vm.NewProxy(MakeBucketObject(vm, uuid, on_start, MakeBucket(name)), &goja.ProxyTrapConfig{
|
|
Get: func(target *goja.Object, property string, receiver goja.Value) (value goja.Value) {
|
|
obj := target.Get(property)
|
|
if obj != nil {
|
|
return obj
|
|
}
|
|
result := target.Get("get").Export().(func(...interface{}) interface{})(property)
|
|
return vm.ToValue(result)
|
|
},
|
|
Set: func(target *goja.Object, property string, value, receiver goja.Value) (success bool) {
|
|
result := target.Get("set").Export().(func(interface{}, interface{}) error)(
|
|
property, value.Export(),
|
|
)
|
|
return result == nil
|
|
},
|
|
})
|
|
})
|
|
|
|
sillyplusJsIplm := func(call goja.ConstructorCall) *goja.Object {
|
|
userId := fmt.Sprintf("%d", rand.Int63())
|
|
call.This.Set("isSlaveMode", func() bool {
|
|
return utils.SlaveMode
|
|
})
|
|
call.This.Set("uuid", func() string {
|
|
return uuid
|
|
})
|
|
call.This.Set("store", func(str string, v interface{}) {
|
|
store.Store(str, v)
|
|
})
|
|
call.This.Set("load", func(str string) interface{} {
|
|
v, _ := store.Load(str)
|
|
return v
|
|
})
|
|
call.This.Set("delete", func(str string) {
|
|
store.Delete(str)
|
|
})
|
|
call.This.Set("session", func(info interface{}) func(...int) interface{} {
|
|
msg := ""
|
|
imTpye := "carry"
|
|
var chatId string
|
|
switch info := info.(type) {
|
|
case string:
|
|
msg = info
|
|
default:
|
|
props := info.(map[string]interface{})
|
|
for i := range props {
|
|
switch strings.ToLower(i) {
|
|
case "imtype":
|
|
imTpye = props[i].(string)
|
|
case "platform":
|
|
imTpye = props[i].(string)
|
|
case "msg", "message":
|
|
msg = props[i].(string)
|
|
case "chatid", "chat_id":
|
|
chatId = fmt.Sprint(props[i].(string))
|
|
case "userid", "user_id":
|
|
userId = props[i].(string)
|
|
}
|
|
}
|
|
}
|
|
if msg == "" {
|
|
return nil
|
|
}
|
|
c := &Faker{
|
|
Type: imTpye,
|
|
Message: msg,
|
|
Carry: make(chan string),
|
|
UserID: userId,
|
|
ChatID: chatId,
|
|
Admin: true,
|
|
}
|
|
Messages <- c
|
|
var f = func(i ...int) interface{} {
|
|
timeOut := 1000 * 100
|
|
if len(i) > 0 {
|
|
timeOut = i[0]
|
|
}
|
|
select {
|
|
case v, ok := <-c.Listen():
|
|
return map[string]interface{}{
|
|
"hasNext": ok,
|
|
"message": v,
|
|
}
|
|
case <-time.After(time.Millisecond * time.Duration(timeOut)):
|
|
return map[string]interface{}{
|
|
"hasNext": false,
|
|
"message": "已超时",
|
|
}
|
|
}
|
|
}
|
|
return f
|
|
})
|
|
return nil
|
|
}
|
|
registry := require.NewRegistry(require.WithLoader(mapFileSystemSourceLoader(uuid)))
|
|
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 := C.AddFunc(cron, func() {
|
|
// mutex := GetMutex(uuid)
|
|
// mutex.Lock()
|
|
// defer mutex.Unlock()
|
|
defer func() {
|
|
err := recover()
|
|
if err != nil {
|
|
console.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) {
|
|
C.Remove(id)
|
|
})
|
|
return o
|
|
})
|
|
|
|
// registry.RegisterNativeModule("express", func(runtime *goja.Runtime, module *goja.Object) {
|
|
// o := module.Get("exports").(*goja.Object)
|
|
// 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,
|
|
// })
|
|
// })
|
|
// }
|
|
// })
|
|
vm.Set("gofor", func(running func() bool, handle func()) {
|
|
go func() {
|
|
for {
|
|
if !func() bool {
|
|
defer func() {
|
|
err := recover()
|
|
if err != nil {
|
|
console.Error("gofor running error:", err)
|
|
}
|
|
}()
|
|
return running()
|
|
}() {
|
|
return
|
|
}
|
|
func() {
|
|
defer func() {
|
|
err := recover()
|
|
if err != nil {
|
|
console.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)
|
|
vm.Set("sillyplus", sillyplusJsIplm)
|
|
vm.Set("call", func(str string) interface{} {
|
|
return RegistFuncs[str]
|
|
})
|
|
vm.Set("fmt", &Fmt{})
|
|
vm.Set("strings", &Strings{})
|
|
// vm.Set("Bucket", BucketJsImpl)
|
|
vm.Set("time", &TimeJsImpl{
|
|
Second: time.Second,
|
|
Minute: time.Minute,
|
|
Hour: time.Hour,
|
|
Day: time.Hour * 24,
|
|
})
|
|
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", func(call goja.ConstructorCall) *goja.Object {
|
|
return Buffer(vm, call)
|
|
})
|
|
vm.Set("fetch", func(wts ...interface{}) interface{} {
|
|
promise, resolve, reject := vm.NewPromise()
|
|
func() {
|
|
func() {
|
|
v := recover()
|
|
if v != nil {
|
|
if err, ok := v.(error); ok {
|
|
reject(Error(vm, err))
|
|
} else {
|
|
reject(Error(vm, fmt.Sprint(v)))
|
|
}
|
|
|
|
}
|
|
}()
|
|
fetch(vm, resolve, reject, wts...)
|
|
}()
|
|
return promise
|
|
})
|
|
vm.Set("request", func(wts ...interface{}) interface{} {
|
|
return fetch(vm, nil, nil, wts...)
|
|
})
|
|
// 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)
|
|
}
|
|
|
|
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)
|
|
}
|