using System.Globalization; using System.Text.Json.Nodes; namespace RadicadeServer.Radicade.Discord; public static class DiscordPayloadJson { private const int MaxContentLength = 2000; private const int MaxTitleLength = 256; private const int MaxDescriptionLength = 4096; private const int MaxFieldNameLength = 256; private const int MaxFieldValueLength = 1024; private const int MaxFieldCount = 25; public static string Build(DiscordPayload payload, string? contentOverride = null, string? embedImageUrl = null) { var embed = new JsonObject(); if (!string.IsNullOrWhiteSpace(payload.Title)) embed["title"] = Truncate(payload.Title, MaxTitleLength); if (!string.IsNullOrWhiteSpace(payload.Description)) embed["description"] = Truncate(payload.Description, MaxDescriptionLength); embed["color"] = payload.Color; var imageUrl = string.IsNullOrWhiteSpace(embedImageUrl) ? payload.ImageUrl : embedImageUrl; if (!string.IsNullOrWhiteSpace(imageUrl)) embed["image"] = new JsonObject { ["url"] = Truncate(imageUrl, MaxTitleLength) }; if (!string.IsNullOrWhiteSpace(payload.ThumbnailUrl)) embed["thumbnail"] = new JsonObject { ["url"] = Truncate(payload.ThumbnailUrl, MaxTitleLength) }; if (!string.IsNullOrWhiteSpace(payload.TimestampUtc) && DateTime.TryParse(payload.TimestampUtc, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out var parsed)) { embed["timestamp"] = parsed.ToString("O"); } var fields = new JsonArray(); foreach (var field in (payload.Fields ?? new List()).Take(MaxFieldCount)) { if (field == null) continue; fields.Add(new JsonObject { ["name"] = Truncate(field.Name ?? "", MaxFieldNameLength), ["value"] = Truncate(field.Value ?? "", MaxFieldValueLength), ["inline"] = field.Inline }); } if (fields.Count > 0) embed["fields"] = fields; var message = new JsonObject { ["content"] = Truncate(contentOverride ?? payload.Title ?? "", MaxContentLength) }; message["embeds"] = new JsonArray { embed }; return message.ToJsonString(); } 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]; } }