From a874fc034214c38667bf1f00d57568d6c820b49b Mon Sep 17 00:00:00 2001 From: DarkRRb <177549718+DarkRRb@users.noreply.github.com> Date: Thu, 30 Oct 2025 03:42:15 +0000 Subject: [PATCH] [Core] Refactor Cache --- .../Common/Interface/OperationExt.cs | 8 +- .../Internal/Context/CacheContext.cs | 405 +++++++++++++----- .../FetchFilteredGroupNotificationsEvent.cs | 16 - .../Events/System/FetchFriendsEvent.cs | 4 +- .../System/FetchGroupNotificationsEvent.cs | 8 +- .../Internal/Logic/MessagingLogic.cs | 12 +- .../FriendRecallMessageProcessor.cs | 8 +- .../GroupMemberDecreaseProcessor.cs | 22 +- .../GroupMemberIncreaseProcessor.cs | 4 +- .../GroupReactionProcessor.cs | 8 +- .../GroupRecallMessageProcessor.cs | 8 +- .../RichTextMsgProcessor.cs | 2 +- .../Internal/Logic/OperationLogic.cs | 14 +- .../FetchFilteredGroupNotificationsService.cs | 81 ---- .../System/FetchGroupNotificationsService.cs | 51 ++- .../Message/Entities/MentionEntity.cs | 8 +- Lagrange.Core/Message/Entities/ReplyEntity.cs | 2 +- Lagrange.Core/Message/MessagePacker.cs | 160 +++++-- 18 files changed, 503 insertions(+), 318 deletions(-) delete mode 100644 Lagrange.Core/Internal/Events/System/FetchFilteredGroupNotificationsEvent.cs delete mode 100644 Lagrange.Core/Internal/Services/System/FetchFilteredGroupNotificationsService.cs diff --git a/Lagrange.Core/Common/Interface/OperationExt.cs b/Lagrange.Core/Common/Interface/OperationExt.cs index 37d946f1..d8f9f41e 100644 --- a/Lagrange.Core/Common/Interface/OperationExt.cs +++ b/Lagrange.Core/Common/Interface/OperationExt.cs @@ -19,13 +19,13 @@ public static Task> FetchCookies(this BotContext cont context.EventContext.GetLogic().FetchClientKey(); public static Task> FetchFriends(this BotContext context, bool refresh = false) => - context.CacheContext.GetFriendList(refresh); + context.CacheContext.ResolveFriends(refresh); public static Task> FetchGroups(this BotContext context, bool refresh = false) => - context.CacheContext.GetGroupList(refresh); + context.CacheContext.ResolveGroups(refresh); - public static Task> FetchMembers(this BotContext context, long groupUin, bool refresh = false) => - context.CacheContext.GetMemberList(groupUin, refresh); + public static Task?> FetchMembers(this BotContext context, long groupUin, bool refresh = false) => + context.CacheContext.ResolveGroupMembers(groupUin, refresh); public static Task> FetchGroupNotifications(this BotContext context, ulong count, ulong start = 0) => context.EventContext.GetLogic().FetchGroupNotifications(count, start); diff --git a/Lagrange.Core/Internal/Context/CacheContext.cs b/Lagrange.Core/Internal/Context/CacheContext.cs index 12a752d3..58139a94 100644 --- a/Lagrange.Core/Internal/Context/CacheContext.cs +++ b/Lagrange.Core/Internal/Context/CacheContext.cs @@ -7,190 +7,363 @@ namespace Lagrange.Core.Internal.Context; internal class CacheContext(BotContext context) { - private List? _friends; + private readonly ConcurrentDictionary _uinStrangers = []; + private readonly ConcurrentDictionary _uidStrangers = []; - private List? _groups; + private readonly ConcurrentDictionary _uinFriends = []; + private readonly ConcurrentDictionary _uidFriends = []; - private readonly ConcurrentDictionary _uinToUid = new(); - private readonly ConcurrentDictionary _uidToUin = new(); + private readonly ConcurrentDictionary _categories = []; - private readonly ConcurrentDictionary> _members = new(); + private readonly ConcurrentDictionary _groups = []; + private readonly ConcurrentDictionary UinMembers, ConcurrentDictionary UidMembers)> _members = []; - private readonly Dictionary _categories = []; - - private readonly Dictionary _strangersWithUid = []; - private readonly Dictionary _strangersWithUin = []; - private readonly SemaphoreSlim _strangersLock = new(1); - - public async Task> GetFriendList(bool refresh = false) + public async Task ResolveStranger(long strangerUin, bool forceRefresh = false) { - if (refresh || _friends == null) Interlocked.Exchange(ref _friends, await FetchFriends()); + do + { + if (forceRefresh) await RefreshStranger(strangerUin); - return _friends; + if (_uinStrangers.TryGetValue(strangerUin, out var stranger)) return stranger; + } while (forceRefresh = !forceRefresh); + return null; } - public async Task> GetGroupList(bool refresh = false) + public async Task ResolveStranger(string strangerUid, bool forceRefresh = false) { - if (refresh) Interlocked.Exchange(ref _groups, await FetchGroups()); - Interlocked.CompareExchange(ref _groups, await FetchGroups(), null); + do + { + if (forceRefresh) await RefreshStranger(strangerUid); - return _groups; + if (_uidStrangers.TryGetValue(strangerUid, out var stranger)) return stranger; + } while (forceRefresh = !forceRefresh); + return null; } - public async Task> GetMemberList(long groupUin, bool refresh = false) + public async Task> ResolveFriends(bool forceRefresh = false) { - if (refresh || !_members.TryGetValue(groupUin, out var members)) - { - members = _members[groupUin] = await FetchGroupMembers(groupUin); - } + if (forceRefresh) await RefreshFriendsAndCategories(); - return members; + return [.. _uinFriends.Values]; } - public async Task> GetCategories(bool refresh = false) + public async Task ResolveFriend(long friendUin, bool forceRefresh = false) { - if (refresh || _categories.Count == 0) Interlocked.Exchange(ref _friends, await FetchFriends()); + do + { + if (forceRefresh) await RefreshFriendsAndCategories(); - return _categories.Values.ToList(); + if (_uinFriends.TryGetValue(friendUin, out var friend)) return friend; + } while (forceRefresh = !forceRefresh); + return null; } - public async Task ResolveFriend(long uin) + public async Task ResolveFriend(string friendUid, bool forceRefresh = false) { - if (_friends == null) Interlocked.Exchange(ref _friends, await FetchFriends()); - var friend = _friends?.FirstOrDefault(f => f.Uin == uin); - - if (friend == null) + do { - _friends = Interlocked.Exchange(ref _friends, await FetchFriends()); - friend = _friends?.FirstOrDefault(f => f.Uin == uin); - } + if (forceRefresh) await RefreshFriendsAndCategories(); - return friend; + if (_uidFriends.TryGetValue(friendUid, out var friend)) return friend; + } while (forceRefresh = !forceRefresh); + return null; } - public async Task<(BotGroup, BotGroupMember)?> ResolveMember(long groupUin, long memberUin) + public async Task> ResolveGroups(bool forceRefresh = false) { - var group = await ResolveGroup(groupUin); - if (group == null) return null; + if (forceRefresh) await RefreshGroups(); - if (!_members.TryGetValue(groupUin, out var members)) - { - members = _members[groupUin] = await FetchGroupMembers(groupUin); - } - var member = members.FirstOrDefault(m => m.Uin == memberUin); - return member == null ? null : (group, member); + return [.. _groups.Values]; } - public async Task ResolveGroup(long groupUin) + public async Task ResolveGroup(long groupUin, bool forceRefresh = false) { - if (_groups == null) Interlocked.Exchange(ref _groups, await FetchGroups()); - var group = _groups?.FirstOrDefault(f => f.GroupUin == groupUin); - - if (group == null) + do { - _groups = Interlocked.Exchange(ref _groups, await FetchGroups()); - group = _groups?.FirstOrDefault(f => f.GroupUin == groupUin); - } + if (forceRefresh) await RefreshGroups(); - return group; + if (_groups.TryGetValue(groupUin, out var group)) return group; + } while (forceRefresh = !forceRefresh); + return null; } - public async Task ResolveStranger(long uin) + public async Task?> ResolveGroupMembers(long groupUin, bool forceRefresh = false) { - await _strangersLock.WaitAsync(); - try + do { - if (_strangersWithUin.TryGetValue(uin, out BotStranger? stranger)) return stranger; - - stranger = await FetchStranger(uin); - _strangersWithUin.Add(uin, stranger); + if (forceRefresh) await RefreshGroupMembers(groupUin); - return stranger; - } - finally { _strangersLock.Release(); } + if (_members.TryGetValue(groupUin, out var members)) return [.. members.UinMembers.Values]; + } while (forceRefresh = !forceRefresh); + return null; } - public async Task ResolveStranger(string uid) + public async Task ResolveGroupMember(long groupUin, long groupMemberUin, bool forceRefresh = false) { - await _strangersLock.WaitAsync(); - try + do { - if (_strangersWithUid.TryGetValue(uid, out BotStranger? stranger)) return stranger; + if (forceRefresh) await RefreshGroupMembers(groupUin); - stranger = await FetchStranger(uid); - _strangersWithUin.TryAdd(stranger.Uin, stranger); - _strangersWithUid.Add(uid, stranger); - - return stranger; - } - finally { _strangersLock.Release(); } + if (_members.TryGetValue(groupUin, out var members) && members.UinMembers.TryGetValue(groupMemberUin, out var member)) return member; + } while (forceRefresh = !forceRefresh); + return null; } - public string? ResolveCachedUid(long uin) => _uinToUid.GetValueOrDefault(uin); - - public long ResolveUin(string uid) + public async Task ResolveGroupMember(long groupUin, string groupMemberUid, bool forceRefresh = false) { - if (_uidToUin.TryGetValue(uid, out long value)) return value; + do + { + if (forceRefresh) await RefreshGroupMembers(groupUin); - long uin = _uinToUid.FirstOrDefault(kvp => kvp.Value == uid).Key; - if (uin != 0) return uin; + if (_members.TryGetValue(groupUin, out var members) && members.UidMembers.TryGetValue(groupMemberUid, out var member)) return member; + } while (forceRefresh = !forceRefresh); + return null; + } - return ResolveStranger(uid).GetAwaiter().GetResult().Uin; + public async Task RefreshStranger(long strangerUin) + { + var result = await context.EventContext.SendEvent(new FetchStrangerByUinEventReq(strangerUin)); + _uinStrangers[result.Stranger.Uin] = result.Stranger; + _uidStrangers[result.Stranger.Uid] = result.Stranger; } - /// - /// Fetches the friends list from the server. - /// - private async Task> FetchFriends() + public async Task RefreshStranger(string strangerUid) { - var friends = new List(); + var result = await context.EventContext.SendEvent(new FetchStrangerByUidEventReq(strangerUid)); + _uinStrangers[result.Stranger.Uin] = result.Stranger; + _uidStrangers[result.Stranger.Uid] = result.Stranger; + } + public async Task RefreshFriendsAndCategories() + { byte[]? cookie = null; do { var result = await context.EventContext.SendEvent(new FetchFriendsEventReq(cookie)); cookie = result.Cookie; - friends.AddRange(result.Friends); - foreach (var category in result.Category) _categories[category.Id] = category; - foreach (var friend in friends) _uinToUid[friend.Uin] = friend.Uid; - } while (cookie != null); + foreach (var friend in result.Friends) + { + _uinFriends[friend.Uin] = friend; + _uidFriends[friend.Uid] = friend; + } - return friends; + foreach (var category in result.Categories) + { + _categories[category.Id] = category; + } + } while (cookie != null); } - private async Task> FetchGroups() + public async Task RefreshGroups() { - var result = await context.EventContext.SendEvent(new FetchGroupsEventReq()); - return result.Groups; + foreach (var group in (await context.EventContext.SendEvent(new FetchGroupsEventReq())).Groups) + { + _groups[group.Uin] = group; + } } - private async Task> FetchGroupMembers(long groupUin) + public async Task RefreshGroupMembers(long groupUin) { - var members = new List(); - byte[]? cookie = null; do { var result = await context.EventContext.SendEvent(new FetchGroupMembersEventReq(groupUin, cookie)); cookie = result.Cookie; - - members.AddRange(result.GroupMembers); - foreach (var member in result.GroupMembers) _uinToUid[member.Uin] = member.Uid; + var (uinMembers, uidMembers) = _members.GetOrAdd(groupUin, _ => ([], [])); + foreach (var member in result.GroupMembers) + { + uinMembers[member.Uin] = member; + uidMembers[member.Uid] = member; + } } while (cookie != null); - - return members; - } - - private async Task FetchStranger(long uin) - { - var result = await context.EventContext.SendEvent(new FetchStrangerByUinEventReq(uin)); - return result.Stranger; - } - - private async Task FetchStranger(string uid) - { - var result = await context.EventContext.SendEvent(new FetchStrangerByUidEventReq(uid)); - return result.Stranger; } -} \ No newline at end of file +} +// { +// private List? _friends; + +// private List? _groups; + +// private readonly ConcurrentDictionary _uinToUid = new(); +// private readonly ConcurrentDictionary _uidToUin = new(); + +// private readonly ConcurrentDictionary> _members = new(); + +// private readonly Dictionary _categories = []; + +// private readonly Dictionary _strangersWithUid = []; +// private readonly Dictionary _strangersWithUin = []; +// private readonly SemaphoreSlim _strangersLock = new(1); + +// public async Task> GetFriendList(bool refresh = false) +// { +// if (refresh || _friends == null) Interlocked.Exchange(ref _friends, await FetchFriends()); + +// return _friends; +// } + +// public async Task> GetGroupList(bool refresh = false) +// { +// if (refresh) Interlocked.Exchange(ref _groups, await FetchGroups()); +// Interlocked.CompareExchange(ref _groups, await FetchGroups(), null); + +// return _groups; +// } + +// public async Task> GetMemberList(long groupUin, bool refresh = false) +// { +// if (refresh || !_members.TryGetValue(groupUin, out var members)) +// { +// members = _members[groupUin] = await FetchGroupMembers(groupUin); +// } + +// return members; +// } + +// public async Task> GetCategories(bool refresh = false) +// { +// if (refresh || _categories.Count == 0) Interlocked.Exchange(ref _friends, await FetchFriends()); + +// return _categories.Values.ToList(); +// } + +// public async Task ResolveFriend(long uin) +// { +// if (_friends == null) Interlocked.Exchange(ref _friends, await FetchFriends()); +// var friend = _friends?.FirstOrDefault(f => f.Uin == uin); + +// if (friend == null) +// { +// _friends = Interlocked.Exchange(ref _friends, await FetchFriends()); +// friend = _friends?.FirstOrDefault(f => f.Uin == uin); +// } + +// return friend; +// } + +// public async Task<(BotGroup, BotGroupMember)?> ResolveMember(long groupUin, long memberUin) +// { +// var group = await ResolveGroup(groupUin); +// if (group == null) return null; + +// if (!_members.TryGetValue(groupUin, out var members)) +// { +// members = _members[groupUin] = await FetchGroupMembers(groupUin); +// } +// var member = members.FirstOrDefault(m => m.Uin == memberUin); +// return member == null ? null : (group, member); +// } + +// public async Task ResolveGroup(long groupUin) +// { +// if (_groups == null) Interlocked.Exchange(ref _groups, await FetchGroups()); +// var group = _groups?.FirstOrDefault(f => f.GroupUin == groupUin); + +// if (group == null) +// { +// _groups = Interlocked.Exchange(ref _groups, await FetchGroups()); +// group = _groups?.FirstOrDefault(f => f.GroupUin == groupUin); +// } + +// return group; +// } + +// public async Task ResolveStranger(long uin) +// { +// await _strangersLock.WaitAsync(); +// try +// { +// if (_strangersWithUin.TryGetValue(uin, out BotStranger? stranger)) return stranger; + +// stranger = await FetchStranger(uin); +// _strangersWithUin.Add(uin, stranger); + +// return stranger; +// } +// finally { _strangersLock.Release(); } +// } + +// public async Task ResolveStranger(string uid) +// { +// await _strangersLock.WaitAsync(); +// try +// { +// if (_strangersWithUid.TryGetValue(uid, out BotStranger? stranger)) return stranger; + +// stranger = await FetchStranger(uid); +// _strangersWithUin.TryAdd(stranger.Uin, stranger); +// _strangersWithUid.Add(uid, stranger); + +// return stranger; +// } +// finally { _strangersLock.Release(); } +// } + +// public string? ResolveCachedUid(long uin) => _uinToUid.GetValueOrDefault(uin); + +// public long ResolveUin(string uid) +// { +// if (_uidToUin.TryGetValue(uid, out long value)) return value; + +// long uin = _uinToUid.FirstOrDefault(kvp => kvp.Value == uid).Key; +// if (uin != 0) return uin; + +// return ResolveStranger(uid).GetAwaiter().GetResult().Uin; +// } + +// /// +// /// Fetches the friends list from the server. +// /// +// private async Task> FetchFriends() +// { +// var friends = new List(); + +// byte[]? cookie = null; +// do +// { +// var result = await context.EventContext.SendEvent(new FetchFriendsEventReq(cookie)); +// cookie = result.Cookie; + +// friends.AddRange(result.Friends); +// foreach (var category in result.Category) _categories[category.Id] = category; +// foreach (var friend in friends) _uinToUid[friend.Uin] = friend.Uid; +// } while (cookie != null); + +// return friends; +// } + +// private async Task> FetchGroups() +// { +// var result = await context.EventContext.SendEvent(new FetchGroupsEventReq()); +// return result.Groups; +// } + +// private async Task> FetchGroupMembers(long groupUin) +// { +// var members = new List(); + +// byte[]? cookie = null; +// do +// { +// var result = await context.EventContext.SendEvent(new FetchGroupMembersEventReq(groupUin, cookie)); +// cookie = result.Cookie; + +// members.AddRange(result.GroupMembers); +// foreach (var member in result.GroupMembers) _uinToUid[member.Uin] = member.Uid; +// } while (cookie != null); + +// return members; +// } + +// private async Task FetchStranger(long uin) +// { +// var result = await context.EventContext.SendEvent(new FetchStrangerByUinEventReq(uin)); +// return result.Stranger; +// } + +// private async Task FetchStranger(string uid) +// { +// var result = await context.EventContext.SendEvent(new FetchStrangerByUidEventReq(uid)); +// return result.Stranger; +// } +// } \ No newline at end of file diff --git a/Lagrange.Core/Internal/Events/System/FetchFilteredGroupNotificationsEvent.cs b/Lagrange.Core/Internal/Events/System/FetchFilteredGroupNotificationsEvent.cs deleted file mode 100644 index c402a900..00000000 --- a/Lagrange.Core/Internal/Events/System/FetchFilteredGroupNotificationsEvent.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using Lagrange.Core.Common.Entity; - -namespace Lagrange.Core.Internal.Events.System; - -internal class FetchFilteredGroupNotificationsEventReq(ulong count, ulong start = 0) : ProtocolEvent -{ - public ulong Count { get; } = count; - - public ulong Start { get; } = start; -} - -internal class FetchFilteredGroupNotificationsEventResp(List groupNotifications) : ProtocolEvent -{ - public List GroupNotifications { get; } = groupNotifications; -} \ No newline at end of file diff --git a/Lagrange.Core/Internal/Events/System/FetchFriendsEvent.cs b/Lagrange.Core/Internal/Events/System/FetchFriendsEvent.cs index a0205c5c..cee1077e 100644 --- a/Lagrange.Core/Internal/Events/System/FetchFriendsEvent.cs +++ b/Lagrange.Core/Internal/Events/System/FetchFriendsEvent.cs @@ -7,11 +7,11 @@ internal class FetchFriendsEventReq(byte[]? cookie) : ProtocolEvent public byte[]? Cookie { get; set; } = cookie; // for the request of next page } -internal class FetchFriendsEventResp(List friends, List category, byte[]? cookie) : ProtocolEvent +internal class FetchFriendsEventResp(List friends, List categories, byte[]? cookie) : ProtocolEvent { public List Friends { get; } = friends; - public List Category { get; } = category; + public List Categories { get; } = categories; public byte[]? Cookie { get; } = cookie; } \ No newline at end of file diff --git a/Lagrange.Core/Internal/Events/System/FetchGroupNotificationsEvent.cs b/Lagrange.Core/Internal/Events/System/FetchGroupNotificationsEvent.cs index 89e899cd..a0c44940 100644 --- a/Lagrange.Core/Internal/Events/System/FetchGroupNotificationsEvent.cs +++ b/Lagrange.Core/Internal/Events/System/FetchGroupNotificationsEvent.cs @@ -1,4 +1,3 @@ -using System.Diagnostics.CodeAnalysis; using Lagrange.Core.Common.Entity; namespace Lagrange.Core.Internal.Events.System; @@ -10,6 +9,13 @@ internal class FetchGroupNotificationsEventReq(ulong count, ulong start = 0) : P public ulong Start { get; } = start; } +internal class FetchFilteredGroupNotificationsEventReq(ulong count, ulong start = 0) : ProtocolEvent +{ + public ulong Count { get; } = count; + + public ulong Start { get; } = start; +} + internal class FetchGroupNotificationsEventResp(List groupNotifications) : ProtocolEvent { public List GroupNotifications { get; } = groupNotifications; diff --git a/Lagrange.Core/Internal/Logic/MessagingLogic.cs b/Lagrange.Core/Internal/Logic/MessagingLogic.cs index 21617900..5a4f8118 100644 --- a/Lagrange.Core/Internal/Logic/MessagingLogic.cs +++ b/Lagrange.Core/Internal/Logic/MessagingLogic.cs @@ -25,8 +25,8 @@ public async Task> GetGroupMessage(long groupUin, ulong startSe public async Task> GetRoamMessage(long peerUin, uint time, uint count) { - string peerUid = context.CacheContext.ResolveCachedUid(peerUin) ?? throw new InvalidTargetException(peerUin); - var result = await context.EventContext.SendEvent(new GetRoamMessageEventReq(peerUid, time, count)); + var friend = (await context.CacheContext.ResolveFriend(peerUin)) ?? throw new InvalidTargetException(peerUin); + var result = await context.EventContext.SendEvent(new GetRoamMessageEventReq(friend.Uid, time, count)); var messages = new List(result.Chains.Count); foreach (var chain in result.Chains) messages.Add(await Parse(chain)); return messages; @@ -34,8 +34,8 @@ public async Task> GetRoamMessage(long peerUin, uint time, uint public async Task> GetC2CMessage(long peerUin, ulong startSequence, ulong endSequence) { - string peerUid = context.CacheContext.ResolveCachedUid(peerUin) ?? throw new InvalidTargetException(peerUin); - var result = await context.EventContext.SendEvent(new GetC2CMessageEventReq(peerUid, startSequence, endSequence)); + var friend = (await context.CacheContext.ResolveFriend(peerUin)) ?? throw new InvalidTargetException(peerUin); + var result = await context.EventContext.SendEvent(new GetC2CMessageEventReq(friend.Uid, startSequence, endSequence)); var messages = new List(result.Chains.Count); foreach (var chain in result.Chains) messages.Add(await Parse(chain)); return messages; @@ -59,8 +59,8 @@ public async Task SendFriendMessage(long friendUin, MessageChain cha public async Task SendGroupMessage(long groupUin, MessageChain chain) { - var (group, self) = await context.CacheContext.ResolveMember(groupUin, context.BotUin) ?? throw new InvalidTargetException(context.BotUin, groupUin); - var message = await BuildMessage(chain, self, group); + var member = await context.CacheContext.ResolveGroupMember(groupUin, context.BotUin) ?? throw new InvalidTargetException(context.BotUin, groupUin); + var message = await BuildMessage(chain, member, member.Group); var result = await context.EventContext.SendEvent(new SendMessageEventReq(message)); if (result == null) throw new InvalidOperationException(); diff --git a/Lagrange.Core/Internal/Logic/MsgPushProccessors/FriendRecallMessageProcessor.cs b/Lagrange.Core/Internal/Logic/MsgPushProccessors/FriendRecallMessageProcessor.cs index 259865a9..38f56cd6 100644 --- a/Lagrange.Core/Internal/Logic/MsgPushProccessors/FriendRecallMessageProcessor.cs +++ b/Lagrange.Core/Internal/Logic/MsgPushProccessors/FriendRecallMessageProcessor.cs @@ -9,12 +9,12 @@ namespace Lagrange.Core.Internal.Logic.MsgPushProccessors; [MsgPushProcessor(MsgType.Event0x210, 139, true)] internal class FriendRecallMessageProcessor : MsgPushProcessorBase { - internal override ValueTask Handle(BotContext bot, MsgType msgType, int subType, PushMessageEvent msgEvt, ReadOnlyMemory? content) + internal override async ValueTask Handle(BotContext bot, MsgType msgType, int subType, PushMessageEvent msgEvt, ReadOnlyMemory? content) { var recall = ProtoHelper.Deserialize(content!.Value.Span); - long fromUin = bot.CacheContext.ResolveUin(recall.Info.FromUid); - long toUin = bot.CacheContext.ResolveUin(recall.Info.ToUid); + long fromUin = (await bot.CacheContext.ResolveFriend(recall.Info.FromUid))?.Uin ?? 0; + long toUin = (await bot.CacheContext.ResolveFriend(recall.Info.ToUid))?.Uin ?? 0; var @event = new BotFriendRecallEvent( fromUin == bot.BotUin ? toUin : fromUin, fromUin, @@ -23,6 +23,6 @@ internal override ValueTask Handle(BotContext bot, MsgType msgType, int su ); bot.EventInvoker.PostEvent(@event); - return ValueTask.FromResult(true); + return true; } } \ No newline at end of file diff --git a/Lagrange.Core/Internal/Logic/MsgPushProccessors/GroupMemberDecreaseProcessor.cs b/Lagrange.Core/Internal/Logic/MsgPushProccessors/GroupMemberDecreaseProcessor.cs index 11c2fe9a..edd12aed 100644 --- a/Lagrange.Core/Internal/Logic/MsgPushProccessors/GroupMemberDecreaseProcessor.cs +++ b/Lagrange.Core/Internal/Logic/MsgPushProccessors/GroupMemberDecreaseProcessor.cs @@ -1,4 +1,5 @@ using Lagrange.Core.Events.EventArgs; +using Lagrange.Core.Exceptions; using Lagrange.Core.Internal.Events.Message; using Lagrange.Core.Internal.Packets.Notify; using Lagrange.Core.Utility; @@ -18,25 +19,32 @@ internal override async ValueTask Handle(BotContext context, MsgType msgTy var op = ProtoHelper.Deserialize(decrease.Operator.AsSpan()); context.EventInvoker.PostEvent(new BotGroupMemberDecreaseEvent( decrease.GroupUin, - context.CacheContext.ResolveUin(decrease.MemberUid), - op.Operator.Uid != null ? context.CacheContext.ResolveUin(op.Operator.Uid) : null + context.BotUin, + op.Operator.Uid != null ? (await context.CacheContext.ResolveStranger(op.Operator.Uid))?.Uin ?? 0 : null )); + await context.CacheContext.RefreshGroups(); return true; } case DecreaseType.Exit: { - await context.CacheContext.GetMemberList(decrease.GroupUin); context.EventInvoker.PostEvent(new BotGroupMemberDecreaseEvent( decrease.GroupUin, - context.CacheContext.ResolveUin(decrease.MemberUid), + (await context.CacheContext.ResolveStranger(decrease.MemberUid))?.Uin ?? 0, null )); + await context.CacheContext.RefreshGroupMembers(decrease.GroupUin); return true; } case DecreaseType.Kick: { - await context.CacheContext.GetMemberList(decrease.GroupUin); - goto case DecreaseType.KickSelf; + var op = ProtoHelper.Deserialize(decrease.Operator.AsSpan()); + context.EventInvoker.PostEvent(new BotGroupMemberDecreaseEvent( + decrease.GroupUin, + (await context.CacheContext.ResolveStranger(decrease.MemberUid))?.Uin ?? 0, + op.Operator.Uid != null ? (await context.CacheContext.ResolveStranger(op.Operator.Uid))?.Uin ?? 0 : null + )); + await context.CacheContext.RefreshGroupMembers(decrease.GroupUin); + return true; } default: { @@ -47,7 +55,7 @@ internal override async ValueTask Handle(BotContext context, MsgType msgTy return false; } - + private enum DecreaseType { KickSelf = 3, diff --git a/Lagrange.Core/Internal/Logic/MsgPushProccessors/GroupMemberIncreaseProcessor.cs b/Lagrange.Core/Internal/Logic/MsgPushProccessors/GroupMemberIncreaseProcessor.cs index 45e4e863..1874f464 100644 --- a/Lagrange.Core/Internal/Logic/MsgPushProccessors/GroupMemberIncreaseProcessor.cs +++ b/Lagrange.Core/Internal/Logic/MsgPushProccessors/GroupMemberIncreaseProcessor.cs @@ -28,8 +28,8 @@ internal override async ValueTask Handle(BotContext context, MsgType msgTy var operatorUin = notification?.OperatorUin; context.EventInvoker.PostEvent(new BotGroupMemberIncreaseEvent( increase.GroupUin, - context.CacheContext.ResolveUin(increase.MemberUid), - context.CacheContext.ResolveUin(Encoding.UTF8.GetString(increase.Operator.AsSpan())), + (await context.CacheContext.ResolveGroupMember(increase.GroupUin, increase.MemberUid))?.Uin ?? 0, + (await context.CacheContext.ResolveGroupMember(increase.GroupUin, Encoding.UTF8.GetString(increase.Operator.AsSpan())))?.Uin ?? 0, increase.IncreaseType, operatorUin)); return true; diff --git a/Lagrange.Core/Internal/Logic/MsgPushProccessors/GroupReactionProcessor.cs b/Lagrange.Core/Internal/Logic/MsgPushProccessors/GroupReactionProcessor.cs index 8f49cc4e..39622a87 100644 --- a/Lagrange.Core/Internal/Logic/MsgPushProccessors/GroupReactionProcessor.cs +++ b/Lagrange.Core/Internal/Logic/MsgPushProccessors/GroupReactionProcessor.cs @@ -9,7 +9,7 @@ namespace Lagrange.Core.Internal.Logic.MsgPushProccessors; [MsgPushProcessor(MsgType.Event0x2DC, 16, true)] internal class GroupReactionProcessor : MsgPushProcessorBase { - internal override ValueTask Handle(BotContext context, MsgType msgType, int subType, + internal override async ValueTask Handle(BotContext context, MsgType msgType, int subType, PushMessageEvent msgEvt, ReadOnlyMemory? content) { var reader = new BinaryPacket(content!.Value.Span); @@ -17,10 +17,10 @@ internal override ValueTask Handle(BotContext context, MsgType msgType, in reader.Skip(4 + 1); var proto = reader.ReadBytes(Prefix.Int16 | Prefix.LengthOnly); var body = ProtoHelper.Deserialize(proto); - if (body.SubType != 35) return ValueTask.FromResult(false); // GroupReactionNotice + if (body.SubType != 35) return false; // GroupReactionNotice var reaction = body.Reaction.Data.Data; - long @operator = context.CacheContext.ResolveUin(reaction.Data.OperatorUid); + long @operator = (await context.CacheContext.ResolveGroupMember(body.GroupUin, reaction.Data.OperatorUid))?.Uin ?? 0; context.EventInvoker.PostEvent(new BotGroupReactionEvent( body.GroupUin, @@ -30,6 +30,6 @@ internal override ValueTask Handle(BotContext context, MsgType msgType, in reaction.Data.Code, reaction.Data.CurrentCount )); - return ValueTask.FromResult(true); + return true; } } \ No newline at end of file diff --git a/Lagrange.Core/Internal/Logic/MsgPushProccessors/GroupRecallMessageProcessor.cs b/Lagrange.Core/Internal/Logic/MsgPushProccessors/GroupRecallMessageProcessor.cs index 7306c2b5..03961000 100644 --- a/Lagrange.Core/Internal/Logic/MsgPushProccessors/GroupRecallMessageProcessor.cs +++ b/Lagrange.Core/Internal/Logic/MsgPushProccessors/GroupRecallMessageProcessor.cs @@ -9,7 +9,7 @@ namespace Lagrange.Core.Internal.Logic.MsgPushProccessors; [MsgPushProcessor(MsgType.Event0x2DC, 17, true)] internal class GroupRecallMessageProcessor : MsgPushProcessorBase { - internal override ValueTask Handle(BotContext context, MsgType msgType, int subType, PushMessageEvent msgEvt, ReadOnlyMemory? content) + internal override async ValueTask Handle(BotContext context, MsgType msgType, int subType, PushMessageEvent msgEvt, ReadOnlyMemory? content) { var packet = new BinaryPacket(content!.Value.Span); // group uin and 1 byte @@ -21,13 +21,13 @@ internal override ValueTask Handle(BotContext context, MsgType msgType, in var @event = new BotGroupRecallEvent( notify.GroupUin, message.Sequence, - context.CacheContext.ResolveUin(message.AuthorUid), - notify.Recall.OperatorUid != null ? context.CacheContext.ResolveUin(notify.Recall.OperatorUid) : 0, + (await context.CacheContext.ResolveGroupMember(notify.GroupUin, message.AuthorUid))?.Uin ?? 0, + notify.Recall.OperatorUid != null ? (await context.CacheContext.ResolveGroupMember(notify.GroupUin, notify.Recall.OperatorUid))?.Uin ?? 0 : 0, notify.Recall.TipInfo?.Tip ?? string.Empty ); context.EventInvoker.PostEvent(@event); } - return ValueTask.FromResult(true); + return true; } } \ No newline at end of file diff --git a/Lagrange.Core/Internal/Logic/MsgPushProccessors/RichTextMsgProcessor.cs b/Lagrange.Core/Internal/Logic/MsgPushProccessors/RichTextMsgProcessor.cs index da73e172..e0b77679 100644 --- a/Lagrange.Core/Internal/Logic/MsgPushProccessors/RichTextMsgProcessor.cs +++ b/Lagrange.Core/Internal/Logic/MsgPushProccessors/RichTextMsgProcessor.cs @@ -29,7 +29,7 @@ internal override async ValueTask Handle(BotContext context, MsgType msgTy groupUin, sequence, context.BotUin, - context.CacheContext.ResolveCachedUid(context.BotUin) ?? string.Empty, + (await context.CacheContext.ResolveFriend(context.BotUin))?.Uid ?? string.Empty, BotGroupNotificationState.Wait, null, null, diff --git a/Lagrange.Core/Internal/Logic/OperationLogic.cs b/Lagrange.Core/Internal/Logic/OperationLogic.cs index b491ef75..388bcf00 100644 --- a/Lagrange.Core/Internal/Logic/OperationLogic.cs +++ b/Lagrange.Core/Internal/Logic/OperationLogic.cs @@ -41,21 +41,13 @@ public async Task GroupRename(long groupUin, string name) public async Task GroupSetSpecialTitle(long groupUin, long targetUin, string title) { - if (context.CacheContext.ResolveCachedUid(targetUin) is not { } uid) - { - await context.CacheContext.GetMemberList(groupUin, true); - uid = context.CacheContext.ResolveCachedUid(targetUin) ?? throw new InvalidTargetException(targetUin); - } + string uid = (await context.CacheContext.ResolveGroupMember(groupUin, targetUin) ?? throw new InvalidTargetException(targetUin, groupUin)).Uid; await context.EventContext.SendEvent(new GroupSetSpecialTitleEventReq(groupUin, uid, title)); } public async Task GroupMemberRename(long groupUin, long targetUin, string name) { - if (context.CacheContext.ResolveCachedUid(targetUin) is not { } uid) - { - await context.CacheContext.GetMemberList(groupUin, true); - uid = context.CacheContext.ResolveCachedUid(targetUin) ?? throw new InvalidTargetException(targetUin); - } + string uid = (await context.CacheContext.ResolveGroupMember(groupUin, targetUin) ?? throw new InvalidTargetException(targetUin, groupUin)).Uid; await context.EventContext.SendEvent(new GroupMemberRenameEventReq(groupUin, uid, name)); } @@ -241,7 +233,7 @@ public async Task> FetchGroupNotifications(ulong public async Task> FetchFilteredGroupNotifications(ulong count, ulong start) { var req = new FetchFilteredGroupNotificationsEventReq(count, start); - var resp = await context.EventContext.SendEvent(req); + var resp = await context.EventContext.SendEvent(req); return resp.GroupNotifications; } diff --git a/Lagrange.Core/Internal/Services/System/FetchFilteredGroupNotificationsService.cs b/Lagrange.Core/Internal/Services/System/FetchFilteredGroupNotificationsService.cs deleted file mode 100644 index 76fdea12..00000000 --- a/Lagrange.Core/Internal/Services/System/FetchFilteredGroupNotificationsService.cs +++ /dev/null @@ -1,81 +0,0 @@ -using Lagrange.Core.Common; -using Lagrange.Core.Common.Entity; -using Lagrange.Core.Internal.Events; -using Lagrange.Core.Internal.Events.System; -using Lagrange.Core.Internal.Packets.Service; - -namespace Lagrange.Core.Internal.Services.System; - -[EventSubscribe(Protocols.All)] -[Service("OidbSvcTrpcTcp.0x10c0_2")] -internal class FetchFilteredGroupNotificationsService : OidbService -{ - private protected override uint Command => 0x10c0; - - private protected override uint Service => 2; - - private protected override Task ProcessRequest(FetchFilteredGroupNotificationsEventReq request, BotContext context) - { - return Task.FromResult(new FetchGroupNotificationsRequest - { - Count = request.Count, - StartSequence = request.Start - }); - } - - private protected override Task ProcessResponse(FetchGroupNotificationsResponse response, BotContext context) - { - if (response.GroupNotifications == null) - { - return Task.FromResult(new FetchFilteredGroupNotificationsEventResp([])); - } - - List notifications = []; - foreach (var request in response.GroupNotifications) - { - var targetUin = context.CacheContext.ResolveUin(request.Target.Uid); - long? operatorUin = request.Operator != null - ? context.CacheContext.ResolveUin(request.Operator.Uid) - : null; - long? inviterUin = request.Inviter != null - ? context.CacheContext.ResolveUin(request.Inviter.Uid) - : null; - - var notification = request.Type switch - { - 1 => new BotGroupJoinNotification( - request.Group.GroupUin, - request.Sequence, - targetUin, - request.Target.Uid, - (BotGroupNotificationState)request.State, - operatorUin, - request.Operator?.Uid, - request.Comment, - true - ), - 22 => new BotGroupInviteNotification( - request.Group.GroupUin, - request.Sequence, - targetUin, - request.Target.Uid, - (BotGroupNotificationState)request.State, - operatorUin, - request.Operator?.Uid, - inviterUin ?? 0, - request.Inviter?.Uid ?? string.Empty, - true - ), - _ => LogUnknownNotificationType(context, request.Type), - }; - if (notification != null) notifications.Add(notification); - } - return Task.FromResult(new FetchFilteredGroupNotificationsEventResp(notifications)); - } - - private BotGroupNotificationBase? LogUnknownNotificationType(BotContext context, ulong type) - { - context.LogDebug(nameof(FetchFilteredGroupNotificationsService), "Unknown filtered notification type: {0}", null, type); - return null; - } -} \ No newline at end of file diff --git a/Lagrange.Core/Internal/Services/System/FetchGroupNotificationsService.cs b/Lagrange.Core/Internal/Services/System/FetchGroupNotificationsService.cs index 1b262b73..81ed32c2 100644 --- a/Lagrange.Core/Internal/Services/System/FetchGroupNotificationsService.cs +++ b/Lagrange.Core/Internal/Services/System/FetchGroupNotificationsService.cs @@ -25,20 +25,49 @@ private protected override Task ProcessRequest(F private protected override Task ProcessResponse(FetchGroupNotificationsResponse response, BotContext context) { - if (response.GroupNotifications == null) + return Helper.ProcessResponse(response, context, false); + } +} + + +[EventSubscribe(Protocols.All)] +[Service("OidbSvcTrpcTcp.0x10c0_2")] +internal class FetchFilteredGroupNotificationsService : OidbService +{ + private protected override uint Command => 0x10c0; + + private protected override uint Service => 2; + + private protected override Task ProcessRequest(FetchFilteredGroupNotificationsEventReq request, BotContext context) + { + return Task.FromResult(new FetchGroupNotificationsRequest { - return Task.FromResult(new FetchGroupNotificationsEventResp([])); - } + Count = request.Count, + StartSequence = request.Start + }); + } + + private protected override Task ProcessResponse(FetchGroupNotificationsResponse response, BotContext context) + { + return Helper.ProcessResponse(response, context, true); + } +} + +file class Helper +{ + public static async Task ProcessResponse(FetchGroupNotificationsResponse response, BotContext context, bool isFiltered) + { + if (response.GroupNotifications == null) return new FetchGroupNotificationsEventResp([]); List notifications = []; foreach (var request in response.GroupNotifications) { - var targetUin = context.CacheContext.ResolveUin(request.Target.Uid); + long targetUin = (await context.CacheContext.ResolveStranger(request.Target.Uid))?.Uin ?? 0; long? operatorUin = request.Operator != null - ? context.CacheContext.ResolveUin(request.Operator.Uid) + ? (await context.CacheContext.ResolveStranger(request.Operator.Uid))?.Uin ?? 0 : null; long? inviterUin = request.Inviter != null - ? context.CacheContext.ResolveUin(request.Inviter.Uid) + ? (await context.CacheContext.ResolveStranger(request.Inviter.Uid))?.Uin ?? 0 : null; var notification = request.Type switch @@ -52,7 +81,7 @@ private protected override Task ProcessRespons operatorUin, request.Operator?.Uid, request.Comment, - false + isFiltered ), 3 => new BotGroupSetAdminNotification( request.Group.GroupUin, @@ -94,18 +123,18 @@ private protected override Task ProcessRespons request.Operator?.Uid, inviterUin ?? 0, request.Inviter?.Uid ?? string.Empty, - false + isFiltered ), _ => LogUnknownNotificationType(context, request.Type), }; if (notification != null) notifications.Add(notification); } - return Task.FromResult(new FetchGroupNotificationsEventResp(notifications)); + return new FetchGroupNotificationsEventResp(notifications); } - private BotGroupNotificationBase? LogUnknownNotificationType(BotContext context, ulong type) + private static BotGroupNotificationBase? LogUnknownNotificationType(BotContext context, ulong type) { - context.LogDebug(nameof(FetchGroupNotificationsService), "Unknown notification type: {0}", null, type); + context.LogDebug(nameof(FetchFilteredGroupNotificationsService), "Unknown filtered notification type: {0}", null, type); return null; } } \ No newline at end of file diff --git a/Lagrange.Core/Message/Entities/MentionEntity.cs b/Lagrange.Core/Message/Entities/MentionEntity.cs index 315dde0c..73616576 100644 --- a/Lagrange.Core/Message/Entities/MentionEntity.cs +++ b/Lagrange.Core/Message/Entities/MentionEntity.cs @@ -24,12 +24,12 @@ async Task IMessageEntity.Preprocess(BotContext context, BotMessage message) switch (message.Receiver) { case BotGroup group: - (_, contact) = await context.CacheContext.ResolveMember(group.Uin, Uin) ?? throw new InvalidTargetException(Uin, group.Uin); + contact = await context.CacheContext.ResolveGroupMember(group.Uin, Uin) ?? throw new InvalidTargetException(Uin, group.Uin); break; - case BotFriend friend: - contact = await context.CacheContext.ResolveFriend(Uin) ?? throw new InvalidTargetException(Uin, friend.Uin); + case BotFriend: // Maybe self + contact = await context.CacheContext.ResolveFriend(Uin) ?? throw new InvalidTargetException(Uin); break; - case BotStranger stranger: + case BotStranger stranger: // hummmm... contact = stranger; break; default: diff --git a/Lagrange.Core/Message/Entities/ReplyEntity.cs b/Lagrange.Core/Message/Entities/ReplyEntity.cs index 6d990540..344382d2 100644 --- a/Lagrange.Core/Message/Entities/ReplyEntity.cs +++ b/Lagrange.Core/Message/Entities/ReplyEntity.cs @@ -28,7 +28,7 @@ async Task IMessageEntity.Postprocess(BotContext context, BotMessage message) Source = message.Contact switch { BotFriend => await context.CacheContext.ResolveFriend(SourceUin), - BotGroupMember s => (await context.CacheContext.ResolveMember(s.Group.GroupUin, SourceUin)).GetValueOrDefault().Item2, + BotGroupMember s => await context.CacheContext.ResolveGroupMember(s.Group.GroupUin, SourceUin), BotStranger => await context.CacheContext.ResolveStranger(SourceUin), _ => null }; diff --git a/Lagrange.Core/Message/MessagePacker.cs b/Lagrange.Core/Message/MessagePacker.cs index 028b52aa..28cadcce 100644 --- a/Lagrange.Core/Message/MessagePacker.cs +++ b/Lagrange.Core/Message/MessagePacker.cs @@ -1,6 +1,7 @@ using System.Diagnostics.CodeAnalysis; using System.Formats.Asn1; using System.Text; +using Lagrange.Core.Common; using Lagrange.Core.Common.Entity; using Lagrange.Core.Internal.Events.System; using Lagrange.Core.Internal.Packets.Message; @@ -15,9 +16,9 @@ namespace Lagrange.Core.Message; internal class MessagePacker { private readonly BotContext _context; - + private readonly List _factory; - + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "All the types are preserved in the csproj by using the TrimmerRootAssembly attribute")] [UnconditionalSuppressMessage("Trimming", "IL2062", Justification = "All the types are preserved in the csproj by using the TrimmerRootAssembly attribute")] [UnconditionalSuppressMessage("Trimming", "IL2072", Justification = "All the types are preserved in the csproj by using the TrimmerRootAssembly attribute")] @@ -50,11 +51,11 @@ public async Task Parse(CommonMessage msg) ClientSequence = contentHead.ClientSequence, Random = contentHead.Random }; - + if (msg.MessageBody is null) return message; - - if (ParsePttRichText(msg.MessageBody.RichText) is { } record) + + if (ParsePttRichText(msg.MessageBody.RichText) is { } record) { message.Entities.Add(record); } @@ -86,46 +87,119 @@ private async Task ResolveContact(int type, RoutingHead routingHead) switch (type) { case 166: - var friend = await _context.CacheContext.ResolveFriend(routingHead.FromUin); - return friend ?? new BotFriend(routingHead.FromUin, routingHead.FromUid, string.Empty, string.Empty, string.Empty, string.Empty, null!); + return await _context.CacheContext.ResolveFriend(routingHead.FromUin) ?? new BotFriend( + routingHead.FromUin, + routingHead.FromUid, + string.Empty, + string.Empty, + string.Empty, + string.Empty, + null!); case 141: - return (await _context.CacheContext.ResolveStranger(routingHead.ToUid)).CloneWithSource(routingHead.CommonC2C.FromTinyId); + return (await _context.CacheContext.ResolveStranger(routingHead.FromUid))?.CloneWithSource(routingHead.CommonC2C.FromTinyId) ?? new( + routingHead.FromUin, + routingHead.FromUid, + string.Empty, + string.Empty, + string.Empty, + 0, + BotGender.Unset, + DateTime.Now, + null, + 0, + string.Empty, + string.Empty, + string.Empty, + null + ); case 82: - var items = await _context.CacheContext.ResolveMember(routingHead.Group.GroupCode, routingHead.FromUin); - if (items != null) return items.Value.Item2; - - var dummyGroup = new BotGroup(routingHead.Group.GroupCode, routingHead.Group.GroupName, 0, 0, 0, null, null, null); - return new BotGroupMember(dummyGroup, routingHead.FromUin, routingHead.FromUid, routingHead.Group.GroupCard, GroupMemberPermission.Member, 0, routingHead.Group.GroupCard, null, DateTime.Now, DateTime.Now, DateTime.Now); - + return await _context.CacheContext.ResolveGroupMember(routingHead.Group.GroupCode, routingHead.FromUin) ?? new BotGroupMember( + new BotGroup( + routingHead.Group.GroupCode, + routingHead.Group.GroupName, + 0, + 0, + 0, + null, + null, + null + ), + routingHead.FromUin, + routingHead.FromUid, + routingHead.Group.GroupCard, + GroupMemberPermission.Member, + 0, + routingHead.Group.GroupCard, + null, + DateTime.Now, + DateTime.Now, + DateTime.Now + ); default: throw new NotImplementedException(); } } - + private async Task ResolveReceiver(int type, RoutingHead routingHead) { switch (type) { case 166: - var friend = await _context.CacheContext.ResolveFriend(routingHead.ToUin); - if (friend == null) - { - return new BotFriend(routingHead.ToUin, routingHead.ToUid, string.Empty, string.Empty, string.Empty, string.Empty, null!); - } - - return friend; + return await _context.CacheContext.ResolveFriend(routingHead.ToUin) ?? new BotFriend( + routingHead.ToUin, + routingHead.ToUid, + string.Empty, + string.Empty, + string.Empty, + string.Empty, + new BotFriendCategory( + 0, + string.Empty, + 0, + 0 + ) + ); case 141: - return (await _context.CacheContext.ResolveStranger(routingHead.ToUid)).CloneWithSource(routingHead.CommonC2C.FromTinyId); + return (await _context.CacheContext.ResolveStranger(routingHead.ToUid))?.CloneWithSource(routingHead.CommonC2C.FromTinyId) ?? new( + routingHead.ToUin, + routingHead.ToUid, + string.Empty, + string.Empty, + string.Empty, + 0, + BotGender.Unset, + DateTime.Now, + null, + 0, + string.Empty, + string.Empty, + string.Empty, + null + ); case 82: - var items = await _context.CacheContext.ResolveMember(routingHead.Group.GroupCode, routingHead.ToUin); - if (items == null) - { - var dummyGroup = new BotGroup(routingHead.Group.GroupCode, routingHead.Group.GroupName, 0, 0, 0, null, null, null); - return new BotGroupMember(dummyGroup, routingHead.ToUin, routingHead.ToUid, routingHead.Group.GroupCard, GroupMemberPermission.Member, 0, routingHead.Group.GroupCard, null, DateTime.Now, DateTime.Now, DateTime.Now); - } - - return items.Value.Item2; + return await _context.CacheContext.ResolveGroupMember(routingHead.Group.GroupCode, routingHead.ToUin) ?? new BotGroupMember( + new BotGroup( + routingHead.Group.GroupCode, + routingHead.Group.GroupName, + 0, + 0, + 0, + null, + null, + null + ), + routingHead.ToUin, + routingHead.ToUid, + routingHead.Group.GroupCard, + GroupMemberPermission.Member, + 0, + routingHead.Group.GroupCard, + null, + DateTime.Now, + DateTime.Now, + DateTime.Now + ); default: throw new NotImplementedException(); } @@ -143,7 +217,7 @@ public static ReadOnlyMemory Build(BotMessage message) case BotStranger: throw new NotSupportedException(); } - + if (message.Receiver is BotGroup group) { routingHead.Group = new Grp { GroupUin = group.GroupUin }; @@ -190,7 +264,7 @@ public static ReadOnlyMemory BuildTrans0X211(BotFriend friend, FileUploadE FileIdCrcMedia = resp.CrcMedia } }; - + var proto = new PbSendMsgReq { RoutingHead = new SendRoutingHead @@ -219,7 +293,7 @@ public static ReadOnlyMemory BuildTrans0X211(BotFriend friend, FileUploadE return ProtoHelper.Serialize(proto); } - public Task BuildFake(BotMessage msg) + public async Task BuildFake(BotMessage msg) { var proto = new CommonMessage { @@ -255,13 +329,13 @@ public Task BuildFake(BotMessage msg) }, MessageBody = new MessageBody { RichText = new RichText { Elems = [] } } }; - + proto.RoutingHead.FromUin = msg.Contact.Uin; - proto.RoutingHead.FromUid = _context.CacheContext.ResolveCachedUid(msg.Contact.Uin) ?? ""; + proto.RoutingHead.FromUid = (await _context.CacheContext.ResolveStranger(msg.Contact.Uin))?.Uid ?? ""; if (msg.Receiver is BotFriend f) { proto.RoutingHead.ToUin = f.Uin; - proto.RoutingHead.ToUid = _context.CacheContext.ResolveCachedUid(f.Uin) ?? ""; + proto.RoutingHead.ToUid = (await _context.CacheContext.ResolveStranger(f.Uin))?.Uid ?? ""; } foreach (var entity in msg.Entities) @@ -270,22 +344,22 @@ public Task BuildFake(BotMessage msg) proto.MessageBody.RichText.Elems.AddRange(elem); } - return Task.FromResult(proto); + return proto; } private RecordEntity? ParsePttRichText(RichText richText) { if (richText.Ptt is not { } ptt) return null; - + var kv = new BinaryPacket(stackalloc byte[100]); kv.Write("filetype", Prefix.Int32 | Prefix.LengthOnly); kv.Write("0", Prefix.Int32 | Prefix.LengthOnly); kv.Write("codec", Prefix.Int32 | Prefix.LengthOnly); kv.Write("1", Prefix.Int32 | Prefix.LengthOnly); - + Span innerSpan = stackalloc byte[200]; Span outerSpan = stackalloc byte[300]; - + var inner = new AsnWriter(AsnEncodingRules.DER); inner.PushSequence(); inner.WriteInteger(1); @@ -303,9 +377,9 @@ public Task BuildFake(BotMessage msg) outer.WriteOctetString(innerSpan[..length]); // inner outer.WriteOctetString(ReadOnlySpan.Empty); // “empty” outer.PopSequence(); - + outer.TryEncode(outerSpan, out length); - + return new RecordEntity { FileUrl = $"https://grouptalk.c2c.qq.com/?ver=2&rkey={Convert.ToHexString(outerSpan[..length])}&voice_codec=1&filetype=0",