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/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/BotGroupKickNotificationStruct.cs b/Lagrange.Core.NativeAPI/NativeModel/Common/BotGroupKickNotificationStruct.cs new file mode 100644 index 00000000..f132b77f --- /dev/null +++ b/Lagrange.Core.NativeAPI/NativeModel/Common/BotGroupKickNotificationStruct.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 BotGroupKickNotificationStruct(BotGroupKickNotification notification) : BotGroupNotificationBaseStruct(notification) +{ + public long OperatorUin = notification.OperatorUin; + + public ByteArrayNative OperatorUid { get; } = Encoding.UTF8.GetBytes(notification.OperatorUid); + + public static implicit operator BotGroupKickNotificationStruct(BotGroupKickNotification e) + { + return new BotGroupKickNotificationStruct(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/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/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/NativeModel/Message/BotMessageStruct.cs b/Lagrange.Core.NativeAPI/NativeModel/Message/BotMessageStruct.cs index 1bd3d588..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 @@ -28,6 +27,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 +165,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 new file mode 100644 index 00000000..bc879b24 --- /dev/null +++ b/Lagrange.Core.NativeAPI/OperateGroupEntryPoint.cs @@ -0,0 +1,293 @@ +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 = "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*/) + { + 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 = "QuitGroup")] + public static void QuitGroup(int index, long groupUin) + { + if (Program.Contexts.Count <= index) + { + return; + } + + BotContext context = Program.Contexts[index].BotContext; + context.GroupQuit(groupUin); + } + + [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 = "RenameGroupMember")] + public static void RenameGroupMember(int index, long groupUin, long targetUin, ByteArrayNative name) + { + if (Program.Contexts.Count <= index) + { + return; + } + + BotContext context = Program.Contexts[index].BotContext; + context.GroupMemberRename(groupUin, targetUin, Encoding.UTF8.GetString(name.ToByteArrayWithoutFree())); + } + + [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")] + 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: + case BotGroupNotificationType.KickSelf: + Marshal.StructureToPtr( + (BotGroupKickNotificationStruct)(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/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 92c9eb28..343e9ea2 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, @@ -51,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) { @@ -66,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) { @@ -81,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) { @@ -96,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) { @@ -111,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) { @@ -126,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) { @@ -155,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) @@ -216,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 7b5c1da6..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); @@ -28,6 +29,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 +42,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(); @@ -48,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/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..dd96d877 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; @@ -253,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); + } } } 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); } 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;