633 lines
14 KiB
Go
633 lines
14 KiB
Go
package core
|
|
|
|
import (
|
|
"context"
|
|
"encoding/base64"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"regexp"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/cdle/sillyplus/core/common"
|
|
"github.com/cdle/sillyplus/core/logs"
|
|
"github.com/cdle/sillyplus/proto3/srpc"
|
|
"github.com/cdle/sillyplus/utils"
|
|
"github.com/dop251/goja"
|
|
// "golang.org/x/image/webp"
|
|
)
|
|
|
|
var sleep = func(i int) {
|
|
time.Sleep(time.Duration(i) * time.Millisecond)
|
|
}
|
|
|
|
func GetScriptNameByUUID(uuid string) string {
|
|
for _, f := range Functions {
|
|
if f.UUID == uuid {
|
|
return fmt.Sprintf("%s%s", f.Title, f.Suffix)
|
|
}
|
|
}
|
|
return "未知脚本"
|
|
}
|
|
|
|
type SenderJsIplm struct {
|
|
Message common.Sender
|
|
Private string
|
|
Group string
|
|
Routine string
|
|
Persistent string
|
|
Vm *goja.Runtime
|
|
UUID string
|
|
NewContent bool
|
|
}
|
|
|
|
type Console struct {
|
|
UUID string
|
|
}
|
|
|
|
var console = &Console{}
|
|
var Logs = &Console{}
|
|
|
|
func (sg *SillyGirlService) Console(ctx context.Context, req *srpc.ConsoleRequest) (*srpc.Empty, error) {
|
|
log := &Console{
|
|
UUID: req.PluginId,
|
|
}
|
|
switch req.Type {
|
|
case "info", "log":
|
|
log.Info(req.Content)
|
|
case "error":
|
|
log.Error(req.Content)
|
|
case "debug":
|
|
log.Debug(req.Content)
|
|
}
|
|
return &srpc.Empty{}, nil
|
|
}
|
|
|
|
func pluginConsole(uuid string) *Console {
|
|
return &Console{
|
|
UUID: uuid,
|
|
}
|
|
}
|
|
|
|
func Broadcast2WebUser(content, class string) {
|
|
if (RegistFuncs["Broadcast2WebUser"]) == nil {
|
|
return
|
|
}
|
|
RegistFuncs["Broadcast2WebUser"].(func(string, string))(content, class)
|
|
}
|
|
|
|
func (c *Console) Info(v ...interface{}) {
|
|
if len(v) == 0 {
|
|
return
|
|
}
|
|
log := utils.FormatLog(v[0], v[1:]...)
|
|
logs.Info(log)
|
|
Broadcast2WebUser(log, "info")
|
|
}
|
|
|
|
func (c *Console) Debug(v ...interface{}) {
|
|
if len(v) == 0 {
|
|
return
|
|
}
|
|
if c.UUID != "" {
|
|
if plugin_debug.GetString(c.UUID) != "b:true" {
|
|
return
|
|
}
|
|
}
|
|
log := utils.FormatLog(v[0], v[1:]...)
|
|
logs.Debug(log)
|
|
Broadcast2WebUser(log, "debug")
|
|
}
|
|
|
|
func (c *Console) Warn(v ...interface{}) {
|
|
if len(v) == 0 {
|
|
return
|
|
}
|
|
log := utils.FormatLog(v[0], v[1:]...)
|
|
logs.Warn(log)
|
|
WritePluginMessage(c.UUID, "warn", log)
|
|
Broadcast2WebUser(log, "warn")
|
|
}
|
|
|
|
func (c *Console) Error(v ...interface{}) {
|
|
if len(v) == 0 {
|
|
return
|
|
}
|
|
log := utils.FormatLog(v[0], v[1:]...)
|
|
logs.Error(log)
|
|
WritePluginMessage(c.UUID, "error", log)
|
|
Broadcast2WebUser(log, "error")
|
|
}
|
|
|
|
func (c *Console) Log(v ...interface{}) {
|
|
if len(v) == 0 {
|
|
return
|
|
}
|
|
log := utils.FormatLog(v[0], v[1:]...)
|
|
logs.Info(log)
|
|
Broadcast2WebUser(log, "log")
|
|
}
|
|
|
|
func (sender *SenderJsIplm) Continue() {
|
|
if sender.NewContent {
|
|
go func() {
|
|
Messages <- sender.Message
|
|
}()
|
|
return
|
|
}
|
|
sender.Message.Continue()
|
|
}
|
|
|
|
func (sender *SenderJsIplm) GetUserID() string {
|
|
|
|
return sender.Message.GetUserID()
|
|
}
|
|
func (sender *SenderJsIplm) GetBotID() string {
|
|
|
|
return sender.Message.GetBotID()
|
|
}
|
|
func (sender *SenderJsIplm) GetBotId() string {
|
|
|
|
return sender.Message.GetBotID()
|
|
}
|
|
|
|
func (sender *SenderJsIplm) GetUserId() string {
|
|
return sender.Message.GetUserID()
|
|
}
|
|
|
|
func (sender *SenderJsIplm) SetContent(s string) {
|
|
if s != sender.GetContent() {
|
|
sender.NewContent = true
|
|
}
|
|
sender.Message.SetContent(s)
|
|
}
|
|
|
|
func (sender *SenderJsIplm) GetContent() string {
|
|
return sender.Message.GetContent()
|
|
}
|
|
func (sender *SenderJsIplm) GetImType() string {
|
|
return sender.Message.GetImType()
|
|
}
|
|
func (sender *SenderJsIplm) GetPlatform() string {
|
|
return sender.Message.GetImType()
|
|
}
|
|
func (sender *SenderJsIplm) RecallMessage(p ...interface{}) {
|
|
sender.Message.RecallMessage(p...)
|
|
}
|
|
func (sender *SenderJsIplm) GetUserName() string {
|
|
return sender.Message.GetUserName()
|
|
}
|
|
func (sender *SenderJsIplm) GetUsername() string {
|
|
return sender.Message.GetUserName()
|
|
}
|
|
|
|
func (sender *SenderJsIplm) GetReplyUserID() int {
|
|
return sender.Message.GetReplyUserID()
|
|
}
|
|
|
|
func (sender *SenderJsIplm) GetReplyUserId() int {
|
|
return sender.Message.GetReplyUserID()
|
|
}
|
|
|
|
func (sender *SenderJsIplm) GetLevel() int {
|
|
return sender.Message.GetLevel()
|
|
}
|
|
|
|
func (sender *SenderJsIplm) SetLevel(l int) {
|
|
sender.Message.SetLevel(l)
|
|
}
|
|
|
|
func (sender *SenderJsIplm) GetChatName() string {
|
|
return sender.Message.GetChatName()
|
|
}
|
|
func (sender *SenderJsIplm) GetMessageID() string {
|
|
return sender.Message.GetMessageID()
|
|
}
|
|
|
|
func (sender *SenderJsIplm) GetMessageId() string {
|
|
return sender.Message.GetMessageID()
|
|
}
|
|
|
|
func (sender *SenderJsIplm) GetGroupCode() string {
|
|
return sender.Message.GetChatID()
|
|
}
|
|
|
|
func (sender *SenderJsIplm) GetChatID() string {
|
|
return sender.Message.GetChatID()
|
|
}
|
|
|
|
func (sender *SenderJsIplm) GetChatId() string {
|
|
return sender.Message.GetChatID()
|
|
}
|
|
|
|
func (sender *SenderJsIplm) Kick(uid string) interface{} {
|
|
err := sender.Message.GroupKick(uid, false)
|
|
if err != nil {
|
|
return err.Error()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (sender *SenderJsIplm) Unkick(uid string) interface{} {
|
|
err := sender.Message.GroupUnkick(uid)
|
|
if err != nil {
|
|
return err.Error()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (sender *SenderJsIplm) Ban(uid string, duration int) interface{} {
|
|
err := sender.Message.GroupBan(uid, duration)
|
|
if err != nil {
|
|
return err.Error()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (sender *SenderJsIplm) Param(i interface{}) string {
|
|
switch i := i.(type) {
|
|
case int:
|
|
return sender.Message.Get(i - 1)
|
|
case int64:
|
|
return sender.Message.Get(int(i - 1))
|
|
case string:
|
|
return sender.Message.Get(i)
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func (sender *SenderJsIplm) GetAllMatch() [][]string {
|
|
return sender.Message.GetAllMatch()
|
|
}
|
|
|
|
func (sender *SenderJsIplm) Params(i int) []string {
|
|
if i == 0 {
|
|
i = 1
|
|
}
|
|
ss := []string{}
|
|
for _, v := range sender.Message.GetAllMatch() {
|
|
ss = append(ss, v[i-1])
|
|
}
|
|
return ss
|
|
}
|
|
|
|
// GetAllMatch
|
|
|
|
func (Sender *SenderJsIplm) Get(i interface{}) string {
|
|
return Sender.Param(i)
|
|
}
|
|
|
|
func (Sender *SenderJsIplm) GetVar(key string) interface{} {
|
|
return Sender.Message.GetVar(key)
|
|
}
|
|
|
|
func (Sender *SenderJsIplm) SetVar(key string, value interface{}) {
|
|
Sender.Message.SetVar(key, value)
|
|
}
|
|
|
|
func (Sender *SenderJsIplm) SetVars(kvs map[string]interface{}) {
|
|
for k, v := range kvs {
|
|
Sender.SetVar(k, v)
|
|
}
|
|
}
|
|
|
|
func (Sender *SenderJsIplm) GetVars() map[string]interface{} {
|
|
return Sender.Message.GetExpandMessageInfo()
|
|
}
|
|
|
|
func (sender *SenderJsIplm) IsAdmin() bool {
|
|
return sender.Message.IsAdmin()
|
|
}
|
|
|
|
func (sender *SenderJsIplm) Action(options map[string]interface{}) interface{} {
|
|
result, err := sender.Message.Action(options)
|
|
return map[string]interface{}{
|
|
"result": result,
|
|
"error": err,
|
|
}
|
|
}
|
|
|
|
func (sender *SenderJsIplm) Reply(texts ...interface{}) interface{} {
|
|
i, err := sender.Message.Reply(texts...)
|
|
var errstr interface{}
|
|
if err != nil {
|
|
// panic(Error(sender.Vm, err))
|
|
errstr = err.Error()
|
|
}
|
|
return map[string]interface{}{
|
|
"message_id": i,
|
|
"error": errstr,
|
|
}
|
|
}
|
|
|
|
func (sender *SenderJsIplm) HoldOn(str ...string) string {
|
|
if len(str) != 0 {
|
|
return "go_again_" + str[0]
|
|
}
|
|
return "go_again_"
|
|
}
|
|
|
|
func arrayss(i interface{}) []string {
|
|
var ss = []string{}
|
|
for _, v := range i.([]interface{}) {
|
|
ss = append(ss, v.(string))
|
|
}
|
|
return ss
|
|
}
|
|
|
|
func (sender *SenderJsIplm) Listen(ps ...interface{}) interface{} {
|
|
// promise, resolve, reject := vm.NewPromise()
|
|
options := []interface{}{}
|
|
var handle func(goja.FunctionCall) goja.Value
|
|
var persistent = sender.Message.GetImType() == "*"
|
|
var routine = persistent
|
|
var carry = &Carry{}
|
|
// var sustainable = false
|
|
// rs := []string{}
|
|
for _, p := range ps {
|
|
switch p := p.(type) {
|
|
case map[string]interface{}:
|
|
props := p
|
|
for i, p := range props {
|
|
switch strings.ToLower(i) {
|
|
case "rules":
|
|
vs := p.([]interface{})
|
|
for _, v := range vs {
|
|
rule := v.(string)
|
|
_rs := formatRule(rule)
|
|
if len(_rs) != 0 {
|
|
carry.Function.Rules = append(carry.Function.Rules, _rs...)
|
|
} else {
|
|
carry.Function.Rules = append(carry.Function.Rules, rule)
|
|
}
|
|
}
|
|
case "timeout":
|
|
options = append(options, time.Duration(utils.Int(p))*time.Millisecond)
|
|
case "handle":
|
|
handle = p.(func(goja.FunctionCall) goja.Value)
|
|
case "listen_private", "private":
|
|
carry.ListenPrivate = p.(bool)
|
|
case "listen_group", "group":
|
|
carry.ListenGroup = p.(bool)
|
|
case "require_admin", "admin":
|
|
carry.RequireAdmin = p.(bool)
|
|
case "allow_platforms":
|
|
carry.AllowPlatforms = arrayss(p)
|
|
case "prohibit_platforms":
|
|
carry.ProhibitPlatforms = arrayss(p)
|
|
case "allow_groups":
|
|
carry.AllowGroups = arrayss(p)
|
|
case "allow_users":
|
|
carry.AllowUsers = arrayss(p)
|
|
case "prohibt_groups":
|
|
carry.ProhibitGroups = arrayss(p)
|
|
case "prohibt_users":
|
|
carry.ProhibitUsers = arrayss(p)
|
|
}
|
|
}
|
|
case bool:
|
|
case []interface{}:
|
|
for i := range p {
|
|
rule := p[i].(string)
|
|
_rs := formatRule(rule)
|
|
if len(_rs) != 0 {
|
|
carry.Function.Rules = append(carry.Function.Rules, _rs...)
|
|
} else {
|
|
carry.Function.Rules = append(carry.Function.Rules, rule)
|
|
}
|
|
}
|
|
case string:
|
|
if p == "private" {
|
|
carry.ListenPrivate = true
|
|
continue
|
|
}
|
|
if p == "group" {
|
|
carry.ListenGroup = true
|
|
continue
|
|
}
|
|
if p == "routine" {
|
|
routine = true
|
|
continue
|
|
}
|
|
if p == "persistent" {
|
|
persistent = true
|
|
continue
|
|
}
|
|
// if p == "sustainable" {
|
|
// persistent = false
|
|
// sustainable = true
|
|
// continue
|
|
// }
|
|
carry.Function.Rules = append(carry.Function.Rules, p)
|
|
case int, int64, int32:
|
|
options = append(options, time.Duration(utils.Int(p))*time.Millisecond)
|
|
case func(goja.FunctionCall) goja.Value:
|
|
handle = p
|
|
}
|
|
}
|
|
if persistent {
|
|
options = append(options, "persistent")
|
|
} else if len(carry.AllowPlatforms) == 0 {
|
|
carry.AllowPlatforms = []string{sender.GetPlatform()}
|
|
}
|
|
carry.UserID = sender.GetUserID()
|
|
carry.ChatID = sender.GetChatID()
|
|
carry.UUID = sender.UUID
|
|
options = append(options, carry)
|
|
var newJsSender *SenderJsIplm
|
|
var await = func() {
|
|
sender.Message.Await(sender.Message, func(newSender common.Sender) interface{} {
|
|
newSender.SetLevel(sender.Message.GetLevel() + 1)
|
|
newJsSender = &SenderJsIplm{
|
|
UUID: sender.UUID,
|
|
Vm: sender.Vm,
|
|
}
|
|
newJsSender.Message = newSender
|
|
if handle != nil {
|
|
if persistent {
|
|
func() {
|
|
defer func() {
|
|
err := recover()
|
|
if err != nil {
|
|
pluginConsole(sender.UUID).Error("%v at %v", err, GetScriptNameByUUID(sender.UUID))
|
|
}
|
|
}()
|
|
// fmt.Println(newJsSender)
|
|
rt := handle(goja.FunctionCall{
|
|
Arguments: []goja.Value{
|
|
sender.Vm.ToValue(newJsSender),
|
|
},
|
|
})
|
|
reply := ""
|
|
if rt != goja.Undefined() {
|
|
reply = rt.ToString().String()
|
|
} else {
|
|
reply = ""
|
|
}
|
|
newSender.Reply(reply)
|
|
}()
|
|
// return GoAgain("")
|
|
} else {
|
|
var rt = handle(goja.FunctionCall{
|
|
Arguments: []goja.Value{
|
|
sender.Vm.ToValue(newJsSender),
|
|
},
|
|
})
|
|
reply := ""
|
|
if rt != goja.Undefined() {
|
|
reply = rt.ToString().String()
|
|
} else {
|
|
reply = ""
|
|
}
|
|
if strings.HasPrefix(reply, "go_again_") {
|
|
reply = strings.Replace(reply, "go_again_", "", 1)
|
|
return GoAgain(reply)
|
|
} else {
|
|
// if sustainable {
|
|
// return GoAgain(reply)
|
|
// }
|
|
if reply == "" {
|
|
return nil
|
|
}
|
|
return reply
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}, options...)
|
|
}
|
|
if !routine {
|
|
await()
|
|
} else {
|
|
go await()
|
|
}
|
|
return newJsSender
|
|
}
|
|
|
|
type TimeJsImpl struct {
|
|
Second time.Duration
|
|
Minute time.Duration
|
|
Hour time.Duration
|
|
Day time.Duration
|
|
Month int
|
|
}
|
|
|
|
func (t *TimeJsImpl) Now() time.Time {
|
|
return time.Now()
|
|
}
|
|
|
|
func (t *TimeJsImpl) Date(year int, month int, day int, hour int, min int, sec int, nsec int) time.Time {
|
|
return time.Date(year, time.Month(month), day, hour, min, sec, nsec, loc)
|
|
}
|
|
|
|
func (t *TimeJsImpl) Sleep(i int) {
|
|
time.Sleep(time.Duration(i) * time.Millisecond)
|
|
}
|
|
|
|
func (t *TimeJsImpl) Unix(sec int64) time.Time {
|
|
return time.Unix(sec, 0)
|
|
}
|
|
|
|
func (t *TimeJsImpl) UnixMilli(sec int64) time.Time {
|
|
return time.UnixMilli(sec)
|
|
}
|
|
|
|
func (t *TimeJsImpl) Parse(timeStr, layout, locale string) (tt time.Time, err error) {
|
|
if locale == "" {
|
|
locale = "Asia/Shanghai"
|
|
}
|
|
local, err := time.LoadLocation(locale) //设置时区
|
|
if err != nil {
|
|
return tt, err
|
|
}
|
|
tt, err = time.ParseInLocation(layout, timeStr, local)
|
|
if err != nil {
|
|
return tt, err
|
|
}
|
|
return tt, nil
|
|
}
|
|
|
|
type Fmt struct {
|
|
}
|
|
|
|
func (sender *Fmt) Sprintf(format string, a ...interface{}) string {
|
|
return fmt.Sprintf(format, a...)
|
|
}
|
|
|
|
func (sender *Fmt) Printf(format string, a ...interface{}) {
|
|
fmt.Printf(format, a...)
|
|
}
|
|
|
|
func (sender *Fmt) Println(a ...interface{}) (int, error) {
|
|
return fmt.Println(a...)
|
|
}
|
|
|
|
func (sender *Fmt) Print(a ...interface{}) (int, error) {
|
|
return fmt.Print(a...)
|
|
}
|
|
|
|
func Url2Base64(imageUrl string) map[string]interface{} {
|
|
response, err := http.Get(imageUrl)
|
|
if err != nil {
|
|
return map[string]interface{}{"error": err.Error()}
|
|
}
|
|
defer response.Body.Close()
|
|
data, err := ioutil.ReadAll(response.Body)
|
|
if err != nil {
|
|
return map[string]interface{}{"error": err.Error()}
|
|
}
|
|
imageBase64 := base64.StdEncoding.EncodeToString(data)
|
|
return map[string]interface{}{"result": imageBase64}
|
|
}
|
|
|
|
func stringToBase64(str string) string {
|
|
return base64.StdEncoding.EncodeToString([]byte(str))
|
|
}
|
|
|
|
func base64ToString(b64 string) string {
|
|
data, err := base64.StdEncoding.DecodeString(b64)
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
return string(data)
|
|
}
|
|
|
|
func formatRule(rule string) []string {
|
|
_rs := []string{}
|
|
FR:
|
|
ress := regexp.MustCompile(`\[([^\s\[\]]+)\]`).FindAllStringSubmatch(rule, -1)
|
|
if len(ress) != 0 {
|
|
res := ress[len(ress)-1]
|
|
var inner = res[1]
|
|
slice := strings.SplitN(inner, ":", 2)
|
|
name := slice[0]
|
|
ps := ""
|
|
if len(slice) == 2 {
|
|
ps = slice[1]
|
|
}
|
|
if strings.HasSuffix(name, "?") {
|
|
name = strings.TrimRight(name, "?")
|
|
rep := ""
|
|
if ps == "" {
|
|
rep = fmt.Sprintf("[%s]", name)
|
|
} else {
|
|
rep = fmt.Sprintf("[%s:%s]", name, ps)
|
|
}
|
|
for l := range _rs {
|
|
_rs[l] = strings.Replace(_rs[l], res[0], rep, 1)
|
|
}
|
|
rule1 := strings.Replace(rule, res[0], rep, 1)
|
|
if len(_rs) == 0 {
|
|
_rs = append(_rs, rule1)
|
|
}
|
|
rule = strings.Replace(rule, res[0], "", 1)
|
|
rule = regexp.MustCompile("\x20{2,}").ReplaceAllString(rule, " ")
|
|
rule = strings.TrimSpace(rule)
|
|
_rs = append(_rs, rule)
|
|
goto FR
|
|
}
|
|
}
|
|
return _rs
|
|
}
|