diff --git a/ChaosBot/ChaosBot.csproj b/ChaosBot/ChaosBot.csproj
index c1612dd..82c074e 100644
--- a/ChaosBot/ChaosBot.csproj
+++ b/ChaosBot/ChaosBot.csproj
@@ -16,9 +16,9 @@
-
+
diff --git a/ChaosBot/Discord/Services/CustomCommandHandler.cs b/ChaosBot/Discord/Services/CustomCommandHandler.cs
index b1e3bd3..da64597 100644
--- a/ChaosBot/Discord/Services/CustomCommandHandler.cs
+++ b/ChaosBot/Discord/Services/CustomCommandHandler.cs
@@ -6,7 +6,6 @@ using ChaosBot.Services;
using ChaosBot.Services.ProgrammingLanguageInterpreter;
using Discord;
using Discord.Commands;
-using Neo.IronLua;
namespace ChaosBot.Discord.Services
{
diff --git a/ChaosBot/Services/ProgrammingLanguageInterpreter/IProgrammingLanguageInterpreter.cs b/ChaosBot/Services/ProgrammingLanguageInterpreter/IProgrammingLanguageInterpreter.cs
index f43d14c..ac8f6ff 100644
--- a/ChaosBot/Services/ProgrammingLanguageInterpreter/IProgrammingLanguageInterpreter.cs
+++ b/ChaosBot/Services/ProgrammingLanguageInterpreter/IProgrammingLanguageInterpreter.cs
@@ -1,10 +1,10 @@
+using System.Threading;
using Discord.Commands;
namespace ChaosBot.Services.ProgrammingLanguageInterpreter
{
public interface IProgrammingLanguageInterpreter
{
- string Interpret(SocketCommandContext context, string content, string command);
- void StopExecution();
+ string Interpret(CancellationToken ct, SocketCommandContext context, string content, string command);
}
}
diff --git a/ChaosBot/Services/ProgrammingLanguageInterpreter/LuaProgrammingLanguageInterpreter.cs b/ChaosBot/Services/ProgrammingLanguageInterpreter/LuaProgrammingLanguageInterpreter.cs
index c87c056..bfdcb0a 100644
--- a/ChaosBot/Services/ProgrammingLanguageInterpreter/LuaProgrammingLanguageInterpreter.cs
+++ b/ChaosBot/Services/ProgrammingLanguageInterpreter/LuaProgrammingLanguageInterpreter.cs
@@ -1,48 +1,54 @@
-using System;
using System.Linq;
+using System.Reflection;
using System.Text;
-using System.Text.RegularExpressions;
+using System.Threading;
using Discord.Commands;
-using Neo.IronLua;
-using NLog;
+using NLua;
namespace ChaosBot.Services.ProgrammingLanguageInterpreter
{
internal class LuaProgrammingLanguageInterpreter : IProgrammingLanguageInterpreter
{
- private static readonly ILogger Logger = Program.GetLogger();
private readonly StringBuilder _outputBuilder = new StringBuilder();
- private Lua _lua;
-
- public string Interpret(SocketCommandContext context, string content, string command)
+ private CancellationToken _ct;
+ private Lua _state;
+
+ public string Interpret(CancellationToken ct, SocketCommandContext context, string content, string command)
{
- using (_lua = new Lua())
+ LoggingFacade.Debug($"Interpreting code for {command} using Lua");
+ LoggingFacade.Trace($"Using CancellationToken: {ct}");
+ _ct = ct;
+ LoggingFacade.Trace("Starting Lua interpreter");
+ _state = new Lua();
+ LoggingFacade.Trace("Setting Lua debug hook");
+ _state.SetDebugHook(KeraLua.LuaHookMask.Line, 0);
+ _state.DebugHook += LuaDebugHook;
+
+ MethodInfo printMethod = GetType().GetMethod("Print", BindingFlags.NonPublic | BindingFlags.Instance);
+ LoggingFacade.Info($"Overwriting print function with {printMethod}");
+ _state["print"] = printMethod;
+
+ LoggingFacade.Trace("Disabling Lua `import` function");
+ _state.DoString ("\nimport = function () end\n");
+
+ LoggingFacade.Trace("Running user Lua code");
+ _state.DoString(content, command);
+
+ LoggingFacade.Trace("Returning Lua output");
+ return _outputBuilder.ToString();
+ }
+
+ private void LuaDebugHook(object sender, NLua.Event.DebugHookEventArgs e)
+ {
+ if (_ct.IsCancellationRequested)
{
- // This needs to be dynamic if we want to call
- // functions from within the lua environment
- // This is a runtime type check
- dynamic env = _lua.CreateEnvironment();
-
- ParamsDelegate printDel = Print;
- env.print = printDel;
-
- env.context = context;
-
- string code = content;
-
- env.dochunk(code, $"{command}.lua");
-
- return _outputBuilder.ToString();
+ Lua l = (Lua) sender;
+ l.State.Error("Timeout kill");
}
}
- public void StopExecution()
- {
- _lua.Dispose();
- }
-
- private delegate void ParamsDelegate(params object[] parameters);
-
+ // This is being used in the `Interpret` function to register the print function
+ // ReSharper disable once UnusedMember.Local
private void Print(params object[] parameters)
{
string str = string.Join(" ", from param in parameters select param == null ? string.Empty : param.ToString());
diff --git a/ChaosBot/Services/ProgrammingLanguageInterpreter/ProgrammingLanguageInterpreterFacade.cs b/ChaosBot/Services/ProgrammingLanguageInterpreter/ProgrammingLanguageInterpreterFacade.cs
index 94ede93..59f85ce 100644
--- a/ChaosBot/Services/ProgrammingLanguageInterpreter/ProgrammingLanguageInterpreterFacade.cs
+++ b/ChaosBot/Services/ProgrammingLanguageInterpreter/ProgrammingLanguageInterpreterFacade.cs
@@ -21,21 +21,19 @@ namespace ChaosBot.Services.ProgrammingLanguageInterpreter
try
{
- Thread taskThread = null;
+ CancellationTokenSource tokenSource = new CancellationTokenSource();
Task task = Task.Run(() =>
{
- taskThread = Thread.CurrentThread;
Thread.CurrentThread.Priority = ThreadPriority.Lowest;
- return interpreter.Interpret(context, customCommand.Content, customCommand.Command);
- });
+ return interpreter.Interpret(tokenSource.Token, context, customCommand.Content, customCommand.Command);
+ }, tokenSource.Token);
- const int timeout = 1000;
+ const int timeout = 250;
bool isTaskCompleted = task.Wait(TimeSpan.FromMilliseconds(timeout));
if (!isTaskCompleted)
{
- interpreter.StopExecution();
- taskThread.Abort();
+ tokenSource.Cancel();
throw new TimeoutException($"Command '{customCommand.Command}' took more than {timeout}ms to run. It has been killed.");
}
@@ -49,6 +47,7 @@ namespace ChaosBot.Services.ProgrammingLanguageInterpreter
}
catch (Exception ex)
{
+ LoggingFacade.Exception(ex);
errorReason = $"There was an error with your code ({ex.GetType().Name}): {ex.Message}";
return false;
}