Add cross-server variable editing (I'll make it use {} instead of strings later)

This commit is contained in:
Govindas 2020-11-25 17:01:11 +02:00
parent c33f49ca3c
commit 22e9cfdd40
5 changed files with 153 additions and 56 deletions

View File

@ -1,5 +1,7 @@
package net.limework.rediskript.managers; package net.limework.rediskript.managers;
import ch.njol.skript.registrations.Classes;
import ch.njol.skript.variables.Variables;
import net.limework.rediskript.RediSkript; import net.limework.rediskript.RediSkript;
import net.limework.rediskript.events.RedisMessageEvent; import net.limework.rediskript.events.RedisMessageEvent;
import net.limework.rediskript.data.Encryption; import net.limework.rediskript.data.Encryption;
@ -13,9 +15,11 @@ import redis.clients.jedis.BinaryJedis;
import redis.clients.jedis.BinaryJedisPubSub; import redis.clients.jedis.BinaryJedisPubSub;
import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig; import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.exceptions.JedisConnectionException;
import javax.crypto.IllegalBlockSizeException; import javax.crypto.IllegalBlockSizeException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
@ -98,6 +102,9 @@ public class RedisManager extends BinaryJedisPubSub implements Runnable {
} catch (Exception e) { } catch (Exception e) {
if (isShuttingDown.get() || !plugin.isEnabled()) {
return;
}
plugin.getLogger().warning(ChatColor.translateAlternateColorCodes('&', "&cConnection to redis has failed! &cReconnecting...")); plugin.getLogger().warning(ChatColor.translateAlternateColorCodes('&', "&cConnection to redis has failed! &cReconnecting..."));
if (this.subscribeJedis != null) { if (this.subscribeJedis != null) {
this.subscribeJedis.close(); this.subscribeJedis.close();
@ -128,23 +135,40 @@ public class RedisManager extends BinaryJedisPubSub implements Runnable {
//encryption is disabled, so let's just get the string //encryption is disabled, so let's just get the string
receivedMessage = new String(message, StandardCharsets.UTF_8); receivedMessage = new String(message, StandardCharsets.UTF_8);
} }
if (receivedMessage != null) { if (receivedMessage != null) {
JSONObject j = new JSONObject(receivedMessage); JSONObject j = new JSONObject(receivedMessage);
//System.out.println("Message got from channel: "+channel +" and the Message: " +json.toString()); if (j.get("Type").equals("Skript")) {
JSONArray messages = j.getJSONArray("Messages"); JSONArray messages = j.getJSONArray("Messages");
RedisMessageEvent event; RedisMessageEvent event;
for (int i = 0 ; i < messages.length(); i++) { for (int i = 0; i < messages.length(); i++) {
event = new RedisMessageEvent(channelString, messages.get(i).toString(), j.getLong("Date"));
//if plugin is disabling, don't call events anymore
if (plugin.isEnabled()) {
RedisMessageEvent finalEvent = event;
Bukkit.getScheduler().runTask(plugin, () -> plugin.getServer().getPluginManager().callEvent(finalEvent));
}
}
} else if (j.get("Type").equals("SkriptVariables")) {
JSONArray variableNames = j.getJSONArray("Names");
boolean delete = false;
Object inputValue = null;
if (j.isNull("Value")) {
delete = true;
} else {
String input = j.getString("Value");
String [] inputs = input.split("\\^", 2);
inputValue = Classes.deserialize(inputs[0], Base64.getDecoder().decode(inputs[1]));
System.out.println(messages.get(i).toString());
event = new RedisMessageEvent(channelString, messages.get(i).toString(), j.getLong("Date")); }
if (plugin.isEnabled()) { for (int i = 0; i < variableNames.length(); i++) {
RedisMessageEvent finalEvent = event; if (delete) {
Bukkit.getScheduler().runTask(plugin, () -> plugin.getServer().getPluginManager().callEvent(finalEvent)); Variables.setVariable(variableNames.get(i).toString(), null, null, false);
} else {
Variables.setVariable(variableNames.get(i).toString(), inputValue, null, false);
}
} }
} }
//if plugin is disabling, don't call events anymore
} }
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
@ -153,6 +177,50 @@ public class RedisManager extends BinaryJedisPubSub implements Runnable {
} }
} }
public void sendMessage(String[] message, String channel) {
JSONObject json = new JSONObject();
json.put("Messages", new JSONArray(message));
json.put("Type", "Skript");
json.put("Date", System.currentTimeMillis()); //for unique string every time & PING calculations
finishSendMessage(json, channel);
}
public void sendVariables(String[] variableNames, String variableValue, String channel) {
JSONObject json = new JSONObject();
json.put("Names", new JSONArray(variableNames));
json.put("Value", variableValue);
json.put("Type", "SkriptVariables");
json.put("Date", System.currentTimeMillis()); //for unique string every time & PING calculations
finishSendMessage(json, channel);
}
public void finishSendMessage(JSONObject json, String channel) {
try {
byte[] message;
if (this.getEncryption().isEncryptionEnabled()) {
message = this.getEncryption().encrypt(json.toString());
} else {
message = json.toString().getBytes(StandardCharsets.UTF_8);
}
//execute sending of redis message on the main thread if plugin is disabling
//so it can still process the sending
//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();
});
} else {
BinaryJedis j = this.getJedisPool().getResource();
j.publish(channel.getBytes(StandardCharsets.UTF_8), message);
j.close();
}
} catch (JedisConnectionException exception) {
exception.printStackTrace();
}
}
public void shutdown() { public void shutdown() {
this.isShuttingDown.set(true); this.isShuttingDown.set(true);

View File

@ -6,12 +6,10 @@ import ch.njol.skript.lang.ExpressionType;
import ch.njol.skript.registrations.EventValues; import ch.njol.skript.registrations.EventValues;
import ch.njol.skript.util.Date; import ch.njol.skript.util.Date;
import ch.njol.skript.util.Getter; import ch.njol.skript.util.Getter;
import ch.njol.skript.util.Timespan;
import net.limework.rediskript.RediSkript; import net.limework.rediskript.RediSkript;
import net.limework.rediskript.events.RedisMessageEvent; import net.limework.rediskript.events.RedisMessageEvent;
import net.limework.rediskript.skript.elements.EvtRedis; import net.limework.rediskript.skript.elements.*;
import net.limework.rediskript.skript.elements.ExprChannel;
import net.limework.rediskript.skript.elements.ExprMessage;
import net.limework.rediskript.skript.elements.ExprMessageDate;
import java.io.IOException; import java.io.IOException;
@ -21,6 +19,8 @@ public class SkriptHook {
try { try {
addon.loadClasses("net.limework.rediskript.skript", "elements"); addon.loadClasses("net.limework.rediskript.skript", "elements");
Skript.registerEvent("redis message", EvtRedis.class, RedisMessageEvent.class, "redis message"); Skript.registerEvent("redis message", EvtRedis.class, RedisMessageEvent.class, "redis message");
Skript.registerExpression(ExprVariableInChannel.class, Object.class, ExpressionType.PROPERTY, "variable %strings% in [redis] channel %string%");
Skript.registerExpression(ExprChannel.class, String.class, ExpressionType.SIMPLE, "redis channel"); Skript.registerExpression(ExprChannel.class, String.class, ExpressionType.SIMPLE, "redis channel");
EventValues.registerEventValue(RedisMessageEvent.class, String.class, new Getter<String, RedisMessageEvent>() { EventValues.registerEventValue(RedisMessageEvent.class, String.class, new Getter<String, RedisMessageEvent>() {
@Override @Override

View File

@ -34,7 +34,6 @@ public class EffSendMessage extends Effect {
String[] message = this.message.getAll(event); String[] message = this.message.getAll(event);
String channel = this.channel.getSingle(event); String channel = this.channel.getSingle(event);
if (message[0] == null) { if (message[0] == null) {
Bukkit.getLogger().warning(ChatColor.translateAlternateColorCodes('&', "&2[&aRediSkript&a] &cRedis message was empty. Please check your code.")); Bukkit.getLogger().warning(ChatColor.translateAlternateColorCodes('&', "&2[&aRediSkript&a] &cRedis message was empty. Please check your code."));
return; return;
@ -43,40 +42,7 @@ public class EffSendMessage extends Effect {
Bukkit.getLogger().warning(ChatColor.translateAlternateColorCodes('&', "&2[&aRediSkript&a] &cChannel was empty. Please check your code.")); Bukkit.getLogger().warning(ChatColor.translateAlternateColorCodes('&', "&2[&aRediSkript&a] &cChannel was empty. Please check your code."));
return; return;
} }
assert plugin != null; plugin.getRm().sendMessage(message, channel);
JSONObject json = new JSONObject();
json.put("Messages", new JSONArray(message));
json.put("Type", "Skript");
json.put("Date", System.currentTimeMillis()); //for unique string every time & PING calculations
byte[] msg;
RedisManager manager = plugin.getRm();
if (manager.getEncryption().isEncryptionEnabled()) {
msg = manager.getEncryption().encrypt(json.toString());
} else {
msg = json.toString().getBytes(StandardCharsets.UTF_8);
}
try {
//execute sending of redis message on the main thread if plugin is disabling
//so it can still process the sending
//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()) {
manager.getRedisService().execute(() -> {
BinaryJedis j = manager.getJedisPool().getResource();
j.publish(channel.getBytes(StandardCharsets.UTF_8), msg);
j.close();
});
} else {
BinaryJedis j = manager.getJedisPool().getResource();
j.publish(channel.getBytes(StandardCharsets.UTF_8), msg);
j.close();
}
} catch (JedisConnectionException exception) {
exception.printStackTrace();
}
} }
@Override @Override

View File

@ -1,5 +0,0 @@
package net.limework.rediskript.skript.elements;
public class EffSetVariableInChannel {
}

View File

@ -0,0 +1,68 @@
package net.limework.rediskript.skript.elements;
import ch.njol.skript.classes.Changer;
import ch.njol.skript.lang.*;
import ch.njol.skript.lang.util.SimpleExpression;
import ch.njol.skript.registrations.Classes;
import ch.njol.skript.variables.SerializedVariable;
import ch.njol.skript.variables.Variables;
import ch.njol.util.Kleenean;
import ch.njol.util.coll.CollectionUtils;
import net.limework.rediskript.RediSkript;
import org.bukkit.Bukkit;
import org.bukkit.event.Event;
import java.util.Base64;
public class ExprVariableInChannel extends SimpleExpression<Object> {
private Expression<String> name;
private Expression<String> channel;
@Override
public boolean init(Expression<?>[] expressions, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parser) {
name = (Expression<String>) expressions[0];
channel = (Expression<String>) expressions[1];
return true;
}
@Override
protected Object[] get(Event event) {
return null;
}
@Override
public boolean isSingle() {
return false;
}
@Override
public Class<? extends Object> getReturnType() {
return Object.class;
}
@Override
public String toString(Event event, boolean b) {
return null;
}
@Override
public void change(Event e, Object[] changer, Changer.ChangeMode mode) {
RediSkript plugin = (RediSkript) Bukkit.getPluginManager().getPlugin("RediSkript");
switch (mode) {
case SET:
SerializedVariable.Value serialized = Classes.serialize(changer[0]);
String encoded = Base64.getEncoder().encodeToString(serialized.data);
encoded = serialized.type + "^" + encoded;
plugin.getRm().sendVariables(name.getAll(e), encoded, channel.getSingle(e));
break;
case DELETE:
plugin.getRm().sendVariables(name.getAll(e), null, channel.getSingle(e));
break;
}
}
@Override
public Class<?>[] acceptChange(Changer.ChangeMode mode) {
if (mode == Changer.ChangeMode.DELETE || mode == Changer.ChangeMode.SET)
return CollectionUtils.array(Object.class);
return null;
}
}