Implement safety features related to custom command LimitedContext #patch
This commit is contained in:
commit
83464d280d
@ -3,8 +3,8 @@ using Discord.Commands;
|
|||||||
|
|
||||||
namespace ChaosBot.Services.ProgrammingLanguageInterpreter
|
namespace ChaosBot.Services.ProgrammingLanguageInterpreter
|
||||||
{
|
{
|
||||||
public interface IProgrammingLanguageInterpreter
|
internal interface IProgrammingLanguageInterpreter
|
||||||
{
|
{
|
||||||
string Interpret(CancellationToken ct, SocketCommandContext context, string content, string command);
|
string Interpret(CancellationToken ct, LimitedSocketCommandContext context, string content, string command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,374 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
|
||||||
|
// Since these need to be accessed, dynamically, from Lua, rider does not know how to handle it.
|
||||||
|
// For the inconsistent naming, I am copying over from discord.net 1-to-1. Blame them.
|
||||||
|
// ReSharper disable UnusedAutoPropertyAccessor.Global
|
||||||
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
// ReSharper disable UnusedMember.Global
|
||||||
|
// ReSharper disable InconsistentNaming
|
||||||
|
|
||||||
|
namespace ChaosBot.Services.ProgrammingLanguageInterpreter
|
||||||
|
{
|
||||||
|
internal class LimitedSocketCommandContext
|
||||||
|
{
|
||||||
|
public LimitedISocketMessageChannel Channel { get; }
|
||||||
|
public LimitedDiscordSocketClient Client { get; }
|
||||||
|
public LimitedSocketGuild Guild { get; }
|
||||||
|
public bool IsPrivate { get; }
|
||||||
|
public LimitedSocketUserMessage Message { get; }
|
||||||
|
public LimitedSocketUser User { get; }
|
||||||
|
|
||||||
|
public LimitedSocketCommandContext(SocketCommandContext context)
|
||||||
|
{
|
||||||
|
Channel = new LimitedISocketMessageChannel(context.Channel);
|
||||||
|
Client = new LimitedDiscordSocketClient(context.Client);
|
||||||
|
Guild = new LimitedSocketGuild(context.Guild);
|
||||||
|
IsPrivate = context.IsPrivate;
|
||||||
|
Message = new LimitedSocketUserMessage(context.Message);
|
||||||
|
User = new LimitedSocketUser(context.User);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class LimitedISocketMessageChannel {
|
||||||
|
public string Name { get; }
|
||||||
|
public ulong Id { get; }
|
||||||
|
public DateTimeOffset CreatedAt { get; }
|
||||||
|
|
||||||
|
public LimitedISocketMessageChannel(ISocketMessageChannel channel)
|
||||||
|
{
|
||||||
|
Name = channel.Name;
|
||||||
|
Id = channel.Id;
|
||||||
|
CreatedAt = channel.CreatedAt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class LimitedDiscordSocketClient
|
||||||
|
{
|
||||||
|
public IActivity Activity { get; }
|
||||||
|
public int Latency { get; }
|
||||||
|
public int ShardId { get; }
|
||||||
|
public UserStatus Status { get; }
|
||||||
|
|
||||||
|
public LimitedDiscordSocketClient(DiscordSocketClient client)
|
||||||
|
{
|
||||||
|
Activity = client.Activity;
|
||||||
|
Latency = client.Latency;
|
||||||
|
ShardId = client.ShardId;
|
||||||
|
Status = client.Status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class LimitedSocketGuild
|
||||||
|
{
|
||||||
|
public ulong Id { get; }
|
||||||
|
public LimitedSocketVoiceChannel AFKChannel { get; }
|
||||||
|
public int AFKTimeout { get; }
|
||||||
|
public ulong? ApplicationId { get; }
|
||||||
|
public IReadOnlyCollection<LimitedSocketCategoryChannel> CategoryChannels { get; }
|
||||||
|
public IReadOnlyCollection<LimitedSocketGuildChannel> Channels { get; }
|
||||||
|
public DateTimeOffset CreatedAt { get; }
|
||||||
|
public LimitedSocketTextChannel DefaultChannel { get; }
|
||||||
|
public int DownloadedMemberCount { get; }
|
||||||
|
public IReadOnlyCollection<LimitedGuildEmote> Emotes { get; }
|
||||||
|
public LimitedSocketRole EveryoneRole { get; }
|
||||||
|
public ExplicitContentFilterLevel ExplicitContentFilter { get; }
|
||||||
|
public bool HasAllMembers { get; }
|
||||||
|
public string IconId { get; }
|
||||||
|
public string IconUrl { get; }
|
||||||
|
public bool IsConnected { get; }
|
||||||
|
public bool IsEmbeddable { get; }
|
||||||
|
public bool IsSynced { get; }
|
||||||
|
public int MemberCount { get; }
|
||||||
|
public MfaLevel MfaLevel { get; }
|
||||||
|
public string Name { get; }
|
||||||
|
public LimitedSocketGuildUser Owner { get; }
|
||||||
|
public ulong OwnerId { get; }
|
||||||
|
public IReadOnlyCollection<LimitedSocketRole> Roles { get; }
|
||||||
|
public string SplashId { get; }
|
||||||
|
public string SplashUrl { get; }
|
||||||
|
public LimitedSocketTextChannel SystemChannel { get; }
|
||||||
|
public IReadOnlyCollection<LimitedSocketTextChannel> TextChannels { get; }
|
||||||
|
public IReadOnlyCollection<LimitedSocketGuildUser> Users { get; }
|
||||||
|
public VerificationLevel VerificationLevel { get; }
|
||||||
|
public IReadOnlyCollection<LimitedSocketVoiceChannel> VoiceChannels { get; }
|
||||||
|
public string VoiceRegionId { get; }
|
||||||
|
|
||||||
|
public LimitedSocketGuild(SocketGuild guild)
|
||||||
|
{
|
||||||
|
Id = guild.Id;
|
||||||
|
AFKChannel = guild.AFKChannel == null ? null : new LimitedSocketVoiceChannel(guild.AFKChannel);
|
||||||
|
AFKTimeout = guild.AFKTimeout;
|
||||||
|
ApplicationId = guild.ApplicationId;
|
||||||
|
CategoryChannels = guild.CategoryChannels.Select(cc => new LimitedSocketCategoryChannel(cc)).ToList();
|
||||||
|
Channels = guild.Channels.Select(c => new LimitedSocketGuildChannel(c)).ToList();
|
||||||
|
CreatedAt = guild.CreatedAt;
|
||||||
|
DefaultChannel = new LimitedSocketTextChannel(guild.DefaultChannel);
|
||||||
|
DownloadedMemberCount = guild.DownloadedMemberCount;
|
||||||
|
Emotes = guild.Emotes.Select(e => new LimitedGuildEmote(e)).ToList();
|
||||||
|
EveryoneRole = new LimitedSocketRole(guild.EveryoneRole);
|
||||||
|
ExplicitContentFilter = guild.ExplicitContentFilter;
|
||||||
|
HasAllMembers = guild.HasAllMembers;
|
||||||
|
IconId = guild.IconId;
|
||||||
|
IconUrl = guild.IconUrl;
|
||||||
|
IsConnected = guild.IsConnected;
|
||||||
|
IsEmbeddable = guild.IsEmbeddable;
|
||||||
|
IsSynced = guild.IsSynced;
|
||||||
|
MemberCount = guild.MemberCount;
|
||||||
|
MfaLevel = guild.MfaLevel;
|
||||||
|
Name = guild.Name;
|
||||||
|
Owner = new LimitedSocketGuildUser(guild.Owner);
|
||||||
|
OwnerId = guild.OwnerId;
|
||||||
|
Roles = guild.Roles.Select(r => new LimitedSocketRole(r)).ToList();
|
||||||
|
SplashId = guild.SplashId;
|
||||||
|
SplashUrl = guild.SplashUrl;
|
||||||
|
SystemChannel = guild.SystemChannel == null ? null : new LimitedSocketTextChannel(guild.SystemChannel);
|
||||||
|
TextChannels = guild.TextChannels.Select(tc => new LimitedSocketTextChannel(tc)).ToList();
|
||||||
|
Users = guild.Users.Select(u => new LimitedSocketGuildUser(u)).ToList();
|
||||||
|
VerificationLevel = guild.VerificationLevel;
|
||||||
|
VoiceChannels = guild.VoiceChannels.Select(vc => new LimitedSocketVoiceChannel(vc)).ToList();
|
||||||
|
VoiceRegionId = guild.VoiceRegionId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class LimitedSocketUserMessage
|
||||||
|
{
|
||||||
|
public LimitedSocketUser Author { get; }
|
||||||
|
public MessageSource Source { get; }
|
||||||
|
public string Content { get; }
|
||||||
|
public DateTimeOffset CreatedAt { get; }
|
||||||
|
public DateTimeOffset Timestamp { get; }
|
||||||
|
public DateTimeOffset? EditedTimestamp { get; }
|
||||||
|
public ulong Id { get; }
|
||||||
|
public bool IsPinned { get; }
|
||||||
|
public bool IsTTS { get; }
|
||||||
|
public IReadOnlyCollection<LimitedSocketGuildChannel> MentionedChannels { get; }
|
||||||
|
public IReadOnlyCollection<LimitedSocketRole> MentionedRoles { get; }
|
||||||
|
public IReadOnlyCollection<LimitedSocketUser> MentionedUsers { get; }
|
||||||
|
public LimitedSocketUserMessage(SocketUserMessage message)
|
||||||
|
{
|
||||||
|
Author = new LimitedSocketUser(message.Author);
|
||||||
|
Source = message.Source;
|
||||||
|
Content = message.Content;
|
||||||
|
CreatedAt = message.CreatedAt;
|
||||||
|
Timestamp = message.Timestamp;
|
||||||
|
EditedTimestamp = message.EditedTimestamp;
|
||||||
|
Id = message.Id;
|
||||||
|
IsPinned = message.IsPinned;
|
||||||
|
IsTTS = message.IsTTS;
|
||||||
|
MentionedChannels = message.MentionedChannels.Select(mc => new LimitedSocketGuildChannel(mc)).ToList();
|
||||||
|
MentionedRoles = message.MentionedRoles.Select(mr => new LimitedSocketRole(mr)).ToList();
|
||||||
|
MentionedUsers = message.MentionedUsers.Select(mu => new LimitedSocketUser(mu)).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class LimitedSocketUser
|
||||||
|
{
|
||||||
|
private readonly SocketUser originalUser;
|
||||||
|
|
||||||
|
public ulong Id { get; }
|
||||||
|
public IActivity Activity { get; }
|
||||||
|
public string AvatarId { get; }
|
||||||
|
public DateTimeOffset CreatedAt { get; }
|
||||||
|
public string Discriminator { get; }
|
||||||
|
public ushort DiscriminatorValue { get; }
|
||||||
|
public bool IsBot { get; }
|
||||||
|
public bool IsWebhook { get; }
|
||||||
|
public string Mention { get; }
|
||||||
|
public UserStatus Status { get; }
|
||||||
|
public string Username { get; }
|
||||||
|
public string GetAvatarUrl => originalUser.GetAvatarUrl();
|
||||||
|
|
||||||
|
public LimitedSocketUser(SocketUser user)
|
||||||
|
{
|
||||||
|
originalUser = user;
|
||||||
|
|
||||||
|
Id = user.Id;
|
||||||
|
Activity = user.Activity;
|
||||||
|
AvatarId = user.AvatarId;
|
||||||
|
CreatedAt = user.CreatedAt;
|
||||||
|
Discriminator = user.Discriminator;
|
||||||
|
DiscriminatorValue = user.DiscriminatorValue;
|
||||||
|
IsBot = user.IsBot;
|
||||||
|
IsWebhook = user.IsWebhook;
|
||||||
|
Mention = user.Mention;
|
||||||
|
Status = user.Status;
|
||||||
|
Username = user.Username;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class LimitedSocketGuildChannel
|
||||||
|
{
|
||||||
|
public string Name { get; }
|
||||||
|
public int Position { get; }
|
||||||
|
public IReadOnlyCollection<Overwrite> PermissionOverwrites { get; }
|
||||||
|
public DateTimeOffset CreatedAt { get; }
|
||||||
|
public ulong Id { get; }
|
||||||
|
public IReadOnlyCollection<LimitedSocketGuildUser> Users { get; }
|
||||||
|
public LimitedSocketGuildChannel(SocketGuildChannel channel)
|
||||||
|
{
|
||||||
|
Name = channel.Name;
|
||||||
|
Position = channel.Position;
|
||||||
|
PermissionOverwrites = channel.PermissionOverwrites;
|
||||||
|
CreatedAt = channel.CreatedAt;
|
||||||
|
Id = channel.Id;
|
||||||
|
Users = channel.Users.Select(u => new LimitedSocketGuildUser(u)).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class LimitedSocketCategoryChannel: LimitedSocketGuildChannel
|
||||||
|
{
|
||||||
|
|
||||||
|
public IReadOnlyCollection<LimitedSocketGuildChannel> Channels { get; }
|
||||||
|
|
||||||
|
public LimitedSocketCategoryChannel(SocketCategoryChannel category) : base(category)
|
||||||
|
{
|
||||||
|
Channels = category.Channels.Select(c => new LimitedSocketGuildChannel(c)).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class LimitedSocketVoiceChannel : LimitedSocketGuildChannel
|
||||||
|
{
|
||||||
|
public int Bitrate { get; }
|
||||||
|
public LimitedICategoryChannel Category { get; }
|
||||||
|
public ulong? CategoryId { get; }
|
||||||
|
public int? UserLimit { get; }
|
||||||
|
|
||||||
|
public LimitedSocketVoiceChannel(SocketVoiceChannel channel) : base(channel)
|
||||||
|
{
|
||||||
|
Bitrate = channel.Bitrate;
|
||||||
|
Category = new LimitedICategoryChannel(channel.Category);
|
||||||
|
CategoryId = channel.CategoryId;
|
||||||
|
UserLimit = channel.UserLimit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class LimitedSocketTextChannel : LimitedSocketGuildChannel
|
||||||
|
{
|
||||||
|
public LimitedICategoryChannel Category { get; }
|
||||||
|
public ulong? CategoryId { get; }
|
||||||
|
public bool IsNsfw { get; }
|
||||||
|
public string Mention { get; }
|
||||||
|
public int SlowModeInterval { get; }
|
||||||
|
public string Topic { get; }
|
||||||
|
|
||||||
|
public LimitedSocketTextChannel(SocketTextChannel channel) : base(channel)
|
||||||
|
{
|
||||||
|
Category = new LimitedICategoryChannel(channel.Category);
|
||||||
|
CategoryId = channel.CategoryId;
|
||||||
|
IsNsfw = channel.IsNsfw;
|
||||||
|
Mention = channel.Mention;
|
||||||
|
SlowModeInterval = channel.SlowModeInterval;
|
||||||
|
Topic = channel.Topic;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal class LimitedSocketGuildUser : LimitedSocketUser
|
||||||
|
{
|
||||||
|
public GuildPermissions GuildPermissions { get; }
|
||||||
|
public int Hierarchy { get; }
|
||||||
|
public bool IsDeafened { get; }
|
||||||
|
public bool IsMuted { get; }
|
||||||
|
public bool IsSelfDeafened { get; }
|
||||||
|
public bool IsSelfMuted { get; }
|
||||||
|
public bool IsSuppressed { get; }
|
||||||
|
public DateTimeOffset? JoinedAt { get; }
|
||||||
|
public string Nickname { get; }
|
||||||
|
public IReadOnlyCollection<LimitedSocketRole> Roles { get; }
|
||||||
|
public LimitedSocketVoiceChannel VoiceChannel { get; }
|
||||||
|
public string VoiceSessionId { get; }
|
||||||
|
public SocketVoiceState? VoiceState { get; }
|
||||||
|
|
||||||
|
public LimitedSocketGuildUser(SocketGuildUser user) : base(user)
|
||||||
|
{
|
||||||
|
GuildPermissions = user.GuildPermissions;
|
||||||
|
Hierarchy = user.Hierarchy;
|
||||||
|
IsDeafened = user.IsDeafened;
|
||||||
|
IsMuted = user.IsMuted;
|
||||||
|
IsSelfDeafened = user.IsSelfDeafened;
|
||||||
|
IsSelfMuted = user.IsSelfMuted;
|
||||||
|
IsSuppressed = user.IsSuppressed;
|
||||||
|
JoinedAt = user.JoinedAt;
|
||||||
|
Nickname = user.Nickname;
|
||||||
|
Roles = user.Roles.Select(r => new LimitedSocketRole(r)).ToList();
|
||||||
|
VoiceChannel = user.VoiceChannel == null ? null : new LimitedSocketVoiceChannel(user.VoiceChannel);
|
||||||
|
VoiceSessionId = user.VoiceSessionId;
|
||||||
|
VoiceState = user.VoiceState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal class LimitedSocketRole
|
||||||
|
{
|
||||||
|
public ulong Id { get; }
|
||||||
|
public Color Color { get; }
|
||||||
|
public DateTimeOffset CreatedAt { get; }
|
||||||
|
public bool IsEveryone { get; }
|
||||||
|
public bool IsHoisted { get; }
|
||||||
|
public bool IsManaged { get; }
|
||||||
|
public bool IsMentionable { get; }
|
||||||
|
public string Mention { get; }
|
||||||
|
public string Name { get; }
|
||||||
|
public GuildPermissions Permissions { get; }
|
||||||
|
public int Position { get; }
|
||||||
|
public LimitedSocketRole(SocketRole role)
|
||||||
|
{
|
||||||
|
Id = role.Id;
|
||||||
|
Color = role.Color;
|
||||||
|
CreatedAt = role.CreatedAt;
|
||||||
|
IsEveryone = role.IsEveryone;
|
||||||
|
IsHoisted = role.IsHoisted;
|
||||||
|
IsManaged = role.IsManaged;
|
||||||
|
IsMentionable = role.IsMentionable;
|
||||||
|
Mention = role.Mention;
|
||||||
|
Name = role.Name;
|
||||||
|
Permissions = role.Permissions;
|
||||||
|
Position = role.Position;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal class LimitedGuildEmote
|
||||||
|
{
|
||||||
|
public string Name { get; }
|
||||||
|
public ulong Id { get; }
|
||||||
|
public bool Animated { get; }
|
||||||
|
public DateTimeOffset CreatedAt { get; }
|
||||||
|
public string Url { get; }
|
||||||
|
public ulong? CreatorId { get; }
|
||||||
|
public bool IsManaged { get; }
|
||||||
|
public bool RequireColons { get; }
|
||||||
|
public IReadOnlyList<ulong> RoleIds { get; }
|
||||||
|
|
||||||
|
public LimitedGuildEmote(GuildEmote emote)
|
||||||
|
{
|
||||||
|
Name = emote.Name;
|
||||||
|
Id = emote.Id;
|
||||||
|
Animated = emote.Animated;
|
||||||
|
CreatedAt = emote.CreatedAt;
|
||||||
|
Url = emote.Url;
|
||||||
|
CreatorId = emote.CreatorId;
|
||||||
|
IsManaged = emote.IsManaged;
|
||||||
|
RequireColons = emote.RequireColons;
|
||||||
|
RoleIds = emote.RoleIds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class LimitedICategoryChannel
|
||||||
|
{
|
||||||
|
public int Position { get; }
|
||||||
|
public ulong GuildId { get; }
|
||||||
|
public IReadOnlyCollection<Overwrite> PermissionOverwrites { get; }
|
||||||
|
public string Name { get; }
|
||||||
|
public DateTimeOffset CreatedAt { get; }
|
||||||
|
public ulong Id { get; }
|
||||||
|
public LimitedICategoryChannel(ICategoryChannel category)
|
||||||
|
{
|
||||||
|
Position = category.Position;
|
||||||
|
GuildId = category.GuildId;
|
||||||
|
PermissionOverwrites = category.PermissionOverwrites;
|
||||||
|
Name = category.Name;
|
||||||
|
CreatedAt = category.CreatedAt;
|
||||||
|
Id = category.Id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,8 @@
|
|||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using NLua;
|
using NLua;
|
||||||
@ -13,7 +15,7 @@ namespace ChaosBot.Services.ProgrammingLanguageInterpreter
|
|||||||
private CancellationToken _ct;
|
private CancellationToken _ct;
|
||||||
private Lua _state;
|
private Lua _state;
|
||||||
|
|
||||||
public string Interpret(CancellationToken ct, SocketCommandContext context, string content, string command)
|
public string Interpret(CancellationToken ct, LimitedSocketCommandContext context, string content, string command)
|
||||||
{
|
{
|
||||||
LoggingFacade.Debug($"Interpreting code for {command} using Lua");
|
LoggingFacade.Debug($"Interpreting code for {command} using Lua");
|
||||||
LoggingFacade.Trace($"Using CancellationToken: {ct}");
|
LoggingFacade.Trace($"Using CancellationToken: {ct}");
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using ChaosBot.Models;
|
using ChaosBot.Models;
|
||||||
@ -22,10 +24,11 @@ namespace ChaosBot.Services.ProgrammingLanguageInterpreter
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
CancellationTokenSource tokenSource = new CancellationTokenSource();
|
CancellationTokenSource tokenSource = new CancellationTokenSource();
|
||||||
|
LimitedSocketCommandContext limitedContext = new LimitedSocketCommandContext(context);
|
||||||
Task<string> task = Task.Run(() =>
|
Task<string> task = Task.Run(() =>
|
||||||
{
|
{
|
||||||
Thread.CurrentThread.Priority = ThreadPriority.Lowest;
|
Thread.CurrentThread.Priority = ThreadPriority.Lowest;
|
||||||
return interpreter.Interpret(tokenSource.Token, context, customCommand.Content, customCommand.Command);
|
return interpreter.Interpret(tokenSource.Token, limitedContext, customCommand.Content, customCommand.Command);
|
||||||
}, tokenSource.Token);
|
}, tokenSource.Token);
|
||||||
|
|
||||||
const int timeout = 250;
|
const int timeout = 250;
|
||||||
@ -38,8 +41,17 @@ namespace ChaosBot.Services.ProgrammingLanguageInterpreter
|
|||||||
}
|
}
|
||||||
|
|
||||||
string output = task.Result;
|
string output = task.Result;
|
||||||
|
|
||||||
if (output.Length > 0)
|
if (output.Length > 2000)
|
||||||
|
{
|
||||||
|
context.Channel.SendMessageAsync($"Command '{customCommand.Command}' has {output.Length} characters of output. That is more than the 2000 limit. Packaging into file...").GetAwaiter().GetResult();
|
||||||
|
Stream stream = new MemoryStream(Encoding.ASCII.GetBytes(output));
|
||||||
|
if (stream.Length > 8 * 1024 * 1024)
|
||||||
|
context.Channel.SendMessageAsync($"Packaged filesize of {stream.Length / 1024 / 1024} MB is too big.");
|
||||||
|
else
|
||||||
|
context.Channel.SendFileAsync(stream, "command-output.txt");
|
||||||
|
}
|
||||||
|
else if (output.Length > 0)
|
||||||
context.Channel.SendMessageAsync(output);
|
context.Channel.SendMessageAsync(output);
|
||||||
else
|
else
|
||||||
context.Channel.SendMessageAsync($"Command '{customCommand.Command}' had no output.");
|
context.Channel.SendMessageAsync($"Command '{customCommand.Command}' had no output.");
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user