using System; 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(); Task task = Task.Run(() => { Thread.CurrentThread.Priority = ThreadPriority.Lowest; return interpreter.Interpret(tokenSource.Token, context, 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 > 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; } } } }