diff --git a/pom.xml b/pom.xml
index aa30787..b9362cc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -82,7 +82,14 @@
redis.clients
jedis
- 2.4.2
+ 2.6.0
+ compile
+
+
+ org.projectlombok
+ lombok
+ 1.14.8
+ provided
\ No newline at end of file
diff --git a/src/main/java/me/vemacs/executeeverywhere/bukkit/EECommand.java b/src/main/java/me/vemacs/executeeverywhere/bukkit/EECommand.java
new file mode 100644
index 0000000..25af165
--- /dev/null
+++ b/src/main/java/me/vemacs/executeeverywhere/bukkit/EECommand.java
@@ -0,0 +1,63 @@
+package me.vemacs.executeeverywhere.bukkit;
+
+import com.google.common.base.Joiner;
+import lombok.RequiredArgsConstructor;
+import org.bukkit.ChatColor;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import redis.clients.jedis.Jedis;
+import redis.clients.jedis.exceptions.JedisConnectionException;
+
+import java.util.Arrays;
+
+@RequiredArgsConstructor
+public class EECommand implements CommandExecutor {
+ private final ExecuteEverywhere plugin;
+
+ @Override
+ public boolean onCommand(final CommandSender commandSender, Command command, String s, String[] args) {
+ if (args.length < 1 || (command.getName().equalsIgnoreCase("eeg") && args.length < 2)) {
+ commandSender.sendMessage(ChatColor.RED + "Invalid usage.");
+ if (command.getName().equalsIgnoreCase("eec")) {
+ commandSender.sendMessage(ChatColor.RED + "/" + s + " ");
+ } else {
+ commandSender.sendMessage(ChatColor.RED + "/" + s + " ");
+ }
+ return true;
+ }
+
+ final String channel;
+ final String run;
+
+ if (command.getName().equals("eeg")) {
+ channel = "ee-" + args[0];
+ run = Joiner.on(' ').join(Arrays.copyOfRange(args, 1, args.length));
+ } else if (command.getName().equals("ee")) {
+ channel = "ee";
+ run = Joiner.on(' ').join(args);
+ commandSender.sendMessage(ChatColor.GRAY + "(Assuming you want to run this command over all Bukkit servers.)");
+ } else if (command.getName().equals("eb")) {
+ channel = "eb";
+ run = Joiner.on(' ').join(args);
+ commandSender.sendMessage(ChatColor.GRAY + "(Assuming you want to run this command over all BungeeCord servers.)");
+ } else {
+ // Shouldn't happen
+ return false;
+ }
+
+ plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable() {
+ @Override
+ public void run() {
+ try (Jedis jedis = plugin.getPool().getResource()) {
+ jedis.publish(channel, run);
+ commandSender.sendMessage(ChatColor.GREEN + "Command successfully queued for execution.");
+ } catch (JedisConnectionException e) {
+ commandSender.sendMessage(ChatColor.RED + "Could not send the command! Please try again.");
+ }
+ }
+ });
+
+ return true;
+ }
+}
diff --git a/src/main/java/me/vemacs/executeeverywhere/bukkit/ExecuteEverywhere.java b/src/main/java/me/vemacs/executeeverywhere/bukkit/ExecuteEverywhere.java
index 5a2578c..a964e3a 100644
--- a/src/main/java/me/vemacs/executeeverywhere/bukkit/ExecuteEverywhere.java
+++ b/src/main/java/me/vemacs/executeeverywhere/bukkit/ExecuteEverywhere.java
@@ -1,55 +1,41 @@
package me.vemacs.executeeverywhere.bukkit;
-import com.google.common.base.Joiner;
-import org.bukkit.ChatColor;
-import org.bukkit.command.Command;
-import org.bukkit.command.CommandSender;
+import lombok.Getter;
+import me.vemacs.executeeverywhere.common.AbstractJedisPubSub;
+import me.vemacs.executeeverywhere.common.EEConfiguration;
import org.bukkit.event.Listener;
-import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;
-import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
-import redis.clients.jedis.JedisPoolConfig;
-import redis.clients.jedis.JedisPubSub;
import java.lang.Override;
+import java.util.List;
public class ExecuteEverywhere extends JavaPlugin implements Listener {
+ @Getter
private JedisPool pool;
- private static final Joiner joiner = Joiner.on(" ");
- private final String CHANNEL = "ee";
- private final String BUNGEE_CHANNEL = "eb";
- private static Plugin instance;
+ @Getter
+ private EEConfiguration configuration;
private EESubscriber eeSubscriber;
@Override
public void onEnable() {
- instance = this;
saveDefaultConfig();
+
String ip = getConfig().getString("ip");
int port = getConfig().getInt("port");
String password = getConfig().getString("password");
- if (password == null || password.equals(""))
- pool = new JedisPool(new JedisPoolConfig(), ip, port, 0);
- else
- pool = new JedisPool(new JedisPoolConfig(), ip, port, 0, password);
- new BukkitRunnable() {
- @Override
- public void run() {
- eeSubscriber = new EESubscriber();
- Jedis jedis = pool.getResource();
- try {
- jedis.subscribe(eeSubscriber, CHANNEL);
- } catch (Exception e) {
- e.printStackTrace();
- pool.returnBrokenResource(jedis);
- getLogger().severe("Unable to connect to Redis server.");
- return;
- }
- pool.returnResource(jedis);
- }
- }.runTaskAsynchronously(this);
+ List serverGroups = getConfig().getStringList("groups");
+ configuration = new EEConfiguration(serverGroups, ip, port, password);
+
+ pool = configuration.getJedisPool();
+
+ getServer().getScheduler().runTaskAsynchronously(this, eeSubscriber = new EESubscriber());
+
+ EECommand command = new EECommand(this);
+ getCommand("ee").setExecutor(command);
+ getCommand("eb").setExecutor(command);
+ getCommand("eeg").setExecutor(command);
}
@Override
@@ -58,66 +44,21 @@ public void onDisable() {
pool.destroy();
}
- @Override
- public boolean onCommand(CommandSender sender, final Command cmd, String label, String[] args) {
- if (args.length == 0) return false;
- String cmdString = joiner.join(args);
- if (cmdString.startsWith("/"))
- cmdString = cmdString.substring(1);
- final String finalCmdString = cmdString;
- new BukkitRunnable() {
- @Override
- public void run() {
- Jedis jedis = pool.getResource();
- try {
- switch (cmd.getName().toLowerCase()) {
- case "eb":
- jedis.publish(BUNGEE_CHANNEL, finalCmdString);
- break;
- default:
- jedis.publish(CHANNEL, finalCmdString);
- }
- } catch (Exception e) {
- pool.returnBrokenResource(jedis);
- }
- pool.returnResource(jedis);
- }
- }.runTaskAsynchronously(this);
- sender.sendMessage(ChatColor.GREEN + "Sent /" + cmdString + " for execution.");
- return true;
- }
+ public class EESubscriber extends AbstractJedisPubSub {
+ public EESubscriber() {
+ super(pool, configuration);
+ }
- public class EESubscriber extends JedisPubSub {
@Override
public void onMessage(String channel, final String msg) {
// Needs to be done in the server thread
new BukkitRunnable() {
@Override
public void run() {
- ExecuteEverywhere.instance.getLogger().info("Dispatching /" + msg);
+ getLogger().info("Dispatching /" + msg);
getServer().dispatchCommand(getServer().getConsoleSender(), msg);
}
- }.runTaskAsynchronously(ExecuteEverywhere.instance);
- }
-
- @Override
- public void onPMessage(String s, String s2, String s3) {
- }
-
- @Override
- public void onSubscribe(String s, int i) {
- }
-
- @Override
- public void onUnsubscribe(String s, int i) {
- }
-
- @Override
- public void onPUnsubscribe(String s, int i) {
- }
-
- @Override
- public void onPSubscribe(String s, int i) {
+ }.runTaskAsynchronously(ExecuteEverywhere.this);
}
}
}
diff --git a/src/main/java/me/vemacs/executeeverywhere/bungee/EECommand.java b/src/main/java/me/vemacs/executeeverywhere/bungee/EECommand.java
new file mode 100644
index 0000000..23224cc
--- /dev/null
+++ b/src/main/java/me/vemacs/executeeverywhere/bungee/EECommand.java
@@ -0,0 +1,69 @@
+package me.vemacs.executeeverywhere.bungee;
+
+import com.google.common.base.Joiner;
+import net.md_5.bungee.api.ChatColor;
+import net.md_5.bungee.api.CommandSender;
+import net.md_5.bungee.api.plugin.Command;
+import redis.clients.jedis.Jedis;
+import redis.clients.jedis.exceptions.JedisConnectionException;
+
+import java.util.Arrays;
+
+public class EECommand extends Command {
+ private final ExecuteEverywhere plugin;
+ private final EECommandKind kind;
+
+ public EECommand(ExecuteEverywhere plugin, String name, EECommandKind kind) {
+ super(name, "executeeverywhere.use");
+ this.kind = kind;
+ this.plugin = plugin;
+ }
+
+ @Override
+ public void execute(final CommandSender commandSender, String[] args) {
+ if (args.length < 1 || (kind == EECommandKind.GROUP && args.length < 2)) {
+ commandSender.sendMessage(ChatColor.RED + "Invalid usage.");
+ if (kind == EECommandKind.GROUP) {
+ commandSender.sendMessage(ChatColor.RED + "/" + getName() + " ");
+ } else {
+ commandSender.sendMessage(ChatColor.RED + "/" + getName() + " ");
+ }
+ return;
+ }
+
+ String group = args[0];
+ final String channel;
+ final String run;
+
+ switch (kind) {
+ case BUNGEECORD:
+ channel = "eb";
+ run = Joiner.on(' ').join(args);
+ commandSender.sendMessage(ChatColor.GRAY + "(Assuming you want to run this command over all BungeeCord servers.)");
+ break;
+ case BUKKIT:
+ channel = "ee";
+ run = Joiner.on(' ').join(args);
+ commandSender.sendMessage(ChatColor.GRAY + "(Assuming you want to run this command over all Bukkit servers.)");
+ break;
+ case GROUP:
+ channel = "ee-" + group;
+ run = Joiner.on(' ').join(Arrays.copyOfRange(args, 1, args.length));
+ break;
+ default:
+ return;
+ }
+
+ plugin.getProxy().getScheduler().runAsync(plugin, new Runnable() {
+ @Override
+ public void run() {
+ try (Jedis jedis = plugin.getPool().getResource()) {
+ jedis.publish(channel, run);
+ commandSender.sendMessage(ChatColor.GREEN + "Command successfully queued for execution.");
+ } catch (JedisConnectionException e) {
+ commandSender.sendMessage(ChatColor.RED + "Could not send the command! Please try again.");
+ }
+ }
+ });
+ }
+}
diff --git a/src/main/java/me/vemacs/executeeverywhere/bungee/EECommandKind.java b/src/main/java/me/vemacs/executeeverywhere/bungee/EECommandKind.java
new file mode 100644
index 0000000..5765f04
--- /dev/null
+++ b/src/main/java/me/vemacs/executeeverywhere/bungee/EECommandKind.java
@@ -0,0 +1,7 @@
+package me.vemacs.executeeverywhere.bungee;
+
+public enum EECommandKind {
+ BUNGEECORD,
+ BUKKIT,
+ GROUP
+}
diff --git a/src/main/java/me/vemacs/executeeverywhere/bungee/ExecuteEverywhere.java b/src/main/java/me/vemacs/executeeverywhere/bungee/ExecuteEverywhere.java
index 82f1d46..8a62a0a 100644
--- a/src/main/java/me/vemacs/executeeverywhere/bungee/ExecuteEverywhere.java
+++ b/src/main/java/me/vemacs/executeeverywhere/bungee/ExecuteEverywhere.java
@@ -1,6 +1,9 @@
package me.vemacs.executeeverywhere.bungee;
import com.google.common.io.ByteStreams;
+import lombok.Getter;
+import me.vemacs.executeeverywhere.common.AbstractJedisPubSub;
+import me.vemacs.executeeverywhere.common.EEConfiguration;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.api.plugin.Plugin;
@@ -13,45 +16,42 @@
import redis.clients.jedis.JedisPubSub;
import java.io.*;
+import java.util.List;
-public class ExecuteEverywhere extends Plugin implements Listener {
+public class ExecuteEverywhere extends Plugin {
+ @Getter
private JedisPool pool;
- private final String BUNGEE_CHANNEL = "eb";
- private static Plugin instance;
-
- Configuration config;
- EESubscriber eeSubscriber;
+ @Getter
+ private EEConfiguration configuration;
+ private EESubscriber eeSubscriber;
@Override
public void onEnable() {
- instance = this;
+ final Configuration config;
try {
config = ConfigurationProvider.getProvider(YamlConfiguration.class).load(
loadResource(this, "config.yml"));
} catch (IOException e) {
- e.printStackTrace();
+ throw new RuntimeException("Unable to read config.yml", e);
}
- final String ip = config.getString("ip");
- final int port = config.getInt("port");
- final String password = config.getString("password");
+
+ String ip = config.getString("ip");
+ int port = config.getInt("port");
+ String password = config.getString("password");
+ List serverGroups = config.getStringList("groups");
+ configuration = new EEConfiguration(serverGroups, ip, port, password);
+
getProxy().getScheduler().runAsync(this, new Runnable() {
@Override
public void run() {
- if (password == null || password.equals(""))
- pool = new JedisPool(new JedisPoolConfig(), ip, port, 0);
- else
- pool = new JedisPool(new JedisPoolConfig(), ip, port, 0, password);
- Jedis jedis = pool.getResource();
- try {
- jedis.subscribe(new EESubscriber(), BUNGEE_CHANNEL);
- } catch (Exception e) {
- e.printStackTrace();
- pool.returnBrokenResource(jedis);
- getLogger().severe("Unable to connect to Redis server.");
- return;
- }
- pool.returnResource(jedis); }
+ pool = configuration.getJedisPool();
+ getProxy().getScheduler().runAsync(ExecuteEverywhere.this, eeSubscriber = new EESubscriber());
+ }
});
+
+ getProxy().getPluginManager().registerCommand(this, new EECommand(this, "ee", EECommandKind.BUKKIT));
+ getProxy().getPluginManager().registerCommand(this, new EECommand(this, "eb", EECommandKind.BUNGEECORD));
+ getProxy().getPluginManager().registerCommand(this, new EECommand(this, "eeg", EECommandKind.GROUP));
}
@Override
@@ -60,32 +60,15 @@ public void onDisable() {
pool.destroy();
}
- public class EESubscriber extends JedisPubSub {
- @Override
- public void onMessage(String channel, final String msg) {
- ExecuteEverywhere.instance.getLogger().info("Dispatching /" + msg);
- ProxyServer ps = ProxyServer.getInstance();
- ps.getPluginManager().dispatchCommand(ps.getConsole(), msg);
- }
-
- @Override
- public void onPMessage(String s, String s2, String s3) {
- }
-
- @Override
- public void onSubscribe(String s, int i) {
+ public class EESubscriber extends AbstractJedisPubSub {
+ public EESubscriber() {
+ super(pool, configuration);
}
@Override
- public void onUnsubscribe(String s, int i) {
- }
-
- @Override
- public void onPUnsubscribe(String s, int i) {
- }
-
- @Override
- public void onPSubscribe(String s, int i) {
+ public void onMessage(String channel, final String msg) {
+ ExecuteEverywhere.this.getLogger().info("Dispatching /" + msg);
+ ProxyServer.getInstance().getPluginManager().dispatchCommand(ProxyServer.getInstance().getConsole(), msg);
}
}
diff --git a/src/main/java/me/vemacs/executeeverywhere/common/AbstractJedisPubSub.java b/src/main/java/me/vemacs/executeeverywhere/common/AbstractJedisPubSub.java
new file mode 100644
index 0000000..155c34b
--- /dev/null
+++ b/src/main/java/me/vemacs/executeeverywhere/common/AbstractJedisPubSub.java
@@ -0,0 +1,44 @@
+package me.vemacs.executeeverywhere.common;
+
+import lombok.RequiredArgsConstructor;
+import redis.clients.jedis.Jedis;
+import redis.clients.jedis.JedisPool;
+import redis.clients.jedis.JedisPubSub;
+
+@RequiredArgsConstructor
+public abstract class AbstractJedisPubSub extends JedisPubSub implements Runnable {
+ private final JedisPool pool;
+ private final EEConfiguration configuration;
+
+ @Override
+ public void run() {
+ try (Jedis jedis = pool.getResource()) {
+ jedis.subscribe(this, configuration.getRedisChannels());
+ }
+ }
+
+ @Override
+ public void onPMessage(String s, String s1, String s2) {
+
+ }
+
+ @Override
+ public void onSubscribe(String s, int i) {
+
+ }
+
+ @Override
+ public void onUnsubscribe(String s, int i) {
+
+ }
+
+ @Override
+ public void onPUnsubscribe(String s, int i) {
+
+ }
+
+ @Override
+ public void onPSubscribe(String s, int i) {
+
+ }
+}
diff --git a/src/main/java/me/vemacs/executeeverywhere/common/EEConfiguration.java b/src/main/java/me/vemacs/executeeverywhere/common/EEConfiguration.java
new file mode 100644
index 0000000..5691d42
--- /dev/null
+++ b/src/main/java/me/vemacs/executeeverywhere/common/EEConfiguration.java
@@ -0,0 +1,41 @@
+package me.vemacs.executeeverywhere.common;
+
+import com.google.common.collect.ObjectArrays;
+import lombok.Data;
+import redis.clients.jedis.JedisPool;
+import redis.clients.jedis.JedisPoolConfig;
+
+import java.util.List;
+
+@Data
+public class EEConfiguration {
+ private final List groups;
+ private final String redisHost;
+ private final int redisPort;
+ private final String redisPassword;
+
+ public String[] getRedisChannels() {
+ String[] channels = groups.toArray(new String[groups.size()]);
+ for (int i = 0; i < channels.length; i++) {
+ channels[i] = "ee-" + channels[i];
+ }
+
+ // For legacy EE compatibility, we add the old "ee" and "eb" channels.
+ if (EEPlatform.BUKKIT.current()) {
+ channels = ObjectArrays.concat("ee", channels);
+ channels = ObjectArrays.concat("ee-bukkit", channels);
+ } else if (EEPlatform.BUNGEECORD.current()) {
+ channels = ObjectArrays.concat("eb", channels);
+ channels = ObjectArrays.concat("ee-bungeecord", channels);
+ }
+
+ return channels;
+ }
+
+ public JedisPool getJedisPool() {
+ if (redisPassword == null || redisPassword.isEmpty())
+ return new JedisPool(new JedisPoolConfig(), redisHost, redisPort, 0);
+ else
+ return new JedisPool(new JedisPoolConfig(), redisHost, redisPort, 0, redisPassword);
+ }
+}
diff --git a/src/main/java/me/vemacs/executeeverywhere/common/EEPlatform.java b/src/main/java/me/vemacs/executeeverywhere/common/EEPlatform.java
new file mode 100644
index 0000000..405dd81
--- /dev/null
+++ b/src/main/java/me/vemacs/executeeverywhere/common/EEPlatform.java
@@ -0,0 +1,28 @@
+package me.vemacs.executeeverywhere.common;
+
+public enum EEPlatform {
+ BUKKIT {
+ @Override
+ public boolean current() {
+ try {
+ Class.forName("org.bukkit.Bukkit");
+ return true;
+ } catch (ClassNotFoundException e) {
+ return false;
+ }
+ }
+ },
+ BUNGEECORD {
+ @Override
+ public boolean current() {
+ try {
+ Class.forName("net.md_5.bungee.api.ProxyServer");
+ return true;
+ } catch (ClassNotFoundException e) {
+ return false;
+ }
+ }
+ };
+
+ public abstract boolean current();
+}
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
index b89f011..5ec90a5 100644
--- a/src/main/resources/config.yml
+++ b/src/main/resources/config.yml
@@ -1,3 +1,6 @@
ip: 127.0.0.1
port: 6379
-password: ""
\ No newline at end of file
+password: ""
+# Example groups:
+# groups: [all, debian7, mybox1, mysql]
+groups: []
\ No newline at end of file
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
index 91d783b..abb4eb9 100644
--- a/src/main/resources/plugin.yml
+++ b/src/main/resources/plugin.yml
@@ -15,6 +15,12 @@ commands:
permission: executeeverywhere.use
usage: /eb
permission-message: You don't have permission to use this.
+ eeg:
+ description: Dispatches a command for execution to all connected servers in a group.
+ aliases: [executegroup]
+ permission: executeeverywhere.use
+ usage: /eeg
+ permission-message: You don't have permission to use this.
permissions:
executeeverywhere.use:
description: Lets you dispatch a command for execution on all servers.