1
0
mirror of https://github.com/Mrs4s/MiraiGo.git synced 2025-06-19 05:55:05 +08:00

refactor(message): ForwardMessage don't impl IMessageElement interface

use ForwardMessage to upload and get the ForwardElement.
This commit is contained in:
wdvxdr 2021-08-03 15:36:20 +08:00
parent feb482e0e3
commit cb396f0f56
No known key found for this signature in database
GPG Key ID: 703F8C071DE7A1B6
6 changed files with 94 additions and 67 deletions

View File

@ -1,10 +1,8 @@
package client package client
import ( import (
"bytes"
"crypto/md5" "crypto/md5"
"encoding/hex" "encoding/hex"
"encoding/xml"
"fmt" "fmt"
"math/rand" "math/rand"
"net" "net"
@ -13,6 +11,9 @@ import (
"strings" "strings"
"time" "time"
"github.com/pkg/errors"
"google.golang.org/protobuf/proto"
"github.com/Mrs4s/MiraiGo/binary" "github.com/Mrs4s/MiraiGo/binary"
"github.com/Mrs4s/MiraiGo/binary/jce" "github.com/Mrs4s/MiraiGo/binary/jce"
devinfo "github.com/Mrs4s/MiraiGo/client/pb" devinfo "github.com/Mrs4s/MiraiGo/client/pb"
@ -20,8 +21,6 @@ import (
"github.com/Mrs4s/MiraiGo/client/pb/oidb" "github.com/Mrs4s/MiraiGo/client/pb/oidb"
"github.com/Mrs4s/MiraiGo/message" "github.com/Mrs4s/MiraiGo/message"
"github.com/Mrs4s/MiraiGo/utils" "github.com/Mrs4s/MiraiGo/utils"
"github.com/pkg/errors"
"google.golang.org/protobuf/proto"
) )
type ( type (
@ -586,12 +585,6 @@ func packUniRequestData(data []byte) (r []byte) {
return return
} }
func XmlEscape(c string) string {
buf := new(bytes.Buffer)
_ = xml.EscapeText(buf, []byte(c))
return buf.String()
}
func genForwardTemplate(resID, preview, title, brief, source, summary string, ts int64, items []*msg.PbMultiMsgItem) *message.ForwardElement { func genForwardTemplate(resID, preview, title, brief, source, summary string, ts int64, items []*msg.PbMultiMsgItem) *message.ForwardElement {
template := fmt.Sprintf(`<?xml version='1.0' encoding='UTF-8'?><msg serviceID="35" templateID="1" action="viewMultiMsg" brief="%s" m_resid="%s" m_fileName="%d" tSum="3" sourceMsgId="0" url="" flag="3" adverSign="0" multiMsgFlag="0"><item layout="1"><title color="#000000" size="34">%s</title> %s<hr></hr><summary size="26" color="#808080">%s</summary></item><source name="%s"></source></msg>`, template := fmt.Sprintf(`<?xml version='1.0' encoding='UTF-8'?><msg serviceID="35" templateID="1" action="viewMultiMsg" brief="%s" m_resid="%s" m_fileName="%d" tSum="3" sourceMsgId="0" url="" flag="3" adverSign="0" multiMsgFlag="0"><item layout="1"><title color="#000000" size="34">%s</title> %s<hr></hr><summary size="26" color="#808080">%s</summary></item><source name="%s"></source></msg>`,
brief, resID, ts, title, preview, summary, source, brief, resID, ts, title, preview, summary, source,
@ -617,7 +610,7 @@ func genLongTemplate(resID, brief string, ts int64) *message.ServiceElement {
return brief return brief
}() }()
template := fmt.Sprintf(`<?xml version='1.0' encoding='UTF-8' standalone='yes' ?><msg serviceID="35" templateID="1" action="viewMultiMsg" brief="%s" m_resid="%s" m_fileName="%d" sourceMsgId="0" url="" flag="3" adverSign="0" multiMsgFlag="1"> <item layout="1"> <title>%s</title> <hr hidden="false" style="0"/> <summary>点击查看完整消息</summary> </item> <source name="聊天记录" icon="" action="" appid="-1"/> </msg>`, template := fmt.Sprintf(`<?xml version='1.0' encoding='UTF-8' standalone='yes' ?><msg serviceID="35" templateID="1" action="viewMultiMsg" brief="%s" m_resid="%s" m_fileName="%d" sourceMsgId="0" url="" flag="3" adverSign="0" multiMsgFlag="1"> <item layout="1"> <title>%s</title> <hr hidden="false" style="0"/> <summary>点击查看完整消息</summary> </item> <source name="聊天记录" icon="" action="" appid="-1"/> </msg>`,
XmlEscape(limited), resID, ts, XmlEscape(limited), utils.XmlEscape(limited), resID, ts, utils.XmlEscape(limited),
) )
return &message.ServiceElement{ return &message.ServiceElement{
Id: 35, Id: 35,

View File

@ -7,6 +7,7 @@ import (
"math" "math"
"math/rand" "math/rand"
"strconv" "strconv"
"strings"
"time" "time"
"github.com/Mrs4s/MiraiGo/client/pb/longmsg" "github.com/Mrs4s/MiraiGo/client/pb/longmsg"
@ -53,14 +54,12 @@ func (c *QQClient) SendGroupMessage(groupCode int64, m *message.SendingMessage,
ret := c.sendGroupMessage(groupCode, false, ret := c.sendGroupMessage(groupCode, false,
&message.SendingMessage{Elements: []message.IMessageElement{ &message.SendingMessage{Elements: []message.IMessageElement{
c.uploadGroupLongMessage(groupCode, c.uploadGroupLongMessage(groupCode,
&message.ForwardMessage{Nodes: []*message.ForwardNode{ message.NewForwardMessage().AddNode(&message.ForwardNode{
{ SenderId: c.Uin,
SenderId: c.Uin, SenderName: c.Nickname,
SenderName: c.Nickname, Time: int32(time.Now().Unix()),
Time: int32(time.Now().Unix()), Message: m.Elements,
Message: m.Elements, }),
},
}},
), ),
}}, }},
) )
@ -71,9 +70,9 @@ func (c *QQClient) SendGroupMessage(groupCode int64, m *message.SendingMessage,
} }
// SendGroupForwardMessage 发送群合并转发消息 // SendGroupForwardMessage 发送群合并转发消息
func (c *QQClient) SendGroupForwardMessage(groupCode int64, m *message.ForwardMessage) *message.GroupMessage { func (c *QQClient) SendGroupForwardMessage(groupCode int64, m *message.ForwardElement) *message.GroupMessage {
return c.sendGroupMessage(groupCode, true, return c.sendGroupMessage(groupCode, true,
&message.SendingMessage{Elements: []message.IMessageElement{c.UploadGroupForwardMessage(groupCode, m)}}, &message.SendingMessage{Elements: []message.IMessageElement{m}},
) )
} }
@ -161,7 +160,7 @@ func (c *QQClient) sendGroupMessage(groupCode int64, forward bool, m *message.Se
} }
func (c *QQClient) uploadGroupLongMessage(groupCode int64, m *message.ForwardMessage) *message.ServiceElement { func (c *QQClient) uploadGroupLongMessage(groupCode int64, m *message.ForwardMessage) *message.ServiceElement {
if len(m.Nodes) >= 200 { if m.Length() >= 200 {
return nil return nil
} }
ts := time.Now().UnixNano() ts := time.Now().UnixNano()
@ -173,25 +172,16 @@ func (c *QQClient) uploadGroupLongMessage(groupCode int64, m *message.ForwardMes
} }
for i, ip := range rsp.Uint32UpIp { for i, ip := range rsp.Uint32UpIp {
err := c.highwayUpload(uint32(ip), int(rsp.Uint32UpPort[i]), rsp.MsgSig, body, 27) err := c.highwayUpload(uint32(ip), int(rsp.Uint32UpPort[i]), rsp.MsgSig, body, 27)
if err == nil { if err != nil {
bri := func() string { continue
var r string
for _, n := range m.Nodes {
r += message.ToReadableString(n.Message)
if len(r) >= 27 {
break
}
}
return r
}()
return genLongTemplate(rsp.MsgResid, bri, ts)
} }
return genLongTemplate(rsp.MsgResid, m.Brief(), ts)
} }
return nil return nil
} }
func (c *QQClient) UploadGroupForwardMessage(groupCode int64, m *message.ForwardMessage) *message.ForwardElement { func (c *QQClient) UploadGroupForwardMessage(groupCode int64, m *message.ForwardMessage) *message.ForwardElement {
if len(m.Nodes) > 200 { if m.Length() > 200 {
return nil return nil
} }
ts := time.Now().UnixNano() ts := time.Now().UnixNano()
@ -203,13 +193,10 @@ func (c *QQClient) UploadGroupForwardMessage(groupCode int64, m *message.Forward
} }
for i, ip := range rsp.Uint32UpIp { for i, ip := range rsp.Uint32UpIp {
err := c.highwayUpload(uint32(ip), int(rsp.Uint32UpPort[i]), rsp.MsgSig, body, 27) err := c.highwayUpload(uint32(ip), int(rsp.Uint32UpPort[i]), rsp.MsgSig, body, 27)
if err == nil { if err != nil {
var pv string continue
for i := 0; i < int(math.Min(4, float64(len(m.Nodes)))); i++ {
pv += fmt.Sprintf(`<title size="26" color="#777777">%s: %s</title>`, XmlEscape(m.Nodes[i].SenderName), XmlEscape(message.ToReadableString(m.Nodes[i].Message)))
}
return genForwardTemplate(rsp.MsgResid, pv, "群聊的聊天记录", "[聊天记录]", "聊天记录", fmt.Sprintf("查看 %d 条转发消息", len(m.Nodes)), ts, items)
} }
return genForwardTemplate(rsp.MsgResid, m.Preview(), "群聊的聊天记录", "[聊天记录]", "聊天记录", fmt.Sprintf("查看 %d 条转发消息", m.Length()), ts, items)
} }
return nil return nil
} }
@ -529,10 +516,11 @@ func (c *QQClient) parseGroupMessage(m *msg.Message) *message.GroupMessage {
if extInfo != nil && len(extInfo.GroupCard) > 0 && extInfo.GroupCard[0] == 0x0A { if extInfo != nil && len(extInfo.GroupCard) > 0 && extInfo.GroupCard[0] == 0x0A {
buf := oidb.D8FCCommCardNameBuf{} buf := oidb.D8FCCommCardNameBuf{}
if err := proto.Unmarshal(extInfo.GroupCard, &buf); err == nil && len(buf.RichCardName) > 0 { if err := proto.Unmarshal(extInfo.GroupCard, &buf); err == nil && len(buf.RichCardName) > 0 {
groupCard = "" var gcard strings.Builder
for _, e := range buf.RichCardName { for _, e := range buf.RichCardName {
groupCard += string(e.Text) gcard.Write(e.Text)
} }
groupCard = gcard.String()
} }
} }
if m.Head.GroupInfo != nil && groupCard != "" && mem.CardName != groupCard { if m.Head.GroupInfo != nil && groupCard != "" && mem.CardName != groupCard {

View File

@ -178,8 +178,7 @@ func NewPrivateReply(m *PrivateMessage) *ReplyElement {
func NewUrlShare(url, title, content, image string) *ServiceElement { func NewUrlShare(url, title, content, image string) *ServiceElement {
template := fmt.Sprintf(`<?xml version="1.0" encoding="utf-8"?><msg templateID="12345" action="web" brief="[分享] %s" serviceID="1" url="%s"><item layout="2"><picture cover="%v"/><title>%v</title><summary>%v</summary></item><source/></msg>`, template := fmt.Sprintf(`<?xml version="1.0" encoding="utf-8"?><msg templateID="12345" action="web" brief="[分享] %s" serviceID="1" url="%s"><item layout="2"><picture cover="%v"/><title>%v</title><summary>%v</summary></item><source/></msg>`,
title, url, image, title, content, title, url, image, title, content)
)
/* /*
template := fmt.Sprintf(`<?xml version='1.0' encoding='UTF-8' standalone='yes'?><msg templateID="123" url="%s" serviceID="33" action="web" actionData="" brief="【链接】%s" flag="8"><item layout="2"><picture cover="%s"/><title>%s</title><summary>%s</summary></item></msg>`, template := fmt.Sprintf(`<?xml version='1.0' encoding='UTF-8' standalone='yes'?><msg templateID="123" url="%s" serviceID="33" action="web" actionData="" brief="【链接】%s" flag="8"><item layout="2"><picture cover="%s"/><title>%s</title><summary>%s</summary></item></msg>`,
url, url, image, title, content, url, url, image, title, content,

View File

@ -1,18 +1,22 @@
package message package message
import ( import (
"bytes"
"crypto/md5" "crypto/md5"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
"github.com/Mrs4s/MiraiGo/binary" "github.com/Mrs4s/MiraiGo/binary"
"github.com/Mrs4s/MiraiGo/client/pb/msg" "github.com/Mrs4s/MiraiGo/client/pb/msg"
"github.com/Mrs4s/MiraiGo/utils"
) )
// *----- Definitions -----* // // *----- Definitions -----* //
// ForwardMessage 添加 Node 请用 AddNode 方法
type ForwardMessage struct { type ForwardMessage struct {
Nodes []*ForwardNode Nodes []*ForwardNode
items []*msg.PbMultiMsgItem
} }
type ForwardNode struct { type ForwardNode struct {
@ -36,26 +40,67 @@ func (e *ForwardElement) Type() ElementType {
return Forward return Forward
} }
func (e *ForwardElement) Pack() (r []*msg.Elem) { func (e *ForwardElement) Pack() []*msg.Elem {
r = []*msg.Elem{} rich := &msg.Elem{
r = append(r, &msg.Elem{
RichMsg: &msg.RichMsg{ RichMsg: &msg.RichMsg{
Template1: append([]byte{1}, binary.ZlibCompress([]byte(e.Content))...), Template1: append([]byte{1}, binary.ZlibCompress(utils.S2B(e.Content))...),
ServiceId: proto.Int32(35), ServiceId: proto.Int32(35),
MsgResId: []byte{}, MsgResId: []byte{},
}, },
}) }
r = append(r, &msg.Elem{ txt := &msg.Elem{
Text: &msg.Text{ Text: &msg.Text{
Str: proto.String("你的QQ暂不支持查看[转发多条消息],请期待后续版本。"), Str: proto.String("你的QQ暂不支持查看[转发多条消息],请期待后续版本。"),
}, },
}) }
return return []*msg.Elem{rich, txt}
} }
// Type impl IMessageElement func NewForwardMessage() *ForwardMessage {
func (f *ForwardMessage) Type() ElementType { return &ForwardMessage{}
return Forward }
// AddNode adds a node to the forward message. return for method chaining.
func (f *ForwardMessage) AddNode(node *ForwardNode) *ForwardMessage {
f.Nodes = append(f.Nodes, node)
for _, item := range node.Message {
if item.Type() != Forward { // quick path
continue
}
if forward, ok := item.(*ForwardElement); ok {
f.items = append(f.items, forward.Items...)
}
}
return f
}
// Length return the length of Nodes.
func (f *ForwardMessage) Length() int { return len(f.Nodes) }
func (f *ForwardMessage) Brief() string {
var brief bytes.Buffer
for _, n := range f.Nodes {
brief.WriteString(ToReadableString(n.Message))
if brief.Len() >= 27 {
break
}
}
return brief.String()
}
func (f *ForwardMessage) Preview() string {
var pv bytes.Buffer
for i, node := range f.Nodes {
if i >= 4 {
break
}
pv.WriteString(`<title size="26" color="#777777">`)
pv.WriteString(utils.XmlEscape(node.SenderName))
pv.WriteString(": ")
pv.WriteString(utils.XmlEscape(ToReadableString(node.Message)))
pv.WriteString("</title>")
}
return pv.String()
} }
func (f *ForwardMessage) CalculateValidationData(seq, random int32, groupCode int64) ([]byte, []byte) { func (f *ForwardMessage) CalculateValidationData(seq, random int32, groupCode int64) ([]byte, []byte) {
@ -81,13 +126,7 @@ func (f *ForwardMessage) CalculateValidationDataForward(seq, random int32, group
Buffer: &msg.PbMultiMsgNew{Msg: msgs}, Buffer: &msg.PbMultiMsgNew{Msg: msgs},
}, },
}} }}
for _, node := range f.Nodes { trans.PbItemList = append(trans.PbItemList, f.items...)
for _, message := range node.Message {
if forwardElement, ok := message.(*ForwardElement); ok {
trans.PbItemList = append(trans.PbItemList, forwardElement.Items...)
}
}
}
b, _ := proto.Marshal(trans) b, _ := proto.Marshal(trans)
data := binary.GZipCompress(b) data := binary.GZipCompress(b)
hash := md5.Sum(data) hash := md5.Sum(data)
@ -95,9 +134,9 @@ func (f *ForwardMessage) CalculateValidationDataForward(seq, random int32, group
} }
func (f *ForwardMessage) packForwardMsg(seq int32, random int32, groupCode int64) []*msg.Message { func (f *ForwardMessage) packForwardMsg(seq int32, random int32, groupCode int64) []*msg.Message {
msgs := make([]*msg.Message, 0, len(f.Nodes)) ml := make([]*msg.Message, 0, len(f.Nodes))
for _, node := range f.Nodes { for _, node := range f.Nodes {
msgs = append(msgs, &msg.Message{ ml = append(ml, &msg.Message{
Head: &msg.MessageHead{ Head: &msg.MessageHead{
FromUin: &node.SenderId, FromUin: &node.SenderId,
MsgSeq: &seq, MsgSeq: &seq,
@ -121,5 +160,5 @@ func (f *ForwardMessage) packForwardMsg(seq int32, random int32, groupCode int64
}, },
}) })
} }
return msgs return ml
} }

View File

@ -418,7 +418,7 @@ func ParseMessageElems(elems []*msg.Elem) []IMessageElement {
} }
if content != "" { if content != "" {
if elem.RichMsg.GetServiceId() == 35 { if elem.RichMsg.GetServiceId() == 35 {
reg := regexp.MustCompile(`m_resid="(.+)"`) reg := regexp.MustCompile(`m_resid="(.*?)"`)
sub := reg.FindAllStringSubmatch(content, -1) sub := reg.FindAllStringSubmatch(content, -1)
if len(sub) > 0 && len(sub[0]) > 1 { if len(sub) > 0 && len(sub[0]) > 1 {
res = append(res, &ForwardElement{ResId: reg.FindAllStringSubmatch(content, -1)[0][1]}) res = append(res, &ForwardElement{ResId: reg.FindAllStringSubmatch(content, -1)[0][1]})

View File

@ -1,6 +1,7 @@
package utils package utils
import ( import (
"encoding/xml"
"math/rand" "math/rand"
"reflect" "reflect"
"strconv" "strconv"
@ -66,3 +67,10 @@ func S2B(s string) (b []byte) {
bh.Len = sh.Len bh.Len = sh.Len
return return
} }
// XmlEscape xml escape string
func XmlEscape(c string) string {
buf := new(strings.Builder)
_ = xml.EscapeText(buf, []byte(c))
return buf.String()
}