960 lines
22 KiB
Go
960 lines
22 KiB
Go
package core
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"math/rand"
|
|
"reflect"
|
|
"regexp"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/cdle/sillyplus/core/common"
|
|
"github.com/cdle/sillyplus/core/logs"
|
|
"github.com/cdle/sillyplus/utils"
|
|
"github.com/dop251/goja"
|
|
)
|
|
|
|
type Message map[string]string
|
|
|
|
type Details struct {
|
|
Content string
|
|
UserID string
|
|
ChatID string
|
|
Username string
|
|
Chatname string
|
|
MessageID string
|
|
}
|
|
|
|
type CustomSender struct {
|
|
BaseSender
|
|
details Details
|
|
F *Factory
|
|
}
|
|
|
|
type MsgChan struct {
|
|
Chan chan string
|
|
Msg map[string]interface{}
|
|
}
|
|
|
|
type GMsgChan struct {
|
|
Chan chan map[string]interface{}
|
|
Msgs []map[string]interface{}
|
|
UpdateTime time.Time
|
|
sync.Mutex
|
|
}
|
|
|
|
type Factory struct {
|
|
botid string
|
|
botplt string
|
|
uuid string
|
|
msgChan chan MsgChan
|
|
demo *CustomSender
|
|
reply func(map[string]interface{}) string
|
|
action func(map[string]interface{}) string
|
|
lm chan bool
|
|
nm int64
|
|
isAdmin func(string) bool
|
|
vm *goja.Runtime
|
|
ctx context.Context
|
|
cancel context.CancelFunc
|
|
destroid bool ////已关闭
|
|
errorTimes int
|
|
Res *Response
|
|
umod bool //类似订阅号一对一被动消息模式
|
|
gmsgChan sync.Map
|
|
sync.RWMutex
|
|
}
|
|
|
|
type Bot [2]string //botplt botid
|
|
|
|
var Bots = map[Bot]*Factory{}
|
|
var BotsLocker sync.RWMutex
|
|
|
|
var ErrNotFind = errors.New("adapter not find")
|
|
|
|
func DestroyAdapterByUUID(uuid string) {
|
|
// BotsLocker.RLock()
|
|
// defer BotsLocker.RUnlock()
|
|
// for i := range Bots {
|
|
// if Bots[i].uuid == uuid {
|
|
// go Bots[i].Destroy()
|
|
// }
|
|
// }
|
|
}
|
|
|
|
func GetMessageByUUID(uuid string) string {
|
|
ss := []string{""}
|
|
BotsLocker.RLock()
|
|
defer BotsLocker.RUnlock()
|
|
for i, bot := range Bots {
|
|
plt, id := i[0], i[1]
|
|
// fmt.Println("plt", plt, "id", id, botplt, bots_id)
|
|
if bot.uuid == uuid {
|
|
ss[0] = plt
|
|
ss = append(ss, id)
|
|
}
|
|
}
|
|
if len(ss) == 0 {
|
|
return ""
|
|
}
|
|
return strings.Join(ss, " ")
|
|
}
|
|
|
|
func GetAdapter(botplt string, bots_id ...string) (*Factory, error) {
|
|
|
|
var bots = []*Factory{}
|
|
var select_bots = []*Factory{}
|
|
var tries = 0
|
|
Try:
|
|
func() {
|
|
BotsLocker.RLock()
|
|
defer BotsLocker.RUnlock()
|
|
for i := range Bots {
|
|
plt, id := i[0], i[1]
|
|
for j := range bots_id {
|
|
if plt == botplt && bots_id[j] == id {
|
|
select_bots = append(select_bots, Bots[i])
|
|
}
|
|
if plt == botplt {
|
|
bots = append(bots, Bots[i])
|
|
}
|
|
}
|
|
}
|
|
}()
|
|
if len(bots) == 0 {
|
|
if tries < 8 {
|
|
tries++
|
|
time.Sleep(10 * time.Millisecond)
|
|
goto Try
|
|
}
|
|
return nil, ErrNotFind
|
|
}
|
|
if len(select_bots) != 0 {
|
|
i := rand.Intn(len(select_bots))
|
|
return select_bots[i], nil
|
|
}
|
|
i := rand.Intn(len(bots))
|
|
return bots[i], ErrNotFind
|
|
}
|
|
|
|
func GetAdapters(botplt string, bots_id ...string) ([]*Factory, error) {
|
|
BotsLocker.RLock()
|
|
defer BotsLocker.RUnlock()
|
|
var bots = []*Factory{}
|
|
var select_bots = []*Factory{}
|
|
for i := range Bots {
|
|
plt, id := i[0], i[1]
|
|
// fmt.Println("plt", plt, "id", id, botplt, bots_id)
|
|
for j := range bots_id {
|
|
if plt == botplt && bots_id[j] == id {
|
|
select_bots = append(select_bots, Bots[i])
|
|
}
|
|
if plt == botplt {
|
|
bots = append(bots, Bots[i])
|
|
}
|
|
}
|
|
}
|
|
if len(bots) == 0 {
|
|
return nil, ErrNotFind
|
|
}
|
|
if len(select_bots) != 0 {
|
|
return select_bots, nil
|
|
}
|
|
return bots, ErrNotFind
|
|
}
|
|
|
|
func GetAdapterBotsID(botplt string) []string {
|
|
BotsLocker.RLock()
|
|
defer BotsLocker.RUnlock()
|
|
var bots_id = []string{}
|
|
for i := range Bots {
|
|
// fmt.Println("==", botplt == i[0], botplt, i[0])
|
|
if botplt == i[0] {
|
|
bots_id = append(bots_id, i[1])
|
|
}
|
|
}
|
|
return bots_id
|
|
}
|
|
func GetAdapterBotPlts() []string {
|
|
BotsLocker.RLock()
|
|
defer BotsLocker.RUnlock()
|
|
var bot_plts = []string{}
|
|
for i := range Bots {
|
|
// fmt.Println("==", botplt == i[0], botplt, i[0])
|
|
has := false
|
|
for _, bot_plt := range bot_plts {
|
|
if bot_plt == i[0] {
|
|
has = true
|
|
}
|
|
}
|
|
if !has {
|
|
bot_plts = append(bot_plts, i[0])
|
|
}
|
|
}
|
|
return bot_plts
|
|
}
|
|
|
|
func (f *Factory) Init(botplt, botid string, params map[string]interface{}) {
|
|
// fmt.Println(params)
|
|
if params != nil {
|
|
if _, ok := params["umod"]; ok {
|
|
f.umod = true
|
|
}
|
|
}
|
|
// fmt.Println("umod", f.umod)
|
|
f.ctx, f.cancel = context.WithCancel(context.Background())
|
|
BotsLocker.Lock()
|
|
defer BotsLocker.Unlock()
|
|
f.botplt = botplt
|
|
f.botid = botid
|
|
f.msgChan = make(chan MsgChan, 100000)
|
|
f.demo = &CustomSender{
|
|
F: f,
|
|
}
|
|
if v, ok := Bots[[2]string{botplt, botid}]; ok {
|
|
if v.uuid != f.uuid {
|
|
go v.Destroy()
|
|
}
|
|
//
|
|
console.Warn("%s机器人%s因冲突销毁!", botplt, botid)
|
|
}
|
|
Bots[[2]string{botplt, botid}] = f
|
|
f.lm = make(chan bool, 10)
|
|
f.nm = 0
|
|
if botid != "" {
|
|
botid = fmt.Sprintf("(%s)", botid)
|
|
}
|
|
console.Log("%s机器人%s已初始化", botplt, botid)
|
|
go func() {
|
|
if f.uuid != "" {
|
|
su := &ScriptUtils{
|
|
script: plugins.GetString(f.uuid),
|
|
}
|
|
str := su.GetValue("message")
|
|
ss := regexp.MustCompile(`\S+`).FindAllString(str, -1)
|
|
if len(ss) == 0 {
|
|
ss = []string{f.botplt}
|
|
}
|
|
if ss[0] != f.botplt {
|
|
ss = []string{f.botplt}
|
|
}
|
|
nss := utils.Unique(ss, f.botid)
|
|
nstr := strings.Join(nss, " ")
|
|
if str != nstr {
|
|
su.SetValue("message", nstr)
|
|
plugins.Set(f.uuid, su.script)
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
|
|
func (f *Factory) Fail() int {
|
|
f.errorTimes++
|
|
if f.errorTimes > 5 {
|
|
go f.Destroy()
|
|
}
|
|
return f.errorTimes
|
|
}
|
|
|
|
func (f *Factory) GetBotID() string {
|
|
return f.botid
|
|
}
|
|
|
|
func (f *Factory) GetPlatform() string {
|
|
return f.botplt
|
|
}
|
|
|
|
func (f *Factory) Success() {
|
|
f.errorTimes = 0
|
|
}
|
|
|
|
func (f *Factory) IsAdapter(botid string) bool {
|
|
BotsLocker.RLock()
|
|
defer BotsLocker.RUnlock()
|
|
for i := range Bots {
|
|
id := i[0]
|
|
if botid == id {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (f *Factory) Masters() []string {
|
|
return strings.Split(strings.Trim(MakeBucket(f.botplt).GetString("masters"), "&"), "&")
|
|
}
|
|
|
|
func (f *Factory) Destroy() {
|
|
BotsLocker.Lock()
|
|
defer BotsLocker.Unlock()
|
|
f.Lock()
|
|
defer f.Unlock()
|
|
if f.destroid {
|
|
return
|
|
}
|
|
f.destroid = true
|
|
f.cancel()
|
|
close(f.msgChan)
|
|
delete(Bots, [2]string{f.botplt, f.botid})
|
|
botid := ""
|
|
if f.botid != "" {
|
|
botid = fmt.Sprintf("(%s)", f.botid)
|
|
} else {
|
|
botid = f.botid
|
|
}
|
|
console.Log("%s机器人%s已销毁", f.botplt, botid)
|
|
go func() {
|
|
if f.uuid != "" {
|
|
su := &ScriptUtils{
|
|
script: plugins.GetString(f.uuid),
|
|
}
|
|
str := su.GetValue("message")
|
|
if str == "" {
|
|
return
|
|
}
|
|
ss := regexp.MustCompile(`\S+`).FindAllString(str, -1)
|
|
if len(ss) == 0 {
|
|
return
|
|
}
|
|
if ss[0] != f.botplt {
|
|
ss = []string{f.botplt}
|
|
}
|
|
nss := utils.Unique(utils.Remove(ss, f.botid))
|
|
if len(nss) == 1 {
|
|
su.DeleteValue("message")
|
|
plugins.Set(f.uuid, su.script)
|
|
} else {
|
|
nstr := strings.Join(nss, " ")
|
|
if str != nstr {
|
|
su.SetValue("message", nstr)
|
|
plugins.Set(f.uuid, su.script)
|
|
}
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
|
|
func (f *Factory) Push(msg map[string]string) map[string]string {
|
|
var demo = *f.demo
|
|
var sender = &demo
|
|
fsps := &common.FakerSenderParams{
|
|
UserID: msg[USER_ID],
|
|
ChatID: msg[CHAT_ID],
|
|
}
|
|
if v, ok := msg[MESSAGE_ID]; ok {
|
|
fsps.MessageID = v
|
|
}
|
|
sender.SetFsps(fsps)
|
|
message_id, err := sender.Reply(msg[CONETNT], PUSH(""))
|
|
return map[string]string{
|
|
"message_id": message_id,
|
|
"error": ErrStr(err),
|
|
}
|
|
}
|
|
|
|
func (f *Factory) SetReplyHandler(function func(map[string]interface{}) string) {
|
|
f.reply = func(m map[string]interface{}) string {
|
|
// if f.uuid != "" {
|
|
// mutex := GetMutex(f.uuid)
|
|
// mutex.Lock()
|
|
// defer mutex.Unlock()
|
|
// }
|
|
defer func() {
|
|
err := recover()
|
|
if err != nil {
|
|
pluginConsole(f.uuid).Error("Sender(\""+f.botplt+"\").SetReply error:", err)
|
|
}
|
|
}()
|
|
return function(m)
|
|
}
|
|
}
|
|
|
|
func (f *Factory) SetActionHandler(function func(map[string]interface{}) string) {
|
|
f.action = func(m map[string]interface{}) string {
|
|
// if f.uuid != "" {
|
|
// mutex := GetMutex(f.uuid)
|
|
// mutex.Lock()
|
|
// defer mutex.Unlock()
|
|
// }
|
|
defer func() {
|
|
err := recover()
|
|
if err != nil {
|
|
pluginConsole(f.uuid).Error("Sender(\""+f.botplt+"\").SetAction error:", err)
|
|
}
|
|
}()
|
|
return function(m)
|
|
}
|
|
}
|
|
|
|
// func (f *Factory) GetReplies() {
|
|
|
|
// }
|
|
|
|
func GetReplyMessage(vm *goja.Runtime, plt string, bots_id []string) *goja.Promise {
|
|
promise, resolve, reject := vm.NewPromise()
|
|
adapters, err := GetAdapters(plt, bots_id...)
|
|
if err != nil {
|
|
go func() {
|
|
time.Sleep(time.Second)
|
|
reject(Error(vm, err))
|
|
}()
|
|
return promise
|
|
}
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
for i := range adapters {
|
|
go func(i int) {
|
|
select {
|
|
case <-ctx.Done():
|
|
logs.Debug("消息获取中断")
|
|
case <-adapters[i].ctx.Done():
|
|
cancel()
|
|
logs.Debug("%s adapter %s destroied", adapters[i].botplt, adapters[i].botid)
|
|
reject("adapter destroied")
|
|
case mc := <-adapters[i].msgChan:
|
|
cancel()
|
|
var msg = map[string]interface{}{}
|
|
for k, v := range mc.Msg {
|
|
msg[k] = v
|
|
}
|
|
obj := adapters[i].vm.NewObject()
|
|
for k, v := range mc.Msg {
|
|
obj.Set(k, v)
|
|
}
|
|
obj.Set("bot_id", adapters[i].botid)
|
|
// msg["bot_id"] = adapters[i].botid
|
|
// msg["setMessageId"] = func(id string) {
|
|
// select {
|
|
// case <-mc.Chan:
|
|
// case <-time.After(time.Millisecond):
|
|
// mc.Chan <- id
|
|
// }
|
|
// }
|
|
// resolve(msg)
|
|
resolve(vm.NewProxy(obj, &goja.ProxyTrapConfig{
|
|
Set: func(target *goja.Object, property string, value, receiver goja.Value) (success bool) {
|
|
if property == "message_id" {
|
|
select {
|
|
case <-mc.Chan:
|
|
return false
|
|
case <-time.After(time.Millisecond):
|
|
}
|
|
mc.Chan <- fmt.Sprint(value.Export())
|
|
}
|
|
return true
|
|
},
|
|
}))
|
|
}
|
|
}(i)
|
|
}
|
|
return promise
|
|
}
|
|
|
|
func (f *Factory) GetReplyMessage() interface{} {
|
|
select {
|
|
case <-f.ctx.Done():
|
|
logs.Debug("%s adapter %s destroied", f.botplt, f.botid)
|
|
panic(Error(f.vm, "adapter destroied"))
|
|
case mc := <-f.msgChan:
|
|
obj := f.vm.NewObject()
|
|
for k, v := range mc.Msg {
|
|
obj.Set(k, v)
|
|
}
|
|
return f.vm.NewProxy(obj, &goja.ProxyTrapConfig{
|
|
Set: func(target *goja.Object, property string, value, receiver goja.Value) (success bool) {
|
|
if property == "message_id" {
|
|
select {
|
|
case <-mc.Chan:
|
|
return false
|
|
case <-time.After(time.Millisecond):
|
|
}
|
|
mc.Chan <- fmt.Sprint(value.Export())
|
|
}
|
|
return true
|
|
},
|
|
})
|
|
}
|
|
}
|
|
|
|
func (f *Factory) GetUserMessages(user_id string, timeout int) []map[string]interface{} {
|
|
if timeout == 0 {
|
|
timeout = 2000
|
|
}
|
|
msgs := []map[string]interface{}{}
|
|
v, loaded := f.gmsgChan.LoadOrStore(user_id, &GMsgChan{})
|
|
ch := v.(*GMsgChan)
|
|
if !loaded {
|
|
// console.Debug("接收创建:", ch.Chan)
|
|
ch.Chan = make(chan map[string]interface{})
|
|
} else {
|
|
// console.Debug("接收加载:", ch.Chan)
|
|
}
|
|
if len(ch.Msgs) != 0 {
|
|
ch.Lock()
|
|
msgs = append(msgs, ch.Msgs...)
|
|
// console.Debug("数组接收:", msgs)
|
|
ch.Msgs = nil
|
|
ch.Unlock()
|
|
timeout = 1
|
|
}
|
|
for {
|
|
select {
|
|
case msg := <-ch.Chan:
|
|
msgs = append(msgs, msg)
|
|
timeout = 1
|
|
// console.Debug("管道接收:", msgs)
|
|
case <-time.After(time.Millisecond * time.Duration(timeout)):
|
|
// console.Debug("无消息")
|
|
goto HELL
|
|
}
|
|
}
|
|
HELL:
|
|
return msgs
|
|
}
|
|
|
|
func (f *Factory) GetMessages(timeout int) []interface{} {
|
|
if timeout == 0 {
|
|
timeout = 2000
|
|
}
|
|
msgs := []interface{}{}
|
|
for {
|
|
select {
|
|
case <-f.ctx.Done():
|
|
logs.Debug("%s adapter %s destroied", f.botplt, f.botid)
|
|
panic(Error(f.vm, "adapter destroied"))
|
|
case mc := <-f.msgChan:
|
|
obj := f.vm.NewObject()
|
|
for k, v := range mc.Msg {
|
|
obj.Set(k, v)
|
|
}
|
|
msgs = append(msgs, f.vm.NewProxy(obj, &goja.ProxyTrapConfig{
|
|
Set: func(target *goja.Object, property string, value, receiver goja.Value) (success bool) {
|
|
if property == "message_id" {
|
|
select {
|
|
case <-mc.Chan:
|
|
return false
|
|
case <-time.After(time.Millisecond):
|
|
}
|
|
mc.Chan <- fmt.Sprint(value.Export())
|
|
}
|
|
return true
|
|
},
|
|
}))
|
|
timeout = 1
|
|
case <-time.After(time.Millisecond * time.Duration(timeout)):
|
|
goto HELL
|
|
}
|
|
}
|
|
HELL:
|
|
return msgs
|
|
}
|
|
|
|
func (f *Factory) Send(function func(map[string]interface{}) string) {
|
|
f.SetReplyHandler(function)
|
|
}
|
|
|
|
func (f *Factory) SetIsAdmin(function func(string) bool) {
|
|
f.isAdmin = func(uid string) bool {
|
|
defer func() {
|
|
err := recover()
|
|
if err != nil {
|
|
pluginConsole(f.uuid).Error("Sender(\""+f.botplt+"\").SetAdmin error:", err)
|
|
}
|
|
}()
|
|
return function(uid)
|
|
}
|
|
}
|
|
|
|
func (f *Factory) Sender2(options map[string]string) *CustomSender {
|
|
var demo = *f.demo
|
|
sender := &demo
|
|
// sender.SetID()
|
|
if options != nil {
|
|
fsp := &common.FakerSenderParams{}
|
|
if v, ok := options[CONETNT]; ok {
|
|
fsp.Content = v
|
|
}
|
|
if v, ok := options[USER_ID]; ok {
|
|
fsp.UserID = v
|
|
}
|
|
if v, ok := options[CHAT_ID]; ok {
|
|
fsp.ChatID = v
|
|
}
|
|
if v, ok := options[MESSAGE_ID]; ok {
|
|
fsp.MessageID = v
|
|
}
|
|
sender.SetFsps(fsp)
|
|
}
|
|
return sender
|
|
}
|
|
|
|
func (f *Factory) Sender(options map[string]string) interface{} {
|
|
return &SenderJsIplm{
|
|
Message: f.Sender2(options),
|
|
Vm: f.vm,
|
|
Private: "private",
|
|
Group: "group",
|
|
Routine: "routine",
|
|
Persistent: "persistent",
|
|
UUID: f.uuid,
|
|
}
|
|
}
|
|
|
|
func (f *Factory) Receive(props map[string]interface{}) *CustomSender {
|
|
var demo = *f.demo
|
|
sender := &demo
|
|
// sender.SetID()
|
|
// console.Log("senderId", sender.GetID())
|
|
emf := map[string]interface{}{}
|
|
for i := range props {
|
|
h := false
|
|
switch strings.ToLower(i) {
|
|
case "content":
|
|
sender.details.Content = strings.TrimSpace(fmt.Sprint(props[i]))
|
|
h = true
|
|
case "message_id", "messageId":
|
|
sender.details.MessageID = utils.Itoa(props[i])
|
|
h = true
|
|
case "user_id", "userId":
|
|
sender.details.UserID = utils.Itoa(props[i])
|
|
h = true
|
|
case "chat_id", "chatId", "group_id", "groupId", "group_code", "groupCode":
|
|
sender.details.ChatID = ChatID(props[i])
|
|
h = true
|
|
case "user_name", "userName":
|
|
sender.details.Username = fmt.Sprint(props[i])
|
|
h = true
|
|
case "chat_name", "chatName", "groupName", "group_name":
|
|
sender.details.Chatname = fmt.Sprint(props[i])
|
|
h = true
|
|
}
|
|
if !h {
|
|
emf[i] = props[i]
|
|
}
|
|
}
|
|
sender.SetExpandMessageInfo(emf)
|
|
// if sender.details.Content != "" {
|
|
Messages <- sender
|
|
// }
|
|
return sender
|
|
}
|
|
|
|
func (sender *CustomSender) GetContent() string {
|
|
if sender.Fsps.Content != "" {
|
|
return sender.Fsps.Content
|
|
}
|
|
return sender.details.Content
|
|
}
|
|
func (sender *CustomSender) GetUserID() string {
|
|
if sender.Fsps.UserID != "" {
|
|
return sender.Fsps.UserID
|
|
}
|
|
return sender.details.UserID
|
|
}
|
|
func (sender *CustomSender) GetChatID() string {
|
|
if !utils.IsZeroOrEmpty(sender.Fsps.ChatID) {
|
|
return fmt.Sprint(sender.Fsps.ChatID)
|
|
}
|
|
return sender.details.ChatID
|
|
}
|
|
func (sender *CustomSender) GetImType() string {
|
|
return sender.F.botplt
|
|
}
|
|
func (sender *CustomSender) GetUserName() string {
|
|
return sender.details.Username
|
|
}
|
|
func (sender *CustomSender) GetChatName() string {
|
|
return sender.details.Chatname
|
|
}
|
|
func (sender *CustomSender) GetMessageID() string {
|
|
if sender.Fsps.MessageID != "" {
|
|
return sender.Fsps.MessageID
|
|
}
|
|
return sender.details.MessageID
|
|
}
|
|
func (sender *CustomSender) GetReplySenderUserID() int {
|
|
if !sender.IsReply() {
|
|
return 0
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func (sender *CustomSender) GetBotID() string {
|
|
return sender.F.botid
|
|
}
|
|
|
|
type PUSH string
|
|
|
|
func (sender *CustomSender) Action(options map[string]interface{}) (interface{}, error) {
|
|
if sender.F.action != nil {
|
|
|
|
return sender.F.action(options), nil
|
|
}
|
|
var platform = sender.F.botplt
|
|
var any *common.Function
|
|
var one *common.Function
|
|
var result interface{}
|
|
var err error
|
|
for _, function := range Functions {
|
|
if function.Reply != nil && function.Reply.Platform == platform {
|
|
if len(function.Reply.BotsID) == 0 {
|
|
any = function
|
|
} else if Contains(function.Reply.BotsID, sender.F.botid) {
|
|
one = function
|
|
}
|
|
}
|
|
}
|
|
if one == nil && any != nil {
|
|
one = any
|
|
}
|
|
if one != nil {
|
|
one.Handle(&CustomSender{
|
|
F: &Factory{
|
|
botplt: "action",
|
|
},
|
|
}, func(vm *goja.Runtime) {
|
|
obj := vm.NewObject()
|
|
for k, v := range options {
|
|
obj.Set(k, v)
|
|
}
|
|
proxy := vm.NewProxy(obj, &goja.ProxyTrapConfig{
|
|
Set: func(target *goja.Object, property string, value, receiver goja.Value) (success bool) {
|
|
if property == "result" {
|
|
result = value
|
|
}
|
|
if property == "error" {
|
|
err = errors.New(value.String())
|
|
}
|
|
return true
|
|
},
|
|
})
|
|
vm.Set("action", proxy)
|
|
vm.Set("adapter", sender.F)
|
|
})
|
|
|
|
}
|
|
return result, err
|
|
}
|
|
|
|
func (sender *CustomSender) Reply(msgs ...interface{}) (string, error) {
|
|
var push = false
|
|
var platform = sender.F.botplt
|
|
var bot_id = sender.F.botid
|
|
var args = []interface{}{}
|
|
for _, item := range msgs {
|
|
switch item := item.(type) {
|
|
case PUSH:
|
|
push = true
|
|
case string:
|
|
args = append(args, item)
|
|
default:
|
|
if item != nil {
|
|
args = append(args, fmt.Sprint(item))
|
|
}
|
|
}
|
|
}
|
|
if len(args) == 0 {
|
|
return "", nil //errors.New("s.reply has no content")
|
|
}
|
|
content := utils.FormatLog(args[0], args[1:]...)
|
|
if !push {
|
|
if IsNoReplyGroup(sender) {
|
|
return "", errors.New("is no reply group")
|
|
}
|
|
}
|
|
content = strings.ReplaceAll(content, "\n\r", "\n")
|
|
content = strings.ReplaceAll(content, "\r\n", "\n")
|
|
content = strings.ReplaceAll(content, "\r", "\n")
|
|
content = regexp.MustCompile("[\n]{3,}").ReplaceAllString(content, "\n\n")
|
|
if content != "" {
|
|
user_id := sender.GetUserID()
|
|
msg := map[string]interface{}{
|
|
"message_id": sender.GetMessageID(),
|
|
"content": content,
|
|
"user_id": user_id,
|
|
"chat_id": sender.GetChatID(),
|
|
"bot_id": bot_id,
|
|
// "uuid": utils.GenUUID(),
|
|
}
|
|
for k, v := range sender.GetExpandMessageInfo() {
|
|
msg[k] = v
|
|
}
|
|
if sender.F.umod { //订阅号模式
|
|
v, loaded := sender.F.gmsgChan.LoadOrStore(user_id, &GMsgChan{})
|
|
ch := v.(*GMsgChan)
|
|
if !loaded {
|
|
// console.Debug("发送创建:", ch.Chan)
|
|
ch.Chan = make(chan map[string]interface{})
|
|
} else {
|
|
// console.Debug("发送加载:", ch.Chan)
|
|
}
|
|
select {
|
|
case ch.Chan <- msg:
|
|
// console.Debug("管道发送:", msg, ch.Chan)
|
|
case <-time.After(time.Second):
|
|
ch.Lock()
|
|
defer ch.Unlock()
|
|
ch.Msgs = append(ch.Msgs, msg)
|
|
// console.Debug("数组发送:", msg)
|
|
}
|
|
return "", nil
|
|
}
|
|
if sender.F.reply == nil { //未设置回复函数
|
|
var any *common.Function
|
|
var one *common.Function
|
|
for _, function := range Functions {
|
|
if function.Reply != nil && function.Reply.Platform == platform {
|
|
if len(function.Reply.BotsID) == 0 {
|
|
any = function
|
|
} else if Contains(function.Reply.BotsID, sender.F.botid) {
|
|
one = function
|
|
}
|
|
}
|
|
}
|
|
if one == nil && any != nil {
|
|
one = any
|
|
}
|
|
if one != nil {
|
|
message_id := ""
|
|
one.Handle(&CustomSender{
|
|
F: &Factory{
|
|
botplt: "message",
|
|
},
|
|
}, func(vm *goja.Runtime) {
|
|
obj := vm.NewObject()
|
|
for k, v := range msg {
|
|
obj.Set(k, v)
|
|
}
|
|
proxy := vm.NewProxy(obj, &goja.ProxyTrapConfig{
|
|
Set: func(target *goja.Object, property string, value, receiver goja.Value) (success bool) {
|
|
message_id = fmt.Sprint(value.Export())
|
|
return true
|
|
},
|
|
})
|
|
vm.Set("msg", proxy)
|
|
vm.Set("message", proxy)
|
|
vm.Set("adapter", sender.F)
|
|
})
|
|
return message_id, nil
|
|
} else { //存储消息
|
|
c := MsgChan{
|
|
Msg: msg,
|
|
Chan: make(chan string),
|
|
}
|
|
if sender.F.destroid {
|
|
return "", errors.New("adapter destroid")
|
|
}
|
|
sender.F.msgChan <- c
|
|
select {
|
|
case id := <-c.Chan:
|
|
return id, nil
|
|
case <-time.After(time.Second * 5):
|
|
close(c.Chan)
|
|
return "", errors.New("获取消息ID超时")
|
|
}
|
|
}
|
|
} else {
|
|
//todo 阻塞延迟异常
|
|
v := sender.F.reply(msg)
|
|
return v, nil
|
|
}
|
|
}
|
|
return "", nil
|
|
}
|
|
|
|
const (
|
|
MESSAGE_ID = "message_id"
|
|
CONETNT = "content"
|
|
USER_ID = "user_id"
|
|
CHAT_ID = "chat_id"
|
|
IS_ADMIN = "is_admin"
|
|
// UUID = "message_id"
|
|
)
|
|
|
|
func (sender *CustomSender) Copy() common.Sender {
|
|
new := reflect.Indirect(reflect.ValueOf(interface{}(sender))).Interface().(CustomSender)
|
|
return &new
|
|
}
|
|
|
|
func (sender *CustomSender) Event() map[string]interface{} {
|
|
e := sender.GetVar("event")
|
|
if e == nil {
|
|
return nil
|
|
}
|
|
return e.(map[string]interface{})
|
|
}
|
|
|
|
func (sender *CustomSender) RecallMessage(ps ...interface{}) {
|
|
recalls := []func(){}
|
|
var timeout int
|
|
for _, p := range ps {
|
|
switch p := p.(type) {
|
|
case int, int64:
|
|
timeout = utils.Int(p)
|
|
case string:
|
|
if p != "" {
|
|
recalls = append(recalls, func() {
|
|
sender.Action(H{
|
|
"type": "delete_message",
|
|
"message_id": p,
|
|
})
|
|
})
|
|
}
|
|
case []string:
|
|
for _, v := range p {
|
|
if v != "" {
|
|
recalls = append(recalls, func() {
|
|
sender.Action(H{
|
|
"type": "delete_message",
|
|
"message_id": v,
|
|
})
|
|
})
|
|
}
|
|
}
|
|
case [][]string:
|
|
for _, v := range p {
|
|
for _, v2 := range v {
|
|
recalls = append(recalls, func() {
|
|
sender.Action(H{
|
|
"type": "delete_message",
|
|
"message_id": v2,
|
|
})
|
|
})
|
|
}
|
|
}
|
|
}
|
|
}
|
|
go func() {
|
|
if timeout != 0 {
|
|
time.Sleep(time.Millisecond * time.Duration(timeout))
|
|
}
|
|
for _, recall := range recalls {
|
|
recall()
|
|
}
|
|
}()
|
|
}
|
|
|
|
func (sender *CustomSender) GroupKick(uid string, reject_add_request bool) error {
|
|
_, err := sender.Reply(mystr.BuildCQCode("kick", H{"user_id": uid, "chat_id": sender.GetChatID(), "forever": reject_add_request}, ""))
|
|
return err
|
|
}
|
|
|
|
func (sender *CustomSender) GroupBan(uid string, duration int) error {
|
|
_, err := sender.Reply(mystr.BuildCQCode("ban", H{"user_id": uid, "chat_id": sender.GetChatID(), "duration": duration}, ""))
|
|
return err
|
|
}
|
|
|
|
func (sender *CustomSender) GroupUnban(uid string) error {
|
|
_, err := sender.Reply(mystr.BuildCQCode("ban", H{"user_id": uid, "chat_id": sender.GetChatID(), "duration": 0}, ""))
|
|
return err
|
|
}
|
|
|
|
func (sender *CustomSender) IsAdmin() bool {
|
|
if sender.F.isAdmin == nil {
|
|
return Contains(strings.Split(MakeBucket(sender.F.botplt).GetString("masters"), "&"), sender.GetUserID())
|
|
}
|
|
return sender.F.isAdmin(sender.GetUserID())
|
|
}
|