Log to discord log channel

This commit is contained in:
Michael Chen 2022-01-18 13:05:34 +01:00
parent 735bc8e8ae
commit a6ee52f70e
No known key found for this signature in database
GPG Key ID: 1CBC7AA5671437BB
2 changed files with 36 additions and 27 deletions

View File

@ -26,6 +26,9 @@ public class BotConfiguration : IBotConfiguration, IBotConfigurator {
[JsonProperty("admins", Required = Required.DisallowNull)] [JsonProperty("admins", Required = Required.DisallowNull)]
[Option("admins", Default = new ulong[] { }, HelpText = "The list of bot administrators.")] [Option("admins", Default = new ulong[] { }, HelpText = "The list of bot administrators.")]
public ulong[] Administrators { get; init; } = Array.Empty<ulong>(); public ulong[] Administrators { get; init; } = Array.Empty<ulong>();
[JsonProperty("logchannel", Required = Required.DisallowNull)]
[Option("logchannel", Default = null, HelpText = "Optionally the id of a channel to mirror log to.")]
public ulong? LogChannel { get; init; } = null;
[JsonIgnore] [JsonIgnore]
public BotConfiguration Config => this; public BotConfiguration Config => this;
} }

View File

@ -31,9 +31,11 @@ public class Program : IDisposable, ICommandHandler<ResponseType>, IUserRoleMana
public IEnumerable<ActiveChannel> Channels => _channels ?? throw new InvalidProgramException("Channels used before verification!"); public IEnumerable<ActiveChannel> Channels => _channels ?? throw new InvalidProgramException("Channels used before verification!");
public ActiveChannel[]? _channels; public ActiveChannel[]? _channels;
private bool disposedValue; private bool disposedValue;
private static ITextChannel? LogChannel;
private readonly RootCommandService _computer; private readonly RootCommandService _computer;
public static bool OnlineNotifications => true; public static bool OnlineNotifications => true;
public const LogSeverity DiscordLogSeverity = LogSeverity.Warning;
private const string ClientScriptName = "MinecraftDiscordBot.ClientScript.lua"; private const string ClientScriptName = "MinecraftDiscordBot.ClientScript.lua";
private const string WebhookName = "minecraftbot"; private const string WebhookName = "minecraftbot";
public readonly string ClientScript; public readonly string ClientScript;
@ -70,11 +72,10 @@ public class Program : IDisposable, ICommandHandler<ResponseType>, IUserRoleMana
_whitelistedChannels = config.Channels.ToHashSet(); _whitelistedChannels = config.Channels.ToHashSet();
} }
private void ComputerConnectedChanged(object? sender, IWebSocketConnection? e) { private void ComputerConnectedChanged(object? sender, IWebSocketConnection? e)
_ = Task.Run(() => Broadcast(i => i.SendMessageAsync(e is not null => _ = Task.Run(() => Broadcast(i => i.SendMessageAsync(e is not null
? "The Minecraft client is now available!" ? "The Minecraft client is now available!"
: "The Minecraft client disconnected!"))); : "The Minecraft client disconnected!")));
}
private void MinecraftMessageReceived(object? sender, ChatEvent e) private void MinecraftMessageReceived(object? sender, ChatEvent e)
=> Task.Run(() => WebhookBroadcast(i => i.SendMessageAsync(e.Message, username: e.Username, avatarUrl: $"https://crafatar.com/renders/head/{e.UUID}"))); => Task.Run(() => WebhookBroadcast(i => i.SendMessageAsync(e.Message, username: e.Username, avatarUrl: $"https://crafatar.com/renders/head/{e.UUID}")));
private Task<T[]> WebhookBroadcast<T>(Func<DiscordWebhookClient, Task<T>> apply) => Task.WhenAll(Channels.Select(i => apply(new DiscordWebhookClient(i.Webhook)))); private Task<T[]> WebhookBroadcast<T>(Func<DiscordWebhookClient, Task<T>> apply) => Task.WhenAll(Channels.Select(i => apply(new DiscordWebhookClient(i.Webhook))));
@ -109,7 +110,12 @@ public class Program : IDisposable, ICommandHandler<ResponseType>, IUserRoleMana
} }
private async Task<bool> HasValidChannels() { private async Task<bool> HasValidChannels() {
if (await GetValidChannels(_whitelistedChannels).ToArrayAsync() is not { Length: > 0 } channels) { if (_config.LogChannel is ulong logChannelId) {
LogChannel = await IsValidChannel(logChannelId);
if (LogChannel is null)
await LogWarningAsync(BotSource, $"The given log channel ID is not valid '{logChannelId}'!");
}
if (await GetValidChannels(_whitelistedChannels) is not { Length: > 0 } channels) {
await LogErrorAsync(BotSource, new InvalidOperationException("No valid textchannel was whitelisted!")); await LogErrorAsync(BotSource, new InvalidOperationException("No valid textchannel was whitelisted!"));
return false; return false;
} }
@ -127,13 +133,14 @@ public class Program : IDisposable, ICommandHandler<ResponseType>, IUserRoleMana
socket.OnMessage = async message => await SocketReceived(socket, message); socket.OnMessage = async message => await SocketReceived(socket, message);
}); });
private async IAsyncEnumerable<ITextChannel> GetValidChannels(IEnumerable<ulong> ids) { private async Task<ITextChannel[]> GetValidChannels(IEnumerable<ulong> ids)
foreach (var channelId in ids) { => (await Task.WhenAll(ids.Select(i => IsValidChannel(i)))).OfType<ITextChannel>().ToArray();
private async Task<ITextChannel?> IsValidChannel(ulong channelId) {
var channel = await _client.GetChannelAsync(channelId); var channel = await _client.GetChannelAsync(channelId);
if (channel is not ITextChannel textChannel) { if (channel is not ITextChannel textChannel) {
if (channel is null) await LogWarningAsync(BotSource, $"Channel with id [{channelId}] does not exist!"); if (channel is null) await LogWarningAsync(BotSource, $"Channel with id [{channelId}] does not exist!");
else await LogWarningAsync(BotSource, $"Channel is not a text channels and will not be used: {channel.Name} [{channel.Id}]!"); else await LogWarningAsync(BotSource, $"Channel is not a text channels and will not be used: {channel.Name} [{channel.Id}]!");
continue; return null;
} }
if (textChannel.Guild is RestGuild guild) { if (textChannel.Guild is RestGuild guild) {
@ -142,8 +149,7 @@ public class Program : IDisposable, ICommandHandler<ResponseType>, IUserRoleMana
} else { } else {
await LogWarningAsync(BotSource, $"Whitelisted in channel: {channel.Name} [{channel.Id}] on unknown server!"); await LogWarningAsync(BotSource, $"Whitelisted in channel: {channel.Name} [{channel.Id}] on unknown server!");
} }
yield return textChannel; return textChannel;
}
} }
private async Task SocketReceived(IWebSocketConnection socket, string message) { private async Task SocketReceived(IWebSocketConnection socket, string message) {
@ -276,11 +282,6 @@ public class Program : IDisposable, ICommandHandler<ResponseType>, IUserRoleMana
public static void LogError(string source, Exception exception) => Log(new(LogSeverity.Error, source, exception?.Message, exception)); public static void LogError(string source, Exception exception) => Log(new(LogSeverity.Error, source, exception?.Message, exception));
private static async Task LogAsync(LogMessage msg) { private static async Task LogAsync(LogMessage msg) {
Log(msg);
await Task.CompletedTask;
}
public static void Log(LogMessage msg) {
lock (LogLock) { lock (LogLock) {
var oldColor = Console.ForegroundColor; var oldColor = Console.ForegroundColor;
try { try {
@ -298,7 +299,12 @@ public class Program : IDisposable, ICommandHandler<ResponseType>, IUserRoleMana
Console.ForegroundColor = oldColor; Console.ForegroundColor = oldColor;
} }
} }
if (msg.Severity <= DiscordLogSeverity && LogChannel is ITextChannel log) {
await log.SendMessageAsync($"{msg.Severity}: {msg}");
} }
}
public static void Log(LogMessage msg) => _ = Task.Run(() => LogAsync(msg));
protected virtual void Dispose(bool disposing) { protected virtual void Dispose(bool disposing) {
if (!disposedValue) { if (!disposedValue) {