From b000e44921dd68b269e07d7f33a8de8ec2107a3a Mon Sep 17 00:00:00 2001 From: Huang Youzhen Date: Thu, 30 Oct 2025 01:02:07 +0800 Subject: [PATCH 1/5] [NativeAPI] Synchronize Core's new features. --- .../Common/BotGroupExitNotificationStruct.cs | 13 + .../BotGroupKickOtherNotificationStruct.cs | 17 ++ .../BotGroupKickSelfNotificationStruct.cs | 17 ++ .../BotGroupSetAdminNotificationStruct.cs | 17 ++ .../BotGroupUnsetAdminNotificationStruct.cs | 17 ++ .../Event/BotFriendRecallEventStruct.cs | 32 +++ .../Event/BotGroupRecallEventStruct.cs | 35 +++ .../Event/ReverseEventCountStruct.cs | 2 + .../OperateGroupEntryPoint.cs | 239 ++++++++++++++++++ .../BotFriendRecallReverseEvent.cs | 18 ++ .../BotGroupRecallReverseEvent.cs | 18 ++ .../ReverseEvent/EventEntryPoint.cs | 2 + .../ReverseEvent/ReverseEventInvoker.cs | 4 + 13 files changed, 431 insertions(+) create mode 100644 Lagrange.Core.NativeAPI/NativeModel/Common/BotGroupExitNotificationStruct.cs create mode 100644 Lagrange.Core.NativeAPI/NativeModel/Common/BotGroupKickOtherNotificationStruct.cs create mode 100644 Lagrange.Core.NativeAPI/NativeModel/Common/BotGroupKickSelfNotificationStruct.cs create mode 100644 Lagrange.Core.NativeAPI/NativeModel/Common/BotGroupSetAdminNotificationStruct.cs create mode 100644 Lagrange.Core.NativeAPI/NativeModel/Common/BotGroupUnsetAdminNotificationStruct.cs create mode 100644 Lagrange.Core.NativeAPI/NativeModel/Event/BotFriendRecallEventStruct.cs create mode 100644 Lagrange.Core.NativeAPI/NativeModel/Event/BotGroupRecallEventStruct.cs create mode 100644 Lagrange.Core.NativeAPI/OperateGroupEntryPoint.cs create mode 100644 Lagrange.Core.NativeAPI/ReverseEvent/BotFriendRecallReverseEvent.cs create mode 100644 Lagrange.Core.NativeAPI/ReverseEvent/BotGroupRecallReverseEvent.cs diff --git a/Lagrange.Core.NativeAPI/NativeModel/Common/BotGroupExitNotificationStruct.cs b/Lagrange.Core.NativeAPI/NativeModel/Common/BotGroupExitNotificationStruct.cs new file mode 100644 index 00000000..d05887ab --- /dev/null +++ b/Lagrange.Core.NativeAPI/NativeModel/Common/BotGroupExitNotificationStruct.cs @@ -0,0 +1,13 @@ +using System.Runtime.InteropServices; +using System.Text; +using Lagrange.Core.Common.Entity; + +namespace Lagrange.Core.NativeAPI.NativeModel.Common; +[StructLayout(LayoutKind.Sequential)] +public class BotGroupExitNotificationStruct(BotGroupExitNotification e) : BotGroupNotificationBaseStruct(e) +{ + public static implicit operator BotGroupExitNotificationStruct(BotGroupExitNotification e) + { + return new BotGroupExitNotificationStruct(e); + } +} diff --git a/Lagrange.Core.NativeAPI/NativeModel/Common/BotGroupKickOtherNotificationStruct.cs b/Lagrange.Core.NativeAPI/NativeModel/Common/BotGroupKickOtherNotificationStruct.cs new file mode 100644 index 00000000..96f07a1e --- /dev/null +++ b/Lagrange.Core.NativeAPI/NativeModel/Common/BotGroupKickOtherNotificationStruct.cs @@ -0,0 +1,17 @@ +using System.Runtime.InteropServices; +using System.Text; +using Lagrange.Core.Common.Entity; + +namespace Lagrange.Core.NativeAPI.NativeModel.Common; +[StructLayout(LayoutKind.Sequential)] +public class BotGroupKickOtherNotificationStruct(BotGroupKickNotification notification) : BotGroupNotificationBaseStruct(notification) +{ + public long OperatorUin = notification.OperatorUin; + + public ByteArrayNative OperatorUid { get; } = Encoding.UTF8.GetBytes(notification.OperatorUid); + + public static implicit operator BotGroupKickOtherNotificationStruct(BotGroupKickNotification e) + { + return new BotGroupKickOtherNotificationStruct(e); + } +} diff --git a/Lagrange.Core.NativeAPI/NativeModel/Common/BotGroupKickSelfNotificationStruct.cs b/Lagrange.Core.NativeAPI/NativeModel/Common/BotGroupKickSelfNotificationStruct.cs new file mode 100644 index 00000000..cd5a70b9 --- /dev/null +++ b/Lagrange.Core.NativeAPI/NativeModel/Common/BotGroupKickSelfNotificationStruct.cs @@ -0,0 +1,17 @@ +using System.Runtime.InteropServices; +using System.Text; +using Lagrange.Core.Common.Entity; + +namespace Lagrange.Core.NativeAPI.NativeModel.Common; +[StructLayout(LayoutKind.Sequential)] +public class BotGroupKickSelfNotificationStruct(BotGroupKickNotification notification) : BotGroupNotificationBaseStruct(notification) +{ + public long OperatorUin = notification.OperatorUin; + + public ByteArrayNative OperatorUid { get; } = Encoding.UTF8.GetBytes(notification.OperatorUid); + + public static implicit operator BotGroupKickSelfNotificationStruct(BotGroupKickNotification e) + { + return new BotGroupKickSelfNotificationStruct(e); + } +} diff --git a/Lagrange.Core.NativeAPI/NativeModel/Common/BotGroupSetAdminNotificationStruct.cs b/Lagrange.Core.NativeAPI/NativeModel/Common/BotGroupSetAdminNotificationStruct.cs new file mode 100644 index 00000000..66b3ecad --- /dev/null +++ b/Lagrange.Core.NativeAPI/NativeModel/Common/BotGroupSetAdminNotificationStruct.cs @@ -0,0 +1,17 @@ +using System.Runtime.InteropServices; +using System.Text; +using Lagrange.Core.Common.Entity; + +namespace Lagrange.Core.NativeAPI.NativeModel.Common; +[StructLayout(LayoutKind.Sequential)] +public class BotGroupSetAdminNotificationStruct(BotGroupSetAdminNotification notification) : BotGroupNotificationBaseStruct(notification) +{ + public long OperatorUin = notification.OperatorUin; + + public ByteArrayNative OperatorUid { get; } = Encoding.UTF8.GetBytes(notification.OperatorUid); + + public static implicit operator BotGroupSetAdminNotificationStruct(BotGroupSetAdminNotification e) + { + return new BotGroupSetAdminNotificationStruct(e); + } +} diff --git a/Lagrange.Core.NativeAPI/NativeModel/Common/BotGroupUnsetAdminNotificationStruct.cs b/Lagrange.Core.NativeAPI/NativeModel/Common/BotGroupUnsetAdminNotificationStruct.cs new file mode 100644 index 00000000..48c4907f --- /dev/null +++ b/Lagrange.Core.NativeAPI/NativeModel/Common/BotGroupUnsetAdminNotificationStruct.cs @@ -0,0 +1,17 @@ +using System.Runtime.InteropServices; +using System.Text; +using Lagrange.Core.Common.Entity; + +namespace Lagrange.Core.NativeAPI.NativeModel.Common; +[StructLayout(LayoutKind.Sequential)] +public class BotGroupUnsetAdminNotificationStruct(BotGroupUnsetAdminNotification notification) : BotGroupNotificationBaseStruct(notification) +{ + public long OperatorUin = notification.OperatorUin; + + public ByteArrayNative OperatorUid { get; } = Encoding.UTF8.GetBytes(notification.OperatorUid); + + public static implicit operator BotGroupUnsetAdminNotificationStruct(BotGroupUnsetAdminNotification e) + { + return new BotGroupUnsetAdminNotificationStruct(e); + } +} diff --git a/Lagrange.Core.NativeAPI/NativeModel/Event/BotFriendRecallEventStruct.cs b/Lagrange.Core.NativeAPI/NativeModel/Event/BotFriendRecallEventStruct.cs new file mode 100644 index 00000000..68c1e4de --- /dev/null +++ b/Lagrange.Core.NativeAPI/NativeModel/Event/BotFriendRecallEventStruct.cs @@ -0,0 +1,32 @@ +using System.Runtime.InteropServices; +using System.Text; +using Lagrange.Core.Events.EventArgs; +using Lagrange.Core.NativeAPI.NativeModel.Common; + +namespace Lagrange.Core.NativeAPI.NativeModel.Event +{ + [StructLayout(LayoutKind.Sequential)] + public struct BotFriendRecallEventStruct : IEventStruct + { + public BotFriendRecallEventStruct() { } + + public long PeerUin = 0; + + public long AuthorUin = 0; + + public ulong Sequence = 0; + + public ByteArrayNative Tip = new(); + + public static implicit operator BotFriendRecallEventStruct(BotFriendRecallEvent e) + { + return new BotFriendRecallEventStruct() + { + PeerUin = e.PeerUin, + AuthorUin = e.AuthorUin, + Sequence = e.Sequence, + Tip = Encoding.UTF8.GetBytes(e.Tip) + }; + } + } +} diff --git a/Lagrange.Core.NativeAPI/NativeModel/Event/BotGroupRecallEventStruct.cs b/Lagrange.Core.NativeAPI/NativeModel/Event/BotGroupRecallEventStruct.cs new file mode 100644 index 00000000..c6e8843c --- /dev/null +++ b/Lagrange.Core.NativeAPI/NativeModel/Event/BotGroupRecallEventStruct.cs @@ -0,0 +1,35 @@ +using System.Runtime.InteropServices; +using System.Text; +using Lagrange.Core.Events.EventArgs; +using Lagrange.Core.NativeAPI.NativeModel.Common; + +namespace Lagrange.Core.NativeAPI.NativeModel.Event +{ + [StructLayout(LayoutKind.Sequential)] + public struct BotGroupRecallEventStruct : IEventStruct + { + public BotGroupRecallEventStruct() { } + + public long GroupUin = 0; + + public ulong Sequence = 0; + + public long AuthorUin = 0; + + public long OperatorUin = 0; + + public ByteArrayNative Tip = new(); + + public static implicit operator BotGroupRecallEventStruct(BotGroupRecallEvent e) + { + return new BotGroupRecallEventStruct() + { + GroupUin = e.GroupUin, + Sequence = e.Sequence, + AuthorUin = e.AuthorUin, + OperatorUin = e.OperatorUin, + Tip = Encoding.UTF8.GetBytes(e.Tip) + }; + } + } +} \ No newline at end of file diff --git a/Lagrange.Core.NativeAPI/NativeModel/Event/ReverseEventCountStruct.cs b/Lagrange.Core.NativeAPI/NativeModel/Event/ReverseEventCountStruct.cs index b6177c1f..d0335621 100644 --- a/Lagrange.Core.NativeAPI/NativeModel/Event/ReverseEventCountStruct.cs +++ b/Lagrange.Core.NativeAPI/NativeModel/Event/ReverseEventCountStruct.cs @@ -9,6 +9,7 @@ public ReverseEventCountStruct() { } public int BotCaptchaEventCount = 0; public int BotFriendRequestEventCount = 0; + public int BotFriendRecallEventCount = 0; public int BotGroupInviteNotificationEventCount = 0; public int BotGroupInviteSelfEventCount = 0; public int BotGroupJoinNotificationEventCount = 0; @@ -16,6 +17,7 @@ public ReverseEventCountStruct() { } public int BotGroupMemberIncreaseEventCount = 0; public int BotGroupNudgeEventCount = 0; public int BotGroupReactionEventCount = 0; + public int BotGroupRecallEventCount = 0; public int BotLoginEventCount = 0; public int BotLogEventCount = 0; public int BotMessageEventCount = 0; diff --git a/Lagrange.Core.NativeAPI/OperateGroupEntryPoint.cs b/Lagrange.Core.NativeAPI/OperateGroupEntryPoint.cs new file mode 100644 index 00000000..0c63bf10 --- /dev/null +++ b/Lagrange.Core.NativeAPI/OperateGroupEntryPoint.cs @@ -0,0 +1,239 @@ +using System.Runtime.InteropServices; +using System.Text; +using Lagrange.Core.Common.Entity; +using Lagrange.Core.Common.Interface; +using Lagrange.Core.NativeAPI.NativeModel.Common; +using Lagrange.Core.NativeAPI.NativeModel.Event; +using Lagrange.Core.NativeAPI.NativeModel.Message; + +namespace Lagrange.Core.NativeAPI +{ + public static class OperateGroupEntryPoint + { + [UnmanagedCallersOnly(EntryPoint = "GetGroupList")] + public static IntPtr GetGroupList(int index, bool refresh /*= false*/) + { + if (Program.Contexts.Count <= index) + { + return IntPtr.Zero; + } + + var context = Program.Contexts[index].BotContext; + var groups = context.FetchGroups(refresh).GetAwaiter().GetResult(); + + var result = new EventArrayStruct(); + if (groups == null || groups.Count == 0) + { + result.Events = IntPtr.Zero; + result.Count = 0; + + IntPtr emptyResultPtr = Marshal.AllocHGlobal(Marshal.SizeOf()); + Marshal.StructureToPtr(result, emptyResultPtr, false); + return emptyResultPtr; + } + + result.Events = Marshal.AllocHGlobal(Marshal.SizeOf() * groups.Count); + result.Count = groups.Count; + for (int i = 0; i < groups.Count; i++) + { + Marshal.StructureToPtr( + (BotGroupStruct)groups[i], + result.Events + i * Marshal.SizeOf(), + false + ); + } + + IntPtr resultPtr = Marshal.AllocHGlobal(Marshal.SizeOf()); + Marshal.StructureToPtr(result, resultPtr, false); + return resultPtr; + } + + [UnmanagedCallersOnly(EntryPoint = "GetMemberList")] + public static IntPtr GetMemberList(int index, long groupUin, bool refresh /*= false*/) + { + if (Program.Contexts.Count <= index) + { + return IntPtr.Zero; + } + + var context = Program.Contexts[index].BotContext; + var members = context.FetchMembers(groupUin, refresh).GetAwaiter().GetResult(); + + var result = new EventArrayStruct(); + if (members == null || members.Count == 0) + { + result.Events = IntPtr.Zero; + result.Count = 0; + + IntPtr emptyResultPtr = Marshal.AllocHGlobal(Marshal.SizeOf()); + Marshal.StructureToPtr(result, emptyResultPtr, false); + return emptyResultPtr; + } + + result.Events = Marshal.AllocHGlobal(Marshal.SizeOf() * members.Count); + result.Count = members.Count; + for (int i = 0; i < members.Count; i++) + { + Marshal.StructureToPtr( + (BotGroupMemberStruct)members[i], + result.Events + i * Marshal.SizeOf(), + false + ); + } + + IntPtr resultPtr = Marshal.AllocHGlobal(Marshal.SizeOf()); + Marshal.StructureToPtr(result, resultPtr, false); + return resultPtr; + } + + [UnmanagedCallersOnly(EntryPoint = "FetchGroupNotifications")] + public static IntPtr FetchGroupNotifications(int index, ulong count, ulong start /*= 0*/) + { + if (Program.Contexts.Count <= index) + { + return IntPtr.Zero; + } + + var context = Program.Contexts[index].BotContext; + var notifications = context.FetchGroupNotifications(count, start).GetAwaiter().GetResult(); + + return GetGroupNotificationsStructPtr(notifications); + } + + [UnmanagedCallersOnly(EntryPoint = "FetchFilteredGroupNotifications")] + public static IntPtr FetchFilteredGroupNotifications(int index, ulong count, ulong start /*= 0*/) + { + if (Program.Contexts.Count <= index) + { + return IntPtr.Zero; + } + + var context = Program.Contexts[index].BotContext; + var notifications = context.FetchFilteredGroupNotifications(count, start).GetAwaiter().GetResult(); + + return GetGroupNotificationsStructPtr(notifications); + } + + [UnmanagedCallersOnly(EntryPoint = "SetGroupNotification")] + public static void SetGroupNotification(int index, long groupUin, ulong sequence, int type, bool isFiltered, int operate, ByteArrayNative message) + { + if (Program.Contexts.Count <= index) + { + return; + } + + var context = Program.Contexts[index].BotContext; + if (message.IsEmpty()) + { + context.SetGroupNotification(groupUin, sequence, (BotGroupNotificationType)type, isFiltered, (GroupNotificationOperate)operate); + return; + } + + context.SetGroupNotification(groupUin, sequence, (BotGroupNotificationType)type, isFiltered, (GroupNotificationOperate)operate, Encoding.UTF8.GetString(message.ToByteArrayWithoutFree())); + } + + [UnmanagedCallersOnly(EntryPoint = "SetGroupReaction")] + public static void SetGroupReaction(int index, long groupUin, ulong sequence, ByteArrayNative code, bool isAdd) + { + if (Program.Contexts.Count <= index) + { + return; + } + + var context = Program.Contexts[index].BotContext; + context.SetGroupReaction(groupUin, sequence, Encoding.UTF8.GetString(code.ToByteArrayWithoutFree()), isAdd); + } + + private static IntPtr GetGroupNotificationsStructPtr(List notifications) + { + EventArrayStruct result = new EventArrayStruct(); + if (notifications == null || notifications.Count == 0) + { + result.Events = IntPtr.Zero; + result.Count = 0; + + IntPtr emptyResultPtr = Marshal.AllocHGlobal(Marshal.SizeOf()); + Marshal.StructureToPtr(result, emptyResultPtr, false); + return emptyResultPtr; + } + + int addressLength = 0; + for (int i = 0; i < notifications.Count; i++) + { + addressLength += notifications[i].Type switch + { + BotGroupNotificationType.Join => Marshal.SizeOf(), + BotGroupNotificationType.SetAdmin => Marshal.SizeOf(), + BotGroupNotificationType.KickOther => Marshal.SizeOf(), + BotGroupNotificationType.KickSelf => Marshal.SizeOf(), + BotGroupNotificationType.Exit => Marshal.SizeOf(), + BotGroupNotificationType.UnsetAdmin => Marshal.SizeOf(), + BotGroupNotificationType.Invite => Marshal.SizeOf(), + _ => throw new ArgumentOutOfRangeException($"Out of notification of type: {notifications[i].Type}"), + }; + } + + result.Events = Marshal.AllocHGlobal(addressLength); + result.Count = notifications.Count; + for (int i = 0; i < notifications.Count; i++) + { + switch (notifications[i].Type) + { + case BotGroupNotificationType.Join: + Marshal.StructureToPtr( + (BotGroupJoinNotificationStruct)(BotGroupJoinNotification)notifications[i], + result.Events + i * Marshal.SizeOf(), + false + ); + break; + case BotGroupNotificationType.SetAdmin: + Marshal.StructureToPtr( + (BotGroupSetAdminNotificationStruct)(BotGroupSetAdminNotification)notifications[i], + result.Events + i * Marshal.SizeOf(), + false + ); + break; + case BotGroupNotificationType.KickOther: + Marshal.StructureToPtr( + (BotGroupKickOtherNotificationStruct)(BotGroupKickNotification)notifications[i], + result.Events + i * Marshal.SizeOf(), + false + ); + break; + case BotGroupNotificationType.KickSelf: + Marshal.StructureToPtr( + (BotGroupKickSelfNotificationStruct)(BotGroupKickNotification)notifications[i], + result.Events + i * Marshal.SizeOf(), + false + ); + break; + case BotGroupNotificationType.Exit: + Marshal.StructureToPtr( + (BotGroupExitNotificationStruct)(BotGroupExitNotification)notifications[i], + result.Events + i * Marshal.SizeOf(), + false + ); + break; + case BotGroupNotificationType.UnsetAdmin: + Marshal.StructureToPtr( + (BotGroupUnsetAdminNotificationStruct)(BotGroupUnsetAdminNotification)notifications[i], + result.Events + i * Marshal.SizeOf(), + false + ); + break; + case BotGroupNotificationType.Invite: + Marshal.StructureToPtr( + (BotGroupInviteNotificationStruct)(BotGroupInviteNotification)notifications[i], + result.Events + i * Marshal.SizeOf(), + false + ); + break; + } + } + + var resultPtr = Marshal.AllocHGlobal(Marshal.SizeOf()); + Marshal.StructureToPtr(result, resultPtr, false); + return resultPtr; + } + } +} \ No newline at end of file diff --git a/Lagrange.Core.NativeAPI/ReverseEvent/BotFriendRecallReverseEvent.cs b/Lagrange.Core.NativeAPI/ReverseEvent/BotFriendRecallReverseEvent.cs new file mode 100644 index 00000000..00733116 --- /dev/null +++ b/Lagrange.Core.NativeAPI/ReverseEvent/BotFriendRecallReverseEvent.cs @@ -0,0 +1,18 @@ +using Lagrange.Core.Events.EventArgs; +using Lagrange.Core.NativeAPI.NativeModel; +using Lagrange.Core.NativeAPI.NativeModel.Event; +using Lagrange.Core.NativeAPI.ReverseEvent.Abstract; + +namespace Lagrange.Core.NativeAPI.ReverseEvent +{ + public class BotFriendRecallReverseEvent : ReverseEventBase + { + public override void RegisterEventHandler(BotContext context) + { + context.EventInvoker.RegisterEvent((ctx, e) => + { + Events.Add((BotFriendRecallEventStruct)e); + }); + } + } +} \ No newline at end of file diff --git a/Lagrange.Core.NativeAPI/ReverseEvent/BotGroupRecallReverseEvent.cs b/Lagrange.Core.NativeAPI/ReverseEvent/BotGroupRecallReverseEvent.cs new file mode 100644 index 00000000..a35c68c9 --- /dev/null +++ b/Lagrange.Core.NativeAPI/ReverseEvent/BotGroupRecallReverseEvent.cs @@ -0,0 +1,18 @@ +using Lagrange.Core.Events.EventArgs; +using Lagrange.Core.NativeAPI.NativeModel; +using Lagrange.Core.NativeAPI.NativeModel.Event; +using Lagrange.Core.NativeAPI.ReverseEvent.Abstract; + +namespace Lagrange.Core.NativeAPI.ReverseEvent +{ + public class BotGroupRecallReverseEvent : ReverseEventBase + { + public override void RegisterEventHandler(BotContext context) + { + context.EventInvoker.RegisterEvent((ctx, e) => + { + Events.Add((BotGroupRecallEventStruct)e); + }); + } + } +} \ No newline at end of file diff --git a/Lagrange.Core.NativeAPI/ReverseEvent/EventEntryPoint.cs b/Lagrange.Core.NativeAPI/ReverseEvent/EventEntryPoint.cs index 92c9eb28..e3467b89 100644 --- a/Lagrange.Core.NativeAPI/ReverseEvent/EventEntryPoint.cs +++ b/Lagrange.Core.NativeAPI/ReverseEvent/EventEntryPoint.cs @@ -13,12 +13,14 @@ public static IntPtr GetEventCount(int index) { BotCaptchaEventCount = Program.Contexts[index].EventInvoker.BotCaptchaEvent.Events.Count, BotFriendRequestEventCount = Program.Contexts[index].EventInvoker.BotFriendRequestEvent.Events.Count, + BotFriendRecallEventCount = Program.Contexts[index].EventInvoker.BotFriendRecallEvent.Events.Count, BotGroupInviteNotificationEventCount = Program.Contexts[index].EventInvoker.BotGroupInviteNotificationEvent.Events.Count, BotGroupJoinNotificationEventCount = Program.Contexts[index].EventInvoker.BotGroupJoinNotificationEvent.Events.Count, BotGroupMemberDecreaseEventCount = Program.Contexts[index].EventInvoker.BotGroupMemberDecreaseEvent.Events.Count, BotGroupMemberIncreaseEventCount = Program.Contexts[index].EventInvoker.BotGroupMemberIncreaseEvent.Events.Count, BotGroupNudgeEventCount = Program.Contexts[index].EventInvoker.BotGroupNudgeEvent.Events.Count, BotGroupReactionEventCount = Program.Contexts[index].EventInvoker.BotGroupReactionEvent.Events.Count, + BotGroupRecallEventCount = Program.Contexts[index].EventInvoker.BotGroupRecallEvent.Events.Count, BotLoginEventCount = Program.Contexts[index].EventInvoker.BotLoginEvent.Events.Count, BotLogEventCount = Program.Contexts[index].EventInvoker.BotLogEvent.Events.Count, BotMessageEventCount = Program.Contexts[index].EventInvoker.BotMessageEvent.Events.Count, diff --git a/Lagrange.Core.NativeAPI/ReverseEvent/ReverseEventInvoker.cs b/Lagrange.Core.NativeAPI/ReverseEvent/ReverseEventInvoker.cs index 7b5c1da6..c5cd16d1 100644 --- a/Lagrange.Core.NativeAPI/ReverseEvent/ReverseEventInvoker.cs +++ b/Lagrange.Core.NativeAPI/ReverseEvent/ReverseEventInvoker.cs @@ -28,6 +28,8 @@ public ReverseEventInvoker(BotContext context) public BotFriendRequestReverseEvent BotFriendRequestEvent { get; } = new(); + public BotFriendRecallReverseEvent BotFriendRecallEvent { get; } = new(); + public BotGroupInviteNotificationReverseEvent BotGroupInviteNotificationEvent { get; } = new(); public BotGroupJoinNotificationReverseEvent BotGroupJoinNotificationEvent { get; } = new(); @@ -39,6 +41,8 @@ public ReverseEventInvoker(BotContext context) public BotGroupNudgeReverseEvent BotGroupNudgeEvent { get; } = new(); public BotGroupReactionReverseEvent BotGroupReactionEvent { get; } = new(); + + public BotGroupRecallReverseEvent BotGroupRecallEvent { get; } = new(); public BotLoginReverseEvent BotLoginEvent { get; } = new(); From 10b0a451f2ec6a5d05c642772e3013c3c72512a6 Mon Sep 17 00:00:00 2001 From: Huang Youzhen Date: Fri, 31 Oct 2025 01:04:31 +0800 Subject: [PATCH 2/5] [NativeAPI] Improved the KickNotification structure & continuously addressed the missing parts compared to Core --- ...t.cs => BotGroupKickNotificationStruct.cs} | 6 +- .../BotGroupKickOtherNotificationStruct.cs | 17 --- .../NativeModel/Message/BotMessageStruct.cs | 8 +- .../OperateGroupEntryPoint.cs | 104 ++++++++++++++---- Lagrange.Core.NativeAPI/SendMessageContext.cs | 20 +++- .../SendMessageEntryPoint.cs | 39 ++++++- .../Internal/Logic/MessagingLogic.cs | 2 +- 7 files changed, 146 insertions(+), 50 deletions(-) rename Lagrange.Core.NativeAPI/NativeModel/Common/{BotGroupKickSelfNotificationStruct.cs => BotGroupKickNotificationStruct.cs} (55%) delete mode 100644 Lagrange.Core.NativeAPI/NativeModel/Common/BotGroupKickOtherNotificationStruct.cs diff --git a/Lagrange.Core.NativeAPI/NativeModel/Common/BotGroupKickSelfNotificationStruct.cs b/Lagrange.Core.NativeAPI/NativeModel/Common/BotGroupKickNotificationStruct.cs similarity index 55% rename from Lagrange.Core.NativeAPI/NativeModel/Common/BotGroupKickSelfNotificationStruct.cs rename to Lagrange.Core.NativeAPI/NativeModel/Common/BotGroupKickNotificationStruct.cs index cd5a70b9..f132b77f 100644 --- a/Lagrange.Core.NativeAPI/NativeModel/Common/BotGroupKickSelfNotificationStruct.cs +++ b/Lagrange.Core.NativeAPI/NativeModel/Common/BotGroupKickNotificationStruct.cs @@ -4,14 +4,14 @@ namespace Lagrange.Core.NativeAPI.NativeModel.Common; [StructLayout(LayoutKind.Sequential)] -public class BotGroupKickSelfNotificationStruct(BotGroupKickNotification notification) : BotGroupNotificationBaseStruct(notification) +public class BotGroupKickNotificationStruct(BotGroupKickNotification notification) : BotGroupNotificationBaseStruct(notification) { public long OperatorUin = notification.OperatorUin; public ByteArrayNative OperatorUid { get; } = Encoding.UTF8.GetBytes(notification.OperatorUid); - public static implicit operator BotGroupKickSelfNotificationStruct(BotGroupKickNotification e) + public static implicit operator BotGroupKickNotificationStruct(BotGroupKickNotification e) { - return new BotGroupKickSelfNotificationStruct(e); + return new BotGroupKickNotificationStruct(e); } } diff --git a/Lagrange.Core.NativeAPI/NativeModel/Common/BotGroupKickOtherNotificationStruct.cs b/Lagrange.Core.NativeAPI/NativeModel/Common/BotGroupKickOtherNotificationStruct.cs deleted file mode 100644 index 96f07a1e..00000000 --- a/Lagrange.Core.NativeAPI/NativeModel/Common/BotGroupKickOtherNotificationStruct.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Runtime.InteropServices; -using System.Text; -using Lagrange.Core.Common.Entity; - -namespace Lagrange.Core.NativeAPI.NativeModel.Common; -[StructLayout(LayoutKind.Sequential)] -public class BotGroupKickOtherNotificationStruct(BotGroupKickNotification notification) : BotGroupNotificationBaseStruct(notification) -{ - public long OperatorUin = notification.OperatorUin; - - public ByteArrayNative OperatorUid { get; } = Encoding.UTF8.GetBytes(notification.OperatorUid); - - public static implicit operator BotGroupKickOtherNotificationStruct(BotGroupKickNotification e) - { - return new BotGroupKickOtherNotificationStruct(e); - } -} diff --git a/Lagrange.Core.NativeAPI/NativeModel/Message/BotMessageStruct.cs b/Lagrange.Core.NativeAPI/NativeModel/Message/BotMessageStruct.cs index 1bd3d588..d6829213 100644 --- a/Lagrange.Core.NativeAPI/NativeModel/Message/BotMessageStruct.cs +++ b/Lagrange.Core.NativeAPI/NativeModel/Message/BotMessageStruct.cs @@ -28,6 +28,10 @@ public BotMessageStruct() { } public int EntityLength = 0; + public ulong Sequence = 0; + + public ulong ClientSequence = 0; + public static implicit operator BotMessageStruct(BotMessage message) { int type = 0; @@ -162,7 +166,9 @@ public static implicit operator BotMessageStruct(BotMessage message) Type = type, Time = Encoding.UTF8.GetBytes(message.Time.ToString("O")), Entities = entitiesPtr, - EntityLength = entitiesLength + EntityLength = entitiesLength, + Sequence = message.Sequence, + ClientSequence = message.ClientSequence }; } } diff --git a/Lagrange.Core.NativeAPI/OperateGroupEntryPoint.cs b/Lagrange.Core.NativeAPI/OperateGroupEntryPoint.cs index 0c63bf10..dbe9cc92 100644 --- a/Lagrange.Core.NativeAPI/OperateGroupEntryPoint.cs +++ b/Lagrange.Core.NativeAPI/OperateGroupEntryPoint.cs @@ -1,7 +1,9 @@ -using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Text; using Lagrange.Core.Common.Entity; using Lagrange.Core.Common.Interface; +using Lagrange.Core.Message; using Lagrange.Core.NativeAPI.NativeModel.Common; using Lagrange.Core.NativeAPI.NativeModel.Event; using Lagrange.Core.NativeAPI.NativeModel.Message; @@ -10,6 +12,34 @@ namespace Lagrange.Core.NativeAPI { public static class OperateGroupEntryPoint { + [UnmanagedCallersOnly(EntryPoint = "FetchGroupNotifications")] + public static IntPtr FetchGroupNotifications(int index, ulong count, ulong start /*= 0*/) + { + if (Program.Contexts.Count <= index) + { + return IntPtr.Zero; + } + + var context = Program.Contexts[index].BotContext; + var notifications = context.FetchGroupNotifications(count, start).GetAwaiter().GetResult(); + + return GetGroupNotificationsStructPtr(notifications); + } + + [UnmanagedCallersOnly(EntryPoint = "FetchFilteredGroupNotifications")] + public static IntPtr FetchFilteredGroupNotifications(int index, ulong count, ulong start /*= 0*/) + { + if (Program.Contexts.Count <= index) + { + return IntPtr.Zero; + } + + var context = Program.Contexts[index].BotContext; + var notifications = context.FetchFilteredGroupNotifications(count, start).GetAwaiter().GetResult(); + + return GetGroupNotificationsStructPtr(notifications); + } + [UnmanagedCallersOnly(EntryPoint = "GetGroupList")] public static IntPtr GetGroupList(int index, bool refresh /*= false*/) { @@ -47,7 +77,7 @@ public static IntPtr GetGroupList(int index, bool refresh /*= false*/) Marshal.StructureToPtr(result, resultPtr, false); return resultPtr; } - + [UnmanagedCallersOnly(EntryPoint = "GetMemberList")] public static IntPtr GetMemberList(int index, long groupUin, bool refresh /*= false*/) { @@ -86,32 +116,64 @@ public static IntPtr GetMemberList(int index, long groupUin, bool refresh /*= fa return resultPtr; } - [UnmanagedCallersOnly(EntryPoint = "FetchGroupNotifications")] - public static IntPtr FetchGroupNotifications(int index, ulong count, ulong start /*= 0*/) + [UnmanagedCallersOnly(EntryPoint = "QuitGroup")] + public static void QuitGroup(int index, long groupUin) { if (Program.Contexts.Count <= index) { - return IntPtr.Zero; + return; } - var context = Program.Contexts[index].BotContext; - var notifications = context.FetchGroupNotifications(count, start).GetAwaiter().GetResult(); + BotContext context = Program.Contexts[index].BotContext; + context.GroupQuit(groupUin); + } - return GetGroupNotificationsStructPtr(notifications); + [UnmanagedCallersOnly(EntryPoint = "RenameGroup")] + public static void RenameGroup(int index, long groupUin, ByteArrayNative name) + { + if (Program.Contexts.Count <= index) + { + return; + } + + BotContext context = Program.Contexts[index].BotContext; + context.GroupRename(groupUin, Encoding.UTF8.GetString(name.ToByteArrayWithoutFree())); } - [UnmanagedCallersOnly(EntryPoint = "FetchFilteredGroupNotifications")] - public static IntPtr FetchFilteredGroupNotifications(int index, ulong count, ulong start /*= 0*/) + [UnmanagedCallersOnly(EntryPoint = "RenameGroupMember")] + public static void RenameGroupMember(int index, long groupUin, long targetUin, ByteArrayNative name) { if (Program.Contexts.Count <= index) { - return IntPtr.Zero; + return; } - var context = Program.Contexts[index].BotContext; - var notifications = context.FetchFilteredGroupNotifications(count, start).GetAwaiter().GetResult(); + BotContext context = Program.Contexts[index].BotContext; + context.GroupMemberRename(groupUin, targetUin, Encoding.UTF8.GetString(name.ToByteArrayWithoutFree())); + } - return GetGroupNotificationsStructPtr(notifications); + [UnmanagedCallersOnly(EntryPoint = "SendGroupNudge")] + public static void SendGroupNudge(int index, long peerUin, long targetUin) + { + if (Program.Contexts.Count <= index) + { + return; + } + + BotContext context = Program.Contexts[index].BotContext; + context.SendGroupNudge(peerUin, targetUin); + } + + [UnmanagedCallersOnly(EntryPoint = "SetGroupSpecialTitle")] + public static void SetGroupSpecialTitle(int index, long groupUin, long targetUin, ByteArrayNative title) + { + if (Program.Contexts.Count <= index) + { + return; + } + + BotContext context = Program.Contexts[index].BotContext; + context.GroupSetSpecialTitle(groupUin, targetUin, Encoding.UTF8.GetString(title.ToByteArrayWithoutFree())); } [UnmanagedCallersOnly(EntryPoint = "SetGroupNotification")] @@ -164,8 +226,8 @@ private static IntPtr GetGroupNotificationsStructPtr(List Marshal.SizeOf(), BotGroupNotificationType.SetAdmin => Marshal.SizeOf(), - BotGroupNotificationType.KickOther => Marshal.SizeOf(), - BotGroupNotificationType.KickSelf => Marshal.SizeOf(), + BotGroupNotificationType.KickOther => Marshal.SizeOf(), + BotGroupNotificationType.KickSelf => Marshal.SizeOf(), BotGroupNotificationType.Exit => Marshal.SizeOf(), BotGroupNotificationType.UnsetAdmin => Marshal.SizeOf(), BotGroupNotificationType.Invite => Marshal.SizeOf(), @@ -194,16 +256,10 @@ private static IntPtr GetGroupNotificationsStructPtr(List(), - false - ); - break; case BotGroupNotificationType.KickSelf: Marshal.StructureToPtr( - (BotGroupKickSelfNotificationStruct)(BotGroupKickNotification)notifications[i], - result.Events + i * Marshal.SizeOf(), + (BotGroupKickNotificationStruct)(BotGroupKickNotification)notifications[i], + result.Events + i * Marshal.SizeOf(), false ); break; diff --git a/Lagrange.Core.NativeAPI/SendMessageContext.cs b/Lagrange.Core.NativeAPI/SendMessageContext.cs index 69b8098f..10e78edf 100644 --- a/Lagrange.Core.NativeAPI/SendMessageContext.cs +++ b/Lagrange.Core.NativeAPI/SendMessageContext.cs @@ -1,4 +1,6 @@ -using System.Text; +using System.Runtime.CompilerServices; +using System.Text; +using Lagrange.Core.Common.Entity; using Lagrange.Core.Message; namespace Lagrange.Core.NativeAPI @@ -51,7 +53,7 @@ public void AddText(int id, byte[] text) } } - public void AddImage(int id, byte[] image, byte[]? summary = null, + public void AddImage(int id, byte[] image, byte[]? summary = null, int subType = 0) { if (MessageBuilders.TryGetValue(id, out var builder)) @@ -67,7 +69,7 @@ public void AddImage(int id, byte[] image, byte[]? summary = null, } } - public void AddLocalImage(int id, byte[] path, byte[]? summary = null, + public void AddLocalImage(int id, byte[] path, byte[]? summary = null, int subType = 0) { if (MessageBuilders.TryGetValue(id, out var builder)) @@ -146,4 +148,16 @@ public void AddLocalVideo(int id, byte[] path, byte[]? thumbPath) } } } + + internal static class BotMessageAccessor + { + [UnsafeAccessor(UnsafeAccessorKind.Field, Name = "k__BackingField")] + public static extern ref BotContact GetContact(this BotMessage message); + + [UnsafeAccessor(UnsafeAccessorKind.Field, Name = "k__BackingField")] + public static extern ref BotContact GetReceiver(this BotMessage message); + + [UnsafeAccessor(UnsafeAccessorKind.Field, Name = "k__BackingField")] + public static extern ref ulong GetClientSequence(this BotMessage message); + } } diff --git a/Lagrange.Core.NativeAPI/SendMessageEntryPoint.cs b/Lagrange.Core.NativeAPI/SendMessageEntryPoint.cs index d36596e4..9bf06da3 100644 --- a/Lagrange.Core.NativeAPI/SendMessageEntryPoint.cs +++ b/Lagrange.Core.NativeAPI/SendMessageEntryPoint.cs @@ -1,5 +1,8 @@ -using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Lagrange.Core.Common.Entity; using Lagrange.Core.Common.Interface; +using Lagrange.Core.Message; using Lagrange.Core.NativeAPI.NativeModel.Common; using Lagrange.Core.NativeAPI.NativeModel.Message; @@ -196,6 +199,40 @@ ByteArrayNative thumbnail ); } + [UnmanagedCallersOnly(EntryPoint = "RecallMessage")] + public static void RecallMessage(int index, int id, BotMessageStruct message) + { + if (Program.Contexts.Count <= index) + { + return; + } + + var context = Program.Contexts[index]; + var message1 = (BotMessage)RuntimeHelpers.GetUninitializedObject(typeof(BotMessage)); + message1.Sequence = message.Sequence; + message1.GetClientSequence() = message.ClientSequence; + + if ((MessageType)message.Type == MessageType.Group) + { + BotGroupMemberStruct member = new(); + Marshal.PtrToStructure( + message.Contact, + member + ); + message1.GetContact() = (BotGroupMember)member; + context.BotContext.RecallMessage(message1); + return; + } + + BotFriendStruct contact = new(); + BotFriendStruct receiver = new(); + Marshal.PtrToStructure(message.Contact, contact); + Marshal.PtrToStructure(message.Receiver, receiver); + message1.GetContact() = (BotFriend)contact; + message1.GetReceiver() = (BotFriend)receiver; + context.BotContext.RecallMessage(message1); + } + [UnmanagedCallersOnly(EntryPoint = "SendFriendMessage")] public static IntPtr SendFriendMessage(int index, int id, long friendUin) { diff --git a/Lagrange.Core/Internal/Logic/MessagingLogic.cs b/Lagrange.Core/Internal/Logic/MessagingLogic.cs index 21617900..c149f0bf 100644 --- a/Lagrange.Core/Internal/Logic/MessagingLogic.cs +++ b/Lagrange.Core/Internal/Logic/MessagingLogic.cs @@ -1,4 +1,4 @@ -using Lagrange.Core.Common.Entity; +using Lagrange.Core.Common.Entity; using Lagrange.Core.Exceptions; using Lagrange.Core.Internal.Events.Message; using Lagrange.Core.Internal.Packets.Message; From 4343e95bc918e7f54ed534174c6fb50ce486b939 Mon Sep 17 00:00:00 2001 From: Huang Youzhen Date: Sat, 1 Nov 2025 11:25:29 +0800 Subject: [PATCH 3/5] [NativeAPI] Unified API function format --- Lagrange.Core.NativeAPI.Test/Program.cs | 4 +- Lagrange.Core.NativeAPI.Test/Wrapper.cs | 4 +- .../NativeModel/Message/BotMessageStruct.cs | 1 - .../ReverseEvent/EventEntryPoint.cs | 50 +++++-- Lagrange.Core.Runner/InteropSignProvider.cs | 140 ++++++++++-------- Lagrange.Core.Runner/Program.cs | 15 +- 6 files changed, 129 insertions(+), 85 deletions(-) diff --git a/Lagrange.Core.NativeAPI.Test/Program.cs b/Lagrange.Core.NativeAPI.Test/Program.cs index f43b5e75..1a4c7094 100644 --- a/Lagrange.Core.NativeAPI.Test/Program.cs +++ b/Lagrange.Core.NativeAPI.Test/Program.cs @@ -18,7 +18,7 @@ static async Task Main(string[] args) IntPtr keystorePtr = IntPtr.Zero; IntPtr botConfigPtr = Marshal.AllocHGlobal(Marshal.SizeOf(botConfig)); Marshal.StructureToPtr(botConfig, botConfigPtr, false); - _index = Wrapper.Initialize(botConfigPtr, keystorePtr); + _index = Wrapper.Initialize(botConfigPtr, keystorePtr, IntPtr.Zero); Console.WriteLine($"Bot initialized with index: {_index}"); int status = Wrapper.Start(_index); Console.WriteLine($"Bot started with status: {status}"); @@ -34,7 +34,7 @@ static async void PollingProcesser(Object? source, System.Timers.ElapsedEventArg { try { - //await GetEventCount(); + // await GetEventCount(); await GetQrCodeEvent(); await GetLogEvent(); } diff --git a/Lagrange.Core.NativeAPI.Test/Wrapper.cs b/Lagrange.Core.NativeAPI.Test/Wrapper.cs index dfb24231..1c448479 100644 --- a/Lagrange.Core.NativeAPI.Test/Wrapper.cs +++ b/Lagrange.Core.NativeAPI.Test/Wrapper.cs @@ -1,4 +1,4 @@ -using System.Runtime.InteropServices; +using System.Runtime.InteropServices; namespace Lagrange.Core.NativeAPI.Test; @@ -7,7 +7,7 @@ public static class Wrapper public const string DLL_NAME = "Lagrange.Core.NativeAPI.dll"; [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)] - public static extern int Initialize(IntPtr botConfigPtr, IntPtr keystorePtr); + public static extern int Initialize(IntPtr botConfigPtr, IntPtr keystorePtr, IntPtr appConfigPtr); [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)] public static extern int Start(int index); diff --git a/Lagrange.Core.NativeAPI/NativeModel/Message/BotMessageStruct.cs b/Lagrange.Core.NativeAPI/NativeModel/Message/BotMessageStruct.cs index d6829213..bb07fb37 100644 --- a/Lagrange.Core.NativeAPI/NativeModel/Message/BotMessageStruct.cs +++ b/Lagrange.Core.NativeAPI/NativeModel/Message/BotMessageStruct.cs @@ -4,7 +4,6 @@ using Lagrange.Core.Message; using Lagrange.Core.Message.Entities; using Lagrange.Core.NativeAPI.NativeModel.Common; -using Lagrange.Core.NativeAPI.NativeModel.Event; using Lagrange.Core.NativeAPI.NativeModel.Message.Entity; namespace Lagrange.Core.NativeAPI.NativeModel.Message diff --git a/Lagrange.Core.NativeAPI/ReverseEvent/EventEntryPoint.cs b/Lagrange.Core.NativeAPI/ReverseEvent/EventEntryPoint.cs index e3467b89..c8d9ed80 100644 --- a/Lagrange.Core.NativeAPI/ReverseEvent/EventEntryPoint.cs +++ b/Lagrange.Core.NativeAPI/ReverseEvent/EventEntryPoint.cs @@ -53,6 +53,21 @@ public static IntPtr GetCaptchaEvent(int index) return eventPtr; } + [UnmanagedCallersOnly(EntryPoint = "GetBotFriendRecallEvent")] + public static IntPtr GetBotFriendRecallEvent(int index) + { + if (index >= Program.Contexts.Count) + { + return IntPtr.Zero; + } + + var botFriendRecallEvent = Program.Contexts[index].EventInvoker.BotFriendRecallEvent; + + IntPtr eventPtr = GetEventStructPtr(botFriendRecallEvent); + + return eventPtr; + } + [UnmanagedCallersOnly(EntryPoint = "GetBotFriendRequestEvent")] public static IntPtr GetBotFriendRequestEvent(int index) { @@ -68,8 +83,8 @@ public static IntPtr GetBotFriendRequestEvent(int index) return eventPtr; } - [UnmanagedCallersOnly(EntryPoint = "GetGroupInviteNotificationEvent")] - public static IntPtr GetGroupInviteNotificationEvent(int index) + [UnmanagedCallersOnly(EntryPoint = "GetBotGroupInviteNotificationEvent")] + public static IntPtr GetBotGroupInviteNotificationEvent(int index) { if (index >= Program.Contexts.Count) { @@ -83,8 +98,8 @@ public static IntPtr GetGroupInviteNotificationEvent(int index) return eventPtr; } - [UnmanagedCallersOnly(EntryPoint = "GetGroupJoinNotificationEvent")] - public static IntPtr GetGroupJoinNotificationEvent(int index) + [UnmanagedCallersOnly(EntryPoint = "GetBotGroupJoinNotificationEvent")] + public static IntPtr GetBotGroupJoinNotificationEvent(int index) { if (index >= Program.Contexts.Count) { @@ -98,8 +113,8 @@ public static IntPtr GetGroupJoinNotificationEvent(int index) return eventPtr; } - [UnmanagedCallersOnly(EntryPoint = "GetGroupMemberDecreaseEvent")] - public static IntPtr GetGroupMemberDecreaseEvent(int index) + [UnmanagedCallersOnly(EntryPoint = "GetBotGroupMemberDecreaseEvent")] + public static IntPtr GetBotGroupMemberDecreaseEvent(int index) { if (index >= Program.Contexts.Count) { @@ -113,8 +128,8 @@ public static IntPtr GetGroupMemberDecreaseEvent(int index) return eventPtr; } - [UnmanagedCallersOnly(EntryPoint = "GetGroupMemberIncreaseEvent")] - public static IntPtr GetGroupMemberIncreaseEvent(int index) + [UnmanagedCallersOnly(EntryPoint = "GetBotGroupMemberIncreaseEvent")] + public static IntPtr GetBotGroupMemberIncreaseEvent(int index) { if (index >= Program.Contexts.Count) { @@ -128,8 +143,8 @@ public static IntPtr GetGroupMemberIncreaseEvent(int index) return eventPtr; } - [UnmanagedCallersOnly(EntryPoint = "GetGroupNudgeEvent")] - public static IntPtr GetGroupNudgeEvent(int index) + [UnmanagedCallersOnly(EntryPoint = "GetBotGroupNudgeEvent")] + public static IntPtr GetBotGroupNudgeEvent(int index) { if (index >= Program.Contexts.Count) { @@ -157,6 +172,21 @@ public static IntPtr GetBotGroupReactionEvent(int index) return eventPtr; } + + [UnmanagedCallersOnly(EntryPoint = "GetBotGroupRecallEvent")] + public static IntPtr GetBotGroupRecallEvent(int index) + { + if (index >= Program.Contexts.Count) + { + return IntPtr.Zero; + } + + var botGroupRecallEvent = Program.Contexts[index].EventInvoker.BotGroupRecallEvent; + + IntPtr eventPtr = GetEventStructPtr(botGroupRecallEvent); + + return eventPtr; + } [UnmanagedCallersOnly(EntryPoint = "GetLoginEvent")] public static IntPtr GetLoginEvent(int index) diff --git a/Lagrange.Core.Runner/InteropSignProvider.cs b/Lagrange.Core.Runner/InteropSignProvider.cs index 470eff57..a61ac5de 100644 --- a/Lagrange.Core.Runner/InteropSignProvider.cs +++ b/Lagrange.Core.Runner/InteropSignProvider.cs @@ -1,13 +1,23 @@ -using System.Runtime.InteropServices; +using System.Text; +using System.Text.Json; +using System.Text.Json.Nodes; +using System.Text.Json.Serialization; using Lagrange.Core.Common; +using Lagrange.Core.Internal.Packets.Service; -namespace Lagrange.Core.Runner; +namespace Lagrange.Core.NativeAPI.NativeModel.Common; -public partial class InteropSignProvider : BotSignProvider +public class LinuxSignProvider(string? signUrl) : BotSignProvider, IDisposable { + private const string Tag = nameof(LinuxSignProvider); + + private readonly HttpClient _client = new(); + + private string Url => signUrl ?? $"https://sign.lagrangecore.org/api/sign/{Context.AppInfo.AppClientVersion}"; + private static readonly HashSet WhiteListCommand = [ - "trpc.o3.ecdh_access.EcdhAccess.SsoEstablishShareKey", + "trpc.o3.ecdh_access.EcdhAccess.SsoEstablishShareKey", "trpc.o3.ecdh_access.EcdhAccess.SsoSecureAccess", "trpc.o3.report.Report.SsoReport", "MessageSvc.PbSendMsg", @@ -49,75 +59,79 @@ public partial class InteropSignProvider : BotSignProvider "OidbSvcTrpcTcp.0xf67_5", "OidbSvcTrpcTcp.0x6d9_4" ]; - - private const string MicroblockSign = "libMicroblockSign"; - - [LibraryImport(MicroblockSign, EntryPoint = "attach")] [return: MarshalAs(UnmanagedType.I1)] - private static partial bool Attach(); - - [LibraryImport(MicroblockSign, EntryPoint = "signData")] [return: MarshalAs(UnmanagedType.I1)] - private static partial bool SignData( - IntPtr cmdName, // const char* - IntPtr srcData, // const uint8_t* - nuint srcDataSize, // size_t → nuint (platform-native) - long seq, // int64_t - IntPtr extraOut, ref nuint extraOutSize, - IntPtr tokenOut, ref nuint tokenOutSize, - IntPtr signOut, ref nuint signOutSize); - - public InteropSignProvider() - { - bool ok = Attach(); - if (!ok) throw new Exception("Failed to attach to MicroblockSign library."); - } public override bool IsWhiteListCommand(string cmd) => WhiteListCommand.Contains(cmd); - public override Task GetSecSign(long uin, string cmd, int seq, ReadOnlyMemory body) + public override async Task GetSecSign(long uin, string cmd, int seq, ReadOnlyMemory body) { - nuint extraOutSize = 0u; - nuint tokenOutSize = 0u; - nuint signOutSize = 0u; - - var extraOut = Marshal.AllocHGlobal(600); - var tokenOut = Marshal.AllocHGlobal(200); - var signOut = Marshal.AllocHGlobal(400); - - var srcData = Marshal.AllocHGlobal(body.Length); - var cmdName = Marshal.StringToHGlobalAnsi(cmd); - Marshal.Copy(body.Span.ToArray(), 0, srcData, body.Length); - try { - if (SignData(cmdName, srcData, (nuint)body.Length, seq, extraOut, ref extraOutSize, tokenOut, ref tokenOutSize, signOut, ref signOutSize)) + var payload = new JsonObject { - var extra = new byte[extraOutSize]; - var token = new byte[tokenOutSize]; - var sign = new byte[signOutSize]; - - Marshal.Copy(extraOut, extra, 0, (int)extraOutSize); - Marshal.Copy(tokenOut, token, 0, (int)tokenOutSize); - Marshal.Copy(signOut, sign, 0, (int)signOutSize); - - return Task.FromResult(new SsoSecureInfo - { - SecSign = sign.ToArray(), - SecToken = token.ToArray(), - SecExtra = extra.ToArray() - }); - } - else + ["cmd"] = cmd, + ["seq"] = seq, + ["src"] = Convert.ToHexString(body.Span), + }; + + var response = await _client.PostAsync(Url, new StringContent(payload.ToJsonString(), Encoding.UTF8, "application/json")); + if (!response.IsSuccessStatusCode) return null; + + var content = JsonHelper.Deserialize(await response.Content.ReadAsStringAsync()); + if (content == null) return null; + + return new SsoSecureInfo { - return Task.FromResult(null); - } + SecSign = Convert.FromHexString(content.Value.Sign), + SecToken = Convert.FromHexString(content.Value.Token), + SecExtra = Convert.FromHexString(content.Value.Extra) + }; } - finally + catch (Exception e) { - Marshal.FreeHGlobal(extraOut); - Marshal.FreeHGlobal(tokenOut); - Marshal.FreeHGlobal(signOut); - Marshal.FreeHGlobal(srcData); - Marshal.FreeHGlobal(cmdName); + Context.LogWarning(Tag, $"Failed to get sign: {e.Message}"); + return null; } } + + public void Dispose() + { + _client.Dispose(); + } + + [Serializable] + internal class Root + { + [JsonPropertyName("value")] public Response Value { get; set; } = new(); + } + + [Serializable] + internal class Response + { + [JsonPropertyName("sign")] public string Sign { get; set; } = string.Empty; + + [JsonPropertyName("token")] public string Token { get; set; } = string.Empty; + + [JsonPropertyName("extra")] public string Extra { get; set; } = string.Empty; + } +} + +internal static partial class JsonHelper +{ + [JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Default, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)] + + [JsonSerializable(typeof(LinuxSignProvider.Root))] + [JsonSerializable(typeof(LinuxSignProvider.Response))] + + [JsonSerializable(typeof(JsonObject))] + [JsonSerializable(typeof(LightApp))] + private partial class CoreSerializerContext : JsonSerializerContext; + + public static T? Deserialize(string json) where T : class => + JsonSerializer.Deserialize(json, typeof(T), CoreSerializerContext.Default) as T; + + public static string Serialize(T value) => + JsonSerializer.Serialize(value, typeof(T), CoreSerializerContext.Default); + + public static ReadOnlyMemory SerializeToUtf8Bytes(T value) => + JsonSerializer.SerializeToUtf8Bytes(value, typeof(T), CoreSerializerContext.Default); } \ No newline at end of file diff --git a/Lagrange.Core.Runner/Program.cs b/Lagrange.Core.Runner/Program.cs index ea793ded..d2a14308 100644 --- a/Lagrange.Core.Runner/Program.cs +++ b/Lagrange.Core.Runner/Program.cs @@ -7,6 +7,7 @@ using Lagrange.Core.Events.EventArgs; using Lagrange.Core.Internal.Packets.Message; using Lagrange.Core.Message; +using Lagrange.Core.NativeAPI.NativeModel.Common; using Lagrange.Core.Utility; namespace Lagrange.Core.Runner; @@ -15,7 +16,7 @@ internal static class Program { private static async Task Main() { - var sign = new InteropSignProvider(); + var sign = new LinuxSignProvider(""); Console.OutputEncoding = Encoding.UTF8; Console.InputEncoding = Encoding.UTF8; @@ -26,18 +27,18 @@ private static async Task Main() { context = BotFactory.Create(new BotConfig { - Protocol = Protocols.Windows, + Protocol = Protocols.Linux, SignProvider = sign, - LogLevel = LogLevel.Trace + LogLevel = LogLevel.Debug }, JsonSerializer.Deserialize(await File.ReadAllTextAsync("keystore.json")) ?? throw new InvalidOperationException()); } else { context = BotFactory.Create(new BotConfig { - Protocol = Protocols.Windows, + Protocol = Protocols.Linux, SignProvider = sign, - LogLevel = LogLevel.Trace + LogLevel = LogLevel.Debug }); } @@ -64,8 +65,8 @@ private static async Task Main() await context.Login(); - var builder = new MessageBuilder().Text("Awoo"); - var message = await context.SendFriendMessage(1925648680, builder.Build()); + //var builder = new MessageBuilder().Text("Awoo"); + //var message = await context.SendFriendMessage(1925648680, builder.Build()); await Task.Delay(-1); } From 33046a8f1ebc57963dd79915bc733afb8bf307f3 Mon Sep 17 00:00:00 2001 From: Huang Youzhen Date: Sun, 2 Nov 2025 15:20:58 +0800 Subject: [PATCH 4/5] [NativeAPI] Added BotOfflineEvent & Adjust RecallMessage func. --- .../Event/BotOfflineEventStruct.cs | 36 ++++++++++ .../OperateGroupEntryPoint.cs | 4 +- .../ReverseEvent/BotOfflineReverseEvent.cs | 16 +++++ .../ReverseEvent/EventEntryPoint.cs | 15 ++++ .../ReverseEvent/ReverseEventInvoker.cs | 3 + .../SendMessageEntryPoint.cs | 68 +++++++++---------- 6 files changed, 105 insertions(+), 37 deletions(-) create mode 100644 Lagrange.Core.NativeAPI/NativeModel/Event/BotOfflineEventStruct.cs create mode 100644 Lagrange.Core.NativeAPI/ReverseEvent/BotOfflineReverseEvent.cs diff --git a/Lagrange.Core.NativeAPI/NativeModel/Event/BotOfflineEventStruct.cs b/Lagrange.Core.NativeAPI/NativeModel/Event/BotOfflineEventStruct.cs new file mode 100644 index 00000000..af777935 --- /dev/null +++ b/Lagrange.Core.NativeAPI/NativeModel/Event/BotOfflineEventStruct.cs @@ -0,0 +1,36 @@ +using System.Runtime.InteropServices; +using System.Text; +using Lagrange.Core.Events.EventArgs; +using Lagrange.Core.NativeAPI.NativeModel.Common; + +namespace Lagrange.Core.NativeAPI.NativeModel.Event +{ + [StructLayout(LayoutKind.Sequential)] + public struct BotOfflineEventStruct : IEventStruct + { + public BotOfflineEventStruct() { } + + public int Reason = 0; + + ByteArrayNative Tag = new(); + + ByteArrayNative Message = new(); + + public static implicit operator BotOfflineEvent(BotOfflineEventStruct e) + { + return new BotOfflineEvent((BotOfflineEvent.Reasons)e.Reason, ( + Encoding.UTF8.GetString(e.Tag), Encoding.UTF8.GetString(e.Message) + )); + } + + public static implicit operator BotOfflineEventStruct(BotOfflineEvent e) + { + return new BotOfflineEventStruct() + { + Reason = (int)e.Reason, + Tag = Encoding.UTF8.GetBytes(e.Tips?.Tag ?? ""), + Message = Encoding.UTF8.GetBytes(e.Tips?.Message ?? ""), + }; + } + } +} \ No newline at end of file diff --git a/Lagrange.Core.NativeAPI/OperateGroupEntryPoint.cs b/Lagrange.Core.NativeAPI/OperateGroupEntryPoint.cs index dbe9cc92..bc879b24 100644 --- a/Lagrange.Core.NativeAPI/OperateGroupEntryPoint.cs +++ b/Lagrange.Core.NativeAPI/OperateGroupEntryPoint.cs @@ -1,9 +1,7 @@ -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; +using System.Runtime.InteropServices; using System.Text; using Lagrange.Core.Common.Entity; using Lagrange.Core.Common.Interface; -using Lagrange.Core.Message; using Lagrange.Core.NativeAPI.NativeModel.Common; using Lagrange.Core.NativeAPI.NativeModel.Event; using Lagrange.Core.NativeAPI.NativeModel.Message; diff --git a/Lagrange.Core.NativeAPI/ReverseEvent/BotOfflineReverseEvent.cs b/Lagrange.Core.NativeAPI/ReverseEvent/BotOfflineReverseEvent.cs new file mode 100644 index 00000000..737b9b89 --- /dev/null +++ b/Lagrange.Core.NativeAPI/ReverseEvent/BotOfflineReverseEvent.cs @@ -0,0 +1,16 @@ +using Lagrange.Core.Events.EventArgs; +using Lagrange.Core.NativeAPI.NativeModel; +using Lagrange.Core.NativeAPI.NativeModel.Event; +using Lagrange.Core.NativeAPI.ReverseEvent.Abstract; + +namespace Lagrange.Core.NativeAPI.ReverseEvent +{ + public class BotOfflineReverseEvent : ReverseEventBase + { + public override void RegisterEventHandler(BotContext context) + { + context.EventInvoker.RegisterEvent((ctx, e) => Events.Add((BotOfflineEventStruct)e) + ); + } + } +} diff --git a/Lagrange.Core.NativeAPI/ReverseEvent/EventEntryPoint.cs b/Lagrange.Core.NativeAPI/ReverseEvent/EventEntryPoint.cs index c8d9ed80..343e9ea2 100644 --- a/Lagrange.Core.NativeAPI/ReverseEvent/EventEntryPoint.cs +++ b/Lagrange.Core.NativeAPI/ReverseEvent/EventEntryPoint.cs @@ -248,6 +248,21 @@ public static IntPtr GetNewDeviceVerifyEvent(int index) return eventPtr; } + [UnmanagedCallersOnly(EntryPoint = "GetOfflineEvent")] + public static IntPtr GetOfflineEvent(int index) + { + if (index >= Program.Contexts.Count) + { + return IntPtr.Zero; + } + + var botOfflineEvent = Program.Contexts[index].EventInvoker.BotOfflineEvent; + + IntPtr eventPtr = GetEventStructPtr(botOfflineEvent); + + return eventPtr; + } + [UnmanagedCallersOnly(EntryPoint = "GetOnlineEvent")] public static IntPtr GetOnlineEvent(int index) { diff --git a/Lagrange.Core.NativeAPI/ReverseEvent/ReverseEventInvoker.cs b/Lagrange.Core.NativeAPI/ReverseEvent/ReverseEventInvoker.cs index c5cd16d1..178c64b4 100644 --- a/Lagrange.Core.NativeAPI/ReverseEvent/ReverseEventInvoker.cs +++ b/Lagrange.Core.NativeAPI/ReverseEvent/ReverseEventInvoker.cs @@ -18,6 +18,7 @@ public ReverseEventInvoker(BotContext context) BotLogEvent.RegisterEventHandler(context); BotMessageEvent.RegisterEventHandler(context); BotNewDeviceVerifyEvent.RegisterEventHandler(context); + BotOfflineEvent.RegisterEventHandler(context); BotOnlineEvent.RegisterEventHandler(context); BotQrCodeEvent.RegisterEventHandler(context); BotQrCodeQueryEvent.RegisterEventHandler(context); @@ -52,6 +53,8 @@ public ReverseEventInvoker(BotContext context) public BotNewDeviceVerifyReverseEvent BotNewDeviceVerifyEvent { get; } = new(); + public BotOfflineReverseEvent BotOfflineEvent { get; } = new(); + public BotOnlineReverseEvent BotOnlineEvent { get; } = new(); public BotQrCodeReverseEvent BotQrCodeEvent { get; } = new(); diff --git a/Lagrange.Core.NativeAPI/SendMessageEntryPoint.cs b/Lagrange.Core.NativeAPI/SendMessageEntryPoint.cs index 9bf06da3..dd96d877 100644 --- a/Lagrange.Core.NativeAPI/SendMessageEntryPoint.cs +++ b/Lagrange.Core.NativeAPI/SendMessageEntryPoint.cs @@ -199,40 +199,6 @@ ByteArrayNative thumbnail ); } - [UnmanagedCallersOnly(EntryPoint = "RecallMessage")] - public static void RecallMessage(int index, int id, BotMessageStruct message) - { - if (Program.Contexts.Count <= index) - { - return; - } - - var context = Program.Contexts[index]; - var message1 = (BotMessage)RuntimeHelpers.GetUninitializedObject(typeof(BotMessage)); - message1.Sequence = message.Sequence; - message1.GetClientSequence() = message.ClientSequence; - - if ((MessageType)message.Type == MessageType.Group) - { - BotGroupMemberStruct member = new(); - Marshal.PtrToStructure( - message.Contact, - member - ); - message1.GetContact() = (BotGroupMember)member; - context.BotContext.RecallMessage(message1); - return; - } - - BotFriendStruct contact = new(); - BotFriendStruct receiver = new(); - Marshal.PtrToStructure(message.Contact, contact); - Marshal.PtrToStructure(message.Receiver, receiver); - message1.GetContact() = (BotFriend)contact; - message1.GetReceiver() = (BotFriend)receiver; - context.BotContext.RecallMessage(message1); - } - [UnmanagedCallersOnly(EntryPoint = "SendFriendMessage")] public static IntPtr SendFriendMessage(int index, int id, long friendUin) { @@ -290,5 +256,39 @@ public static IntPtr SendGroupMessage(int index, int id, long groupUin) return IntPtr.Zero; } } + + [UnmanagedCallersOnly(EntryPoint = "RecallMessage")] + public static void RecallMessage(int index, BotMessageStruct message) + { + if (Program.Contexts.Count <= index) + { + return; + } + + var context = Program.Contexts[index]; + var message1 = (BotMessage)RuntimeHelpers.GetUninitializedObject(typeof(BotMessage)); + message1.Sequence = message.Sequence; + message1.GetClientSequence() = message.ClientSequence; + + if ((MessageType)message.Type == MessageType.Group) + { + BotGroupMemberStruct member = new(); + Marshal.PtrToStructure( + message.Contact, + member + ); + message1.GetContact() = (BotGroupMember)member; + context.BotContext.RecallMessage(message1); + return; + } + + BotFriendStruct contact = new(); + BotFriendStruct receiver = new(); + Marshal.PtrToStructure(message.Contact, contact); + Marshal.PtrToStructure(message.Receiver, receiver); + message1.GetContact() = (BotFriend)contact; + message1.GetReceiver() = (BotFriend)receiver; + context.BotContext.RecallMessage(message1); + } } } From e7d362b1178f93eee7b9685943b3371fd6699507 Mon Sep 17 00:00:00 2001 From: Huang Youzhen Date: Fri, 9 Jan 2026 00:57:02 +0800 Subject: [PATCH 5/5] [NativeAPI] A minor correction --- Lagrange.Core.NativeAPI/OperateGroupEntryPoint.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Lagrange.Core.NativeAPI/OperateGroupEntryPoint.cs b/Lagrange.Core.NativeAPI/OperateGroupEntryPoint.cs index bc879b24..759c8063 100644 --- a/Lagrange.Core.NativeAPI/OperateGroupEntryPoint.cs +++ b/Lagrange.Core.NativeAPI/OperateGroupEntryPoint.cs @@ -104,7 +104,7 @@ public static IntPtr GetMemberList(int index, long groupUin, bool refresh /*= fa { Marshal.StructureToPtr( (BotGroupMemberStruct)members[i], - result.Events + i * Marshal.SizeOf(), + result.Events + i * Marshal.SizeOf(), false ); } @@ -246,6 +246,7 @@ private static IntPtr GetGroupNotificationsStructPtr(List