Skip to content

Commit

Permalink
feat: 支持群和好友戳一戳事件
Browse files Browse the repository at this point in the history
  • Loading branch information
Redmomn committed Jul 14, 2024
1 parent a8bda65 commit 271f89c
Show file tree
Hide file tree
Showing 7 changed files with 224 additions and 3 deletions.
2 changes: 2 additions & 0 deletions client/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ type QQClient struct {
NewFriendRequestEvent EventHandle[*event.NewFriendRequest] // 好友申请
FriendRecallEvent EventHandle[*event.FriendRecall]
RenameEvent EventHandle[*event.Rename]
FriendPokeEvent EventHandle[*event.FriendPokeEvent]
GroupPokeEvent EventHandle[*event.GroupPokeEvent]

// client event handles
eventHandlers eventHandlers
Expand Down
23 changes: 23 additions & 0 deletions client/event/friend.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package event

import (
"strconv"

"github.com/LagrangeDev/LagrangeGo/client/packets/pb/message"
)

Expand All @@ -26,6 +28,12 @@ type (
Uid string
Nickname string
}

// FriendPokeEvent 好友戳一戳事件 from miraigo
FriendPokeEvent struct {
Sender uint32
Receiver uint32
}
)

func ParseFriendRequestNotice(event *message.FriendRequest, msg *message.PushMsg) *NewFriendRequest {
Expand Down Expand Up @@ -63,3 +71,18 @@ func ParseFriendRenameEvent(event *message.FriendRenameMsg) *Rename {
Nickname: event.Body.Data.RenameData.NickName,
}
}

func ParsePokeEvent(event *message.PokeEventData) *FriendPokeEvent {
e := FriendPokeEvent{}
for _, data := range event.Extra {
switch data.Key {
case "uin_str1":
sender, _ := strconv.Atoi(data.Value)
e.Sender = uint32(sender)
case "uin_str2":
receiver, _ := strconv.Atoi(data.Value)
e.Receiver = uint32(receiver)
}
}
return &e
}
16 changes: 16 additions & 0 deletions client/event/group.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,13 @@ type (
SenderNick string
OperatorNick string
}

// GroupPokeEvent 群戳一戳事件 from miraigo
GroupPokeEvent struct {
GroupUin uint32
Sender uint32
Receiver uint32
}
)

type GroupInvite struct {
Expand Down Expand Up @@ -218,3 +225,12 @@ func ParseGroupDigestEvent(event *message.EssenceNotify) *GroupDigestEvent {
OperatorNick: event.EssenceMessage.OperatorName,
}
}

func PaeseGroupPokeEvent(event *message.PokeEvent, groupUin uint32) *GroupPokeEvent {
e := ParsePokeEvent(event.Data)
return &GroupPokeEvent{
GroupUin: groupUin,
Sender: e.Sender,
Receiver: e.Receiver,
}
}
26 changes: 23 additions & 3 deletions client/listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ package client

