Switch lua library to NLua and implement cancellation
This commit is contained in:
parent
514a835233
commit
29813a599c
@ -16,9 +16,9 @@
|
|||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.6" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="3.1.6" />
|
<PackageReference Include="Microsoft.Extensions.Configuration" Version="3.1.6" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.6" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.6" />
|
||||||
<PackageReference Include="NeoLua" Version="1.3.11" />
|
|
||||||
<PackageReference Include="NLog" Version="4.7.2" />
|
<PackageReference Include="NLog" Version="4.7.2" />
|
||||||
<PackageReference Include="NLog.Extensions.Logging" Version="1.6.4" />
|
<PackageReference Include="NLog.Extensions.Logging" Version="1.6.4" />
|
||||||
|
<PackageReference Include="NLua" Version="1.5.1" />
|
||||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="3.1.2" />
|
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="3.1.2" />
|
||||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql.Design" Version="1.1.2" />
|
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql.Design" Version="1.1.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@ -6,7 +6,6 @@ using ChaosBot.Services;
|
|||||||
using ChaosBot.Services.ProgrammingLanguageInterpreter;
|
using ChaosBot.Services.ProgrammingLanguageInterpreter;
|
||||||
using Discord;
|
using Discord;
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using Neo.IronLua;
|
|
||||||
|
|
||||||
namespace ChaosBot.Discord.Services
|
namespace ChaosBot.Discord.Services
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
|
using System.Threading;
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
|
|
||||||
namespace ChaosBot.Services.ProgrammingLanguageInterpreter
|
namespace ChaosBot.Services.ProgrammingLanguageInterpreter
|
||||||
{
|
{
|
||||||
public interface IProgrammingLanguageInterpreter
|
public interface IProgrammingLanguageInterpreter
|
||||||
{
|
{
|
||||||
string Interpret(SocketCommandContext context, string content, string command);
|
string Interpret(CancellationToken ct, SocketCommandContext context, string content, string command);
|
||||||
void StopExecution();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,48 +1,54 @@
|
|||||||
using System;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Threading;
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using Neo.IronLua;
|
using NLua;
|
||||||
using NLog;
|
|
||||||
|
|
||||||
namespace ChaosBot.Services.ProgrammingLanguageInterpreter
|
namespace ChaosBot.Services.ProgrammingLanguageInterpreter
|
||||||
{
|
{
|
||||||
internal class LuaProgrammingLanguageInterpreter : IProgrammingLanguageInterpreter
|
internal class LuaProgrammingLanguageInterpreter : IProgrammingLanguageInterpreter
|
||||||
{
|
{
|
||||||
private static readonly ILogger Logger = Program.GetLogger();
|
|
||||||
private readonly StringBuilder _outputBuilder = new StringBuilder();
|
private readonly StringBuilder _outputBuilder = new StringBuilder();
|
||||||
private Lua _lua;
|
private CancellationToken _ct;
|
||||||
|
private Lua _state;
|
||||||
public string Interpret(SocketCommandContext context, string content, string command)
|
|
||||||
|
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
|
Lua l = (Lua) sender;
|
||||||
// functions from within the lua environment
|
l.State.Error("Timeout kill");
|
||||||
// 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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StopExecution()
|
// This is being used in the `Interpret` function to register the print function
|
||||||
{
|
// ReSharper disable once UnusedMember.Local
|
||||||
_lua.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
private delegate void ParamsDelegate(params object[] parameters);
|
|
||||||
|
|
||||||
private void Print(params object[] parameters)
|
private void Print(params object[] parameters)
|
||||||
{
|
{
|
||||||
string str = string.Join(" ", from param in parameters select param == null ? string.Empty : param.ToString());
|
string str = string.Join(" ", from param in parameters select param == null ? string.Empty : param.ToString());
|
||||||
|
|||||||
@ -21,21 +21,19 @@ namespace ChaosBot.Services.ProgrammingLanguageInterpreter
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Thread taskThread = null;
|
CancellationTokenSource tokenSource = new CancellationTokenSource();
|
||||||
Task<string> task = Task.Run(() =>
|
Task<string> task = Task.Run(() =>
|
||||||
{
|
{
|
||||||
taskThread = Thread.CurrentThread;
|
|
||||||
Thread.CurrentThread.Priority = ThreadPriority.Lowest;
|
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));
|
bool isTaskCompleted = task.Wait(TimeSpan.FromMilliseconds(timeout));
|
||||||
|
|
||||||
if (!isTaskCompleted)
|
if (!isTaskCompleted)
|
||||||
{
|
{
|
||||||
interpreter.StopExecution();
|
tokenSource.Cancel();
|
||||||
taskThread.Abort();
|
|
||||||
throw new TimeoutException($"Command '{customCommand.Command}' took more than {timeout}ms to run. It has been killed.");
|
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)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
LoggingFacade.Exception(ex);
|
||||||
errorReason = $"There was an error with your code ({ex.GetType().Name}): {ex.Message}";
|
errorReason = $"There was an error with your code ({ex.GetType().Name}): {ex.Message}";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user