From 61a4b169530bd1d21e01db214b6e1e392fed22e0 Mon Sep 17 00:00:00 2001 From: mohammed jasem alaajel <34905970+ham1255@users.noreply.github.com> Date: Wed, 23 Dec 2020 21:04:23 +0400 Subject: [PATCH 1/4] new ConnectionController! --- .../net/limework/rediskript/RediSkript.java | 22 +-- .../commands/CommandReloadRedis.java | 4 +- ...RedisManager.java => RedisController.java} | 163 +++++++----------- .../skript/elements/EffSendMessage.java | 2 +- .../elements/ExprVariableInChannel.java | 4 +- src/main/resources/plugin.yml | 2 +- 6 files changed, 84 insertions(+), 113 deletions(-) rename src/main/java/net/limework/rediskript/managers/{RedisManager.java => RedisController.java} (68%) diff --git a/src/main/java/net/limework/rediskript/RediSkript.java b/src/main/java/net/limework/rediskript/RediSkript.java index c2c1fde..d65e5af 100644 --- a/src/main/java/net/limework/rediskript/RediSkript.java +++ b/src/main/java/net/limework/rediskript/RediSkript.java @@ -8,7 +8,7 @@ import ch.njol.skript.util.Date; import ch.njol.skript.util.Getter; import net.limework.rediskript.commands.CommandReloadRedis; import net.limework.rediskript.events.RedisMessageEvent; -import net.limework.rediskript.managers.RedisManager; +import net.limework.rediskript.managers.RedisController; import net.limework.rediskript.skript.elements.*; import org.bukkit.plugin.java.JavaPlugin; @@ -16,14 +16,14 @@ import java.io.IOException; public class RediSkript extends JavaPlugin { - //Redis manager - private RedisManager rm; + private RedisController redisController; - public void startRedis(boolean reload) { - if (reload) { reloadConfig(); } - rm = new RedisManager(this); - rm.start(); + public void reloadRedis(){ + redisController.shutdown(); + redisController = new RedisController(this); } + + public void registerSyntax() { SkriptAddon addon = Skript.registerAddon(this); try { @@ -60,16 +60,16 @@ public class RediSkript extends JavaPlugin { @Override public void onEnable() { saveDefaultConfig(); - startRedis(false); + redisController = new RedisController(this); getServer().getPluginCommand("reloadredis").setExecutor(new CommandReloadRedis(this)); registerSyntax(); } @Override public void onDisable() { - if (rm != null) rm.shutdown(); + if (redisController != null) redisController.shutdown(); } - public RedisManager getRedisManager() { - return rm; + public RedisController getRC() { + return redisController; } } \ No newline at end of file diff --git a/src/main/java/net/limework/rediskript/commands/CommandReloadRedis.java b/src/main/java/net/limework/rediskript/commands/CommandReloadRedis.java index 4eef890..fc9717b 100644 --- a/src/main/java/net/limework/rediskript/commands/CommandReloadRedis.java +++ b/src/main/java/net/limework/rediskript/commands/CommandReloadRedis.java @@ -27,10 +27,10 @@ public class CommandReloadRedis implements CommandExecutor { new BukkitRunnable() { @Override public void run() { - plugin.getRedisManager().reload(); + plugin.reloadRedis(); } }.runTaskAsynchronously(plugin); - + //not sending to sender, because this command can only be executed via console Bukkit.getLogger().info(ChatColor.translateAlternateColorCodes('&', "&eReloaded channels, encryption and login details!")); diff --git a/src/main/java/net/limework/rediskript/managers/RedisManager.java b/src/main/java/net/limework/rediskript/managers/RedisController.java similarity index 68% rename from src/main/java/net/limework/rediskript/managers/RedisManager.java rename to src/main/java/net/limework/rediskript/managers/RedisController.java index eff0e5c..204227a 100644 --- a/src/main/java/net/limework/rediskript/managers/RedisManager.java +++ b/src/main/java/net/limework/rediskript/managers/RedisController.java @@ -8,46 +8,43 @@ import net.limework.rediskript.events.RedisMessageEvent; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.configuration.Configuration; +import org.bukkit.scheduler.BukkitTask; import org.cryptomator.siv.UnauthenticCiphertextException; import org.json.JSONArray; import org.json.JSONObject; -import redis.clients.jedis.BinaryJedis; -import redis.clients.jedis.BinaryJedisPubSub; -import redis.clients.jedis.JedisPool; -import redis.clients.jedis.JedisPoolConfig; +import redis.clients.jedis.*; import redis.clients.jedis.exceptions.JedisConnectionException; import javax.crypto.IllegalBlockSizeException; import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.List; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicBoolean; -public class RedisManager extends BinaryJedisPubSub implements Runnable { - - private ExecutorService RedisReconnector; - private RediSkript plugin; - - private JedisPool jedisPool; - private ExecutorService RedisService; +public class RedisController extends BinaryJedisPubSub implements Runnable { - //sub - private BinaryJedis subscribeJedis; - private List channels; - private AtomicBoolean isShuttingDown = new AtomicBoolean(false); - private Encryption encryption; + //Jedis Pool to be used by every another class. + private final JedisPool jedisPool; + + //this seems useless unless tls is OFF! + private final Encryption encryption; + + private byte[][] channelsInByte; + + private final AtomicBoolean isConnectionBroken; + private final RediSkript plugin; + private BukkitTask ConnectionTask; - public RedisManager(RediSkript plugin) { + public RedisController(RediSkript plugin) { this.plugin = plugin; - Configuration config = this.plugin.getConfig(); + Configuration config = plugin.getConfig(); JedisPoolConfig JConfig = new JedisPoolConfig(); int maxConnections = config.getInt("Redis.MaxConnections"); - if (maxConnections < 2) { maxConnections = 2; } - + if (maxConnections < 2) { + maxConnections = 2; + } JConfig.setMaxTotal(maxConnections); JConfig.setMaxIdle(maxConnections); JConfig.setMinIdle(1); @@ -58,50 +55,34 @@ public class RedisManager extends BinaryJedisPubSub implements Runnable { config.getInt("Redis.TimeOut"), config.getString("Redis.Password"), config.getBoolean("Redis.useTLS")); - RedisReconnector = Executors.newSingleThreadExecutor(); - RedisService = Executors.newSingleThreadExecutor(); - try { - this.subscribeJedis = this.jedisPool.getResource(); - } catch (Exception ignored) {} - - this.channels = config.getStringList("Channels"); encryption = new Encryption(config); - - } - - public void start() { - this.RedisReconnector.execute(this); + setupChannels(config); + isConnectionBroken = new AtomicBoolean(true); + //Start the main task on async thread + ConnectionTask = plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin,this, 0 , 20 * 5 ); } @Override public void run() { - while (!isShuttingDown.get() && plugin.isEnabled()) { - try { - plugin.getLogger().info(ChatColor.translateAlternateColorCodes('&', "&cConnecting to redis...")); - if (!this.subscribeJedis.isConnected()) this.subscribeJedis = this.jedisPool.getResource(); - plugin.getLogger().info(ChatColor.translateAlternateColorCodes('&', "&aRedis connected!")); - byte[][] channelsInByte = new byte[channels.size()][1]; - for (int x = 0; x < channels.size(); x++) { - channelsInByte[x] = channels.get(x).getBytes(StandardCharsets.UTF_8); - } - this.subscribeJedis.subscribe(this, channelsInByte); - - - } catch (Exception e) { - if (isShuttingDown.get() || !plugin.isEnabled()) { - return; - } - plugin.getLogger().warning(ChatColor.translateAlternateColorCodes('&', "&cConnection to redis has failed! &cReconnecting...")); - if (this.subscribeJedis != null) { - this.subscribeJedis.close(); - } - } - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } + if (!isConnectionBroken.get()) { + return; } + System.out.println("connecting to redis!"); + try (Jedis jedis = jedisPool.getResource()) { + isConnectionBroken.set(false); + System.out.println("connected to redis!"); + jedis.subscribe(this, channelsInByte); + + } catch (Exception e) { + isConnectionBroken.set(true); + e.printStackTrace(); + } + } + + public void shutdown() { + ConnectionTask.cancel(); + this.unsubscribe(); + jedisPool.close(); } @Override @@ -170,7 +151,7 @@ public class RedisManager extends BinaryJedisPubSub implements Runnable { //I will add this once someone tells me how to remove from Skript variable //because using SET operation has issues with inconvertible types (Double and Long) //variable = (Variable) Variables.getVariable(variableNames.get(i).toString(), null, false); - // variable.change(null, (Object[]) inputValue, Changer.ChangeMode.REMOVE); + // variable.change(null, (Object[]) inputValue, Changer.ChangeMode.REMOVE); break; case "SET": Variables.setVariable(variableNames.get(i).toString(), inputValue, null, false); @@ -186,6 +167,7 @@ public class RedisManager extends BinaryJedisPubSub implements Runnable { } } + public void sendMessage(String[] message, String channel) { JSONObject json = new JSONObject(); json.put("Messages", new JSONArray(message)); @@ -193,6 +175,7 @@ public class RedisManager extends BinaryJedisPubSub implements Runnable { json.put("Date", System.currentTimeMillis()); //for unique string every time & PING calculations finishSendMessage(json, channel); } + public void sendVariables(String[] variableNames, String[] variableValues, String channel, String operation) { JSONObject json = new JSONObject(); json.put("Names", new JSONArray(variableNames)); @@ -209,8 +192,8 @@ public class RedisManager extends BinaryJedisPubSub implements Runnable { public void finishSendMessage(JSONObject json, String channel) { try { byte[] message; - if (this.getEncryption().isEncryptionEnabled()) { - message = this.getEncryption().encrypt(json.toString()); + if (encryption.isEncryptionEnabled()) { + message = encryption.encrypt(json.toString()); } else { message = json.toString().getBytes(StandardCharsets.UTF_8); } @@ -218,51 +201,39 @@ public class RedisManager extends BinaryJedisPubSub implements Runnable { //sending a redis message blocks main thread if there's no more connections available //so to avoid issues, it's best to do it always on separate thread if (plugin.isEnabled()) { - this.getRedisService().execute(() -> { - BinaryJedis j = this.getJedisPool().getResource(); - j.publish(channel.getBytes(StandardCharsets.UTF_8), message); - j.close(); + plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> { + try (BinaryJedis j = jedisPool.getResource()) { + j.publish(channel.getBytes(StandardCharsets.UTF_8), message); + } catch (Exception e) { + System.out.println("Error sending redis message!"); + e.printStackTrace(); + } + }); } else { //execute sending of redis message on the main thread if plugin is disabling //so it can still process the sending - BinaryJedis j = this.getJedisPool().getResource(); - j.publish(channel.getBytes(StandardCharsets.UTF_8), message); - j.close(); + try (BinaryJedis j = jedisPool.getResource()) { + j.publish(channel.getBytes(StandardCharsets.UTF_8), message); + } catch (Exception e) { + e.printStackTrace(); + } + } } catch (JedisConnectionException exception) { exception.printStackTrace(); } } - public void shutdown() { - - this.isShuttingDown.set(true); - - if (this.subscribeJedis != null) { - this.unsubscribe(); - this.subscribeJedis.close(); + private void setupChannels(Configuration config) { + List channels = config.getStringList("Channels"); + channelsInByte = new byte[channels.size()][1]; + for (int x = 0; x < channels.size(); x++) { + channelsInByte[x] = channels.get(x).getBytes(StandardCharsets.UTF_8); } - - if (this.jedisPool != null) { - jedisPool.close(); - } - this.RedisReconnector.shutdown(); - this.RedisService.shutdown(); - - } - public void reload() { - this.shutdown(); - plugin.startRedis(true); } - public JedisPool getJedisPool() { - return jedisPool; + public Boolean isRedisConnectionOffline() { + return isConnectionBroken.get(); } - - public Encryption getEncryption() { - return encryption; - } - - public ExecutorService getRedisService() { return RedisService; } } diff --git a/src/main/java/net/limework/rediskript/skript/elements/EffSendMessage.java b/src/main/java/net/limework/rediskript/skript/elements/EffSendMessage.java index f98d5b1..87d1048 100644 --- a/src/main/java/net/limework/rediskript/skript/elements/EffSendMessage.java +++ b/src/main/java/net/limework/rediskript/skript/elements/EffSendMessage.java @@ -35,7 +35,7 @@ public class EffSendMessage extends Effect { Bukkit.getLogger().warning(ChatColor.translateAlternateColorCodes('&', "&2[&aRediSkript&a] &cChannel was empty. Please check your code.")); return; } - plugin.getRedisManager().sendMessage(message, channel); + plugin.getRC().sendMessage(message, channel); } @Override diff --git a/src/main/java/net/limework/rediskript/skript/elements/ExprVariableInChannel.java b/src/main/java/net/limework/rediskript/skript/elements/ExprVariableInChannel.java index 80c760f..757538c 100644 --- a/src/main/java/net/limework/rediskript/skript/elements/ExprVariableInChannel.java +++ b/src/main/java/net/limework/rediskript/skript/elements/ExprVariableInChannel.java @@ -66,10 +66,10 @@ public class ExprVariableInChannel extends SimpleExpression { } } String operation = mode.toString(); - plugin.getRedisManager().sendVariables(name.getAll(e), values, channel.getSingle(e), operation); + plugin.getRC().sendVariables(name.getAll(e), values, channel.getSingle(e), operation); break; case DELETE: - plugin.getRedisManager().sendVariables(name.getAll(e), null, channel.getSingle(e), "SET"); + plugin.getRC().sendVariables(name.getAll(e), null, channel.getSingle(e), "SET"); break; } } diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 3bd822d..01d33a2 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,7 +1,7 @@ main: net.limework.rediskript.RediSkript name: ${project.name} version: ${project.version} -authors: [Govindas, ham1255, DaemonicKing] +authors: [Govindas, ham1255, DaemonicKing, limework.net] api-version: 1.13 depend: [Skript] commands: From a387b9486127d4475b55ec37227d6ec8380a87c0 Mon Sep 17 00:00:00 2001 From: mohammed jasem alaajel <34905970+ham1255@users.noreply.github.com> Date: Fri, 25 Dec 2020 21:43:20 +0400 Subject: [PATCH 2/4] added replacement for system prinltn messages --- .../java/net/limework/rediskript/RediSkript.java | 14 +++++++++++++- .../rediskript/managers/RedisController.java | 8 ++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/limework/rediskript/RediSkript.java b/src/main/java/net/limework/rediskript/RediSkript.java index d65e5af..233f7d6 100644 --- a/src/main/java/net/limework/rediskript/RediSkript.java +++ b/src/main/java/net/limework/rediskript/RediSkript.java @@ -10,6 +10,7 @@ import net.limework.rediskript.commands.CommandReloadRedis; import net.limework.rediskript.events.RedisMessageEvent; import net.limework.rediskript.managers.RedisController; import net.limework.rediskript.skript.elements.*; +import org.bukkit.ChatColor; import org.bukkit.plugin.java.JavaPlugin; import java.io.IOException; @@ -18,11 +19,21 @@ public class RediSkript extends JavaPlugin { private RedisController redisController; - public void reloadRedis(){ + public void reloadRedis() { redisController.shutdown(); redisController = new RedisController(this); } + public void sendLogs(String message) { + getLogger().info( + ChatColor.translateAlternateColorCodes('&', "&b[RediSkript]&e " + message) + ); + } + public void sendErrorLogs(String message) { + getLogger().severe( + ChatColor.translateAlternateColorCodes('&', "&b[RediSkript]&c " + message) + ); + } public void registerSyntax() { SkriptAddon addon = Skript.registerAddon(this); @@ -69,6 +80,7 @@ public class RediSkript extends JavaPlugin { public void onDisable() { if (redisController != null) redisController.shutdown(); } + public RedisController getRC() { return redisController; } diff --git a/src/main/java/net/limework/rediskript/managers/RedisController.java b/src/main/java/net/limework/rediskript/managers/RedisController.java index 204227a..1cb4b00 100644 --- a/src/main/java/net/limework/rediskript/managers/RedisController.java +++ b/src/main/java/net/limework/rediskript/managers/RedisController.java @@ -34,7 +34,7 @@ public class RedisController extends BinaryJedisPubSub implements Runnable { private final AtomicBoolean isConnectionBroken; private final RediSkript plugin; - private BukkitTask ConnectionTask; + private final BukkitTask ConnectionTask; public RedisController(RediSkript plugin) { @@ -67,15 +67,15 @@ public class RedisController extends BinaryJedisPubSub implements Runnable { if (!isConnectionBroken.get()) { return; } - System.out.println("connecting to redis!"); + plugin.sendLogs("Connecting to redis......"); try (Jedis jedis = jedisPool.getResource()) { isConnectionBroken.set(false); - System.out.println("connected to redis!"); + plugin.sendLogs("&aConnection to redis has established!"); jedis.subscribe(this, channelsInByte); } catch (Exception e) { isConnectionBroken.set(true); - e.printStackTrace(); + plugin.sendLogs("Connection has &kFAILED &cor Unable to connect to redis retrying to make connection..."); } } From 0ab1913e5fa3f75ef8085266ac69ae6cb5432db0 Mon Sep 17 00:00:00 2001 From: mohammed jasem alaajel <34905970+ham1255@users.noreply.github.com> Date: Fri, 25 Dec 2020 23:27:06 +0400 Subject: [PATCH 3/4] Fixed bug where connection manager is keep reconnecting when connection reconnect after failure --- .../net/limework/rediskript/RediSkript.java | 4 ++-- .../rediskript/managers/RedisController.java | 17 +++++++++++++---- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/main/java/net/limework/rediskript/RediSkript.java b/src/main/java/net/limework/rediskript/RediSkript.java index 233f7d6..509d0bc 100644 --- a/src/main/java/net/limework/rediskript/RediSkript.java +++ b/src/main/java/net/limework/rediskript/RediSkript.java @@ -26,12 +26,12 @@ public class RediSkript extends JavaPlugin { public void sendLogs(String message) { getLogger().info( - ChatColor.translateAlternateColorCodes('&', "&b[RediSkript]&e " + message) + ChatColor.translateAlternateColorCodes('&', "&b" + message) ); } public void sendErrorLogs(String message) { getLogger().severe( - ChatColor.translateAlternateColorCodes('&', "&b[RediSkript]&c " + message) + ChatColor.translateAlternateColorCodes('&', "&c" + message) ); } diff --git a/src/main/java/net/limework/rediskript/managers/RedisController.java b/src/main/java/net/limework/rediskript/managers/RedisController.java index 1cb4b00..5d52d47 100644 --- a/src/main/java/net/limework/rediskript/managers/RedisController.java +++ b/src/main/java/net/limework/rediskript/managers/RedisController.java @@ -33,6 +33,7 @@ public class RedisController extends BinaryJedisPubSub implements Runnable { private byte[][] channelsInByte; private final AtomicBoolean isConnectionBroken; + private final AtomicBoolean isConnecting; private final RediSkript plugin; private final BukkitTask ConnectionTask; @@ -58,30 +59,38 @@ public class RedisController extends BinaryJedisPubSub implements Runnable { encryption = new Encryption(config); setupChannels(config); isConnectionBroken = new AtomicBoolean(true); + isConnecting = new AtomicBoolean(false); //Start the main task on async thread - ConnectionTask = plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin,this, 0 , 20 * 5 ); + ConnectionTask = plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, this, 0, 20 * 5); } @Override public void run() { - if (!isConnectionBroken.get()) { + if (!isConnectionBroken.get() || isConnecting.get()) { return; } plugin.sendLogs("Connecting to redis......"); + isConnecting.set(true); try (Jedis jedis = jedisPool.getResource()) { isConnectionBroken.set(false); plugin.sendLogs("&aConnection to redis has established!"); jedis.subscribe(this, channelsInByte); - } catch (Exception e) { + isConnecting.set(false); isConnectionBroken.set(true); plugin.sendLogs("Connection has &kFAILED &cor Unable to connect to redis retrying to make connection..."); + e.printStackTrace(); } } public void shutdown() { ConnectionTask.cancel(); - this.unsubscribe(); + try { + this.unsubscribe(); + } catch (Exception e) { + plugin.sendErrorLogs("Something went wrong during unsubscribing..."); + } + jedisPool.close(); } From c84bb62b853bf8e67bc945905964c781da91e395 Mon Sep 17 00:00:00 2001 From: mohammed jasem alaajel <34905970+ham1255@users.noreply.github.com> Date: Sat, 26 Dec 2020 14:03:27 +0400 Subject: [PATCH 4/4] Update RedisController.java --- .../rediskript/managers/RedisController.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/limework/rediskript/managers/RedisController.java b/src/main/java/net/limework/rediskript/managers/RedisController.java index 5d52d47..65e0ccd 100644 --- a/src/main/java/net/limework/rediskript/managers/RedisController.java +++ b/src/main/java/net/limework/rediskript/managers/RedisController.java @@ -35,6 +35,7 @@ public class RedisController extends BinaryJedisPubSub implements Runnable { private final AtomicBoolean isConnectionBroken; private final AtomicBoolean isConnecting; private final RediSkript plugin; + private final boolean debugMode = false; //todo: will be later in the config in future release. private final BukkitTask ConnectionTask; @@ -79,7 +80,9 @@ public class RedisController extends BinaryJedisPubSub implements Runnable { isConnecting.set(false); isConnectionBroken.set(true); plugin.sendLogs("Connection has &kFAILED &cor Unable to connect to redis retrying to make connection..."); - e.printStackTrace(); + if (debugMode) { + e.printStackTrace(); + } } } @@ -89,6 +92,9 @@ public class RedisController extends BinaryJedisPubSub implements Runnable { this.unsubscribe(); } catch (Exception e) { plugin.sendErrorLogs("Something went wrong during unsubscribing..."); + if (debugMode) { + e.printStackTrace(); + } } jedisPool.close(); @@ -170,9 +176,11 @@ public class RedisController extends BinaryJedisPubSub implements Runnable { } } } catch (Exception e) { - e.printStackTrace(); - Bukkit.getLogger().warning(ChatColor.translateAlternateColorCodes('&', "&cI got a message that was empty from channel " + channelString + " please check your code that you used to send the message. Message content:")); - Bukkit.getLogger().warning(receivedMessage); + plugin.sendErrorLogs("&cI got a message that was empty from channel " + channelString + " please check your code that you used to send the message. Message content:"); + if (debugMode) { + e.printStackTrace(); + plugin.sendErrorLogs(receivedMessage); + } } }