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("Cache", cache) vm.Set("Temp", cache) 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) vm.Set("getListenOnGroups", func(plt string) []string { groups := []string{} ListenOnGroups.Range(func(key, value any) bool { if value == plt { groups = append(groups, key.(string)) } return true }) StaticListenOnGroups.Range(func(key, value any) bool { if value == plt { groups = append(groups, key.(string)) } return true }) groups = utils.Unique(groups) return groups }) } 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) }