1
0
mirror of https://github.com/Mrs4s/MiraiGo.git synced 2025-05-04 11:07:40 +08:00

long message supported.

This commit is contained in:
Mrs4s 2020-07-29 12:44:43 +08:00
parent 0ecd91e142
commit 98a77a6cf3
9 changed files with 980 additions and 739 deletions

View File

@ -17,7 +17,8 @@ qq-android协议的golang实现 移植于mirai
- [x] 表情
- [x] At
- [x] 回复
- [ ] 长消息
- [x] 长消息
- [ ] 富文本 ( xml/json/小程序 等 )
- [x] 合并转发
#### 事件

View File

@ -383,18 +383,8 @@ func (c *QQClient) buildDeleteOnlinePushPacket(uin int64, seq uint16, delMsg []j
}
// MessageSvc.PbSendMsg
func (c *QQClient) buildGroupSendingPacket(groupCode int64, r int32, m *message.SendingMessage) (uint16, []byte) {
func (c *QQClient) buildGroupSendingPacket(groupCode int64, r int32, forward bool, m *message.SendingMessage) (uint16, []byte) {
seq := c.nextSeq()
forward := func() bool {
for _, elem := range m.Elements {
if e, ok := elem.(*message.ServiceElement); ok {
if e.Id == 35 {
return true
}
}
}
return false
}()
req := &msg.SendMessageRequest{
RoutingHead: &msg.RoutingHead{Grp: &msg.Grp{GroupCode: groupCode}},
ContentHead: &msg.ContentHead{PkgNum: 1},
@ -834,7 +824,7 @@ func (c *QQClient) buildGroupMutePacket(groupCode, memberUin int64, time uint32)
}
// MultiMsg.ApplyUp
func (c *QQClient) buildMultiApplyUpPacket(data, hash []byte, groupUin int64) (uint16, []byte) {
func (c *QQClient) buildMultiApplyUpPacket(data, hash []byte, buType int32, groupUin int64) (uint16, []byte) {
seq := c.nextSeq()
req := &multimsg.MultiReqBody{
Subcmd: 1,
@ -850,7 +840,7 @@ func (c *QQClient) buildMultiApplyUpPacket(data, hash []byte, groupUin int64) (u
MsgType: 3,
},
},
BuType: 2,
BuType: buType,
}
payload, _ := proto.Marshal(req)
packet := packets.BuildUniPacket(c.Uin, seq, "MultiMsg.ApplyUp", 1, c.OutGoingPacketSessionId, EmptyBytes, c.sigInfo.d2Key, payload)

View File

@ -205,6 +205,25 @@ func (c *QQClient) GetFriendList() (*FriendListResponse, error) {
}
func (c *QQClient) SendGroupMessage(groupCode int64, m *message.SendingMessage) *message.GroupMessage {
imgCount := m.Count(func(e message.IMessageElement) bool { return e.Type() == message.Image })
msgLen := message.EstimateLength(m.Elements, 703)
if msgLen > 5000 || imgCount > 50 {
return nil
}
if msgLen > 702 || imgCount > 2 {
return c.sendGroupLongOrForwardMessage(groupCode, true, &message.ForwardMessage{Nodes: []*message.ForwardNode{
{
SenderId: c.Uin,
SenderName: c.Nickname,
Time: int32(time.Now().Unix()),
Message: m.Elements,
},
}})
}
return c.sendGroupMessage(groupCode, false, m)
}
func (c *QQClient) sendGroupMessage(groupCode int64, forward bool, m *message.SendingMessage) *message.GroupMessage {
eid := utils.RandomString(6)
mr := int32(rand.Uint32())
ch := make(chan int32)
@ -214,7 +233,7 @@ func (c *QQClient) SendGroupMessage(groupCode int64, m *message.SendingMessage)
}
})
defer c.onGroupMessageReceipt(eid)
_, pkt := c.buildGroupSendingPacket(groupCode, mr, m)
_, pkt := c.buildGroupSendingPacket(groupCode, mr, forward, m)
_ = c.send(pkt)
var mid int32
ret := &message.GroupMessage{
@ -281,14 +300,24 @@ func (c *QQClient) GetForwardMessage(resId string) *message.ForwardMessage {
return ret
}
func (c *QQClient) SendForwardMessage(groupCode int64, m *message.ForwardMessage) *message.GroupMessage {
func (c *QQClient) SendGroupForwardMessage(groupCode int64, m *message.ForwardMessage) *message.GroupMessage {
return c.sendGroupLongOrForwardMessage(groupCode, false, m)
}
func (c *QQClient) sendGroupLongOrForwardMessage(groupCode int64, isLong bool, m *message.ForwardMessage) *message.GroupMessage {
if len(m.Nodes) >= 200 {
return nil
}
ts := time.Now().Unix()
seq := c.nextGroupSeq()
data, hash := m.CalculateValidationData(seq, rand.Int31(), groupCode)
i, err := c.sendAndWait(c.buildMultiApplyUpPacket(data, hash, utils.ToGroupUin(groupCode)))
i, err := c.sendAndWait(c.buildMultiApplyUpPacket(data, hash, func() int32 {
if isLong {
return 1
} else {
return 2
}
}(), utils.ToGroupUin(groupCode)))
if err != nil {
return nil
}
@ -311,11 +340,24 @@ func (c *QQClient) SendForwardMessage(groupCode int64, m *message.ForwardMessage
updServer := binary.UInt32ToIPV4Address(uint32(ip))
err := c.highwayUploadImage(updServer+":"+strconv.FormatInt(int64(rsp.Uint32UpPort[i]), 10), rsp.MsgSig, body, 27)
if err == nil {
if !isLong {
var pv string
for i := 0; i < int(math.Min(4, float64(len(m.Nodes)))); i++ {
pv += fmt.Sprintf(`<title size="26" color="#777777">%s: %s</title>`, m.Nodes[i].SenderName, message.ToReadableString(m.Nodes[i].Message))
}
return c.SendGroupMessage(groupCode, genForwardCard(rsp.MsgResid, pv, "群聊的聊天记录", "[聊天记录]", "聊天记录", fmt.Sprintf("查看 %d 条转发消息", len(m.Nodes)), ts))
return c.sendGroupMessage(groupCode, true, genForwardTemplate(rsp.MsgResid, pv, "群聊的聊天记录", "[聊天记录]", "聊天记录", fmt.Sprintf("查看 %d 条转发消息", len(m.Nodes)), ts))
}
bri := func() string {
var r string
for _, n := range m.Nodes {
r += message.ToReadableString(n.Message)
if len(r) >= 27 {
break
}
}
return r
}()
return c.sendGroupMessage(groupCode, false, genLongTemplate(rsp.MsgResid, bri, ts))
}
}
return nil

View File

@ -278,12 +278,36 @@ func packRequestDataV3(data []byte) (r []byte) {
return
}
func genForwardCard(resId, preview, title, brief, source, summary string, ts int64) *message.SendingMessage {
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)
func genForwardTemplate(resId, preview, title, brief, source, summary string, ts int64) *message.SendingMessage {
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,
)
return &message.SendingMessage{Elements: []message.IMessageElement{
&message.ServiceElement{
Id: 35,
Content: template,
ResId: resId,
SubType: "Forward",
},
}}
}
func genLongTemplate(resId, brief string, ts int64) *message.SendingMessage {
limited := func() string {
if len(brief) > 30 {
return brief[:30] + "…"
}
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>`,
limited, resId, ts, limited,
)
return &message.SendingMessage{Elements: []message.IMessageElement{
&message.ServiceElement{
Id: 35,
Content: template,
ResId: resId,
SubType: "Long",
},
}}
}

File diff suppressed because it is too large Load Diff

View File

@ -217,7 +217,7 @@ message Elem {
//WorkflowNotifyMsg? msgWorkflowNotify = 48;
//PatsElem? patElem = 49;
//GroupPostElem? groupPostElem = 50;
//LightAppElem? lightApp = 51;
LightAppElem lightApp = 51;
//EIMInfo? eimInfo = 52;
//CommonElem? commonElem = 53;
}
@ -430,6 +430,11 @@ message Face {
bytes buf = 11;
}
message LightAppElem {
bytes data = 1;
bytes msgResid = 2;
}
message CustomFace {
bytes guid = 1;
string filePath = 2;

View File

@ -51,6 +51,8 @@ type ReplyElement struct {
type ServiceElement struct {
Id int32
Content string
ResId string
SubType string
}
type ForwardElement struct {

View File

@ -5,7 +5,9 @@ import (
"encoding/hex"
"github.com/Mrs4s/MiraiGo/binary"
"github.com/Mrs4s/MiraiGo/client/pb/msg"
"github.com/Mrs4s/MiraiGo/utils"
"github.com/golang/protobuf/proto"
"math"
"reflect"
"regexp"
"strconv"
@ -148,6 +150,47 @@ func (msg *SendingMessage) Append(e IMessageElement) *SendingMessage {
return msg
}
func (msg *SendingMessage) Any(filter func(e IMessageElement) bool) bool {
for _, e := range msg.Elements {
if filter(e) {
return true
}
}
return false
}
func (msg *SendingMessage) Count(filter func(e IMessageElement) bool) (c int) {
for _, e := range msg.Elements {
if filter(e) {
c++
}
}
return
}
func EstimateLength(elems []IMessageElement, limit int) int {
sum := 0
for _, elem := range elems {
if sum >= limit {
break
}
left := int(math.Max(float64(limit-sum), 0))
switch e := elem.(type) {
case *TextElement:
sum += utils.ChineseLength(e.Content, left)
case *AtElement:
sum += utils.ChineseLength(e.Display, left)
case *ReplyElement:
sum += 444 + EstimateLength(e.Elements, left)
case *ImageElement, *GroupImageElement, *FriendImageElement:
sum += 260
default:
sum += utils.ChineseLength(ToReadableString([]IMessageElement{elem}), left)
}
}
return sum
}
func (s *Sender) DisplayName() string {
if s.CardName == "" {
return s.Nickname
@ -260,15 +303,27 @@ func ToProtoElems(elems []IMessageElement, generalFlags bool) (r []*msg.Elem) {
}
}
if generalFlags {
L:
for _, elem := range elems {
switch elem.(type) {
switch e := elem.(type) {
case *ServiceElement:
if e.SubType == "Long" {
r = append(r, &msg.Elem{
GeneralFlags: &msg.GeneralFlags{
LongTextFlag: 1,
LongTextResid: e.ResId,
PbReserve: []byte{0x78, 0x00, 0xF8, 0x01, 0x00, 0xC8, 0x02, 0x00},
},
})
break L
}
d, _ := hex.DecodeString("08097800C80100F00100F80100900200C80200980300A00320B00300C00300D00300E803008A04020803900480808010B80400C00400")
r = append(r, &msg.Elem{
GeneralFlags: &msg.GeneralFlags{
PbReserve: d,
},
})
break L
}
}
}
@ -290,6 +345,19 @@ func ParseMessageElems(elems []*msg.Elem) []IMessageElement {
}
continue
}
if elem.LightApp != nil && len(elem.LightApp.Data) > 1 {
var content string
if elem.LightApp.Data[0] == 0 {
content = string(elem.LightApp.Data[1:])
}
if elem.LightApp.Data[0] == 1 {
content = string(binary.ZlibUncompress(elem.LightApp.Data[1:]))
}
if content != "" {
// TODO: 解析具体的APP
return append(res, NewText(content))
}
}
if elem.Text != nil {
if len(elem.Text.Attr6Buf) == 0 {
res = append(res, NewText(elem.Text.Str))

View File

@ -21,3 +21,23 @@ func RandomStringRange(len int, str string) string {
}
return res
}
func ChineseLength(str string, limit int) int {
sum := 0
for _, r := range []rune(str) {
switch {
case r >= '\u0000' && r <= '\u007F':
sum += 1
case r >= '\u0080' && r <= '\u07FF':
sum += 2
case r >= '\u0800' && r <= '\uFFFF':
sum += 3
default:
sum += 4
}
if sum >= limit {
break
}
}
return sum
}