github.com/LagrangeDev/LagrangeGo@v0.0.0-20240512064304-ad4a85e10cb4/message/message.go (about) 1 package message 2 3 // 部分借鉴 https://github.com/Mrs4s/MiraiGo/blob/master/message/message.go 4 5 import ( 6 "reflect" 7 "strconv" 8 "strings" 9 10 "github.com/LagrangeDev/LagrangeGo/client/packets/pb/message" 11 "github.com/LagrangeDev/LagrangeGo/internal/proto" 12 "github.com/LagrangeDev/LagrangeGo/utils" 13 "github.com/LagrangeDev/LagrangeGo/utils/binary" 14 ) 15 16 type IMessage interface { 17 GetElements() []IMessageElement 18 Chat() int64 19 ToString() string 20 Texts() []string 21 } 22 23 const ( 24 Text ElementType = iota // 文本 25 Image // 图片 26 Face // 表情 27 At // 艾特 28 Reply // 回复 29 Service // 服务 30 Forward // 转发 31 File // 文件 32 Voice // 语音 33 Video // 视频 34 LightApp // 轻应用 35 RedBag // 红包 36 ) 37 38 type ( 39 PrivateMessage struct { 40 Id int32 41 InternalId int32 42 Self int64 43 Target int64 44 Time int32 45 Sender *Sender 46 Elements []IMessageElement 47 } 48 49 TempMessage struct { 50 Id int32 51 GroupCode uint32 52 GroupName string 53 Self uint32 54 Sender *Sender 55 Elements []IMessageElement 56 } 57 58 GroupMessage struct { 59 Id int32 60 InternalId int32 61 GroupCode uint32 62 GroupName string 63 Sender *Sender 64 Time uint64 65 Elements []IMessageElement 66 OriginalObject *message.PushMsgBody 67 } 68 69 SendingMessage struct { 70 Elements []IMessageElement 71 } 72 73 Sender struct { 74 Uin uint32 75 Uid string 76 Nickname string 77 CardName string 78 AnonymousInfo *AnonymousInfo 79 IsFriend bool 80 } 81 82 AnonymousInfo struct { 83 AnonymousId string 84 AnonymousNick string 85 } 86 87 IMessageElement interface { 88 Type() ElementType 89 } 90 91 ElementType int 92 ) 93 94 func (s *Sender) IsAnonymous() bool { 95 return s.Uin == 80000000 96 } 97 98 func ParsePrivateMessage(msg *message.PushMsg) *PrivateMessage { 99 return &PrivateMessage{ 100 Id: int32(msg.Message.ContentHead.Sequence.Unwrap()), 101 Self: int64(msg.Message.ResponseHead.ToUin), 102 Target: int64(msg.Message.ResponseHead.FromUin), 103 Sender: &Sender{ 104 Uin: msg.Message.ResponseHead.FromUin, 105 Uid: msg.Message.ResponseHead.FromUid.Unwrap(), 106 IsFriend: true, 107 }, 108 Time: int32(msg.Message.ContentHead.TimeStamp.Unwrap()), 109 Elements: parseMessageElements(msg.Message.Body.RichText.Elems), 110 } 111 } 112 113 func ParseGroupMessage(msg *message.PushMsg) *GroupMessage { 114 return &GroupMessage{ 115 Id: int32(msg.Message.ContentHead.Sequence.Unwrap()), 116 GroupCode: msg.Message.ResponseHead.Grp.GroupUin, 117 GroupName: msg.Message.ResponseHead.Grp.GroupName, 118 Sender: &Sender{ 119 Uin: msg.Message.ResponseHead.FromUin, 120 Uid: msg.Message.ResponseHead.FromUid.Unwrap(), 121 Nickname: msg.Message.ResponseHead.Grp.MemberName, 122 CardName: msg.Message.ResponseHead.Grp.MemberName, 123 IsFriend: false, 124 }, 125 Time: msg.Message.ContentHead.TimeStamp.Unwrap(), 126 Elements: parseMessageElements(msg.Message.Body.RichText.Elems), 127 OriginalObject: msg.Message, 128 } 129 } 130 131 func ParseTempMessage(msg *message.PushMsg) *TempMessage { 132 return &TempMessage{ 133 Elements: parseMessageElements(msg.Message.Body.RichText.Elems), 134 } 135 } 136 137 func parseMessageElements(msg []*message.Elem) []IMessageElement { 138 var res []IMessageElement 139 140 for _, elem := range msg { 141 if elem.SrcMsg != nil && len(elem.SrcMsg.OrigSeqs) != 0 { 142 r := &ReplyElement{ 143 ReplySeq: int32(elem.SrcMsg.OrigSeqs[0]), 144 Time: elem.SrcMsg.Time.Unwrap(), 145 Sender: elem.SrcMsg.SenderUin, 146 GroupID: elem.SrcMsg.ToUin.Unwrap(), 147 Elements: parseMessageElements(elem.SrcMsg.Elems), 148 } 149 res = append(res, r) 150 } 151 152 if elem.Text != nil { 153 switch { 154 case len(elem.Text.Attr6Buf) > 0: 155 att6 := binary.NewReader(elem.Text.Attr6Buf) 156 att6.SkipBytes(7) 157 target := att6.ReadU32() 158 at := NewAt(target, elem.Text.Str.Unwrap()) 159 at.SubType = AtTypeGroupMember 160 res = append(res, at) 161 default: 162 res = append(res, NewText(func() string { 163 if strings.Contains(elem.Text.Str.Unwrap(), "\r") && !strings.Contains(elem.Text.Str.Unwrap(), "\r\n") { 164 return strings.ReplaceAll(elem.Text.Str.Unwrap(), "\r", "\r\n") 165 } 166 return elem.Text.Str.Unwrap() 167 }())) 168 } 169 } 170 171 if elem.Face != nil { 172 if len(elem.Face.Old) > 0 { 173 faceId := elem.Face.Index 174 if faceId.IsSome() { 175 res = append(res, &FaceElement{FaceID: uint16(faceId.Unwrap())}) 176 } 177 } else if elem.CommonElem.ServiceType == 37 && elem.CommonElem.PbElem != nil { 178 qFace := message.QFaceExtra{} 179 err := proto.Unmarshal(elem.CommonElem.PbElem, &qFace) 180 if err == nil { 181 faceId := qFace.FaceId 182 if faceId.IsSome() { 183 res = append(res, &FaceElement{FaceID: uint16(faceId.Unwrap()), isLargeFace: true}) 184 } 185 } 186 } else if elem.CommonElem.ServiceType == 33 && elem.CommonElem.PbElem != nil { 187 qFace := message.QSmallFaceExtra{} 188 err := proto.Unmarshal(elem.CommonElem.PbElem, &qFace) 189 if err == nil { 190 res = append(res, &FaceElement{FaceID: uint16(qFace.FaceId), isLargeFace: false}) 191 } 192 } 193 } 194 195 if elem.VideoFile != nil { 196 return []IMessageElement{ 197 &ShortVideoElement{ 198 Name: elem.VideoFile.FileName, 199 Uuid: utils.S2B(elem.VideoFile.FileUuid), 200 Size: elem.VideoFile.FileSize, 201 ThumbSize: elem.VideoFile.ThumbFileSize, 202 Md5: elem.VideoFile.FileMd5, 203 ThumbMd5: elem.VideoFile.ThumbFileMd5, 204 }, 205 } 206 } 207 208 if elem.CustomFace != nil { 209 if len(elem.CustomFace.Md5) == 0 { 210 continue 211 } 212 213 var url string 214 if strings.Contains(elem.CustomFace.OrigUrl, "rkey") { 215 url = "https://multimedia.nt.qq.com.cn" + elem.CustomFace.OrigUrl 216 } else { 217 url = "http://gchat.qpic.cn" + elem.CustomFace.OrigUrl 218 } 219 220 res = append(res, &GroupImageElement{ 221 FileId: int64(elem.CustomFace.FileId), 222 ImageId: elem.CustomFace.FilePath, 223 Size: elem.CustomFace.Size, 224 Width: elem.CustomFace.Width, 225 Height: elem.CustomFace.Height, 226 Url: url, 227 Md5: elem.CustomFace.Md5, 228 }) 229 } 230 231 if elem.NotOnlineImage != nil { 232 if len(elem.NotOnlineImage.PicMd5) == 0 { 233 continue 234 } 235 236 var url string 237 if strings.Contains(elem.NotOnlineImage.OrigUrl, "rkey") { 238 url = "https://multimedia.nt.qq.com.cn" + elem.NotOnlineImage.OrigUrl 239 } else { 240 url = "http://gchat.qpic.cn" + elem.NotOnlineImage.OrigUrl 241 } 242 243 res = append(res, &FriendImageElement{ 244 ImageId: elem.NotOnlineImage.FilePath, 245 Size: elem.NotOnlineImage.FileLen, 246 Url: url, 247 Md5: elem.NotOnlineImage.PicMd5, 248 }) 249 } 250 } 251 252 return res 253 } 254 255 func (msg *GroupMessage) ToString() (res string) { 256 var strBuilder strings.Builder 257 for _, elem := range msg.Elements { 258 switch e := elem.(type) { 259 case *TextElement: 260 strBuilder.WriteString(e.Content) 261 case *GroupImageElement: 262 strBuilder.WriteString("[Image: ") 263 strBuilder.WriteString(e.ImageId) 264 strBuilder.WriteString("]") 265 case *AtElement: 266 strBuilder.WriteString(e.Display) 267 case *ReplyElement: 268 strBuilder.WriteString("[Reply: ") 269 strBuilder.WriteString(strconv.FormatInt(int64(e.ReplySeq), 10)) 270 strBuilder.WriteString("]") 271 case *FaceElement: 272 strBuilder.WriteString("[Face: ") 273 strBuilder.WriteString(strconv.FormatInt(int64(e.FaceID), 10)) 274 if e.isLargeFace { 275 strBuilder.WriteString(", isLargeFace: true]") 276 } 277 strBuilder.WriteString("]") 278 } 279 } 280 res = strBuilder.String() 281 return 282 } 283 284 func ToReadableString(m []IMessageElement) string { 285 sb := new(strings.Builder) 286 for _, elem := range m { 287 switch e := elem.(type) { 288 case *TextElement: 289 sb.WriteString(e.Content) 290 case *GroupImageElement, *FriendImageElement: 291 sb.WriteString("[图片]") 292 case *AtElement: 293 sb.WriteString(e.Display) 294 case *ReplyElement: 295 sb.WriteString("[回复]") 296 case *FaceElement: 297 sb.WriteString("[表情:") 298 sb.WriteString(strconv.FormatInt(int64(e.FaceID), 10)) 299 sb.WriteString("]") 300 } 301 } 302 return sb.String() 303 } 304 305 func NewSendingMessage() *SendingMessage { 306 return &SendingMessage{} 307 } 308 309 func (msg *SendingMessage) GetElems() []IMessageElement { 310 return msg.Elements 311 } 312 313 // Append 要传入msg的引用 314 func (msg *SendingMessage) Append(e IMessageElement) *SendingMessage { 315 v := reflect.ValueOf(e) 316 if v.Kind() == reflect.Ptr && !v.IsNil() { 317 msg.Elements = append(msg.Elements, e) 318 } 319 return msg 320 } 321 322 func (msg *SendingMessage) FirstOrNil(f func(element IMessageElement) bool) IMessageElement { 323 for _, elem := range msg.Elements { 324 if f(elem) { 325 return elem 326 } 327 } 328 return nil 329 } 330 331 func PackElementsToBody(msgElems []IMessageElement) (msgBody *message.MessageBody) { 332 if len(msgElems) == 0 { 333 return 334 } 335 elems := make([]*message.Elem, 0, len(msgElems)) 336 for _, elem := range msgElems { 337 bd, ok := elem.(ElementBuilder) 338 if !ok { 339 continue 340 } 341 elems = append(elems, bd.BuildElement()...) 342 } 343 msgBody = &message.MessageBody{ 344 RichText: &message.RichText{Elems: elems}, 345 } 346 return 347 }