mirror of
https://github.com/Mrs4s/go-cqhttp.git
synced 2025-05-07 20:45:53 +08:00
Merge pull request #659 from wdvxdr1123/patch/cqcode_fast
⚡ Speed up cqcode parsing
This commit is contained in:
commit
65112f8752
188
coolq/cqcode.go
188
coolq/cqcode.go
@ -4,21 +4,23 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
goBinary "encoding/binary"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
xml2 "encoding/xml"
|
xml2 "encoding/xml"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
"github.com/Mrs4s/MiraiGo/binary"
|
"github.com/Mrs4s/MiraiGo/binary"
|
||||||
"github.com/Mrs4s/MiraiGo/message"
|
"github.com/Mrs4s/MiraiGo/message"
|
||||||
@ -40,6 +42,26 @@ var IgnoreInvalidCQCode = false
|
|||||||
// SplitURL 是否分割URL
|
// SplitURL 是否分割URL
|
||||||
var SplitURL = false
|
var SplitURL = false
|
||||||
|
|
||||||
|
// magicCQ 代表 uint32([]byte("[CQ:"))
|
||||||
|
var magicCQ = uint32(0)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
const sizeInt = int(unsafe.Sizeof(0))
|
||||||
|
x := 0x1234
|
||||||
|
p := unsafe.Pointer(&x)
|
||||||
|
p2 := (*[sizeInt]byte)(p)
|
||||||
|
if p2[0] == 0 {
|
||||||
|
magicCQ = goBinary.BigEndian.Uint32([]byte("[CQ:"))
|
||||||
|
} else {
|
||||||
|
magicCQ = goBinary.LittleEndian.Uint32([]byte("[CQ:"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add 指针运算
|
||||||
|
func add(ptr unsafe.Pointer, offset uintptr) unsafe.Pointer {
|
||||||
|
return unsafe.Pointer(uintptr(ptr) + offset)
|
||||||
|
}
|
||||||
|
|
||||||
const maxImageSize = 1024 * 1024 * 30 // 30MB
|
const maxImageSize = 1024 * 1024 * 30 // 30MB
|
||||||
const maxVideoSize = 1024 * 1024 * 100 // 100MB
|
const maxVideoSize = 1024 * 1024 * 100 // 100MB
|
||||||
// PokeElement 拍一拍
|
// PokeElement 拍一拍
|
||||||
@ -335,66 +357,14 @@ func ToStringMessage(e []message.IMessageElement, id int64, isRaw ...bool) (r st
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ConvertStringMessage 将消息字符串转为消息元素数组
|
// ConvertStringMessage 将消息字符串转为消息元素数组
|
||||||
func (bot *CQBot) ConvertStringMessage(msg string, isGroup bool) (r []message.IMessageElement) {
|
func (bot *CQBot) ConvertStringMessage(s string, isGroup bool) (r []message.IMessageElement) {
|
||||||
index := 0
|
var t, key string
|
||||||
stat := 0
|
var d map[string]string
|
||||||
rMsg := []rune(msg)
|
ptr := unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&s)).Data)
|
||||||
var tempText, cqCode []rune
|
l := len(s)
|
||||||
hasNext := func() bool {
|
i, j, CQBegin := 0, 0, 0
|
||||||
return index < len(rMsg)
|
|
||||||
}
|
|
||||||
next := func() rune {
|
|
||||||
r := rMsg[index]
|
|
||||||
index++
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
move := func(steps int) {
|
|
||||||
index += steps
|
|
||||||
}
|
|
||||||
peekN := func(count int) string {
|
|
||||||
lastIdx := int(math.Min(float64(index+count), float64(len(rMsg))))
|
|
||||||
return string(rMsg[index:lastIdx])
|
|
||||||
}
|
|
||||||
isCQCodeBegin := func(r rune) bool {
|
|
||||||
return r == '[' && peekN(3) == "CQ:"
|
|
||||||
}
|
|
||||||
saveTempText := func() {
|
|
||||||
if len(tempText) != 0 {
|
|
||||||
if SplitURL {
|
|
||||||
for _, t := range global.SplitURL(CQCodeUnescapeText(string(tempText))) {
|
|
||||||
r = append(r, message.NewText(t))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
r = append(r, message.NewText(CQCodeUnescapeText(string(tempText))))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tempText = []rune{}
|
|
||||||
cqCode = []rune{}
|
|
||||||
}
|
|
||||||
saveCQCode := func() {
|
saveCQCode := func() {
|
||||||
defer func() {
|
|
||||||
cqCode = []rune{}
|
|
||||||
tempText = []rune{}
|
|
||||||
}()
|
|
||||||
s := strings.SplitN(string(cqCode), ",", -1)
|
|
||||||
if len(s) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
t := s[0]
|
|
||||||
params := make(map[string]string)
|
|
||||||
for i := 1; i < len(s); i++ {
|
|
||||||
p := s[i]
|
|
||||||
p = strings.TrimSpace(p)
|
|
||||||
if p == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
data := strings.SplitN(p, "=", 2)
|
|
||||||
if len(data) == 2 {
|
|
||||||
params[data[0]] = CQCodeUnescapeValue(data[1])
|
|
||||||
} else {
|
|
||||||
params[p] = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if t == "reply" { // reply 特殊处理
|
if t == "reply" { // reply 特殊处理
|
||||||
if len(r) > 0 {
|
if len(r) > 0 {
|
||||||
if _, ok := r[0].(*message.ReplyElement); ok {
|
if _, ok := r[0].(*message.ReplyElement); ok {
|
||||||
@ -402,8 +372,8 @@ func (bot *CQBot) ConvertStringMessage(msg string, isGroup bool) (r []message.IM
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mid, err := strconv.Atoi(params["id"])
|
mid, err := strconv.Atoi(d["id"])
|
||||||
customText := params["text"]
|
customText := d["text"]
|
||||||
if err == nil {
|
if err == nil {
|
||||||
org := bot.GetMessage(int32(mid))
|
org := bot.GetMessage(int32(mid))
|
||||||
if org != nil {
|
if org != nil {
|
||||||
@ -418,12 +388,12 @@ func (bot *CQBot) ConvertStringMessage(msg string, isGroup bool) (r []message.IM
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else if customText != "" {
|
} else if customText != "" {
|
||||||
sender, err := strconv.ParseInt(params["qq"], 10, 64)
|
sender, err := strconv.ParseInt(d["qq"], 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("警告:自定义 Reply 元素中必须包含Uin")
|
log.Warnf("警告:自定义 Reply 元素中必须包含Uin")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
msgTime, err := strconv.ParseInt(params["time"], 10, 64)
|
msgTime, err := strconv.ParseInt(d["time"], 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
msgTime = time.Now().Unix()
|
msgTime = time.Now().Unix()
|
||||||
}
|
}
|
||||||
@ -439,14 +409,14 @@ func (bot *CQBot) ConvertStringMessage(msg string, isGroup bool) (r []message.IM
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if t == "forward" { // 单独处理转发
|
if t == "forward" { // 单独处理转发
|
||||||
if id, ok := params["id"]; ok {
|
if id, ok := d["id"]; ok {
|
||||||
r = []message.IMessageElement{bot.Client.DownloadForwardMessage(id)}
|
r = []message.IMessageElement{bot.Client.DownloadForwardMessage(id)}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elem, err := bot.ToElement(t, params, isGroup)
|
elem, err := bot.ToElement(t, d, isGroup)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
org := "[CQ:" + string(cqCode) + "]"
|
org := s[CQBegin:i]
|
||||||
if !IgnoreInvalidCQCode {
|
if !IgnoreInvalidCQCode {
|
||||||
log.Warnf("转换CQ码 %v 时出现错误: %v 将原样发送.", org, err)
|
log.Warnf("转换CQ码 %v 时出现错误: %v 将原样发送.", org, err)
|
||||||
r = append(r, message.NewText(org))
|
r = append(r, message.NewText(org))
|
||||||
@ -462,32 +432,70 @@ func (bot *CQBot) ConvertStringMessage(msg string, isGroup bool) (r []message.IM
|
|||||||
r = append(r, i...)
|
r = append(r, i...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for hasNext() {
|
|
||||||
ch := next()
|
S1: // Plain Text
|
||||||
switch stat {
|
for ; i < l; i++ {
|
||||||
case 0:
|
if *(*byte)(add(ptr, uintptr(i))) == '[' && i+4 < l &&
|
||||||
if isCQCodeBegin(ch) {
|
*(*uint32)(add(ptr, uintptr(i))) == magicCQ { // Magic :uint32([]byte("[CQ:"))
|
||||||
saveTempText()
|
if i > j {
|
||||||
tempText = append(tempText, []rune("[CQ:")...)
|
r = append(r, message.NewText(CQCodeUnescapeText(s[j:i])))
|
||||||
move(3)
|
|
||||||
stat = 1
|
|
||||||
} else {
|
|
||||||
tempText = append(tempText, ch)
|
|
||||||
}
|
|
||||||
case 1:
|
|
||||||
if isCQCodeBegin(ch) {
|
|
||||||
move(-1)
|
|
||||||
stat = 0
|
|
||||||
} else if ch == ']' {
|
|
||||||
saveCQCode()
|
|
||||||
stat = 0
|
|
||||||
} else {
|
|
||||||
cqCode = append(cqCode, ch)
|
|
||||||
tempText = append(tempText, ch)
|
|
||||||
}
|
}
|
||||||
|
CQBegin = i
|
||||||
|
i += 4
|
||||||
|
j = i
|
||||||
|
goto S2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
saveTempText()
|
goto End
|
||||||
|
S2: // CQCode Type
|
||||||
|
d = make(map[string]string)
|
||||||
|
for ; i < l; i++ {
|
||||||
|
switch *(*byte)(add(ptr, uintptr(i))) {
|
||||||
|
case ',': // CQ Code with params
|
||||||
|
t = s[j:i]
|
||||||
|
i++
|
||||||
|
j = i
|
||||||
|
goto S3
|
||||||
|
case ']': // CQ Code without params
|
||||||
|
t = s[j:i]
|
||||||
|
i++
|
||||||
|
j = i
|
||||||
|
saveCQCode()
|
||||||
|
goto S1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
goto End
|
||||||
|
S3: // CQCode param key
|
||||||
|
for ; i < l; i++ {
|
||||||
|
if *(*byte)(add(ptr, uintptr(i))) == '=' {
|
||||||
|
key = s[j:i]
|
||||||
|
i++
|
||||||
|
j = i
|
||||||
|
goto S4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
goto End
|
||||||
|
S4: // CQCode param value
|
||||||
|
for ; i < l; i++ {
|
||||||
|
switch *(*byte)(add(ptr, uintptr(i))) {
|
||||||
|
case ',': // more param
|
||||||
|
d[key] = CQCodeUnescapeValue(s[j:i])
|
||||||
|
i++
|
||||||
|
j = i
|
||||||
|
goto S3
|
||||||
|
case ']':
|
||||||
|
d[key] = CQCodeUnescapeValue(s[j:i])
|
||||||
|
i++
|
||||||
|
j = i
|
||||||
|
saveCQCode()
|
||||||
|
goto S1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
goto End
|
||||||
|
End:
|
||||||
|
if i > j {
|
||||||
|
r = append(r, message.NewText(CQCodeUnescapeText(s[j:i])))
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
25
coolq/cqcode_test.go
Normal file
25
coolq/cqcode_test.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package coolq
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/Mrs4s/MiraiGo/client"
|
||||||
|
"github.com/Mrs4s/go-cqhttp/global"
|
||||||
|
)
|
||||||
|
|
||||||
|
var bot = NewQQBot(client.NewClient(1, ""), global.DefaultConfig())
|
||||||
|
|
||||||
|
func TestCQBot_ConvertStringMessage(t *testing.T) {
|
||||||
|
for _, v := range bot.ConvertStringMessage(`[CQ:face,id=115,text=111][CQ:face,id=217]] [CQ:text,text=123] [`, false) {
|
||||||
|
fmt.Println(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var bench = `asdfqwerqwerqwer[CQ:face,id=115,text=111]asdfasdfasdfasdfasdfasdfasd[CQ:face,id=217]] [CQ:text,text=123] [`
|
||||||
|
|
||||||
|
func BenchmarkCQBot_ConvertStringMessage(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
bot.ConvertStringMessage(bench, false)
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user