Compare commits

..

7 Commits
1.3.4 ... 1.3.6

7 changed files with 210 additions and 139 deletions

View File

@@ -1,6 +1,7 @@
[![RediSkript Build](https://github.com/Limework/RediSkript/actions/workflows/maven.yml/badge.svg?branch=master)](https://github.com/Limework/RediSkript/actions/workflows/maven.yml)
RediSkript allows you to communicate between your servers with use of Redis, it's very fast and easy to use.
## RediSkript
Allows you to communicate between your Minecraft servers with use of Redis and Skript, it's very fast and easy to use.
Skript: https://github.com/SkriptLang/Skript Skript: https://github.com/SkriptLang/Skript
@@ -12,7 +13,11 @@ You can transfer any data in the form of text between your servers, you can prog
It is developed and maintained by Govindas & the team of Govindas Limework developers. It is developed and maintained by Govindas & the team of Govindas Limework developers.
Redis Message: There is only one command: **/reloadredis** it fully reloads the configuration, you can reload IP, password, channels and everything else.
You only need to have matching configuration in every server for communication and a Redis server to connect to. I recommend using a VPS for hosting redis server, but there also are free redis hosting options available.
### Redis Message
``` ```
on redis message: on redis message:
if redis channel is "world": if redis channel is "world":
@@ -24,12 +29,14 @@ command /sendredis <text> <text>:
send redis message arg 1 to channel arg 2 send redis message arg 1 to channel arg 2
send redis message "hello world!" to channel "world" send redis message "hello world!" to channel "world"
``` ```
Managing variables: ### Managing variables
``` ```
set variables "test::1", "test::2", "test::3" in channel "global" to 100 set variables "test::1", "test::2", "test::3" in channel "global" to 100
#then use this in any server that listens to "global" redis channel and was online when the above line was executed: #then use this in any server that listens to "global" redis channel and was online when the above line was executed:
send "%{test::*}%" #outputs 100, 100 and 100 send "%{test::*}%" #outputs 100, 100 and 100
add 100 to variables "test::1" and "test::2" in channel "global"
remove 10 from variable "test::1" in channel "global"
delete variables "test::*" in channel "global" delete variables "test::*" in channel "global"
set variable "test::%uuid of player%" in channel "playerdata" to tool of player set variable "test::%uuid of player%" in channel "playerdata" to tool of player
@@ -41,11 +48,8 @@ Syntax:
variable[s] %strings% in [redis] [channel] %string% variable[s] %strings% in [redis] [channel] %string%
``` ```
There is only one command: **/reloadredis** it fully reloads the configuration, you can reload IP, password, channels and everything else. ### Configuration
plugins/RediSkript/config.yml
You only need to have matching configuration in every server for communication and a Redis server to connect to. I recommend using VPS for hosting redis server, I personally use VPS from humbleservers.com.
Configuration:
``` ```
Redis: Redis:
#a secure password that cannot be cracked, please change it! #a secure password that cannot be cracked, please change it!
@@ -72,13 +76,12 @@ Redis:
#the encryption configuration must be the same across all servers in order to communicate #the encryption configuration must be the same across all servers in order to communicate
#use 16 characters long key for AES-128 encryption #use 16 characters long key for AES-128 encryption
#32 characters long key for AES-256 encryption #32 characters long key for AES-256 encryption (recommended)
#AES-128 is faster, but less secure (but it is not crackable by today's technology as of 2020, may be crackable by quantum computers)
#the AES implementation used in RediSkript uses SIV mode, which makes the same key resistant to cracking for a big count of messages without the need of changing the key very often #the AES implementation used in RediSkript uses SIV mode, which makes the same key resistant to cracking for a big count of messages without the need of changing the key very often
EncryptMessages: true EncryptMessages: true
#EncryptionKey and MacKey must be different #EncryptionKey and MacKey must be different
EncryptionKey: "16CHARACTERS KEY" EncryptionKey: "32CHARACTERS KEY"
MacKey: "16CHARACTERS KEY" MacKey: "32CHARACTERS KEY"
#the channels from which this server can receive messages #the channels from which this server can receive messages

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>RediSkript</artifactId> <artifactId>RediSkript</artifactId>
<groupId>net.limework</groupId> <groupId>net.limework</groupId>
<version>1.3.4</version> <version>1.3.6-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@@ -57,7 +57,7 @@
<dependency> <dependency>
<groupId>com.github.SkriptLang</groupId> <groupId>com.github.SkriptLang</groupId>
<artifactId>Skript</artifactId> <artifactId>Skript</artifactId>
<version>2.5.3</version> <version>2.6.1</version>
<type>jar</type> <type>jar</type>
<exclusions> <exclusions>
<exclusion> <exclusion>
@@ -73,11 +73,6 @@
<version>1.16.5-R0.1-SNAPSHOT</version> <version>1.16.5-R0.1-SNAPSHOT</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.7.0</version>
</dependency>
<dependency> <dependency>
<groupId>net.limework</groupId> <groupId>net.limework</groupId>
<artifactId>RediSkript-core</artifactId> <artifactId>RediSkript-core</artifactId>

View File

@@ -19,6 +19,7 @@ import java.nio.charset.StandardCharsets;
import java.util.Base64; import java.util.Base64;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
public class RedisController extends BinaryJedisPubSub implements Runnable { public class RedisController extends BinaryJedisPubSub implements Runnable {
@@ -46,18 +47,30 @@ public class RedisController extends BinaryJedisPubSub implements Runnable {
int maxConnections = config.getInt("Redis.MaxConnections"); int maxConnections = config.getInt("Redis.MaxConnections");
//do not allow less than 2 max connections as that causes issues //do not allow less than 2 max connections as that causes issues
if (maxConnections < 2) { maxConnections = 2; } if (maxConnections < 2) {
maxConnections = 2;
}
JConfig.setMaxTotal(maxConnections); JConfig.setMaxTotal(maxConnections);
JConfig.setMaxIdle(maxConnections); JConfig.setMaxIdle(maxConnections);
JConfig.setMinIdle(1); JConfig.setMinIdle(1);
JConfig.setBlockWhenExhausted(true); JConfig.setBlockWhenExhausted(true);
final String password = config.getString("Redis.Password", "");
if (password.isEmpty()) {
this.jedisPool = new JedisPool(JConfig, this.jedisPool = new JedisPool(JConfig,
config.getString("Redis.Host"), config.getString("Redis.Host", "127.0.0.1"),
config.getInt("Redis.Port"), config.getInt("Redis.Port", 6379),
config.getInt("Redis.TimeOut"), config.getInt("Redis.TimeOut", 9000),
config.getString("Redis.Password"), config.getBoolean("Redis.useTLS", false));
config.getBoolean("Redis.useTLS")); } else {
this.jedisPool = new JedisPool(JConfig,
config.getString("Redis.Host", "127.0.0.1"),
config.getInt("Redis.Port", 6379),
config.getInt("Redis.TimeOut", 9000),
password,
config.getBoolean("Redis.useTLS", false));
}
encryption = new Encryption(config.getBoolean("Redis.EncryptMessages"), encryption = new Encryption(config.getBoolean("Redis.EncryptMessages"),
config.getString("Redis.EncryptionKey"), config.getString("Redis.EncryptionKey"),
config.getString("Redis.MacKey")); config.getString("Redis.MacKey"));
@@ -101,7 +114,7 @@ public class RedisController extends BinaryJedisPubSub implements Runnable {
} }
@Override @Override
public void onMessage(byte[] channel, byte[] message){ public void onMessage(byte[] channel, byte[] message) {
String channelString = new String(channel, StandardCharsets.UTF_8); String channelString = new String(channel, StandardCharsets.UTF_8);
String receivedMessage = null; String receivedMessage = null;
try { try {
@@ -134,51 +147,117 @@ public class RedisController extends BinaryJedisPubSub implements Runnable {
//Transfer variables between servers //Transfer variables between servers
JSONArray variableNames = j.getJSONArray("Names"); JSONArray varNames = j.getJSONArray("Names");
Object inputValue; Object inputValue;
String changeValue = null; String changeValue = null;
JSONArray variableValues = null; JSONArray varValues = null;
if (!j.isNull("Values")) { if (!j.isNull("Values")) {
variableValues = j.getJSONArray("Values"); varValues = j.getJSONArray("Values");
} }
for (int i = 0; i < variableNames.length(); i++) { for (int i = 0; i < varNames.length(); i++) {
String varName = varNames.get(i).toString();
if (j.isNull("Values")) { if (j.isNull("Values")) {
//only check for SET here, because null has to be ignored in all other cases
// only check for SET here, because null has to be ignored in all other cases
if (j.getString("Operation").equals("SET")) { if (j.getString("Operation").equals("SET")) {
Variables.setVariable(variableNames.get(i).toString(), null, null, false); Variables.setVariable(varName, null, null, false);
} }
} else { } else {
if (!variableValues.isNull(i)) { if (!varValues.isNull(i)) {
changeValue = variableValues.get(i).toString(); changeValue = varValues.get(i).toString();
} }
String[] inputs = changeValue.split("\\^", 2); String[] inputs = changeValue.split("\\^", 2);
inputValue = Classes.deserialize(inputs[0], Base64.getDecoder().decode(inputs[1])); inputValue = Classes.deserialize(inputs[0], Base64.getDecoder().decode(inputs[1]));
switch (j.getString("Operation")) { switch (j.getString("Operation")) {
case "ADD": case "ADD":
//I will add this once someone tells me how to remove from Skript variable if (varName.charAt(varName.length() - 1) == '*') {
//because using SET operation has issues with inconvertible types (Double and Long) plugin.getLogger().log(Level.WARNING, "Adding to {::*} variables in RediSkript is not supported. Variable name: " + varName);
//variable = (Variable) Variables.getVariable(variableNames.get(i).toString(), null, false); continue;
// variable.change(null, (Object[]) inputValue, Changer.ChangeMode.REMOVE); }
Object variable = Variables.getVariable(varName, null, false);
if (variable == null) {
Variables.setVariable(varName, inputValue, null, false);
} else if (variable instanceof Long) {
if (inputValue instanceof Long) {
Variables.setVariable(varName, (Long) variable + (Long) inputValue, null, false);
} else if (inputValue instanceof Double) {
// convert Long variable to Double
variable = Double.valueOf((Long) variable);
Variables.setVariable(varName, (Double) variable + (Double) inputValue, null, false);
} else {
// Not supported input type
plugin.getLogger().log(Level.WARNING, "Unsupported add action of data type (" + inputValue.getClass().getName() + ") on variable: " + varName);
continue;
}
} else if (variable instanceof Double) {
if (inputValue instanceof Double) {
Variables.setVariable(varName, (Double) variable + (Double) inputValue, null, false);
} else if (inputValue instanceof Long) {
Variables.setVariable(varName, (Double) variable + ((Long) inputValue).doubleValue(), null, false);
} else {
// Not supported input type
plugin.getLogger().log(Level.WARNING, "Unsupported add action of data type (" + inputValue.getClass().getName() + ") on variable: " + varName);
continue;
}
} else {
// Not supported input type
plugin.getLogger().log(Level.WARNING, "Unsupported variable type in add action (" + variable.getClass().getName() + ") on variable: " + varName);
continue;
}
break;
case "REMOVE": case "REMOVE":
//I will add this once someone tells me how to remove from Skript variable if (varName.charAt(varName.length() - 1) == '*') {
//because using SET operation has issues with inconvertible types (Double and Long) plugin.getLogger().log(Level.WARNING, "Removing from {::*} variables in RediSkript is not supported. Variable name: " + varName);
//variable = (Variable) Variables.getVariable(variableNames.get(i).toString(), null, false); continue;
// variable.change(null, (Object[]) inputValue, Changer.ChangeMode.REMOVE); }
variable = Variables.getVariable(varName, null, false);
if (variable == null) {
if (inputValue instanceof Long) {
Variables.setVariable(varName, -(Long) inputValue, null, false);
} else if (inputValue instanceof Double) {
Variables.setVariable(varName, -(Double) inputValue, null, false);
} else {
// Not supported input type
plugin.getLogger().log(Level.WARNING, "Unsupported remove action of data type (" + inputValue.getClass().getName() + ") on variable: " + varName);
continue;
}
} else if (variable instanceof Long) {
if (inputValue instanceof Long) {
Variables.setVariable(varName, (Long) variable - (Long) inputValue, null, false);
} else if (inputValue instanceof Double) {
// convert Long variable to Double
variable = Double.valueOf((Long) variable);
Variables.setVariable(varName, (Double) variable - (Double) inputValue, null, false);
} else {
// Not supported input type
plugin.getLogger().log(Level.WARNING, "Unsupported remove action of data type (" + inputValue.getClass().getName() + ") on variable: " + varName);
continue;
}
} else if (variable instanceof Double) {
if (inputValue instanceof Double) {
Variables.setVariable(varName, (Double) variable - (Double) inputValue, null, false);
} else if (inputValue instanceof Long) {
Variables.setVariable(varName, (Double) variable - ((Long) inputValue).doubleValue(), null, false);
}
} else {
// Not supported input type
plugin.getLogger().log(Level.WARNING, "Unsupported variable type in remove action (" + variable.getClass().getName() + ") on variable: " + varName);
continue;
}
break; break;
case "SET": case "SET":
String variableName = variableNames.get(i).toString();
//this is needed, because setting a {variable::*} causes weird behavior, like //this is needed, because setting a {variable::*} causes weird behavior, like
//1st set operation is no data, 2nd has data, etc. //1st set operation is no data, 2nd has data, etc.
//if you set it to null before action, it works correctly //if you set it to null before action, it works correctly
if (varName.charAt(varName.length() - 1) == '*') {
if (variableName.charAt(variableName.length()-1) == '*') { Variables.setVariable(varName, null, null, false);
Variables.setVariable(variableName, null, null, false);
} }
Variables.setVariable(variableNames.get(i).toString(), inputValue, null, false); Variables.setVariable(varNames.get(i).toString(), inputValue, null, false);
break;
} }
} }
@@ -226,7 +305,7 @@ public class RedisController extends BinaryJedisPubSub implements Runnable {
//so to avoid issues, it's best to do it always on separate thread //so to avoid issues, it's best to do it always on separate thread
if (plugin.isEnabled()) { if (plugin.isEnabled()) {
plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> { plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> {
try (BinaryJedis j = jedisPool.getResource()) { try (Jedis j = jedisPool.getResource()) {
j.publish(channel.getBytes(StandardCharsets.UTF_8), message); j.publish(channel.getBytes(StandardCharsets.UTF_8), message);
} catch (Exception e) { } catch (Exception e) {
plugin.sendErrorLogs("Error sending redis message!"); plugin.sendErrorLogs("Error sending redis message!");
@@ -236,7 +315,7 @@ public class RedisController extends BinaryJedisPubSub implements Runnable {
} else { } else {
//execute sending of redis message on the main thread if plugin is disabling //execute sending of redis message on the main thread if plugin is disabling
//so it can still process the sending //so it can still process the sending
try (BinaryJedis j = jedisPool.getResource()) { try (Jedis j = jedisPool.getResource()) {
j.publish(channel.getBytes(StandardCharsets.UTF_8), message); j.publish(channel.getBytes(StandardCharsets.UTF_8), message);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();

View File

@@ -73,7 +73,7 @@ public class ExprVariableInChannel extends SimpleExpression<Object> {
@Override @Override
public Class<?>[] acceptChange(Changer.ChangeMode mode) { public Class<?>[] acceptChange(Changer.ChangeMode mode) {
//if (mode == Changer.ChangeMode.DELETE || mode == Changer.ChangeMode.SET || mode == Changer.ChangeMode.ADD || mode == Changer.ChangeMode.REMOVE) //if (mode == Changer.ChangeMode.DELETE || mode == Changer.ChangeMode.SET || mode == Changer.ChangeMode.ADD || mode == Changer.ChangeMode.REMOVE)
if (mode == Changer.ChangeMode.DELETE || mode == Changer.ChangeMode.SET) if (mode == Changer.ChangeMode.DELETE || mode == Changer.ChangeMode.SET || mode == Changer.ChangeMode.ADD || mode == Changer.ChangeMode.REMOVE)
return CollectionUtils.array(Object.class); return CollectionUtils.array(Object.class);
return null; return null;

View File

@@ -23,13 +23,13 @@ Redis:
#the encryption configuration must be the same across all servers in order to communicate #the encryption configuration must be the same across all servers in order to communicate
#use 16 characters long key for AES-128 encryption #use 16 characters long key for AES-128 encryption
#32 characters long key for AES-256 encryption #32 characters long key for AES-256 encryption (recommended)
#AES-128 is faster, but less secure (but it is not crackable by today's technology as of 2020, may be crackable by quantum computers) #AES-128 is faster, but less secure (but it is not crackable by today's technology as of 2020, may be crackable by quantum computers)
#the AES implementation used in RediSkript uses SIV mode, which makes the same key resistant to cracking for a big count of messages without the need of changing the key very often #the AES implementation used in RediSkript uses SIV mode, which makes the same key resistant to cracking for a big count of messages without the need of changing the key very often
EncryptMessages: true EncryptMessages: true
#EncryptionKey and MacKey must be different #EncryptionKey and MacKey must be different
EncryptionKey: "16CHARACTERS KEY" EncryptionKey: "32CHARACTERS KEY"
MacKey: "16CHARACTERS KEY" MacKey: "32CHARACTERS KEY"
#the channels from which this server can receive messages #the channels from which this server can receive messages

View File

@@ -5,21 +5,10 @@
<parent> <parent>
<artifactId>RediSkript</artifactId> <artifactId>RediSkript</artifactId>
<groupId>net.limework</groupId> <groupId>net.limework</groupId>
<version>1.3.4</version> <version>1.3.6-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>RediSkript-core</artifactId> <artifactId>RediSkript-core</artifactId>
<dependencies>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.5.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project> </project>

13
pom.xml
View File

@@ -6,7 +6,7 @@
<groupId>net.limework</groupId> <groupId>net.limework</groupId>
<artifactId>RediSkript</artifactId> <artifactId>RediSkript</artifactId>
<version>1.3.4</version> <version>1.3.6-SNAPSHOT</version>
<modules> <modules>
<module>RediSkript-core</module> <module>RediSkript-core</module>
<module>RediSkript-bukkit</module> <module>RediSkript-bukkit</module>
@@ -43,18 +43,23 @@
<dependency> <dependency>
<groupId>org.json</groupId> <groupId>org.json</groupId>
<artifactId>json</artifactId> <artifactId>json</artifactId>
<version>20210307</version> <version>20220320</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.cryptomator</groupId> <groupId>org.cryptomator</groupId>
<artifactId>siv-mode</artifactId> <artifactId>siv-mode</artifactId>
<version>1.4.1</version> <version>1.4.4</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-pool2 --> <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-pool2 -->
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId> <artifactId>commons-pool2</artifactId>
<version>2.6.2</version> <version>2.11.1</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.2.2</version>
</dependency> </dependency>
</dependencies> </dependencies>
</project> </project>