// , // /| __ // / | ,-~ / // Y :| // / // | jj /( .^ // >-"~"-v" // / Y // jo o | // ( ~T~j // >._-' _./ // / "~" | // Y _, | // /| ;-"~ _ l /// l/ ,-"~ \ //\//\/ .- \ // Y / Y -Row // l I ! // ]\ _\ /"\ //(" ~----( ~ Y. ) #endregion bunny public async Task <DiscordMessage> SendWebhookMessage(string content = null, DiscordEmbed[] embeds = null, FileStream fileStream = null, string fileName = null) { var dwb = new DiscordWebhookBuilder(); if (!(embeds is null)) { if (embeds.Length > 10) { throw new ArgumentException("More than 10 embeds provided."); } dwb.AddEmbeds(embeds); } if (!(content is null)) { dwb.WithContent(content); } if (!(fileStream is null) && !(fileName is null)) { dwb.AddFile(Path.GetFileName(fileName), fileStream); } if (embeds is null && content is null && fileStream is null) { throw new ArgumentException("Cannot send an empty message."); } return(await webhook.ExecuteAsync(dwb)); }
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 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); }
public async Task SendWebhookFilesAsync(CommandContext ctx) { var webhook = await ctx.Channel.CreateWebhookAsync("webhook-test"); using (var fs = new FileStream("ADumbFile.txt", FileMode.Open, FileAccess.Read)) { // Verify that the lib resets the position when asked var builder = new DiscordWebhookBuilder() .WithContent("Testing the `AddFile(Dictionary<string, stream>)` Overload with resetting the postion turned on.") .AddFiles(new Dictionary <string, Stream>() { { "ADumbFile1.txt", fs } }, true); await builder.SendAsync(webhook); await builder.SendAsync(webhook); builder.Clear(); //Verify the lib doesnt reset the position. THe file sent should have 0 bytes. builder.WithContent("Testing the `AddFile(Dictionary<string, stream> files)` Overload with resetting the postion turned off The 2nd file sent should have 0 bytes.") .AddFiles(new Dictionary <string, Stream>() { { "ADumbFile1.txt", fs } }, false); await builder.SendAsync(webhook); await builder.SendAsync(webhook); builder.Clear(); fs.Position = 0; // Verify that the lib resets the position when asked builder.WithContent("Testing the `AddFile(Stream stream)` Overload with resetting the postion turned on.") .AddFile(fs, true); await builder.SendAsync(webhook); await builder.SendAsync(webhook); builder.Clear(); //Verify the lib doesnt reset the position. THe file sent should have 0 bytes. builder.WithContent("Testing the `AddFile(Stream stream)` Overload with resetting the postion turned off. The 2nd file sent should have 0 bytes.") .AddFile(fs, false); await builder.SendAsync(webhook); await builder.SendAsync(webhook); builder.Clear(); fs.Position = 0; // Verify that the lib resets the position when asked builder.WithContent("Testing the `AddFile(string fileName, Stream stream)` Overload with resetting the postion turned on.") .AddFile("ADumbFile2.txt", fs, true); await builder.SendAsync(webhook); await builder.SendAsync(webhook); builder.Clear(); //Verify the lib doesnt reset the position. THe file sent should have 0 bytes. builder.WithContent("Testing the `AddFile(string fileName, Stream stream)` Overload with resetting the postion turned off. The 2nd file sent should have 0 bytes.") .AddFile("ADumbFile2.txt", fs, false); await builder.SendAsync(webhook); await builder.SendAsync(webhook); } await webhook.DeleteAsync(); }