import (
"errors"
"reflect"
"runtime/debug"

"github.com/RomiChan/protobuf/proto"
"github.com/LagrangeDev/LagrangeGo/internal/proto"

eventConverter "github.com/LagrangeDev/LagrangeGo/client/event"
"github.com/LagrangeDev/LagrangeGo/client/internal/network"
Expand Down Expand Up @@ -37,7 +38,6 @@ func decodeOlPushServicePacket(c *QQClient, pkt *network.Packet) (any, error) {
if pkg.Body == nil {
return nil, errors.New("message body is empty")
}

switch typ {
case 166, 208: // 166 for private msg, 208 for private record
prvMsg := msgConverter.ParsePrivateMessage(&msg)
Expand Down Expand Up @@ -165,6 +165,13 @@ func decodeOlPushServicePacket(c *QQClient, pkt *network.Packet) (any, error) {
}
c.RenameEvent.dispatch(c, eventConverter.ParseSelfRenameEvent(&pb, &c.transport.Sig))
return nil, nil
case 290: // friend poke event
pb := message.PokeEventData{}
err = proto.Unmarshal(pkg.Body.MsgContent, &pb)
if err != nil {
return nil, err
}
c.FriendPokeEvent.dispatch(c, eventConverter.ParsePokeEvent(&pb))
default:
c.warning("unknown subtype %d of type 0x210, proto data: %x", subType, pkg.Body.MsgContent)
}
Expand All @@ -179,7 +186,20 @@ func decodeOlPushServicePacket(c *QQClient, pkt *network.Packet) (any, error) {
}
c.GroupDigestEvent.dispatch(c, eventConverter.ParseGroupDigestEvent(&pb))
return nil, nil
case 20: // nudget(grp_id only)
case 20: // group poke event
pb := message.PokeEvent{}
err = proto.Unmarshal(pkg.Body.MsgContent, &pb)
if err != nil {
return nil, err
}
result, _ := proto.ReadField(4, pkg.Body.MsgContent)
var groupUin uint32
for _, r := range result {
if r.Type == reflect.TypeOf(int64(0)) {
groupUin = uint32(r.Vaule.(int64))
}
}
c.GroupPokeEvent.dispatch(c, eventConverter.PaeseGroupPokeEvent(&pb, groupUin))
return nil, nil
case 17: // recall
reader := binary.NewReader(pkg.Body.MsgContent)
Expand Down
25 changes: 25 additions & 0 deletions client/packets/pb/message/component.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions client/packets/pb/message/component.proto
Original file line number Diff line number Diff line change
Expand Up @@ -175,3 +175,25 @@ message PokeExtra {
uint32 Field8 = 8;
}

message PokeEvent {
// sfixed64 GroupUin = 4;
uint32 Field13 = 13;
PokeEventData Data = 26;
uint32 Field27 = 27;
uint32 Field39 = 39;
}

message PokeEventData {
uint32 Field1 = 1;
uint32 Field2 = 2;
uint32 Field3 = 3;
uint32 Seq = 6;
repeated PokeDataExtra Extra = 7;
string XMLDescription = 8;
uint32 Random = 10;
}

message PokeDataExtra {
string key = 1;
string value = 2;
}
113 changes: 113 additions & 0 deletions internal/proto/dynamic_read.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package proto

import (
"bytes"
"encoding/binary"
"fmt"
"io"
"reflect"
)

const (
WireVarint = 0
WireFixed64 = 1
WireBytes = 2
WireStartGroup = 3
WireEndGroup = 4
WireFixed32 = 5
WireSFixed32 = 5 | (1 << 3)
WireSFixed64 = 1 | (1 << 3)
)

type TypeValue struct {
Type reflect.Type
Vaule any
}

func readVarint(r io.Reader) (int64, error) {
var result int64
var shift uint
for {
var b byte
err := binary.Read(r, binary.LittleEndian, &b)
if err != nil {
return 0, err
}
result |= int64(b&0x7F) << shift
if b&0x80 == 0 {
break
}
shift += 7
}
return result, nil
}

func readFixed64(r io.Reader) (uint64, error) {
var result uint64
err := binary.Read(r, binary.LittleEndian, &result)
return result, err
}

// 从字节数组读取一个定长32位整数
func readFixed32(r io.Reader) (uint32, error) {
var result uint32
err := binary.Read(r, binary.LittleEndian, &result)
return result, err
}

func readSFixed32(r io.Reader) (int32, error) {

Check failure on line 58 in internal/proto/dynamic_read.go

View workflow job for this annotation

GitHub Actions / lint

func `readSFixed32` is unused (unused)
var result int32
err := binary.Read(r, binary.LittleEndian, &result)
return result, err
}

// 从字节数组读取有符号定长64位整数
func readSFixed64(r io.Reader) (int64, error) {

Check failure on line 65 in internal/proto/dynamic_read.go

View workflow job for this annotation

GitHub Actions / lint

func `readSFixed64` is unused (unused)
var result int64
err := binary.Read(r, binary.LittleEndian, &result)
return result, err
}

// 从字节数组读取字节切片
func readBytes(r io.Reader) ([]byte, error) {
length, err := readVarint(r)
if err != nil {
return nil, err
}
result := make([]byte, length)
_, err = io.ReadFull(r, result)
return result, err
}

func ReadField(targetField int64, data []byte) ([]*TypeValue, error) {
r := bytes.NewReader(data)
result := make([]*TypeValue, 0, 2)
for r.Len() > 0 {
key, err := readVarint(r)
if err != nil {
return nil, err
}
field := key >> 3
wireType := key & 0x7
var value any
switch wireType {
case WireVarint:
value, err = readVarint(r)

Check failure on line 95 in internal/proto/dynamic_read.go

View workflow job for this annotation

GitHub Actions / lint

ineffectual assignment to err (ineffassign)
case WireFixed64:
value, err = readFixed64(r)

Check failure on line 97 in internal/proto/dynamic_read.go

View workflow job for this annotation

GitHub Actions / lint

ineffectual assignment to err (ineffassign)
case WireBytes:
value, err = readBytes(r)

Check failure on line 99 in internal/proto/dynamic_read.go

View workflow job for this annotation

GitHub Actions / lint

ineffectual assignment to err (ineffassign)
case WireFixed32:
value, err = readFixed32(r)
default:
return nil, fmt.Errorf("unsupported wire type: %d", wireType)
}
if field == targetField {
result = append(result, &TypeValue{
Type: reflect.TypeOf(value),
Vaule: value,
})
}
}
return result, nil
}

0 comments on commit 271f89c

Please sign in to comment.