using System.Net.Http.Headers; using System.Text; namespace RadicadeServer.Radicade.Discord; public static class ReportDiscord { private static readonly HttpClient Http = CreateHttpClient(); private static HttpClient CreateHttpClient() { var client = new HttpClient { Timeout = TimeSpan.FromSeconds(30) }; client.DefaultRequestHeaders.UserAgent.ParseAdd("DiscordBot (https://radicade.app, 1.0)"); return client; } public sealed record DiscordAttachment(string Filename, byte[] Data, string MimeType); public static void SendAsync(string webhookUrl, string content, DiscordPayload payload) => SendAsync(webhookUrl, content, payload, null, null); public static void SendAsync(string webhookUrl, string content, DiscordPayload payload, IReadOnlyList? attachments, string? embedImageUrl = null) { if (string.IsNullOrWhiteSpace(webhookUrl)) return; _ = Task.Run(async () => { try { using var response = attachments is { Count: > 0 } ? await PostWithFilesAsync(webhookUrl, content, payload, attachments, embedImageUrl) : await PostJsonAsync(webhookUrl, content, payload, embedImageUrl); if (!response.IsSuccessStatusCode) { var errorBody = await response.Content.ReadAsStringAsync(); } } catch (Exception) { } }); } private static async Task PostJsonAsync(string url, string content, DiscordPayload payload, string? embedImageUrl) { var body = DiscordPayloadJson.Build(payload, content, embedImageUrl); using var request = new HttpRequestMessage(HttpMethod.Post, url); request.Content = new StringContent(body, Encoding.UTF8, "application/json"); return await Http.SendAsync(request); } private static async Task PostWithFilesAsync(string url, string content, DiscordPayload payload, IReadOnlyList attachments, string? embedImageUrl) { var json = DiscordPayloadJson.Build(payload, content, embedImageUrl); using var form = new MultipartFormDataContent(); form.Add(new StringContent(json, Encoding.UTF8, "application/json"), "payload_json"); for (int i = 0; i < attachments.Count; i++) { var file = new ByteArrayContent(attachments[i].Data); file.Headers.ContentType = new MediaTypeHeaderValue(attachments[i].MimeType); form.Add(file, $"files[{i}]", attachments[i].Filename); } return await Http.PostAsync(url, form); } private static string Truncate(string value, int max) { if (string.IsNullOrEmpty(value)) return ""; if (value.Length <= max) return value; var cut = max; if (char.IsHighSurrogate(value[cut - 1]) && cut < value.Length && char.IsLowSurrogate(value[cut])) cut--; return value[..cut]; } }