= Updated plugins to each have their own global context

This commit is contained in:
Matthew Cech
2019-04-20 23:02:43 -07:00
parent 30ed670218
commit 25d8d51b1d
6 changed files with 71 additions and 71 deletions
+1
View File
@@ -1,6 +1,7 @@
-- Example plugin stub. This function is called and passed the input message. -- Example plugin stub. This function is called and passed the input message.
-- If nil is returned, the plugin is considered to have not run, but if any -- If nil is returned, the plugin is considered to have not run, but if any
-- other value is returned, it's interpreted as a string and sent back to the user. -- other value is returned, it's interpreted as a string and sent back to the user.
-- 'local' Variables inside of this file persiste between plugin calls.
function plugin(message) function plugin(message)
return nil; return nil;
end end
+17 -12
View File
@@ -74,35 +74,40 @@ public class CommandManager
} }
// Calls the command but on a whole new thread! // Calls the command but on a whole new thread!
public void InvokeOnNewThread(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response responseContext) public boolean InvokeOnNewThread(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response responseContext)
{ {
// This is here to prevent spinning up a thread if this wasn't even a command. // This is here to prevent spinning up a thread if this wasn't even a command.
if(input == null || !input.IsValid()) if(input == null || !input.IsValid())
return; return false;
// Spin up a thread and begin it. The thread carries the info needed to invoke the command. Command command = commands.get(input.key);
CommandThread newThread = new CommandThread(this, input, guild, channel, user, responseContext); if(command != null)
threadAccumulator.add(newThread); {
newThread.start(); // Spin up a thread and begin it. The thread carries the info needed to invoke the command.
CommandThread newThread = new CommandThread(this, input, guild, channel, user, responseContext);
threadAccumulator.add(newThread);
newThread.start();
return true;
}
else
{
GlobalLog.Warn(LogFilter.Command, "User " + user.name + " tried to invoke command that doesn't exist: " + input.key);
return false;
}
} }
// Calls the command specified with the key, providing user information arguments, etc. // Calls the command specified with the key, providing user information arguments, etc.
public void Invoke(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response responseContext) void Invoke(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response responseContext)
{ {
if(input == null || !input.IsValid()) if(input == null || !input.IsValid())
return; return;
Command command = commands.get(input.key); Command command = commands.get(input.key);
if(command != null) if(command != null)
{ {
++invokeCount; ++invokeCount;
command.Invoke(guild, channel, user, input, responseContext); command.Invoke(guild, channel, user, input, responseContext);
} }
else
{
GlobalLog.Warn(LogFilter.Command, "User " + user.name + " tried to invoke command that doesn't exist: " + input.key);
}
} }
// Looks up command by name. If it exists, dumps help text, otherwise returns null. // Looks up command by name. If it exists, dumps help text, otherwise returns null.
+34 -2
View File
@@ -6,17 +6,25 @@ import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.stream.Stream; import java.util.stream.Stream;
//To promote flexibility, plugins are lua file with predefined callbacks. import org.luaj.vm2.Globals;
//They are executed between the initial built-in preprocessing and the command parsing. import org.luaj.vm2.LuaValue;
import org.luaj.vm2.lib.jse.JsePlatform;
// To promote flexibility, plugins are lua file with predefined callbacks.
// They are executed between the initial built-in preprocessing and the command parsing.
// This class wraps the lua layer - provides all the processing and function calls to the lua binding.
public class Plugin public class Plugin
{ {
public Path filepath; public Path filepath;
public String contents; public String contents;
private Globals globals;
private LuaValue func_plugin;
public Plugin(Path filepath) public Plugin(Path filepath)
{ {
this.filepath = filepath; this.filepath = filepath;
StringBuilder contentBuilder = new StringBuilder(); StringBuilder contentBuilder = new StringBuilder();
try try
@@ -25,10 +33,34 @@ public class Plugin
stream.forEach(str -> contentBuilder.append(str).append("\n")); stream.forEach(str -> contentBuilder.append(str).append("\n"));
stream.close(); stream.close();
contents = contentBuilder.toString(); contents = contentBuilder.toString();
globals = JsePlatform.standardGlobals();
globals.load(contents).call();
func_plugin = globals.get("plugin");
String output = null;
} }
catch (IOException e) catch (IOException e)
{ {
PluginLog.Error(e.getMessage()); PluginLog.Error(e.getMessage());
} }
} }
public String Run(String args)
{
try
{
LuaValue res = func_plugin.call(LuaValue.valueOf(args));
if(!res.isnil())
return res.toString();
}
catch(Exception e)
{
PluginLog.Error("Failed to run plugin from file " + filepath);
}
return null;
}
} }
-42
View File
@@ -1,42 +0,0 @@
package core.lua;
import org.luaj.vm2.Globals;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.lib.jse.JsePlatform;
// This class wraps the lua layer - provides all the processing and function
// calls to the lua binding.
public class PluginLoader
{
private Globals globals;
public PluginLoader()
{
globals = JsePlatform.standardGlobals();
PluginLog.Log("Created new PluginLoader lua environment");
}
public String Process(Plugin toProcess, String args)
{
globals.load(toProcess.contents).call();
LuaValue pluginFunc = globals.get("plugin");
String output = null;
try
{
LuaValue res = pluginFunc.call(LuaValue.valueOf(args));
if(res.isnil())
output = null;
else
output = res.toString();
}
catch(Exception e)
{
output = null;
}
return output;
}
}
+6 -6
View File
@@ -9,7 +9,6 @@ import java.util.stream.Stream;
// Reads in, handles, and manipulates plugins. Plugins are loaded in the order they appear in the folder. // Reads in, handles, and manipulates plugins. Plugins are loaded in the order they appear in the folder.
public class PluginManager public class PluginManager
{ {
public PluginLoader pluginLoader;
public final String pluginFolder; public final String pluginFolder;
public ArrayList<Plugin> plugins; public ArrayList<Plugin> plugins;
@@ -22,7 +21,6 @@ public class PluginManager
{ {
this.pluginFolder = folder; this.pluginFolder = folder;
plugins = new ArrayList<Plugin>(); plugins = new ArrayList<Plugin>();
this.pluginLoader = new PluginLoader();
try try
{ {
@@ -37,16 +35,18 @@ public class PluginManager
} }
} }
public String CallAll(String input) // Runs all plugins, returning when it gets a non-nill result.
// Otherwise, returns null.
public String RunAll(String input)
{ {
for(int i = 0; i < plugins.size(); ++i) for(int i = 0; i < plugins.size(); ++i)
{ {
Plugin script = plugins.get(i); Plugin plugin = plugins.get(i);
String out = pluginLoader.Process(script, input); String out = plugin.Run(input);
if(out != null) if(out != null)
{ {
PluginLog.Log("Executed plugin at " + script.filepath); PluginLog.Log("Executed plugin at " + plugin.filepath);
return out; return out;
} }
} }
+11 -7
View File
@@ -75,14 +75,18 @@ public class Main extends ListenerAdapter
// RP logging system // RP logging system
RPManager.instance.addLine(channel, user, input); RPManager.instance.addLine(channel, user, input);
// Run plugins right before invoking the commands but after all other setup //
String output = pluginManager.CallAll(input.message);
// Spin up the command if no plugins ran. Otherwise, send a response.
if(output == null) // Attempt to spin up a command. If the command doesn't exist.
commandManager.InvokeOnNewThread(guild, channel, user, input, response); // Run plugins right before invoking the commands but after all other setup.
else if(commandManager.InvokeOnNewThread(guild, channel, user, input, response) == false)
response.Call(output); {
String pluginOutput = pluginManager.RunAll(input.message);
if(pluginOutput != null)
response.Call(pluginOutput);
}
// Run any upkeep we need to // Run any upkeep we need to
PerCommandUpkeep(); PerCommandUpkeep();