diff --git a/core/function.go b/core/function.go index 32a94c0..eaa7aac 100644 --- a/core/function.go +++ b/core/function.go @@ -1,6 +1,7 @@ package core import ( + "fmt" "os" "regexp" "strings" @@ -56,7 +57,6 @@ func AddCommand(prefix string, cmds []Function) { if prefix != "" { cmds[j].Rules[i] = prefix + `\s+` + cmds[j].Rules[i] } - cmds[j].Rules[i] = strings.Replace(cmds[j].Rules[i], "(", `[(]`, -1) cmds[j].Rules[i] = strings.Replace(cmds[j].Rules[i], ")", `[)]`, -1) cmds[j].Rules[i] = regexp.MustCompile(`\?$`).ReplaceAllString(cmds[j].Rules[i], `(.+)`) @@ -80,6 +80,15 @@ func AddCommand(prefix string, cmds []Function) { func handleMessage(sender Sender) { defer sender.Finish() + key := fmt.Sprintf("u=%v&c=%v&i=%v", sender.GetUserID(), sender.GetChatID(), sender.GetImType()) + if v, ok := waits.Load(key); ok { + c := v.(Carry) + if m := regexp.MustCompile(c.Pattern).FindString(sender.GetContent()); m != "" { + c.Chan <- m + sender.Reply(<-c.Result) + return + } + } for _, function := range functions { for _, rule := range function.Rules { var matched bool diff --git a/core/im.go b/core/im.go index 0085bbd..2be3f9f 100644 --- a/core/im.go +++ b/core/im.go @@ -1,6 +1,9 @@ package core import ( + "errors" + "fmt" + "sync" "time" ) @@ -27,6 +30,7 @@ type Sender interface { Finish() Continue() IsContinue() bool + Await(func(string, error) interface{}, ...interface{}) } type Edit int @@ -196,3 +200,65 @@ func (sender *BaseSender) IsReply() bool { func (sender *BaseSender) GetMessageID() int { return 0 } + +func (sender *BaseSender) GetUserID() interface{} { + return nil +} +func (sender *BaseSender) GetChatID() interface{} { + return nil +} +func (sender *BaseSender) GetImType() string { + return "" +} + +var TimeOutError = errors.New("指令超时") +var InterruptError = errors.New("被其他指令中断") + +var waits sync.Map + +type Carry struct { + Chan chan interface{} + Pattern string + Result chan interface{} +} + +func (sender *BaseSender) Await(callback func(string, error) interface{}, params ...interface{}) { + c := Carry{} + timeout := time.Second * 20 + for _, param := range params { + switch param.(type) { + case string: + c.Pattern = param.(string) + case time.Duration: + timeout = param.(time.Duration) + case func() string: + callback = param.(func(string, error) interface{}) + } + } + if callback == nil { + return + } + if c.Pattern == "" { + return + } + c.Chan = make(chan interface{}, 1) + c.Result = make(chan interface{}, 1) + key := fmt.Sprintf("u=%v&c=%v&i=%v", sender.GetUserID(), sender.GetChatID(), sender.GetImType()) + if oc, ok := waits.LoadOrStore(key, c); ok { + oc.(Carry).Chan <- InterruptError + } + defer waits.Delete(key) + select { + case result := <-c.Chan: + switch result.(type) { + case string: + c.Result <- callback(result.(string), nil) + return + case error: + c.Result <- callback("", result.(error)) + } + return + case <-time.After(timeout): + c.Result <- callback("", TimeOutError) + } +} diff --git a/core/test.go b/core/test.go index ae61206..24c134d 100644 --- a/core/test.go +++ b/core/test.go @@ -161,8 +161,18 @@ func initSys() { if !IsBucket(b) { return errors.New("不存在的存储桶") } + old := b.Get(s.Get(1)) b.Set(s.Get(1), s.Get(2)) - return "设置成功" + go func() { + s.Await(func(_ string, e error) interface{} { + if e != nil { + return nil + } + b.Set(s.Get(1), old) + return "已撤回。" + }, "^撤回$", time.Second*60) + }() + return "操作成功,如果你后悔了,请在60s内对我说\"撤回\",即可撤销本次操作。" }, }, { diff --git a/im/wxmp/init.go b/im/wxmp/init.go index 5de9ea4..8c55b61 100644 --- a/im/wxmp/init.go +++ b/im/wxmp/init.go @@ -45,6 +45,7 @@ func init() { sender.uid = int(time.Now().UnixNano()) u2i.Set(msg.FromUserName, sender.uid) } + core.Senders <- sender end := <-sender.Wait ss := []string{}