From b3d50802024c05f9892a6bbe48063cc3a2f866fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=88=88=E5=B0=8F=E8=8D=B7?= Date: Sun, 20 Nov 2022 17:05:06 +0800 Subject: [PATCH] Fix UserUnbanned not working --- samples/Kook.Net.Samples.SimpleBot/Program.cs | 254 +++++------------- src/Kook.Net.Core/Entities/Guilds/IGuild.cs | 11 + src/Kook.Net.Rest/BaseKookClient.cs | 6 +- .../Entities/Guilds/GuildHelper.cs | 12 + .../Entities/Guilds/RestGuild.cs | 3 + src/Kook.Net.Rest/KookRestApiClient.cs | 6 +- src/Kook.Net.Rest/Net/DefaultRestClient.cs | 28 +- .../Net/Queue/RequestQueueBucket.cs | 1 + .../BaseSocketClient.Event.cs | 13 +- .../Entities/Guilds/SocketGuild.cs | 2 + .../Entities/Guilds/SocketGuildHelper.cs | 12 + src/Kook.Net.WebSocket/KookSocketClient.cs | 4 +- 12 files changed, 150 insertions(+), 202 deletions(-) diff --git a/samples/Kook.Net.Samples.SimpleBot/Program.cs b/samples/Kook.Net.Samples.SimpleBot/Program.cs index e7e65cd5..5d1832da 100644 --- a/samples/Kook.Net.Samples.SimpleBot/Program.cs +++ b/samples/Kook.Net.Samples.SimpleBot/Program.cs @@ -9,19 +9,13 @@ class Program { private readonly KookSocketClient _client; private readonly string _token; - private readonly ulong _guildId; - private readonly ulong _channelId; public static Task Main(string[] args) => new Program().MainAsync(); public Program() { _token = Environment.GetEnvironmentVariable("KookDebugToken", EnvironmentVariableTarget.User) ?? throw new ArgumentNullException(nameof(_token)); - _guildId = ulong.Parse(Environment.GetEnvironmentVariable("KookDebugGuild", EnvironmentVariableTarget.User) - ?? throw new ArgumentNullException(nameof(_token))); - _channelId = ulong.Parse(Environment.GetEnvironmentVariable("KookDebugChannel", EnvironmentVariableTarget.User) - ?? throw new ArgumentNullException(nameof(_token))); - _client = new(new KookSocketConfig() + _client = new(new KookSocketConfig { AlwaysDownloadUsers = true, AlwaysDownloadVoiceStates = true, @@ -30,34 +24,77 @@ public Program() LogLevel = LogSeverity.Debug }); - _client.Log += ClientOnLog; - _client.GuildMemberOnline += ClientOnGuildMemberOnline; - // _client.MessageReceived += ClientOnMessageReceived; - // _client.DirectMessageReceived += ClientOnDirectMessageReceived; - _client.Ready += ClientOnReady; + #region BaseKookClient + + _client.Log += log => Task.Run(() => Console.WriteLine(log.ToString())); + _client.LoggedIn += () => Task.CompletedTask; + _client.LoggedOut += () => Task.CompletedTask; + + #endregion + + #region KookSocketClient + + _client.Connected += () => Task.CompletedTask; + _client.Disconnected += exception => Task.CompletedTask; + _client.Ready += () => Task.CompletedTask; + _client.LatencyUpdated += (before, after) => Task.CompletedTask; + + #endregion + + #region BaseSocketClient + + _client.ChannelCreated += channel => Task.CompletedTask; + _client.ChannelDestroyed += channel => Task.CompletedTask; + _client.ChannelUpdated += (before, after) => Task.CompletedTask; + + _client.ReactionAdded += (message, channel, reaction) => Task.CompletedTask; + _client.ReactionRemoved += (message, channel, reaction) => Task.CompletedTask; + _client.DirectReactionAdded += (message, channel, reaction) => Task.CompletedTask; + _client.DirectReactionRemoved += (message, channel, reaction) => Task.CompletedTask; + + _client.MessageReceived += message => Task.CompletedTask; + _client.MessageDeleted += (message, channel) => Task.CompletedTask; + _client.MessageUpdated += (before, after, channel) => Task.CompletedTask; + _client.MessagePinned += (before, after, channel, @operator) => Task.CompletedTask; + _client.MessageUnpinned += (before, after, channel, @operator) => Task.CompletedTask; + + _client.DirectMessageReceived += message => Task.CompletedTask; + _client.DirectMessageDeleted += (message, channel) => Task.CompletedTask; + _client.DirectMessageUpdated += (before, after, channel) => Task.CompletedTask; + + _client.UserJoined += (user, time) => Task.CompletedTask; + _client.UserLeft += (guild, user, time) => Task.CompletedTask; + _client.UserBanned += (users, @operator, guild) => Task.CompletedTask; + _client.UserUnbanned += (users, @operator, guild) => Task.CompletedTask; + _client.UserUpdated += (before, after) => Task.CompletedTask; + _client.CurrentUserUpdated += (before, after) => Task.CompletedTask; + _client.GuildMemberUpdated += (before, after) => Task.CompletedTask; + _client.GuildMemberOnline += (users, time) => Task.CompletedTask; + _client.GuildMemberOffline += (users, time) => Task.CompletedTask; + + _client.UserConnected += (user, channel, guild, time) => Task.CompletedTask; + _client.UserDisconnected += (user, channel, guild, time) => Task.CompletedTask; + + _client.RoleCreated += role => Task.CompletedTask; + _client.RoleDeleted += role => Task.CompletedTask; + _client.RoleUpdated += (before, after) => Task.CompletedTask; + _client.EmoteCreated += (emote, guild) => Task.CompletedTask; _client.EmoteDeleted += (emote, guild) => Task.CompletedTask; _client.EmoteUpdated += (before, after, guild) => Task.CompletedTask; - // _client.MessageButtonClicked += ClientOnMessageButtonClicked; - // _client.MessageDeleted += async (msg, channel) => - // { - // Console.WriteLine($"Message {(await msg.GetOrDownloadAsync()).CleanContent} deleted in {(await channel.GetOrDownloadAsync()).Name}"); - // }; - // _client.MessageButtonClicked += async (value, user, message, channel, guild) => - // { - // - // }; - } - private Task ClientOnGuildMemberOnline(IReadOnlyCollection arg1, DateTimeOffset arg2) - { - return Task.CompletedTask; + _client.JoinedGuild += guild => Task.CompletedTask; + _client.LeftGuild += guild => Task.CompletedTask; + _client.GuildUpdated += (before, after) => Task.CompletedTask; + _client.GuildAvailable += guild => Task.CompletedTask; + _client.GuildUnavailable += guild => Task.CompletedTask; + + _client.MessageButtonClicked += (value, user, message, channel, guild) => Task.CompletedTask; + _client.DirectMessageButtonClicked += (value, user, message, channel) => Task.CompletedTask; + + #endregion + } - // - // private Task ClientOnDirectMessageReceived(SocketMessage arg) - // { - // return Task.CompletedTask; - // } public async Task MainAsync() { @@ -65,161 +102,4 @@ public async Task MainAsync() await _client.StartAsync(); await Task.Delay(Timeout.Infinite); } - - // private async Task ClientOnMessageReceived(SocketMessage arg) - // { - // Console.WriteLine($"{arg.Author.Username} in {arg.Channel.Name}: {arg.Content}"); - // string argCleanContent = arg.CleanContent; - // if (arg.Author.Id == _client.CurrentUser.Id) return; - // if (arg.Author.IsBot == true) return; - // if (arg.Content != "/test") return; - // await arg.Channel.SendTextAsync("收到了!", quote: new Quote(arg.Id)); - // // await msg.UpdateAsync(); - // // await CardDemo(arg); - // await ModifyMessageDemo(arg); - // } - // - private async Task ClientOnReady() - { - await Task.Delay(TimeSpan.FromSeconds(5)); - // KookSocketClient kookSocketClient = _client; - // SocketGuildUser socketGuildUser = kookSocketClient.GetGuild(7557797319758285).GetUser(821393881); - // List socketGuildUsers = kookSocketClient.GetGuild(7557797319758285).Users.Where(x => x.IsDeafened == true).ToList(); - // IReadOnlyCollection readOnlyCollection = kookSocketClient.GetGuild(7557797319758285).GetVoiceChannel(9816956151862920).ConnectedUsers; - // IReadOnlyCollection connectedUsers = await kookSocketClient.GetGuild(7557797319758285).GetVoiceChannel(9816956151862920).GetConnectedUsersAsync(); - // Stream stream = await new HttpClient().GetStreamAsync("https://img.kaiheila.cn/attachments/2021-01/21/600975671b9ab.mp3"); - // await _client.GetUser(2810246202).SendFileAsync(new FileAttachment(stream, "Filename", AttachmentType.Audio)); - // Cacheable message = await (await _client.GetUserAsync(2810246202)).SendTextAsync("1234567"); - // IUserMessage msg = await message.GetOrDownloadAsync(); - // (Guid messageId, DateTimeOffset messageTimestamp) = await _client.GetGuild(7557797319758285).GetTextChannel(7888175654136995) - // .SendFileAsync(new FileAttachment(stream, "Filename", AttachmentType.Audio)); - // (Guid messageId, DateTimeOffset messageTimestamp) = await _client.GetGuild(7557797319758285) - // .GetTextChannel(7888175654136995) - // .SendVideoMessageAsync("D:\\1.mp4"); - // IMessage message = await _client.GetGuild(7557797319758285).GetTextChannel(7888175654136995) - // .GetMessageAsync(Guid.Parse("dad3df69-af9e-4bb9-8b8c-c2ca2239685e")); - // SocketDMChannel socketDMChannel = await _client.GetUser(2810246202).CreateDMChannelAsync(); - // IMessage messageAsync = await socketDMChannel.GetMessageAsync(Guid.Parse("0f2b0e9f-82ea-4c30-b91d-7956b10fbd29")); - IMessage listAsync = await _client.GetGuild(7557797319758285).GetTextChannel(7888175654136995).GetMessageAsync(Guid.Parse("617573e1-edb5-43c7-93d1-3c6430078c6b")); - // IDMChannel socketDMChannel = await (await _client.GetUserAsync(2810246202)).CreateDMChannelAsync(); - // List> async = await socketDMChannel.GetMessagesAsync().ToListAsync(); - } - - // { - // // await _client.Rest.AddReactionAsync(Guid.Parse("9062d5a9-9290-434c-b295-5b5835121cb1"), Emote.Parse("(emj)loading(emj)[1990044438283387/WiGtuv3F1d05k05k]", TagMode.KMarkdown)); - // // await Task.Delay(TimeSpan.FromSeconds(5)); - // // IUser result = await _client.GetUserAsync(2810246202); - // // IUser userAsync = await _client.GetUserAsync(1896684851); - // return Task.CompletedTask; - // } - // - private async Task ClientOnLog(LogMessage arg) - { - await Task.Delay(0); - Console.WriteLine(arg.ToString()); - } - // - // private async Task ClientOnMessageButtonClicked(string value, SocketUser user, IMessage msg, SocketTextChannel channel, SocketGuild guild) - // { - // // await msg.AddReactionAsync(Emote.Parse("[:djbigfan:1990044438283387/hvBcVC4nHX03k03k]", TagMode.PlainText)); - // // await msg.AddReactionAsync(Emote.Parse("(emj)djbigfan(emj)[1990044438283387/hvBcVC4nHX03k03k]", TagMode.KMarkdown)); - // // await msg.RemoveReactionAsync(Emote.Parse("[:djbigfan:1990044438283387/hvBcVC4nHX03k03k]", TagMode.PlainText), _client.CurrentUser); - // // IEnumerable selectMany = (await _client.GetGuild(1990044438283387).GetTextChannel(6286033651700207).GetMessagesAsync(Guid.Parse("ed260ee9-1616-44ec-abff-d5cfcf9903a0"), Direction.Around, 5).ToListAsync()).SelectMany(x => x.ToList()); - // // await _client.GetUserAsync(0); - // // IReadOnlyCollection pinnedMessagesAsync = await _client.GetGuild(1990044438283387).GetTextChannel(6286033651700207).GetPinnedMessagesAsync(); - // // await (user as SocketGuildUser).AddRoleAsync(1681537); - // // IEnumerable flattenAsync = await _client.GetGuild(1990044438283387).GetRole(300643).GetUsersAsync().FlattenAsync().ConfigureAwait(false); - // // IReadOnlyCollection readOnlyCollection = await _client.GetGuild(1990044438283387).GetInvitesAsync(); - // // IInvite invite = await _client.GetGuild(1990044438283387).CreateInviteAsync(InviteMaxAge.NeverExpires, InviteMaxUses.Fifty); - // // SocketGuild socketGuild = _client.GetGuild(1990044438283387); - // // IEnumerable games = await _client.Rest.GetGamesAsync().FlattenAsync().ConfigureAwait(false); - // await _client.GetGuild(1990044438283387).GetTextChannel(6286033651700207) - // .SendImageMessageAsync("E:\\OneDrive\\Pictures\\86840227_p0_新年.png"); - // } - // - // private async Task CardDemo(SocketMessage message) - // { - // if (message.Author.Id == _client.CurrentUser.Id) return; - // if (message.Content != "/test") return; - // CardBuilder cardBuilder = new CardBuilder() - // .WithSize(CardSize.Large) - // .AddModule(new HeaderModuleBuilder().WithText("This is header")) - // .AddModule(new DividerModuleBuilder()) - // .AddModule(new SectionModuleBuilder().WithText("**This** *is* ~~kmarkdown~~", true)) - // .AddModule(new SectionModuleBuilder() - // .WithText(new ParagraphStructBuilder() - // .WithColumnCount(2) - // .AddField(new PlainTextElementBuilder().WithContent("多列文本测试")) - // .AddField(new KMarkdownElementBuilder().WithContent("**昵称**\n白给Doc")) - // .AddField(new KMarkdownElementBuilder().WithContent("**在线时间**\n9:00-21:00")) - // .AddField(new KMarkdownElementBuilder().WithContent("**服务器**\n吐槽中心"))) - // .WithAccessory(new ImageElementBuilder() - // .WithSource("https://img.kaiheila.cn/assets/2021-01/7kr4FkWpLV0ku0ku.jpeg") - // .WithSize(ImageSize.Small)) - // .WithMode(SectionAccessoryMode.Unspecified)) - // .AddModule(new SectionModuleBuilder() - // .WithText(new PlainTextElementBuilder().WithContent("您是否认为\"KOOK\"是最好的语音软件?")) - // .WithAccessory(new ButtonElementBuilder().WithTheme(ButtonTheme.Primary).WithText("完全同意", false)) - // .WithMode(SectionAccessoryMode.Right)) - // .AddModule(new ContainerModuleBuilder() - // .AddElement(new ImageElementBuilder().WithSource("https://img.kaiheila.cn/assets/2021-01/7kr4FkWpLV0ku0ku.jpeg"))) - // .AddModule(new ImageGroupModuleBuilder() - // .AddElement(new ImageElementBuilder().WithSource("https://img.kaiheila.cn/assets/2021-01/pWsmcLsPJq08c08c.jpeg")) - // .AddElement(new ImageElementBuilder().WithSource("https://img.kaiheila.cn/assets/2021-01/YIfHfnvxaV0dw0dw.jpg"))) - // .AddModule(new ContextModuleBuilder() - // .AddElement(new PlainTextElementBuilder().WithContent("KOOK 气氛组,等你一起来搞事情")) - // .AddElement(new ImageElementBuilder().WithSource("https://img.kaiheila.cn/assets/2021-01/7kr4FkWpLV0ku0ku.jpeg")) - // .AddElement(new ImageElementBuilder().WithSource("https://img.kaiheila.cn/assets/2021-01/7kr4FkWpLV0ku0ku.jpeg")) - // .AddElement(new ImageElementBuilder().WithSource("https://img.kaiheila.cn/assets/2021-01/7kr4FkWpLV0ku0ku.jpeg"))) - // .AddModule(new ActionGroupModuleBuilder() - // .AddElement(new ButtonElementBuilder().WithTheme(ButtonTheme.Primary).WithText("确定").WithValue("ok")) - // .AddElement(new ButtonElementBuilder().WithTheme(ButtonTheme.Danger).WithText("取消").WithValue("cancel"))) - // .AddModule(new FileModuleBuilder() - // .WithSource("https://img.kaiheila.cn/attachments/2021-01/21/600972b5d0d31.txt") - // .WithTitle("KOOK 介绍.txt")) - // .AddModule(new AudioModuleBuilder() - // .WithSource("https://img.kaiheila.cn/attachments/2021-01/21/600975671b9ab.mp3") - // .WithTitle("命运交响曲") - // .WithCover("https://img.kaiheila.cn/assets/2021-01/rcdqa8fAOO0hs0mc.jpg")) - // .AddModule(new VideoModuleBuilder() - // .WithSource("https://img.kaiheila.cn/attachments/2021-01/20/6008127e8c8de.mp4") - // .WithTitle("有本事别笑")) - // .AddModule(new DividerModuleBuilder()) - // .AddModule(new CountdownModuleBuilder().WithMode(CountdownMode.Day).WithEndTime(DateTimeOffset.Now.AddMinutes(1))) - // .AddModule(new CountdownModuleBuilder().WithMode(CountdownMode.Hour).WithEndTime(DateTimeOffset.Now.AddMinutes(1))) - // .AddModule(new CountdownModuleBuilder().WithMode(CountdownMode.Second).WithEndTime(DateTimeOffset.Now.AddMinutes(2)).WithStartTime(DateTimeOffset.Now.AddMinutes(1))); - // - // (Guid MessageId, DateTimeOffset MessageTimestamp) response = await _client.GetGuild(((SocketUserMessage) message).Guild.Id) - // .GetTextChannel(message.Channel.Id) - // .SendCardAsync(cardBuilder.Build(), quote: new Quote(message.Id)); - // } - // - // private static async Task ModifyMessageDemo(SocketMessage message) - // { - // await Task.Delay(TimeSpan.FromSeconds(1)); - // - // SocketTextChannel channel = message.Channel as SocketTextChannel; - // (Guid MessageId, DateTimeOffset MessageTimestamp) response = await channel - // .SendTextAsync("BeforeModification"); - // await Task.Delay(TimeSpan.FromSeconds(1)); - // - // IUserMessage msg = await channel.GetMessageAsync(response.MessageId) as IUserMessage; - // await msg!.ModifyAsync(properties => properties.Content += "\n==========\nModified"); - // await Task.Delay(TimeSpan.FromSeconds(1)); - // - // await msg.DeleteAsync(); - // await Task.Delay(TimeSpan.FromSeconds(1)); - // - // response = await channel.SendCardAsync(new CardBuilder() - // .AddModule(new HeaderModuleBuilder().WithText("Test")).Build()); - // await Task.Delay(TimeSpan.FromSeconds(1)); - // - // msg = await channel.GetMessageAsync(response.MessageId) as IUserMessage; - // await msg!.ModifyAsync(properties => - // { - // properties.Cards = properties.Cards.Append(new CardBuilder() - // .AddModule(new DividerModuleBuilder()) - // .AddModule(new HeaderModuleBuilder().WithText("ModificationHeader")).Build()); - // }); - // } } \ No newline at end of file diff --git a/src/Kook.Net.Core/Entities/Guilds/IGuild.cs b/src/Kook.Net.Core/Entities/Guilds/IGuild.cs index 42a08933..95ae92ae 100644 --- a/src/Kook.Net.Core/Entities/Guilds/IGuild.cs +++ b/src/Kook.Net.Core/Entities/Guilds/IGuild.cs @@ -185,6 +185,17 @@ public interface IGuild : IEntity /// Task>> GetBoostSubscriptionsAsync(RequestOptions options = null); + /// + /// Gets subscriptions which are not expired for this guild. + /// + /// The options to be used when sending the request. + /// + /// A task that represents the asynchronous retrieval operation. The task result contains + /// a collection of which are not expired, + /// each representing the subscriptions information. + /// + Task>> GetActiveBoostSubscriptionsAsync(RequestOptions options = null); + #endregion #region Guild Bans diff --git a/src/Kook.Net.Rest/BaseKookClient.cs b/src/Kook.Net.Rest/BaseKookClient.cs index bf4f3ac7..8ffaddb9 100644 --- a/src/Kook.Net.Rest/BaseKookClient.cs +++ b/src/Kook.Net.Rest/BaseKookClient.cs @@ -6,11 +6,11 @@ namespace Kook.Rest; public abstract class BaseKookClient : IKookClient { #region BaseKookClient - public event Func Log { add { _logEvent.Add(value); } remove { _logEvent.Remove(value); } } + public event Func Log { add => _logEvent.Add(value); remove => _logEvent.Remove(value); } internal readonly AsyncEvent> _logEvent = new AsyncEvent>(); - public event Func LoggedIn { add { _loggedInEvent.Add(value); } remove { _loggedInEvent.Remove(value); } } + public event Func LoggedIn { add => _loggedInEvent.Add(value); remove => _loggedInEvent.Remove(value); } private readonly AsyncEvent> _loggedInEvent = new AsyncEvent>(); - public event Func LoggedOut { add { _loggedOutEvent.Add(value); } remove { _loggedOutEvent.Remove(value); } } + public event Func LoggedOut { add => _loggedOutEvent.Add(value); remove => _loggedOutEvent.Remove(value); } private readonly AsyncEvent> _loggedOutEvent = new AsyncEvent>(); internal readonly Logger _restLogger; diff --git a/src/Kook.Net.Rest/Entities/Guilds/GuildHelper.cs b/src/Kook.Net.Rest/Entities/Guilds/GuildHelper.cs index 40b768c4..7d2064fe 100644 --- a/src/Kook.Net.Rest/Entities/Guilds/GuildHelper.cs +++ b/src/Kook.Net.Rest/Entities/Guilds/GuildHelper.cs @@ -27,6 +27,18 @@ public static async Task); } + public static async Task>> GetActiveBoostSubscriptionsAsync( + IGuild guild, BaseKookClient client, RequestOptions options) + { + IEnumerable subscriptions = await client.ApiClient + .GetGuildBoostSubscriptionsAsync(guild.Id, since: DateTimeOffset.Now, options: options).FlattenAsync(); + return subscriptions.GroupBy(x => x.UserId) + .ToImmutableDictionary(x => RestUser.Create(client, x.First().User) as IUser, + x => x.GroupBy(y => (y.StartTime, y.EndTime)) + .Select(y => new BoostSubscriptionMetadata(y.Key.StartTime, y.Key.EndTime, y.Count())) + .ToImmutableArray() as IReadOnlyCollection); + } + public static int GetMaxBitrate(IGuild guild) { var tierFactor = guild.BoostLevel switch diff --git a/src/Kook.Net.Rest/Entities/Guilds/RestGuild.cs b/src/Kook.Net.Rest/Entities/Guilds/RestGuild.cs index d5c0c704..6242e3f7 100644 --- a/src/Kook.Net.Rest/Entities/Guilds/RestGuild.cs +++ b/src/Kook.Net.Rest/Entities/Guilds/RestGuild.cs @@ -163,6 +163,9 @@ public Task LeaveAsync(RequestOptions options = null) /// public Task>> GetBoostSubscriptionsAsync(RequestOptions options = null) => GuildHelper.GetBoostSubscriptionsAsync(this, Kook, options); + /// + public Task>> GetActiveBoostSubscriptionsAsync(RequestOptions options = null) + => GuildHelper.GetActiveBoostSubscriptionsAsync(this, Kook, options); #endregion diff --git a/src/Kook.Net.Rest/KookRestApiClient.cs b/src/Kook.Net.Rest/KookRestApiClient.cs index 7f00709a..f4726ed9 100644 --- a/src/Kook.Net.Rest/KookRestApiClient.cs +++ b/src/Kook.Net.Rest/KookRestApiClient.cs @@ -439,13 +439,17 @@ public async Task RemoveGuildMuteDeafAsync(CreateOrRemoveGuildMuteDeafParams arg } public IAsyncEnumerable> GetGuildBoostSubscriptionsAsync(ulong guildId, + DateTimeOffset? since = null, DateTimeOffset? until = null, int limit = KookConfig.MaxUsersPerBatch, int fromPage = 1, RequestOptions options = null) { Preconditions.NotEqual(guildId, 0, nameof(guildId)); + string query = $"guild_id={guildId}"; + if (since.HasValue) query += $"&start_time={since.Value.ToUnixTimeMilliseconds()}"; + if (until.HasValue) query += $"&end_time={until.Value.ToUnixTimeMilliseconds()}"; options = RequestOptions.CreateOrClone(options); var ids = new BucketIds(guildId: guildId); - return SendPagedAsync(HttpMethod.Get, (pageSize, page) => $"guild-boost/history?guild_id={guildId}&page_size={pageSize}&page={page}", + return SendPagedAsync(HttpMethod.Get, (pageSize, page) => $"guild-boost/history?{query}&page_size={pageSize}&page={page}", ids, clientBucket: ClientBucketType.SendEdit, pageMeta: new PageMeta(pageSize: 50), options: options); } diff --git a/src/Kook.Net.Rest/Net/DefaultRestClient.cs b/src/Kook.Net.Rest/Net/DefaultRestClient.cs index d9fd8d9f..9f92e09c 100644 --- a/src/Kook.Net.Rest/Net/DefaultRestClient.cs +++ b/src/Kook.Net.Rest/Net/DefaultRestClient.cs @@ -25,10 +25,15 @@ internal sealed class DefaultRestClient : IRestClient, IDisposable private readonly HttpClient _client; private readonly string _baseUrl; - private readonly JsonSerializerOptions _serializerOptions; private CancellationToken _cancelToken; private bool _isDisposed; +#if DEBUG_REST + private readonly JsonSerializerOptions _serializerOptions; + private int _requestId; + private readonly SemaphoreSlim _requestIdLock = new SemaphoreSlim(1, 1); +#endif + public DefaultRestClient(string baseUrl, bool useProxy = false) { _baseUrl = baseUrl; @@ -44,11 +49,14 @@ public DefaultRestClient(string baseUrl, bool useProxy = false) SetHeader("accept-encoding", "gzip, deflate"); _cancelToken = CancellationToken.None; + +#if DEBUG_REST _serializerOptions = new JsonSerializerOptions { Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, NumberHandling = JsonNumberHandling.AllowReadingFromString }; +#endif } private void Dispose(bool disposing) { @@ -164,12 +172,18 @@ public async Task SendAsync(HttpMethod method, string endpoint, IR private async Task SendInternalAsync(HttpRequestMessage request, CancellationToken cancelToken) { +#if DEBUG_REST + await _requestIdLock.WaitAsync(1, cancelToken); + _requestId++; + int requestId = _requestId; + _requestIdLock.Release(); +#endif using (var cancelTokenSource = CancellationTokenSource.CreateLinkedTokenSource(_cancelToken, cancelToken)) { #if DEBUG_REST - Debug.WriteLine($"[REST] {request.Method} {request.RequestUri} {request.Content?.Headers.ContentType?.MediaType}"); - if (request.Content?.Headers.ContentType?.MediaType == "application/json") - Debug.WriteLine($"[REST] {await request.Content.ReadAsStringAsync().ConfigureAwait(false)}"); + Debug.WriteLine($"[REST] [{requestId}] {request.Method} {request.RequestUri} {request.Content?.Headers.ContentType?.MediaType}"); + if (request.Content?.Headers.ContentType?.MediaType == "application/json") + Debug.WriteLine($"[REST] {await request.Content.ReadAsStringAsync().ConfigureAwait(false)}"); #endif cancelToken = cancelTokenSource.Token; HttpResponseMessage response = await _client.SendAsync(request, cancelToken).ConfigureAwait(false); @@ -178,11 +192,11 @@ private async Task SendInternalAsync(HttpRequestMessage request, C var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); #if DEBUG_REST - Debug.WriteLine($"[REST] {response.StatusCode} {response.ReasonPhrase}"); + Debug.WriteLine($"[REST] [{requestId}] {response.StatusCode} {response.ReasonPhrase}"); if (response.Content?.Headers.ContentType?.MediaType == "application/json") - Debug.WriteLine($"[REST] {await response.Content.ReadAsStringAsync().ConfigureAwait(false)}"); + Debug.WriteLine($"[REST] [{requestId}] {await response.Content.ReadAsStringAsync().ConfigureAwait(false)}"); #endif - return new RestResponse(response.StatusCode, headers, stream, response.Content.Headers.ContentType); + return new RestResponse(response.StatusCode, headers, stream, response.Content?.Headers.ContentType); } } diff --git a/src/Kook.Net.Rest/Net/Queue/RequestQueueBucket.cs b/src/Kook.Net.Rest/Net/Queue/RequestQueueBucket.cs index 63d3fd6c..abf1c305 100644 --- a/src/Kook.Net.Rest/Net/Queue/RequestQueueBucket.cs +++ b/src/Kook.Net.Rest/Net/Queue/RequestQueueBucket.cs @@ -1,4 +1,5 @@ using System.Net; +using System.Net.Mime; using System.Text; using System.Text.Encodings.Web; using System.Text.Json; diff --git a/src/Kook.Net.WebSocket/BaseSocketClient.Event.cs b/src/Kook.Net.WebSocket/BaseSocketClient.Event.cs index 727747a0..8f19b003 100644 --- a/src/Kook.Net.WebSocket/BaseSocketClient.Event.cs +++ b/src/Kook.Net.WebSocket/BaseSocketClient.Event.cs @@ -414,6 +414,11 @@ public event Func UserLeft /// The guild where the banning action takes place is passed in the event handler parameter as /// . /// + /// + /// The banning actions are usually taken with kicking, and the kicking action takes place + /// before the banning action according to the KOOK gateway events. Therefore, the banned users + /// parameter is usually a collection of . + /// /// public event Func, SocketUser, SocketGuild, Task> UserBanned { @@ -441,12 +446,16 @@ public event Func, SocketUser, SocketGuild, Task /// . /// /// - public event Func UserUnbanned + /// + /// The unbanning actions are usually taken to users that are not in the guild. Therefore, the unbanned users + /// parameter is usually a collection of . + /// + public event Func, SocketUser, SocketGuild, Task> UserUnbanned { add => _userUnbannedEvent.Add(value); remove => _userUnbannedEvent.Remove(value); } - internal readonly AsyncEvent> _userUnbannedEvent = new AsyncEvent>(); + internal readonly AsyncEvent, SocketUser, SocketGuild, Task>> _userUnbannedEvent = new AsyncEvent, SocketUser, SocketGuild, Task>>(); /// Fired when a user is updated. public event Func UserUpdated { diff --git a/src/Kook.Net.WebSocket/Entities/Guilds/SocketGuild.cs b/src/Kook.Net.WebSocket/Entities/Guilds/SocketGuild.cs index f59b9705..66241c2d 100644 --- a/src/Kook.Net.WebSocket/Entities/Guilds/SocketGuild.cs +++ b/src/Kook.Net.WebSocket/Entities/Guilds/SocketGuild.cs @@ -460,6 +460,8 @@ public Task LeaveAsync(RequestOptions options = null) /// public Task>> GetBoostSubscriptionsAsync(RequestOptions options = null) => SocketGuildHelper.GetBoostSubscriptionsAsync(this, Kook, options); + public Task>> GetActiveBoostSubscriptionsAsync(RequestOptions options = null) + => SocketGuildHelper.GetActiveBoostSubscriptionsAsync(this, Kook, options); #endregion diff --git a/src/Kook.Net.WebSocket/Entities/Guilds/SocketGuildHelper.cs b/src/Kook.Net.WebSocket/Entities/Guilds/SocketGuildHelper.cs index 9555b164..9d275d55 100644 --- a/src/Kook.Net.WebSocket/Entities/Guilds/SocketGuildHelper.cs +++ b/src/Kook.Net.WebSocket/Entities/Guilds/SocketGuildHelper.cs @@ -29,4 +29,16 @@ public static async Task); } + public static async Task>> GetActiveBoostSubscriptionsAsync( + SocketGuild guild, BaseSocketClient client, RequestOptions options) + { + IEnumerable subscriptions = await client.ApiClient + .GetGuildBoostSubscriptionsAsync(guild.Id, since: DateTimeOffset.Now, options: options).FlattenAsync(); + return subscriptions.GroupBy(x => x.UserId) + .ToImmutableDictionary(x => guild.GetUser(x.Key) ?? client.GetUser(x.Key) ?? RestUser.Create(client, x.First().User) as IUser, + x => x.GroupBy(y => (y.StartTime, y.EndTime)) + .Select(y => new BoostSubscriptionMetadata(y.Key.StartTime, y.Key.EndTime, y.Count())) + .ToImmutableArray() as IReadOnlyCollection); + } + } \ No newline at end of file diff --git a/src/Kook.Net.WebSocket/KookSocketClient.cs b/src/Kook.Net.WebSocket/KookSocketClient.cs index cf3ffe99..33e51cb0 100644 --- a/src/Kook.Net.WebSocket/KookSocketClient.cs +++ b/src/Kook.Net.WebSocket/KookSocketClient.cs @@ -1260,10 +1260,10 @@ private async Task ProcessMessageAsync(GatewaySocketFrameType gatewaySocketFrame { SocketUser operatorUser = guild.GetUser(data.OperatorUserId) ?? (SocketUser) SocketUnknownUser.Create(this, State, data.OperatorUserId); - var bannedUsers = data.UserIds.Select(id => guild.GetUser(id) + var unbannedUsers = data.UserIds.Select(id => guild.GetUser(id) ?? (SocketUser) SocketUnknownUser.Create(this, State, id)) .ToReadOnlyCollection(() => data.UserIds.Length); - await TimedInvokeAsync(_userBannedEvent, nameof(UserBanned), bannedUsers, operatorUser, guild).ConfigureAwait(false); + await TimedInvokeAsync(_userUnbannedEvent, nameof(UserUnbanned), unbannedUsers, operatorUser, guild).ConfigureAwait(false); } else {