Add round end Discord pings, discord webhook API (#19468)
This commit is contained in:
101
Content.Server/Discord/DiscordWebhook.cs
Normal file
101
Content.Server/Discord/DiscordWebhook.cs
Normal file
@@ -0,0 +1,101 @@
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Content.Server.Discord;
|
||||
|
||||
public sealed class DiscordWebhook : IPostInjectInit
|
||||
{
|
||||
[Dependency] private readonly ILogManager _log = default!;
|
||||
|
||||
private const string BaseUrl = "https://discord.com/api/v10/webhooks";
|
||||
private readonly HttpClient _http = new();
|
||||
private ISawmill _sawmill = default!;
|
||||
|
||||
private string GetUrl(WebhookIdentifier identifier)
|
||||
{
|
||||
return $"{BaseUrl}/{identifier.Id}/{identifier.Token}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the webhook data from the given webhook url.
|
||||
/// </summary>
|
||||
/// <param name="url">The url to get the data from.</param>
|
||||
/// <returns>The webhook data returned from the url.</returns>
|
||||
public async Task<WebhookData?> GetWebhook(string url)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await _http.GetFromJsonAsync<WebhookData>(url);
|
||||
}
|
||||
catch
|
||||
{
|
||||
_sawmill.Error($"Error getting discord webhook data. Stack trace:\n{Environment.StackTrace}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the webhook data from the given webhook url.
|
||||
/// </summary>
|
||||
/// <param name="url">The url to get the data from.</param>
|
||||
/// <param name="onComplete">The delegate to invoke with the obtained data, if any.</param>
|
||||
public async void GetWebhook(string url, Action<WebhookData> onComplete)
|
||||
{
|
||||
if (await GetWebhook(url) is { } data)
|
||||
onComplete(data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the webhook data from the given webhook url if it is not null or whitespace.
|
||||
/// </summary>
|
||||
/// <param name="url">The url to get the data from.</param>
|
||||
/// <param name="onComplete">The delegate to invoke with the obtained data, if any.</param>
|
||||
public async void TryGetWebhook(string url, Action<WebhookData> onComplete)
|
||||
{
|
||||
if (await GetWebhook(url) is { } data)
|
||||
onComplete(data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new webhook message with the given identifier and payload.
|
||||
/// </summary>
|
||||
/// <param name="identifier">The identifier for the webhook url.</param>
|
||||
/// <param name="payload">The payload to create the message from.</param>
|
||||
/// <returns>The response from Discord's API.</returns>
|
||||
public async Task<HttpResponseMessage> CreateMessage(WebhookIdentifier identifier, WebhookPayload payload)
|
||||
{
|
||||
var url = $"{GetUrl(identifier)}?wait=true";
|
||||
return await _http.PostAsJsonAsync(url, payload);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a webhook message with the given identifier and message id.
|
||||
/// </summary>
|
||||
/// <param name="identifier">The identifier for the webhook url.</param>
|
||||
/// <param name="messageId">The message id to delete.</param>
|
||||
/// <returns>The response from Discord's API.</returns>
|
||||
public async Task<HttpResponseMessage> DeleteMessage(WebhookIdentifier identifier, ulong messageId)
|
||||
{
|
||||
var url = $"{GetUrl(identifier)}/messages/{messageId}";
|
||||
return await _http.DeleteAsync(url);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new webhook message with the given identifier, message id and payload.
|
||||
/// </summary>
|
||||
/// <param name="identifier">The identifier for the webhook url.</param>
|
||||
/// <param name="messageId">The message id to edit.</param>
|
||||
/// <param name="payload">The payload used to edit the message.</param>
|
||||
/// <returns>The response from Discord's API.</returns>
|
||||
public async Task<HttpResponseMessage> EditMessage(WebhookIdentifier identifier, ulong messageId, WebhookPayload payload)
|
||||
{
|
||||
var url = $"{GetUrl(identifier)}/messages/{messageId}";
|
||||
return await _http.PatchAsJsonAsync(url, payload);
|
||||
}
|
||||
|
||||
void IPostInjectInit.PostInject()
|
||||
{
|
||||
_sawmill = _log.GetSawmill("DISCORD");
|
||||
}
|
||||
}
|
||||
42
Content.Server/Discord/WebhookData.cs
Normal file
42
Content.Server/Discord/WebhookData.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Content.Server.Discord;
|
||||
|
||||
// https://discord.com/developers/docs/resources/webhook#webhook-object-webhook-structure
|
||||
public struct WebhookData
|
||||
{
|
||||
[JsonPropertyName("id")]
|
||||
public ulong Id { get; set; }
|
||||
|
||||
[JsonPropertyName("type")]
|
||||
public int Type { get; set; }
|
||||
|
||||
[JsonPropertyName("guild_id")]
|
||||
public ulong? GuildId { get; set; }
|
||||
|
||||
[JsonPropertyName("channel_id")]
|
||||
public ulong? ChannelId { get; set; }
|
||||
|
||||
[JsonPropertyName("user")]
|
||||
public WebhookUser? User { get; set; }
|
||||
|
||||
[JsonPropertyName("name")]
|
||||
public string? Name { get; set; }
|
||||
|
||||
[JsonPropertyName("avatar")]
|
||||
public string? Avatar { get; set; }
|
||||
|
||||
[JsonPropertyName("token")]
|
||||
public string Token { get; set; }
|
||||
|
||||
[JsonPropertyName("application_id")]
|
||||
public ulong? ApplicationId { get; set; }
|
||||
|
||||
[JsonPropertyName("url")]
|
||||
public string? Url { get; set; }
|
||||
|
||||
public WebhookIdentifier ToIdentifier()
|
||||
{
|
||||
return new WebhookIdentifier(Id, Token);
|
||||
}
|
||||
}
|
||||
20
Content.Server/Discord/WebhookEmbed.cs
Normal file
20
Content.Server/Discord/WebhookEmbed.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Content.Server.Discord;
|
||||
|
||||
// https://discord.com/developers/docs/resources/channel#embed-object-embed-structure
|
||||
public struct WebhookEmbed
|
||||
{
|
||||
[JsonPropertyName("description")]
|
||||
public string Description { get; set; } = "";
|
||||
|
||||
[JsonPropertyName("color")]
|
||||
public int Color { get; set; } = 0;
|
||||
|
||||
[JsonPropertyName("footer")]
|
||||
public WebhookEmbedFooter? Footer { get; set; } = null;
|
||||
|
||||
public WebhookEmbed()
|
||||
{
|
||||
}
|
||||
}
|
||||
17
Content.Server/Discord/WebhookEmbedFooter.cs
Normal file
17
Content.Server/Discord/WebhookEmbedFooter.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Content.Server.Discord;
|
||||
|
||||
// https://discord.com/developers/docs/resources/channel#embed-object-embed-footer-structure
|
||||
public struct WebhookEmbedFooter
|
||||
{
|
||||
[JsonPropertyName("text")]
|
||||
public string Text { get; set; } = "";
|
||||
|
||||
[JsonPropertyName("icon_url")]
|
||||
public string? IconUrl { get; set; }
|
||||
|
||||
public WebhookEmbedFooter()
|
||||
{
|
||||
}
|
||||
}
|
||||
3
Content.Server/Discord/WebhookIdentifier.cs
Normal file
3
Content.Server/Discord/WebhookIdentifier.cs
Normal file
@@ -0,0 +1,3 @@
|
||||
namespace Content.Server.Discord;
|
||||
|
||||
public record struct WebhookIdentifier(ulong Id, string Token);
|
||||
18
Content.Server/Discord/WebhookMentions.cs
Normal file
18
Content.Server/Discord/WebhookMentions.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Content.Server.Discord;
|
||||
|
||||
public struct WebhookMentions
|
||||
{
|
||||
[JsonPropertyName("parse")]
|
||||
public HashSet<string> Parse { get; set; } = new();
|
||||
|
||||
public WebhookMentions()
|
||||
{
|
||||
}
|
||||
|
||||
public void AllowRoleMentions()
|
||||
{
|
||||
Parse.Add("roles");
|
||||
}
|
||||
}
|
||||
29
Content.Server/Discord/WebhookPayload.cs
Normal file
29
Content.Server/Discord/WebhookPayload.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Content.Server.Discord;
|
||||
|
||||
// https://discord.com/developers/docs/resources/channel#message-object-message-structure
|
||||
public struct WebhookPayload
|
||||
{
|
||||
/// <summary>
|
||||
/// The message to send in the webhook. Maximum of 2000 characters.
|
||||
/// </summary>
|
||||
[JsonPropertyName("content")]
|
||||
public string Content { get; set; } = "";
|
||||
|
||||
[JsonPropertyName("username")]
|
||||
public string? Username { get; set; }
|
||||
|
||||
[JsonPropertyName("avatar_url")]
|
||||
public string? AvatarUrl { get; set; } = "";
|
||||
|
||||
[JsonPropertyName("embeds")]
|
||||
public List<WebhookEmbed>? Embeds { get; set; } = null;
|
||||
|
||||
[JsonPropertyName("allowed_mentions")]
|
||||
public WebhookMentions AllowedMentions { get; set; } = new();
|
||||
|
||||
public WebhookPayload()
|
||||
{
|
||||
}
|
||||
}
|
||||
58
Content.Server/Discord/WebhookUser.cs
Normal file
58
Content.Server/Discord/WebhookUser.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Content.Server.Discord;
|
||||
|
||||
// https://discord.com/developers/docs/resources/user#user-object
|
||||
public struct WebhookUser
|
||||
{
|
||||
[JsonPropertyName("id")]
|
||||
public ulong Id { get; set; }
|
||||
|
||||
[JsonPropertyName("username")]
|
||||
public string Username { get; set; }
|
||||
|
||||
[JsonPropertyName("discriminator")]
|
||||
public string Discriminator { get; set; }
|
||||
|
||||
[JsonPropertyName("global_name")]
|
||||
public string? GlobalName { get; set; }
|
||||
|
||||
[JsonPropertyName("avatar")]
|
||||
public string? Avatar { get; set; }
|
||||
|
||||
[JsonPropertyName("bot")]
|
||||
public bool? Bot { get; set; }
|
||||
|
||||
[JsonPropertyName("system")]
|
||||
public bool? System { get; set; }
|
||||
|
||||
[JsonPropertyName("mfa_enabled")]
|
||||
public bool? MfaEnabled { get; set; }
|
||||
|
||||
[JsonPropertyName("banner")]
|
||||
public string? Banner { get; set; }
|
||||
|
||||
[JsonPropertyName("accent_color")]
|
||||
public int? AccentColor { get; set; }
|
||||
|
||||
[JsonPropertyName("locale")]
|
||||
public string? Locale { get; set; }
|
||||
|
||||
[JsonPropertyName("verified")]
|
||||
public bool? Verified { get; set; }
|
||||
|
||||
[JsonPropertyName("email")]
|
||||
public string? Email { get; set; }
|
||||
|
||||
[JsonPropertyName("flags")]
|
||||
public int? Flags { get; set; }
|
||||
|
||||
[JsonPropertyName("premium_type")]
|
||||
public int? PremiumType { get; set; }
|
||||
|
||||
[JsonPropertyName("public_flags")]
|
||||
public int? PublicFlags { get; set; }
|
||||
|
||||
[JsonPropertyName("avatar_decoration")]
|
||||
public string? AvatarDecoration { get; set; }
|
||||
}
|
||||
Reference in New Issue
Block a user