diff --git a/client/builders.go b/client/builders.go index ca9e85c4..66d6e8c4 100644 --- a/client/builders.go +++ b/client/builders.go @@ -1000,16 +1000,6 @@ func (c *QQClient) buildGroupNameUpdatePacket(groupCode int64, newName string) ( return c.buildGroupOperationPacket(body) } -func (c *QQClient) buildGroupMemoUpdatePacket(groupCode int64, newMemo string) (uint16, []byte) { - body := &oidb.D89AReqBody{ - GroupCode: groupCode, - StGroupInfo: &oidb.D89AGroupinfo{ - IngGroupMemo: []byte(newMemo), - }, - } - return c.buildGroupOperationPacket(body) -} - // OidbSvc.0x89a_0 func (c *QQClient) buildGroupMuteAllPacket(groupCode int64, mute bool) (uint16, []byte) { shutUpTime := int32(0) diff --git a/client/client.go b/client/client.go index 1402433f..db270ef1 100644 --- a/client/client.go +++ b/client/client.go @@ -19,6 +19,7 @@ import ( "github.com/Mrs4s/MiraiGo/binary" "github.com/Mrs4s/MiraiGo/client/internal/auth" "github.com/Mrs4s/MiraiGo/client/internal/highway" + "github.com/Mrs4s/MiraiGo/client/internal/intern" "github.com/Mrs4s/MiraiGo/client/internal/network" "github.com/Mrs4s/MiraiGo/client/internal/oicq" "github.com/Mrs4s/MiraiGo/client/pb/msg" @@ -578,6 +579,7 @@ func (c *QQClient) GetGroupList() ([]*GroupInfo, error) { if err != nil { return nil, err } + interner := intern.NewStringInterner() r := rsp.([]*GroupInfo) wg := sync.WaitGroup{} batch := 50 @@ -590,11 +592,12 @@ func (c *QQClient) GetGroupList() ([]*GroupInfo, error) { for j := i; j < k; j++ { go func(g *GroupInfo, wg *sync.WaitGroup) { defer wg.Done() - m, err := c.GetGroupMembers(g) + m, err := c.getGroupMembers(g, interner) if err != nil { return } g.Members = m + g.Name = interner.Intern(g.Name) }(r[j], &wg) } wg.Wait() @@ -603,6 +606,11 @@ func (c *QQClient) GetGroupList() ([]*GroupInfo, error) { } func (c *QQClient) GetGroupMembers(group *GroupInfo) ([]*GroupMemberInfo, error) { + interner := intern.NewStringInterner() + return c.getGroupMembers(group, interner) +} + +func (c *QQClient) getGroupMembers(group *GroupInfo, interner *intern.StringInterner) ([]*GroupMemberInfo, error) { var nextUin int64 var list []*GroupMemberInfo for { @@ -620,6 +628,9 @@ func (c *QQClient) GetGroupMembers(group *GroupInfo) ([]*GroupMemberInfo, error) if m.Uin == group.OwnerUin { m.Permission = Owner } + m.CardName = interner.Intern(m.CardName) + m.Nickname = interner.Intern(m.Nickname) + m.SpecialTitle = interner.Intern(m.SpecialTitle) } list = append(list, rsp.list...) if nextUin == 0 { @@ -755,10 +766,6 @@ func (c *QQClient) updateGroupName(groupCode int64, newName string) { _, _ = c.sendAndWait(c.buildGroupNameUpdatePacket(groupCode, newName)) } -func (c *QQClient) updateGroupMemo(groupCode int64, newMemo string) { - _, _ = c.sendAndWait(c.buildGroupMemoUpdatePacket(groupCode, newMemo)) -} - func (c *QQClient) groupMuteAll(groupCode int64, mute bool) { _, _ = c.sendAndWait(c.buildGroupMuteAllPacket(groupCode, mute)) } diff --git a/client/decoders.go b/client/decoders.go index 6a021980..9fa05b43 100644 --- a/client/decoders.go +++ b/client/decoders.go @@ -509,7 +509,6 @@ func decodeGroupListResponse(c *QQClient, _ *network.IncomingPacketInfo, payload Uin: g.GroupUin, Code: g.GroupCode, Name: g.GroupName, - Memo: g.GroupMemo, OwnerUin: g.GroupOwnerUin, MemberCount: uint16(g.MemberNum), MaxMemberCount: uint16(g.MaxGroupMemberNum), @@ -537,6 +536,10 @@ func decodeGroupMemberListResponse(_ *QQClient, _ *network.IncomingPacketInfo, p next := r.ReadInt64(4) l := make([]*GroupMemberInfo, 0, len(members)) for _, m := range members { + permission := Member + if m.Flag&1 != 0 { + permission = Administrator + } l = append(l, &GroupMemberInfo{ Uin: m.MemberUin, Nickname: m.Nick, @@ -547,12 +550,7 @@ func decodeGroupMemberListResponse(_ *QQClient, _ *network.IncomingPacketInfo, p LastSpeakTime: m.LastSpeakTime, SpecialTitle: m.SpecialTitle, ShutUpTimestamp: m.ShutUpTimestap, - Permission: func() MemberPermission { - if m.Flag == 1 { - return Administrator - } - return Member - }(), + Permission: permission, }) } return &groupMemberListResponse{ diff --git a/client/group_info.go b/client/group_info.go index fbe24303..4b7b1f1d 100644 --- a/client/group_info.go +++ b/client/group_info.go @@ -27,7 +27,6 @@ type ( Uin int64 Code int64 Name string - Memo string OwnerUin int64 GroupCreateTime uint32 GroupLevel uint32 @@ -237,7 +236,6 @@ func decodeGroupInfoResponse(c *QQClient, _ *network.IncomingPacketInfo, payload Uin: int64(*info.GroupInfo.GroupUin), Code: int64(*info.GroupCode), Name: string(info.GroupInfo.GroupName), - Memo: string(info.GroupInfo.GroupMemo), GroupCreateTime: *info.GroupInfo.GroupCreateTime, GroupLevel: *info.GroupInfo.GroupLevel, OwnerUin: int64(*info.GroupInfo.GroupOwner), @@ -270,13 +268,6 @@ func (g *GroupInfo) UpdateName(newName string) { } } -func (g *GroupInfo) UpdateMemo(newMemo string) { - if g.AdministratorOrOwner() { - g.client.updateGroupMemo(g.Code, newMemo) - g.Memo = newMemo - } -} - func (g *GroupInfo) UpdateGroupHeadPortrait(img []byte) { if g.AdministratorOrOwner() { _ = g.client.uploadGroupHeadPortrait(g.Uin, img) diff --git a/client/internal/intern/string.go b/client/internal/intern/string.go new file mode 100644 index 00000000..a112cff6 --- /dev/null +++ b/client/internal/intern/string.go @@ -0,0 +1,32 @@ +package intern + +import ( + "sync" +) + +// String Interning is a technique for reducing the memory footprint of large +// strings. It can re-use strings that are already in memory. + +type StringInterner struct { + mu sync.RWMutex + strings map[string]string +} + +func NewStringInterner() *StringInterner { + return &StringInterner{ + strings: make(map[string]string), + } +} + +func (i *StringInterner) Intern(s string) string { + i.mu.RLock() + if v, ok := i.strings[s]; ok { + i.mu.RUnlock() + return v + } + i.mu.RUnlock() + i.mu.Lock() + i.strings[s] = s + i.mu.Unlock() + return s +}