using System; using System.IO; using System.Text; using System.Threading; using System.Threading.Tasks; using ChaosBot.Models; using Discord.Commands; namespace ChaosBot.Services.ProgrammingLanguageInterpreter { public static class ProgrammingLanguageInterpreterFacade { public static bool TryInterpret(SocketCommandContext context, CustomCommand customCommand, out string errorReason) { errorReason = ""; IProgrammingLanguageInterpreter interpreter = ProgrammingLanguageInterpreterFactory.GetInterpreter(customCommand.Type); if (interpreter == null) { errorReason = "Could not set up an interpreter for the code"; return false; } try { CancellationTokenSource tokenSource = new CancellationTokenSource(); LimitedSocketCommandContext limitedContext = new LimitedSocketCommandContext(context); Task task = Task.Run(() => { Thread.CurrentThread.Priority = ThreadPriority.Lowest; return interpreter.Interpret(tokenSource.Token, limitedContext, customCommand.Content, customCommand.Command); }, tokenSource.Token); const int timeout = 250; bool isTaskCompleted = task.Wait(TimeSpan.FromMilliseconds(timeout)); if (!isTaskCompleted) { tokenSource.Cancel(); throw new TimeoutException($"Command '{customCommand.Command}' took more than {timeout}ms to run. It has been killed."); } string output = task.Result; 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); else context.Channel.SendMessageAsync($"Command '{customCommand.Command}' had no output."); return true; } catch (Exception ex) { LoggingFacade.Exception(ex); errorReason = $"There was an error with your code ({ex.GetType().Name}): {ex.Message}"; return false; } } } }