first commit
This commit is contained in:
@@ -0,0 +1,555 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/cdle/sillyplus/core/common"
|
||||
"github.com/cdle/sillyplus/utils"
|
||||
)
|
||||
|
||||
var RegistedSenders = map[string]func() common.Sender{}
|
||||
|
||||
type Faker struct {
|
||||
Message string
|
||||
Type string
|
||||
UserID string
|
||||
ChatID string
|
||||
Carry chan string
|
||||
BaseSender
|
||||
Admin bool
|
||||
}
|
||||
|
||||
func (sender *Faker) Listen() chan string {
|
||||
return sender.Carry
|
||||
}
|
||||
|
||||
func (sender *Faker) GetContent() string {
|
||||
if sender.Fsps.Content != "" {
|
||||
return sender.Fsps.Content
|
||||
}
|
||||
return sender.Message
|
||||
}
|
||||
|
||||
func (sender *Faker) GetUserID() string {
|
||||
return sender.UserID
|
||||
}
|
||||
|
||||
func (sender *Faker) GetBotID() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (sender *Faker) GetChatID() string {
|
||||
return sender.ChatID
|
||||
}
|
||||
|
||||
func (sender *Faker) GetImType() string {
|
||||
if sender.Type == "" {
|
||||
return "fake"
|
||||
}
|
||||
return sender.Type
|
||||
}
|
||||
|
||||
func (sender *Faker) GetMessageID() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (sender *Faker) GetUserName() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (sender *Faker) GetChatName() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (sender *Faker) IsReply() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (sender *Faker) GetReplyUserID() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (sender *Faker) GetRawMessage() interface{} {
|
||||
return sender.Message
|
||||
}
|
||||
|
||||
func (sender *Faker) IsAdmin() bool {
|
||||
return sender.Admin
|
||||
}
|
||||
|
||||
func (sender *Faker) IsMedia() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (sender *Faker) Reply(msgs ...interface{}) (string, error) {
|
||||
rt := ""
|
||||
for _, msg := range msgs {
|
||||
switch msg := msg.(type) {
|
||||
case []byte:
|
||||
rt = (string(msg))
|
||||
case string:
|
||||
rt = msg
|
||||
}
|
||||
}
|
||||
{
|
||||
|
||||
for _, v := range regexp.MustCompile(`\[CQ:image,file=([^\[\]]+)\]`).FindAllStringSubmatch(rt, -1) {
|
||||
// qr := qrcode2console.NewQRCode2ConsoleWithUrl(v[1], true)
|
||||
// defer qr.Output()
|
||||
rt = strings.Replace(rt, fmt.Sprintf(`[CQ:image,file=%s]`, v[1]), "", -1)
|
||||
}
|
||||
}
|
||||
|
||||
// if rt != "" && n != nil {
|
||||
// NotifyMasters(rt)
|
||||
// }
|
||||
|
||||
// if rt != "" && sender.Carry != nil {
|
||||
// sender.Carry <- rt
|
||||
// }
|
||||
|
||||
if rt != "" && sender.Type == "terminal" {
|
||||
fmt.Printf("\x1b[%dm%s \x1b[0m\n", 31, rt)
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (sender *Faker) Delete() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sender *Faker) Disappear(lifetime ...time.Duration) {
|
||||
|
||||
}
|
||||
|
||||
func (sender *Faker) Finish() {
|
||||
if sender.Carry != nil {
|
||||
close(sender.Carry)
|
||||
}
|
||||
}
|
||||
|
||||
func (sender *Faker) Copy() common.Sender {
|
||||
new := reflect.Indirect(reflect.ValueOf(interface{}(sender))).Interface().(Faker)
|
||||
return &new
|
||||
}
|
||||
|
||||
func (sender *Faker) GroupKick(uid string, reject_add_request bool) {
|
||||
|
||||
}
|
||||
|
||||
func (sender *Faker) GroupBan(uid string, duration int) {
|
||||
|
||||
}
|
||||
|
||||
type BaseSender struct {
|
||||
matches [][]string
|
||||
goon bool
|
||||
Fsps common.FakerSenderParams
|
||||
Atlast bool
|
||||
ToSendMessages []string
|
||||
IsFinished bool
|
||||
Duration *time.Duration
|
||||
mark interface{}
|
||||
params []string
|
||||
level int
|
||||
}
|
||||
|
||||
func (sender *BaseSender) SetLevel(l int) {
|
||||
sender.level = l
|
||||
}
|
||||
|
||||
func (sender *BaseSender) GetLevel() int {
|
||||
return sender.level
|
||||
}
|
||||
|
||||
func (sender *BaseSender) SetMark(mark interface{}) {
|
||||
sender.mark = mark
|
||||
}
|
||||
|
||||
func (sender *BaseSender) GetMark() interface{} {
|
||||
return sender.mark
|
||||
}
|
||||
|
||||
func (sender *BaseSender) SetMatch(ss []string) {
|
||||
sender.matches = [][]string{ss}
|
||||
}
|
||||
func (sender *BaseSender) SetParams(ss []string) {
|
||||
sender.params = ss
|
||||
}
|
||||
func (sender *BaseSender) SetAllMatch(ss [][]string) {
|
||||
sender.matches = ss
|
||||
}
|
||||
|
||||
func (sender *BaseSender) SetContent(content string) {
|
||||
sender.Fsps.Content = content
|
||||
}
|
||||
|
||||
func (sender *BaseSender) SetFsps(fsps *common.FakerSenderParams) {
|
||||
sender.Fsps = *fsps
|
||||
}
|
||||
|
||||
func (sender *BaseSender) GetMatch() []string {
|
||||
return sender.matches[0]
|
||||
}
|
||||
|
||||
func (sender *BaseSender) GetAllMatch() [][]string {
|
||||
return sender.matches
|
||||
}
|
||||
|
||||
func (sender *BaseSender) Continue() {
|
||||
sender.goon = true
|
||||
}
|
||||
|
||||
func (sender *BaseSender) IsContinue() bool {
|
||||
return sender.goon
|
||||
}
|
||||
|
||||
func (sender *BaseSender) ClearContinue() {
|
||||
sender.goon = false
|
||||
}
|
||||
|
||||
func (sender *BaseSender) Get(i interface{}) string {
|
||||
switch i := i.(type) {
|
||||
case int:
|
||||
if len(sender.matches) == 0 {
|
||||
return ""
|
||||
}
|
||||
if len(sender.matches[0]) < i+1 {
|
||||
return ""
|
||||
}
|
||||
return sender.matches[0][i]
|
||||
case string:
|
||||
for j := range sender.params {
|
||||
if sender.params[j] == i {
|
||||
return sender.Get(j)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (sender *BaseSender) Delete() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sender *BaseSender) Disappear(lifetime ...time.Duration) {
|
||||
|
||||
}
|
||||
|
||||
func (sender *BaseSender) Finish() {
|
||||
sender.IsFinished = true
|
||||
}
|
||||
|
||||
func (sender *BaseSender) IsMedia() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (sender *BaseSender) GetRawMessage() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sender *BaseSender) IsReply() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (sender *BaseSender) GetMessageID() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (sender *BaseSender) RecallMessage(...interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sender *BaseSender) GetUserID() string {
|
||||
return ""
|
||||
}
|
||||
func (sender *BaseSender) GetChatID() string {
|
||||
return ""
|
||||
}
|
||||
func (sender *BaseSender) Push(msg map[string]string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
func (sender *BaseSender) GetImType() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (sender *BaseSender) GroupKick(uid string, reject_add_request bool) {
|
||||
|
||||
}
|
||||
|
||||
func (sender *BaseSender) GroupUnkick(uid string) {
|
||||
|
||||
}
|
||||
|
||||
func (sender *BaseSender) GroupBan(uid string, duration int) {
|
||||
|
||||
}
|
||||
|
||||
func (sender *BaseSender) GroupUnban(uid string) {
|
||||
|
||||
}
|
||||
|
||||
func (sender *BaseSender) GetUserName() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (sender *BaseSender) IsAdmin() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (sender *BaseSender) GetChatName() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (sender *BaseSender) GetReplyUserID() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (sender *BaseSender) GetReplyMessageID() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (sender *BaseSender) AtLast() {
|
||||
sender.Atlast = true
|
||||
}
|
||||
|
||||
func (sender *BaseSender) UAtLast() {
|
||||
sender.Atlast = false
|
||||
}
|
||||
|
||||
func (sender *BaseSender) Stop() {
|
||||
panic("stop")
|
||||
}
|
||||
|
||||
func (sender *BaseSender) IsAtLast() bool {
|
||||
return sender.Atlast
|
||||
}
|
||||
|
||||
func (sender *BaseSender) MessagesToSend() string {
|
||||
return strings.Join(sender.ToSendMessages, "\n")
|
||||
}
|
||||
|
||||
var ErrorTimeOut = errors.New("指令超时")
|
||||
var ErrorInterrupt = errors.New("被其他指令中断")
|
||||
|
||||
type Carrys struct {
|
||||
list map[int64]*Carry
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
func (cs *Carrys) Add(key int64, c *Carry) {
|
||||
// logs.Info("add", c.Function.Rules)
|
||||
cs.Lock()
|
||||
defer cs.Unlock()
|
||||
cs.list[key] = c
|
||||
}
|
||||
|
||||
func (cs *Carrys) Remove(Key1 int64) {
|
||||
cs.Lock()
|
||||
defer cs.Unlock()
|
||||
for key := range cs.list {
|
||||
if key == Key1 {
|
||||
// logs.Info("rem", cs.list[key].Function.Rules)
|
||||
delete(cs.list, Key1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (cs *Carrys) RemoveByUUID(uuid string) {
|
||||
cs.Foreach(func(key int64, c *Carry) bool {
|
||||
if c.UUID == uuid {
|
||||
cs.Remove(key)
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
func (cs *Carrys) Foreach(f func(key int64, c *Carry) bool) {
|
||||
cs.RLock()
|
||||
defer cs.RUnlock()
|
||||
for key, c := range cs.list {
|
||||
f(key, c)
|
||||
}
|
||||
}
|
||||
|
||||
var waits = map[int]*Carrys{
|
||||
1: {
|
||||
list: map[int64]*Carry{},
|
||||
},
|
||||
2: {
|
||||
list: map[int64]*Carry{},
|
||||
},
|
||||
3: {
|
||||
list: map[int64]*Carry{},
|
||||
},
|
||||
4: {
|
||||
list: map[int64]*Carry{},
|
||||
},
|
||||
5: {
|
||||
list: map[int64]*Carry{},
|
||||
},
|
||||
}
|
||||
|
||||
type Carry struct {
|
||||
// Rules []string
|
||||
Chan chan interface{}
|
||||
Result chan interface{}
|
||||
Message common.Sender
|
||||
Function common.Function
|
||||
RequireAdmin bool
|
||||
AllowPlatforms []string
|
||||
ProhibitPlatforms []string
|
||||
AllowGroups []string
|
||||
ProhibitGroups []string
|
||||
AllowUsers []string
|
||||
ProhibitUsers []string
|
||||
ListenPrivate bool
|
||||
ListenGroup bool
|
||||
UserID string
|
||||
ChatID string
|
||||
UUID string
|
||||
}
|
||||
|
||||
type again string
|
||||
|
||||
var Again again = ""
|
||||
|
||||
var GoAgain = func(str string) again {
|
||||
return again(str)
|
||||
}
|
||||
|
||||
type YesOrNo string
|
||||
|
||||
var YesNo YesOrNo = "yeson"
|
||||
var Yes YesOrNo = "yes"
|
||||
var No YesOrNo = "no"
|
||||
|
||||
type Range []int
|
||||
|
||||
type Switch []string
|
||||
|
||||
var listenCounter int64
|
||||
|
||||
func (s *BaseSender) Await(message common.Sender, callback func(common.Sender) interface{}, params ...interface{}) interface{} {
|
||||
timeout := time.Hour * 999999
|
||||
var handleErr func(error)
|
||||
var persistent = false
|
||||
var c *Carry
|
||||
for _, param := range params {
|
||||
switch param := param.(type) {
|
||||
case string:
|
||||
if param == "persistent" {
|
||||
persistent = true
|
||||
} else {
|
||||
c.Function.Rules = append(c.Function.Rules, param)
|
||||
}
|
||||
case []string:
|
||||
c.Function.Rules = append(c.Function.Rules, param...)
|
||||
case time.Duration:
|
||||
du := param
|
||||
if du != 0 {
|
||||
timeout = du
|
||||
}
|
||||
case func(error):
|
||||
handleErr = param
|
||||
case *Carry:
|
||||
c = param
|
||||
}
|
||||
}
|
||||
c.Message = message
|
||||
if len(c.Function.Rules) == 0 {
|
||||
c.Function.Rules = []string{`raw [\s\S]+`}
|
||||
}
|
||||
fmtRule(&c.Function)
|
||||
c.Chan = make(chan interface{}, 1)
|
||||
c.Result = make(chan interface{}, 1)
|
||||
key := atomic.AddInt64(&listenCounter, 1)
|
||||
// key := fmt.Sprintf("u=%v&c=%v&i=%v&t=%v&p=%v", message.GetUserID(), message.GetChatID(), message.GetImType(), atomic.LoadInt64(&listenCounter))
|
||||
// if fg != nil {
|
||||
// if *fg == "me" {
|
||||
// key += "&f=me"
|
||||
// } else {
|
||||
// key += "&f=true"
|
||||
// }
|
||||
// }
|
||||
waits[4-s.level].Add(key, c)
|
||||
defer func() {
|
||||
waits[4-s.level].Remove(key)
|
||||
}()
|
||||
for {
|
||||
select {
|
||||
case result := <-c.Chan:
|
||||
switch s := result.(type) {
|
||||
case common.Sender:
|
||||
if callback == nil {
|
||||
return s.GetContent()
|
||||
}
|
||||
if persistent {
|
||||
go func() {
|
||||
c.Result <- callback(s)
|
||||
}()
|
||||
continue
|
||||
}
|
||||
result := callback(s)
|
||||
if v, ok := result.(again); ok { //阻塞
|
||||
if v == "" {
|
||||
c.Result <- nil
|
||||
} else {
|
||||
c.Result <- string(v)
|
||||
}
|
||||
} else if _, ok := result.(YesOrNo); ok {
|
||||
o := strings.ToLower(regexp.MustCompile("[yYnN]").FindString(s.GetContent()))
|
||||
if o == "y" {
|
||||
return Yes
|
||||
}
|
||||
if o == "n" {
|
||||
return No
|
||||
}
|
||||
c.Result <- "Y or n ?"
|
||||
} else if vv, ok := result.(Switch); ok {
|
||||
ct := s.GetContent()
|
||||
for _, v := range vv {
|
||||
if ct == v {
|
||||
return v
|
||||
}
|
||||
}
|
||||
c.Result <- fmt.Sprintf("请从%s中选择一个。", strings.Join(vv, "、"))
|
||||
} else if vv, ok := result.(Range); ok {
|
||||
ct := s.GetContent()
|
||||
n := utils.Int(ct)
|
||||
if fmt.Sprint(n) == ct {
|
||||
if (n >= vv[0]) && (n <= vv[1]) {
|
||||
|
||||
return n
|
||||
}
|
||||
}
|
||||
c.Result <- fmt.Sprintf("请从%d~%d中选择一个整数。", vv[0], vv[1])
|
||||
} else {
|
||||
c.Result <- result
|
||||
return s.GetContent()
|
||||
}
|
||||
|
||||
case error:
|
||||
if handleErr != nil {
|
||||
handleErr(s)
|
||||
}
|
||||
c.Result <- nil
|
||||
return nil
|
||||
}
|
||||
case <-time.After(timeout):
|
||||
if handleErr != nil {
|
||||
handleErr(ErrorTimeOut)
|
||||
}
|
||||
c.Result <- nil
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user