diff --git a/ChaosBot/Services/ProgrammingLanguageInterpreter/IProgrammingLanguageInterpreter.cs b/ChaosBot/Services/ProgrammingLanguageInterpreter/IProgrammingLanguageInterpreter.cs index ac8f6ff..ec5f6b1 100644 --- a/ChaosBot/Services/ProgrammingLanguageInterpreter/IProgrammingLanguageInterpreter.cs +++ b/ChaosBot/Services/ProgrammingLanguageInterpreter/IProgrammingLanguageInterpreter.cs @@ -3,8 +3,8 @@ using Discord.Commands; 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); } } diff --git a/ChaosBot/Services/ProgrammingLanguageInterpreter/LimitedSocketCommandContext.cs b/ChaosBot/Services/ProgrammingLanguageInterpreter/LimitedSocketCommandContext.cs new file mode 100644 index 0000000..f2c06e7 --- /dev/null +++ b/ChaosBot/Services/ProgrammingLanguageInterpreter/LimitedSocketCommandContext.cs @@ -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 CategoryChannels { get; } + public IReadOnlyCollection Channels { get; } + public DateTimeOffset CreatedAt { get; } + public LimitedSocketTextChannel DefaultChannel { get; } + public int DownloadedMemberCount { get; } + public IReadOnlyCollection 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 Roles { get; } + public string SplashId { get; } + public string SplashUrl { get; } + public LimitedSocketTextChannel SystemChannel { get; } + public IReadOnlyCollection TextChannels { get; } + public IReadOnlyCollection Users { get; } + public VerificationLevel VerificationLevel { get; } + public IReadOnlyCollection 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 MentionedChannels { get; } + public IReadOnlyCollection MentionedRoles { get; } + public IReadOnlyCollection 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 PermissionOverwrites { get; } + public DateTimeOffset CreatedAt { get; } + public ulong Id { get; } + public IReadOnlyCollection 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 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 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 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 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; + } + } +} diff --git a/ChaosBot/Services/ProgrammingLanguageInterpreter/LuaProgrammingLanguageInterpreter.cs b/ChaosBot/Services/ProgrammingLanguageInterpreter/LuaProgrammingLanguageInterpreter.cs index bd55f54..c55422e 100644 --- a/ChaosBot/Services/ProgrammingLanguageInterpreter/LuaProgrammingLanguageInterpreter.cs +++ b/ChaosBot/Services/ProgrammingLanguageInterpreter/LuaProgrammingLanguageInterpreter.cs @@ -1,6 +1,8 @@ +using System; using System.Linq; using System.Reflection; using System.Text; +using System.Text.Json; using System.Threading; using Discord.Commands; using NLua; @@ -13,7 +15,7 @@ namespace ChaosBot.Services.ProgrammingLanguageInterpreter private CancellationToken _ct; 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.Trace($"Using CancellationToken: {ct}"); diff --git a/ChaosBot/Services/ProgrammingLanguageInterpreter/ProgrammingLanguageInterpreterFacade.cs b/ChaosBot/Services/ProgrammingLanguageInterpreter/ProgrammingLanguageInterpreterFacade.cs index 59f85ce..1e1988f 100644 --- a/ChaosBot/Services/ProgrammingLanguageInterpreter/ProgrammingLanguageInterpreterFacade.cs +++ b/ChaosBot/Services/ProgrammingLanguageInterpreter/ProgrammingLanguageInterpreterFacade.cs @@ -22,10 +22,11 @@ namespace ChaosBot.Services.ProgrammingLanguageInterpreter try { CancellationTokenSource tokenSource = new CancellationTokenSource(); + LimitedSocketCommandContext limitedContext = new LimitedSocketCommandContext(context); Task task = Task.Run(() => { 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); const int timeout = 250;