Commit e74603bf authored by Adam Gausmann's avatar Adam Gausmann

Merge branch '1.2-release' into 'master'

1.2 release

See merge request !19
parents 708a698d dcc257fe
Pipeline #7639407 passed with stages
in 38 seconds
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>samurai</artifactId> <artifactId>samurai</artifactId>
<groupId>ninja.nonemu</groupId> <groupId>ninja.nonemu</groupId>
<version>1.2-SNAPSHOT</version> <version>1.2</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
......
...@@ -14,6 +14,11 @@ public interface Plugin { ...@@ -14,6 +14,11 @@ public interface Plugin {
*/ */
void init() throws Exception; void init() throws Exception;
/**
* Called periodically by the plugin manager, once for every iteration of the bot's main loop.
*/
void run() throws Exception;
/** /**
* Called when the bot is ready to remove the plugin. A good time to free resources! * Called when the bot is ready to remove the plugin. A good time to free resources!
*/ */
......
package ninja.nonemu.samurai.plugin; package ninja.nonemu.samurai.plugin;
import java.util.Map;
/** /**
* Responsible for loading and managing plugins for the bot. * Responsible for loading and managing plugins for the bot.
*/ */
...@@ -11,7 +13,7 @@ public interface PluginManager { ...@@ -11,7 +13,7 @@ public interface PluginManager {
* @param plugin The plugin to register. * @param plugin The plugin to register.
* @param name The name of the plugin. * @param name The name of the plugin.
*/ */
void registerPlugin(Plugin plugin, String name); void registerPlugin(Plugin plugin, String name) throws Exception;
/** /**
* Registers a plugin extended from the plugin base using its given name. * Registers a plugin extended from the plugin base using its given name.
...@@ -19,7 +21,28 @@ public interface PluginManager { ...@@ -19,7 +21,28 @@ public interface PluginManager {
* <br>Equivalent to {@code registerPlugin(plugin, plugin.getId())}. * <br>Equivalent to {@code registerPlugin(plugin, plugin.getId())}.
* @param plugin The plugin to register. * @param plugin The plugin to register.
*/ */
default void registerPlugin(PluginBase plugin) { default void registerPlugin(PluginBase plugin) throws Exception {
registerPlugin(plugin, plugin.getName()); registerPlugin(plugin, plugin.getName());
} }
/**
* Calls the named plugin's {@link Plugin#cleanup()} method and removes it from the list.
* @param name The name of the plugin; case-insensitive
*/
void unregisterPlugin(String name) throws Exception;
/**
* Retrieves a registered plugin, given its name.
* @param name The name of the plugin; case-insensitive
* @return The plugin with the given name, or {@code null} if no plugin with that name is registered.
*/
Plugin getPlugin(String name);
/**
* Generates a map of all plugins that are registered at the time of this method's execution.
* <br>The key is a case-insensitive string that denotes the plugin's name, and each corresponding value is that
* plugin's instance.
* @return A map containing all registered Plugin instances.
*/
Map<String, Plugin> getPlugins();
} }
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<groupId>ninja.nonemu</groupId> <groupId>ninja.nonemu</groupId>
<artifactId>samurai</artifactId> <artifactId>samurai</artifactId>
<version>1.2-SNAPSHOT</version> <version>1.2</version>
<modules> <modules>
<module>api</module> <module>api</module>
<module>runtime</module> <module>runtime</module>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>samurai</artifactId> <artifactId>samurai</artifactId>
<groupId>ninja.nonemu</groupId> <groupId>ninja.nonemu</groupId>
<version>1.2-SNAPSHOT</version> <version>1.2</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
......
package ninja.nonemu.samurai.command; package ninja.nonemu.samurai.command;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import ninja.nonemu.samurai.BotImpl; import ninja.nonemu.samurai.BotImpl;
import ninja.nonemu.samurai.connection.Connection; import ninja.nonemu.samurai.connection.Connection;
import ninja.nonemu.samurai.connection.User; import ninja.nonemu.samurai.connection.User;
import ninja.nonemu.samurai.connection.UserMask; import ninja.nonemu.samurai.connection.UserMask;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
public class CommandExecutorImpl { public class CommandExecutorImpl {
private final BotImpl bot; private final BotImpl bot;
...@@ -75,6 +77,12 @@ public class CommandExecutorImpl { ...@@ -75,6 +77,12 @@ public class CommandExecutorImpl {
"msg <target> <message>", "msg <target> <message>",
true true
), this::handleMsg); ), this::handleMsg);
commandSystem.registerCommand(new CommandInfo(
"plugins",
"Returns a list of all registered plugins.",
"plugins",
false
), this::handlePlugins);
} }
private boolean handleVersion(CommandSender sender, CommandInfo info, String label, String[] args) { private boolean handleVersion(CommandSender sender, CommandInfo info, String label, String[] args) {
...@@ -263,6 +271,15 @@ public class CommandExecutorImpl { ...@@ -263,6 +271,15 @@ public class CommandExecutorImpl {
return false; return false;
} }
private boolean handlePlugins(CommandSender sender, CommandInfo info, String label, String[] args) {
Set<String> pluginSet = bot.getPluginManager().getPlugins().keySet();
String[] pluginNames = new String[pluginSet.size()];
pluginSet.toArray(pluginNames);
sender.sendChat(String.format("Plugins (%d): %s", pluginNames.length, String.join(",", pluginNames)));
return true;
}
private Connection getConnection(String name) { private Connection getConnection(String name) {
return bot.getConnectionManager().getConnection(name); return bot.getConnectionManager().getConnection(name);
} }
......
package ninja.nonemu.samurai.plugin; package ninja.nonemu.samurai.plugin;
import ninja.nonemu.samurai.BotImpl;
import org.apache.logging.log4j.Logger;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
...@@ -8,8 +11,6 @@ import java.net.URLClassLoader; ...@@ -8,8 +11,6 @@ import java.net.URLClassLoader;
import java.util.Map; import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.jar.JarFile; import java.util.jar.JarFile;
import ninja.nonemu.samurai.BotImpl;
import org.apache.logging.log4j.Logger;
public class PluginManagerImpl implements PluginManager { public class PluginManagerImpl implements PluginManager {
...@@ -34,6 +35,7 @@ public class PluginManagerImpl implements PluginManager { ...@@ -34,6 +35,7 @@ public class PluginManagerImpl implements PluginManager {
if (files != null) { if (files != null) {
for (File file : files) { for (File file : files) {
PluginBase plugin = null;
try { try {
JarFile jarFile = new JarFile(file); JarFile jarFile = new JarFile(file);
String className = jarFile.getManifest().getMainAttributes().getValue("Plugin-Class"); String className = jarFile.getManifest().getMainAttributes().getValue("Plugin-Class");
...@@ -47,8 +49,7 @@ public class PluginManagerImpl implements PluginManager { ...@@ -47,8 +49,7 @@ public class PluginManagerImpl implements PluginManager {
} }
PluginBase.setDefaultBot(bot); PluginBase.setDefaultBot(bot);
PluginBase plugin = (PluginBase) pluginClass.getConstructor().newInstance(); plugin = (PluginBase) pluginClass.getConstructor().newInstance();
registerPlugin(plugin);
} catch (IOException e) { } catch (IOException e) {
logger.error("I/O error while loading plugin. Check to see that your manifest file exists.", e); logger.error("I/O error while loading plugin. Check to see that your manifest file exists.", e);
...@@ -63,10 +64,18 @@ public class PluginManagerImpl implements PluginManager { ...@@ -63,10 +64,18 @@ public class PluginManagerImpl implements PluginManager {
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
logger.error("Cannot load plugin. Make sure the bot can access the plugin class.", e); logger.error("Cannot load plugin. Make sure the bot can access the plugin class.", e);
} }
if (plugin != null) {
try {
registerPlugin(plugin);
} catch (Exception e) {
logger.error("Plugin threw an exception while initializing", e);
}
}
} }
} }
} else if (pluginDir.exists()) { } else if (pluginDir.exists()) {
logger.error("Plugin directory is not a directory. Please move that file and restart the bot."); logger.error("Plugin directory `./plugins' is not a directory. Please move that file and restart the bot.");
System.exit(1); System.exit(1);
} else { } else {
pluginDir.mkdir(); pluginDir.mkdir();
...@@ -74,30 +83,75 @@ public class PluginManagerImpl implements PluginManager { ...@@ -74,30 +83,75 @@ public class PluginManagerImpl implements PluginManager {
} }
public void run() { public void run() {
plugins.values().forEach((plugin) -> {
try {
plugin.run();
} catch (Exception e) {
logger.error("Plugin threw an exception while running", e);
}
});
} }
public void cleanup() { public void cleanup() {
logger.trace("Cleaning up plugin manager"); logger.trace("Cleaning up plugin manager");
plugins.keySet().iterator().forEachRemaining((name) -> {
try {
unregisterPlugin(name);
} catch (Exception e) {
logger.error("Plugin threw an exception while cleaning up", e);
}
});
} }
@Override @Override
public void registerPlugin(Plugin plugin, String name) { public void registerPlugin(Plugin plugin, String name) throws Exception {
logger.info("Registering plugin {}", name);
if (plugins.containsKey(name)) { if (plugins.containsKey(name)) {
throw new IllegalStateException("A plugin is already registered with that name"); logger.warn("A plugin is already registered as {}; aborting", name);
return;
}
if (plugins.containsValue(plugin)) {
logger.warn("That instance of Plugin ({}) is already registered; aborting", plugin);
return;
} }
logger.info("Registering plugin {}", plugin);
plugins.put(name, plugin); plugins.put(name, plugin);
try { try {
plugin.init(); plugin.init();
} catch (Exception e) { } catch (Exception e) {
logger.error("Unable to initialize plugin", e);
plugins.remove(name); plugins.remove(name);
throw e;
} }
} }
@Override
public void unregisterPlugin(String name) throws Exception {
logger.info("Unregistering plugin {}", name);
if (!plugins.containsKey(name)) {
logger.warn("No Plugin is registered as {}; aborting", name);
}
Plugin plugin = plugins.get(name);
try {
plugin.cleanup();
} finally {
plugins.remove(name);
}
}
@Override
public Plugin getPlugin(String name) {
return plugins.get(name);
}
@Override
public Map<String, Plugin> getPlugins() {
Map<String, Plugin> result = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
result.putAll(plugins);
return result;
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment