private async Task <ulong> ExecuteWebhookInner(DiscordChannel channel, DiscordWebhook webhook, string name, string avatarUrl, string content, IReadOnlyList <DiscordAttachment> attachments, bool allowEveryone, bool hasRetried = false) { content = content.Truncate(2000); var dwb = new DiscordWebhookBuilder(); dwb.WithUsername(FixClyde(name).Truncate(80)); dwb.WithContent(content); dwb.AddMentions(content.ParseAllMentions(allowEveryone, channel.Guild)); if (!string.IsNullOrWhiteSpace(avatarUrl)) { dwb.WithAvatarUrl(avatarUrl); } var attachmentChunks = ChunkAttachmentsOrThrow(attachments, 8 * 1024 * 1024); if (attachmentChunks.Count > 0) { _logger.Information("Invoking webhook with {AttachmentCount} attachments totalling {AttachmentSize} MiB in {AttachmentChunks} chunks", attachments.Count, attachments.Select(a => a.FileSize).Sum() / 1024 / 1024, attachmentChunks.Count); await AddAttachmentsToBuilder(dwb, attachmentChunks[0]); } DiscordMessage response; using (_metrics.Measure.Timer.Time(BotMetrics.WebhookResponseTime)) { try { response = await webhook.ExecuteAsync(dwb); } catch (JsonReaderException) { // This happens sometimes when we hit a CloudFlare error (or similar) on Discord's end // Nothing we can do about this - happens sometimes under server load, so just drop the message and give up throw new WebhookExecutionErrorOnDiscordsEnd(); } catch (NotFoundException e) { var errorText = e.WebResponse?.Response; if (errorText != null && errorText.Contains("10015") && !hasRetried) { // Error 10015 = "Unknown Webhook" - this likely means the webhook was deleted // but is still in our cache. Invalidate, refresh, try again _logger.Warning("Error invoking webhook {Webhook} in channel {Channel}", webhook.Id, webhook.ChannelId); var newWebhook = await _webhookCache.InvalidateAndRefreshWebhook(channel, webhook); return(await ExecuteWebhookInner(channel, newWebhook, name, avatarUrl, content, attachments, allowEveryone, hasRetried : true)); } throw; } } // We don't care about whether the sending succeeds, and we don't want to *wait* for it, so we just fork it off var _ = TrySendRemainingAttachments(webhook, name, avatarUrl, attachmentChunks); return(response.Id); }
public async Task ExecuteAsync(DiscordRestClient rest, PartnerSenderArguments senderArguments) { if (senderArguments.DevelopmentStressTest) { await ExecuteStressTestMessage(rest); return; } bool vanity = this.Match.VanityInvite is not null && this.Match.DonorRank >= DonorService.VANITY_LIMIT; bool attachEmbeds = this.Match.DonorRank >= DonorService.EMBED_LIMIT; DiscordWebhookBuilder?hook = new DiscordWebhookBuilder() .WithContent($"{this.Match.Message}\n\n" + $"https://discord.gg/" + $"{(vanity ? this.Match.VanityInvite : this.Match.Invite)}") .WithUsername($"{this.Match.GuildName} | Partner Bot"); if (attachEmbeds) { if (this.Match.DonorRank >= DonorService.HIGHEST_RANK) { hook.AddEmbeds(this.Match.MessageEmbeds); } else if (this.Match.MessageEmbeds.Count > 0) { hook.AddEmbed(this.Match.MessageEmbeds[0]); } } hook.AddEmbed(new DiscordEmbedBuilder() .WithColor(DiscordColor.Gray) .WithTitle("Partner Bot Advertisment") .WithDescription($"**ID:** {this.Match.GuildId}") .WithFooter($"pb-advert{(this.Match.NSFW ? " | NSFW" : "")}", rest.CurrentApplication.GetAvatarUrl(ImageFormat.Png)) .WithImageUrl(this.Match.Banner)); if (!string.IsNullOrWhiteSpace(this.Match.GuildIcon)) { hook.WithAvatarUrl(this.Match.GuildIcon); } await rest.ExecuteWebhookAsync(this.WebhookId, this.WebhookToken, hook); if (this.ExtraMessage is not null) { var eDat = new PartnerData(this, this.ExtraMessage); await eDat.ExecuteAsync(rest, senderArguments); } }
public async Task SpoilCommand(CommandContext ctx, [Description("The message text"), RemainingText] string content) { var message = new DiscordWebhookBuilder(); foreach (var attachment in ctx.Message.Attachments) { message.AddFile("SPOILER_" + attachment.FileName, GetStreamFromUrl(attachment.Url)); } message.WithContent(content); message.WithAvatarUrl(ctx.Member.GetAvatarUrl(ImageFormat.Auto)); message.WithUsername(ctx.Member.DisplayName); var webhook = (await ctx.Channel.GetWebhooksAsync()).FirstOrDefault(); if (webhook == null) { webhook = await ctx.Channel.CreateWebhookAsync("SpoilHook"); } await webhook.ExecuteAsync(message); }
private async Task TrySendRemainingAttachments(DiscordWebhook webhook, string name, string avatarUrl, IReadOnlyList <IReadOnlyCollection <DiscordAttachment> > attachmentChunks) { if (attachmentChunks.Count <= 1) { return; } for (var i = 1; i < attachmentChunks.Count; i++) { var dwb = new DiscordWebhookBuilder(); if (avatarUrl != null) { dwb.WithAvatarUrl(avatarUrl); } dwb.WithUsername(name); await AddAttachmentsToBuilder(dwb, attachmentChunks[i]); await webhook.ExecuteAsync(dwb); } }