mirror of
https://github.com/proxiodev/RedisBungee.git
synced 2024-11-22 20:28:00 +00:00
API converted to support RedisCluster
This commit is contained in:
parent
e986d5f1fb
commit
44f9a0945d
@ -6,6 +6,8 @@ import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.imaginarycode.minecraft.redisbungee.internal.RedisBungeePlugin;
|
||||
import com.imaginarycode.minecraft.redisbungee.internal.summoners.JedisSummoner;
|
||||
import com.imaginarycode.minecraft.redisbungee.internal.summoners.Summoner;
|
||||
import com.imaginarycode.minecraft.redisbungee.internal.util.RedisBungeeMode;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import redis.clients.jedis.Jedis;
|
||||
import redis.clients.jedis.JedisPool;
|
||||
@ -311,30 +313,60 @@ public class RedisBungeeAPI {
|
||||
* @since 0.7.0
|
||||
*/
|
||||
public Jedis requestJedis() {
|
||||
return this.plugin.getJedisSummoner().requestJedis();
|
||||
if (getMode() == RedisBungeeMode.SINGLE) {
|
||||
return ((JedisSummoner) this.plugin.getSummoner()).obtainResource();
|
||||
} else {
|
||||
throw new RuntimeException("RedisBungee is on Cluster MODE!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This gets Redis Bungee {@link JedisPool}
|
||||
* @return {@link JedisPool}
|
||||
* @since 0.6.5
|
||||
*/
|
||||
public JedisPool getJedisPool() {
|
||||
return this.plugin.getJedisSummoner().getJedisPool();
|
||||
if (getMode() == RedisBungeeMode.SINGLE) {
|
||||
return ((JedisSummoner) this.plugin.getSummoner()).getJedisPool();
|
||||
} else {
|
||||
throw new RuntimeException("RedisBungee is on Cluster MODE!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This gets Redis Bungee {@link JedisPool}
|
||||
* @return {@link JedisPool}
|
||||
* @since 0.6.5
|
||||
*/
|
||||
public JedisSummoner getJedisSummoner() {
|
||||
return this.plugin.getJedisSummoner();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* returns Summoner class responsible for Single Jedis {@link Jedis}, Cluster Jedis {@link redis.clients.jedis.JedisCluster} handling
|
||||
*
|
||||
* @return {@link Summoner}
|
||||
* @since 0.8.0
|
||||
*/
|
||||
public Summoner<?> getSummoner() {
|
||||
return this.plugin.getSummoner();
|
||||
}
|
||||
|
||||
/**
|
||||
* This gives you instance of Jedis Cluster
|
||||
* @return {@link redis.clients.jedis.JedisCluster}
|
||||
* @since 0.8.0
|
||||
*/
|
||||
public Jedis requestClusterJedis() {
|
||||
if (getMode() == RedisBungeeMode.CLUSTER) {
|
||||
return ((JedisSummoner) this.plugin.getSummoner()).obtainResource();
|
||||
} else {
|
||||
throw new RuntimeException("RedisBungee is on single MODE!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* shows what mode is RedisBungee is on
|
||||
* @return {@link RedisBungeeMode}
|
||||
* @since 0.8.0
|
||||
*/
|
||||
public RedisBungeeMode getMode() {
|
||||
return this.plugin.getRedisBungeeMode();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Api instance
|
||||
* @return the API instance.
|
||||
* @since 0.6.5
|
||||
*/
|
||||
|
@ -8,7 +8,9 @@ import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.imaginarycode.minecraft.redisbungee.internal.util.RedisTask;
|
||||
import redis.clients.jedis.Jedis;
|
||||
import redis.clients.jedis.JedisCluster;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.InetAddress;
|
||||
@ -52,12 +54,17 @@ public abstract class AbstractDataManager<P, PL, PD, PS> {
|
||||
return plugin.isPlayerOnAServer(player) ? plugin.getPlayerServerName(player) : null;
|
||||
|
||||
try {
|
||||
return serverCache.get(uuid, new Callable<String>() {
|
||||
return serverCache.get(uuid, new RedisTask<String>(plugin.getApi()) {
|
||||
@Override
|
||||
public String call() throws Exception {
|
||||
try (Jedis tmpRsc = plugin.getJedisSummoner().requestJedis()) {
|
||||
return Objects.requireNonNull(tmpRsc.hget("player:" + uuid, "server"), "user not found");
|
||||
public String singleJedisTask(Jedis jedis) {
|
||||
return Objects.requireNonNull(jedis.hget("player:" + uuid, "server"), "user not found");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String clusterJedisTask(JedisCluster jedisCluster) {
|
||||
return Objects.requireNonNull(jedisCluster.hget("player:" + uuid, "server"), "user not found");
|
||||
|
||||
}
|
||||
});
|
||||
} catch (ExecutionException | UncheckedExecutionException e) {
|
||||
@ -76,12 +83,15 @@ public abstract class AbstractDataManager<P, PL, PD, PS> {
|
||||
return plugin.getConfiguration().getServerId();
|
||||
|
||||
try {
|
||||
return proxyCache.get(uuid, new Callable<String>() {
|
||||
return proxyCache.get(uuid, new RedisTask<String>(plugin.getApi()) {
|
||||
@Override
|
||||
public String call() throws Exception {
|
||||
try (Jedis tmpRsc = plugin.getJedisSummoner().requestJedis()) {
|
||||
return Objects.requireNonNull(tmpRsc.hget("player:" + uuid, "proxy"), "user not found");
|
||||
public String singleJedisTask(Jedis jedis) {
|
||||
return Objects.requireNonNull(jedis.hget("player:" + uuid, "proxy"), "user not found");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String clusterJedisTask(JedisCluster jedisCluster) {
|
||||
return Objects.requireNonNull(jedisCluster.hget("player:" + uuid, "proxy"), "user not found");
|
||||
}
|
||||
});
|
||||
} catch (ExecutionException | UncheckedExecutionException e) {
|
||||
@ -99,15 +109,21 @@ public abstract class AbstractDataManager<P, PL, PD, PS> {
|
||||
return plugin.getPlayerIp(player);
|
||||
|
||||
try {
|
||||
return ipCache.get(uuid, new Callable<InetAddress>() {
|
||||
return ipCache.get(uuid, new RedisTask<InetAddress>(plugin.getApi()) {
|
||||
@Override
|
||||
public InetAddress call() throws Exception {
|
||||
try (Jedis tmpRsc = plugin.getJedisSummoner().requestJedis()) {
|
||||
String result = tmpRsc.hget("player:" + uuid, "ip");
|
||||
public InetAddress singleJedisTask(Jedis jedis) {
|
||||
String result = jedis.hget("player:" + uuid, "ip");
|
||||
if (result == null)
|
||||
throw new NullPointerException("user not found");
|
||||
return InetAddresses.forString(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetAddress clusterJedisTask(JedisCluster jedisCluster) {
|
||||
String result = jedisCluster.hget("player:" + uuid, "ip");
|
||||
if (result == null)
|
||||
throw new NullPointerException("user not found");
|
||||
return InetAddresses.forString(result);
|
||||
}
|
||||
});
|
||||
} catch (ExecutionException | UncheckedExecutionException e) {
|
||||
@ -125,13 +141,17 @@ public abstract class AbstractDataManager<P, PL, PD, PS> {
|
||||
return 0;
|
||||
|
||||
try {
|
||||
return lastOnlineCache.get(uuid, new Callable<Long>() {
|
||||
return lastOnlineCache.get(uuid, new RedisTask<Long>(plugin.getApi()) {
|
||||
@Override
|
||||
public Long call() throws Exception {
|
||||
try (Jedis tmpRsc = plugin.getJedisSummoner().requestJedis()) {
|
||||
String result = tmpRsc.hget("player:" + uuid, "online");
|
||||
return result == null ? -1 : Long.valueOf(result);
|
||||
public Long singleJedisTask(Jedis jedis) {
|
||||
String result = jedis.hget("player:" + uuid, "online");
|
||||
return result == null ? -1 : Long.parseLong(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long clusterJedisTask(JedisCluster jedisCluster) {
|
||||
String result = jedisCluster.hget("player:" + uuid, "online");
|
||||
return result == null ? -1 : Long.parseLong(result);
|
||||
}
|
||||
});
|
||||
} catch (ExecutionException e) {
|
||||
@ -149,6 +169,7 @@ public abstract class AbstractDataManager<P, PL, PD, PS> {
|
||||
|
||||
// Invalidate all entries related to this player, since they now lie. (call invalidate(uuid))
|
||||
public abstract void onPostLogin(PL event);
|
||||
|
||||
// Invalidate all entries related to this player, since they now lie. (call invalidate(uuid))
|
||||
public abstract void onPlayerDisconnect(PD event);
|
||||
|
||||
@ -181,7 +202,8 @@ public abstract class AbstractDataManager<P, PL, PD, PS> {
|
||||
Object event;
|
||||
try {
|
||||
event = plugin.getNetworkJoinEventClass().getDeclaredConstructor(UUID.class).newInstance(message1.getTarget());
|
||||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
|
||||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException |
|
||||
NoSuchMethodException e) {
|
||||
throw new RuntimeException("unable to dispatch an network join event", e);
|
||||
}
|
||||
plugin.callEvent(event);
|
||||
@ -200,7 +222,8 @@ public abstract class AbstractDataManager<P, PL, PD, PS> {
|
||||
Object event;
|
||||
try {
|
||||
event = plugin.getNetworkQuitEventClass().getDeclaredConstructor(UUID.class).newInstance(message2.getTarget());
|
||||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
|
||||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException |
|
||||
NoSuchMethodException e) {
|
||||
throw new RuntimeException("unable to dispatch an network quit event", e);
|
||||
}
|
||||
plugin.callEvent(event);
|
||||
@ -217,7 +240,8 @@ public abstract class AbstractDataManager<P, PL, PD, PS> {
|
||||
Object event;
|
||||
try {
|
||||
event = plugin.getServerChangeEventClass().getDeclaredConstructor(UUID.class, String.class, String.class).newInstance(message3.getTarget(), ((ServerChangePayload) message3.getPayload()).getOldServer(), ((ServerChangePayload) message3.getPayload()).getServer());
|
||||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
|
||||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException |
|
||||
NoSuchMethodException e) {
|
||||
throw new RuntimeException("unable to dispatch an server change event", e);
|
||||
}
|
||||
plugin.callEvent(event);
|
||||
@ -275,7 +299,7 @@ public abstract class AbstractDataManager<P, PL, PD, PS> {
|
||||
}
|
||||
}
|
||||
|
||||
public static class ServerChangePayload{
|
||||
public static class ServerChangePayload {
|
||||
private final String server;
|
||||
private final String oldServer;
|
||||
|
||||
|
@ -1,13 +1,14 @@
|
||||
package com.imaginarycode.minecraft.redisbungee.internal;
|
||||
|
||||
import com.imaginarycode.minecraft.redisbungee.internal.util.RedisTask;
|
||||
import redis.clients.jedis.Jedis;
|
||||
import redis.clients.jedis.JedisCluster;
|
||||
import redis.clients.jedis.exceptions.JedisConnectionException;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class PubSubListener implements Runnable {
|
||||
private JedisPubSubHandler jpsh;
|
||||
@ -21,14 +22,15 @@ public class PubSubListener implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try (Jedis rsc = plugin.getJedisSummoner().requestJedis()) {
|
||||
RedisTask<Void> subTask = new RedisTask<Void>(plugin.getApi()) {
|
||||
@Override
|
||||
public Void singleJedisTask(Jedis jedis) {
|
||||
try {
|
||||
|
||||
jpsh = new JedisPubSubHandler(plugin);
|
||||
addedChannels.add("redisbungee-" + plugin.getConfiguration().getServerId());
|
||||
addedChannels.add("redisbungee-allservers");
|
||||
addedChannels.add("redisbungee-data");
|
||||
rsc.subscribe(jpsh, addedChannels.toArray(new String[0]));
|
||||
jedis.subscribe(jpsh, addedChannels.toArray(new String[0]));
|
||||
} catch (Exception e) {
|
||||
// FIXME: Extremely ugly hack
|
||||
// Attempt to unsubscribe this instance and try again.
|
||||
@ -42,6 +44,36 @@ public class PubSubListener implements Runnable {
|
||||
*/
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void clusterJedisTask(JedisCluster jedisCluster) {
|
||||
try {
|
||||
jpsh = new JedisPubSubHandler(plugin);
|
||||
addedChannels.add("redisbungee-" + plugin.getConfiguration().getServerId());
|
||||
addedChannels.add("redisbungee-allservers");
|
||||
addedChannels.add("redisbungee-data");
|
||||
jedisCluster.subscribe(jpsh, addedChannels.toArray(new String[0]));
|
||||
} catch (Exception e) {
|
||||
// FIXME: Extremely ugly hack
|
||||
// Attempt to unsubscribe this instance and try again.
|
||||
plugin.logWarn("PubSub error, attempting to recover.");
|
||||
try {
|
||||
jpsh.unsubscribe();
|
||||
} catch (Exception e1) {
|
||||
/* This may fail with
|
||||
- java.net.SocketException: Broken pipe
|
||||
- redis.clients.jedis.exceptions.JedisConnectionException: JedisPubSub was not subscribed to a Jedis instance
|
||||
*/
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
subTask.execute();
|
||||
} catch (JedisConnectionException e) {
|
||||
plugin.logWarn("PubSub error, attempting to recover in 5 secs.");
|
||||
plugin.executeAsyncAfter(this, TimeUnit.SECONDS, 5);
|
||||
|
@ -2,7 +2,8 @@ package com.imaginarycode.minecraft.redisbungee.internal;
|
||||
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.imaginarycode.minecraft.redisbungee.RedisBungeeAPI;
|
||||
import com.imaginarycode.minecraft.redisbungee.internal.summoners.JedisSummoner;
|
||||
import com.imaginarycode.minecraft.redisbungee.internal.summoners.Summoner;
|
||||
import com.imaginarycode.minecraft.redisbungee.internal.util.RedisBungeeMode;
|
||||
import com.imaginarycode.minecraft.redisbungee.internal.util.uuid.UUIDTranslator;
|
||||
import redis.clients.jedis.Jedis;
|
||||
|
||||
@ -31,11 +32,7 @@ public interface RedisBungeePlugin<P> extends EventsPlatform{
|
||||
|
||||
}
|
||||
|
||||
Jedis requestJedis();
|
||||
|
||||
boolean isJedisAvailable();
|
||||
|
||||
JedisSummoner getJedisSummoner();
|
||||
Summoner<?> getSummoner();
|
||||
|
||||
RedisBungeeConfiguration getConfiguration();
|
||||
|
||||
@ -101,4 +98,6 @@ public interface RedisBungeePlugin<P> extends EventsPlatform{
|
||||
|
||||
void loadConfig() throws Exception;
|
||||
|
||||
RedisBungeeMode getRedisBungeeMode();
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,30 @@
|
||||
package com.imaginarycode.minecraft.redisbungee.internal.summoners;
|
||||
|
||||
import redis.clients.jedis.JedisCluster;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class ClusterJedisSummoner implements Summoner<JedisCluster> {
|
||||
public final JedisCluster jedisCluster;
|
||||
private boolean closed = false;
|
||||
|
||||
public ClusterJedisSummoner(JedisCluster jedisCluster) {
|
||||
this.jedisCluster = jedisCluster;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JedisCluster obtainResource() {
|
||||
return jedisCluster;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return !closed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
this.closed = true;
|
||||
jedisCluster.close();
|
||||
}
|
||||
}
|
@ -1,25 +1,35 @@
|
||||
package com.imaginarycode.minecraft.redisbungee.internal.summoners;
|
||||
|
||||
import redis.clients.jedis.Jedis;
|
||||
import redis.clients.jedis.JedisCluster;
|
||||
import redis.clients.jedis.JedisPool;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
|
||||
public class JedisSummoner implements Summoner<Jedis> {
|
||||
|
||||
/**
|
||||
* This class intended for future release to support redis sentinel or redis clusters
|
||||
*
|
||||
* @author Ham1255
|
||||
* @since 0.7.0
|
||||
*
|
||||
*/
|
||||
public interface JedisSummoner extends Closeable {
|
||||
private final JedisPool jedisPool;
|
||||
|
||||
Jedis requestJedis();
|
||||
public JedisSummoner(JedisPool jedisPool) {
|
||||
this.jedisPool = jedisPool;
|
||||
}
|
||||
|
||||
boolean isJedisAvailable();
|
||||
@Override
|
||||
public Jedis obtainResource() {
|
||||
return jedisPool.getResource();
|
||||
}
|
||||
|
||||
JedisPool getJedisPool();
|
||||
public JedisPool getJedisPool() {
|
||||
return this.jedisPool;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return !jedisPool.isClosed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
this.jedisPool.close();
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,34 +0,0 @@
|
||||
package com.imaginarycode.minecraft.redisbungee.internal.summoners;
|
||||
|
||||
import redis.clients.jedis.Jedis;
|
||||
import redis.clients.jedis.JedisPool;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class SinglePoolJedisSummoner implements JedisSummoner {
|
||||
final JedisPool jedisPool;
|
||||
|
||||
public SinglePoolJedisSummoner(JedisPool jedisPool) {
|
||||
this.jedisPool = jedisPool;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Jedis requestJedis() {
|
||||
return this.jedisPool.getResource();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJedisAvailable() {
|
||||
return !this.jedisPool.isClosed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JedisPool getJedisPool() {
|
||||
return this.jedisPool;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
jedisPool.close();
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.imaginarycode.minecraft.redisbungee.internal.summoners;
|
||||
|
||||
import java.io.Closeable;
|
||||
|
||||
|
||||
/**
|
||||
* This class intended for future release to support redis sentinel or redis clusters
|
||||
*
|
||||
* @author Ham1255
|
||||
* @since 0.7.0
|
||||
*
|
||||
*/
|
||||
public interface Summoner<P> extends Closeable {
|
||||
|
||||
P obtainResource();
|
||||
|
||||
boolean isAvailable();
|
||||
|
||||
|
||||
}
|
@ -2,6 +2,7 @@ package com.imaginarycode.minecraft.redisbungee.internal.util;
|
||||
|
||||
import com.imaginarycode.minecraft.redisbungee.internal.RedisBungeePlugin;
|
||||
import redis.clients.jedis.Jedis;
|
||||
import redis.clients.jedis.JedisCluster;
|
||||
import redis.clients.jedis.exceptions.JedisDataException;
|
||||
|
||||
import java.util.List;
|
||||
@ -14,10 +15,20 @@ public class LuaManager {
|
||||
}
|
||||
|
||||
public Script createScript(String script) {
|
||||
try (Jedis jedis = plugin.getJedisSummoner().requestJedis()) {
|
||||
RedisTask<Script> scriptRedisTask = new RedisTask<Script>(plugin.getApi()) {
|
||||
@Override
|
||||
public Script singleJedisTask(Jedis jedis) {
|
||||
String hash = jedis.scriptLoad(script);
|
||||
return new Script(script, hash);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Script clusterJedisTask(JedisCluster jedisCluster) {
|
||||
String hash = jedisCluster.scriptLoad(script, null);
|
||||
return new Script(script, hash);
|
||||
}
|
||||
};
|
||||
return scriptRedisTask.execute();
|
||||
}
|
||||
|
||||
public class Script {
|
||||
@ -38,9 +49,10 @@ public class LuaManager {
|
||||
}
|
||||
|
||||
public Object eval(List<String> keys, List<String> args) {
|
||||
RedisTask<Object> objectRedisTask = new RedisTask<Object>(plugin.getApi()) {
|
||||
@Override
|
||||
public Object singleJedisTask(Jedis jedis) {
|
||||
Object data;
|
||||
|
||||
try (Jedis jedis = plugin.getJedisSummoner().requestJedis()) {
|
||||
try {
|
||||
data = jedis.evalsha(hashed, keys, args);
|
||||
} catch (JedisDataException e) {
|
||||
@ -50,9 +62,27 @@ public class LuaManager {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clusterJedisTask(JedisCluster jedisCluster) {
|
||||
Object data;
|
||||
try {
|
||||
data = jedisCluster.evalsha(hashed, keys, args);
|
||||
} catch (JedisDataException e) {
|
||||
if (e.getMessage().startsWith("NOSCRIPT")) {
|
||||
data = jedisCluster.eval(script, keys, args);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
return objectRedisTask.execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,5 @@
|
||||
package com.imaginarycode.minecraft.redisbungee.internal.util;
|
||||
|
||||
public enum RedisBungeeMode {
|
||||
SINGLE, CLUSTER
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
package com.imaginarycode.minecraft.redisbungee.internal.util;
|
||||
|
||||
import com.imaginarycode.minecraft.redisbungee.internal.RedisBungeePlugin;
|
||||
import redis.clients.jedis.Jedis;
|
||||
import redis.clients.jedis.exceptions.JedisConnectionException;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
|
||||
|
||||
public abstract class RedisCallable<T> implements Callable<T>, Runnable {
|
||||
private final RedisBungeePlugin<?> plugin;
|
||||
|
||||
public RedisCallable(RedisBungeePlugin<?> plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T call() {
|
||||
return run(false);
|
||||
}
|
||||
|
||||
public void run() {
|
||||
call();
|
||||
}
|
||||
|
||||
private T run(boolean retry) {
|
||||
try (Jedis jedis = plugin.getJedisSummoner().requestJedis()) {
|
||||
return call(jedis);
|
||||
} catch (JedisConnectionException e) {
|
||||
plugin.logFatal("Unable to get connection");
|
||||
|
||||
if (!retry) {
|
||||
// Wait one second before retrying the task
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e1) {
|
||||
throw new RuntimeException("task failed to run", e1);
|
||||
}
|
||||
return run(true);
|
||||
}
|
||||
}
|
||||
|
||||
throw new RuntimeException("task failed to run");
|
||||
}
|
||||
|
||||
protected abstract T call(Jedis jedis);
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package com.imaginarycode.minecraft.redisbungee.internal.util;
|
||||
|
||||
import com.imaginarycode.minecraft.redisbungee.RedisBungeeAPI;
|
||||
import com.imaginarycode.minecraft.redisbungee.internal.summoners.ClusterJedisSummoner;
|
||||
import com.imaginarycode.minecraft.redisbungee.internal.summoners.JedisSummoner;
|
||||
import com.imaginarycode.minecraft.redisbungee.internal.summoners.Summoner;
|
||||
import redis.clients.jedis.Jedis;
|
||||
import redis.clients.jedis.JedisCluster;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public abstract class RedisTask<V> implements Runnable, Callable<V> {
|
||||
|
||||
private final Summoner<?> summoner;
|
||||
private final RedisBungeeAPI api;
|
||||
|
||||
@Override
|
||||
public V call() throws Exception {
|
||||
return execute();
|
||||
}
|
||||
|
||||
public RedisTask(RedisBungeeAPI api) {
|
||||
this.api = api;
|
||||
this.summoner = api.getSummoner();
|
||||
}
|
||||
|
||||
public abstract V singleJedisTask(Jedis jedis);
|
||||
|
||||
public abstract V clusterJedisTask(JedisCluster jedisCluster);
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
this.execute();
|
||||
}
|
||||
|
||||
public V execute(){
|
||||
if (api.getMode() == RedisBungeeMode.SINGLE) {
|
||||
JedisSummoner jedisSummoner = (JedisSummoner) summoner;
|
||||
try (Jedis jedis = jedisSummoner.obtainResource()) {
|
||||
return this.singleJedisTask(jedis);
|
||||
}
|
||||
|
||||
} else if (api.getMode() == RedisBungeeMode.CLUSTER) {
|
||||
ClusterJedisSummoner clusterJedisSummoner = (ClusterJedisSummoner) summoner;
|
||||
return this.clusterJedisTask(clusterJedisSummoner.obtainResource());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -4,16 +4,18 @@ import com.google.common.base.Charsets;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.gson.Gson;
|
||||
import com.imaginarycode.minecraft.redisbungee.RedisBungeeAPI;
|
||||
import com.imaginarycode.minecraft.redisbungee.internal.RedisBungeePlugin;
|
||||
|
||||
import com.imaginarycode.minecraft.redisbungee.internal.util.RedisTask;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import redis.clients.jedis.Jedis;
|
||||
import redis.clients.jedis.JedisCluster;
|
||||
import redis.clients.jedis.Pipeline;
|
||||
import redis.clients.jedis.exceptions.JedisException;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public final class UUIDTranslator {
|
||||
@ -41,7 +43,7 @@ public final class UUIDTranslator {
|
||||
uuidToNameMap.put(uuid, entry);
|
||||
}
|
||||
|
||||
public final UUID getTranslatedUuid(@NonNull String player, boolean expensiveLookups) {
|
||||
public UUID getTranslatedUuid(@NonNull String player, boolean expensiveLookups) {
|
||||
// If the player is online, give them their UUID.
|
||||
// Remember, local data > remote data.
|
||||
if (plugin.getPlayer(player) != null)
|
||||
@ -71,9 +73,9 @@ public final class UUIDTranslator {
|
||||
if (!plugin.isOnlineMode()) {
|
||||
return UUID.nameUUIDFromBytes(("OfflinePlayer:" + player).getBytes(Charsets.UTF_8));
|
||||
}
|
||||
|
||||
// Let's try Redis.
|
||||
try (Jedis jedis = plugin.getJedisSummoner().requestJedis()) {
|
||||
RedisTask<UUID> redisTask = new RedisTask<UUID>(plugin.getApi()) {
|
||||
@Override
|
||||
public UUID singleJedisTask(Jedis jedis) {
|
||||
String stored = jedis.hget("uuid-cache", player.toLowerCase());
|
||||
if (stored != null) {
|
||||
// Found an entry value. Deserialize it.
|
||||
@ -108,6 +110,51 @@ public final class UUIDTranslator {
|
||||
return entry.getValue();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID clusterJedisTask(JedisCluster jedisCluster) {
|
||||
String stored = jedisCluster.hget("uuid-cache", player.toLowerCase());
|
||||
if (stored != null) {
|
||||
// Found an entry value. Deserialize it.
|
||||
CachedUUIDEntry entry = gson.fromJson(stored, CachedUUIDEntry.class);
|
||||
|
||||
// Check for expiry:
|
||||
if (entry.expired()) {
|
||||
jedisCluster.hdel("uuid-cache", player.toLowerCase());
|
||||
// Doesn't hurt to also remove the UUID entry as well.
|
||||
jedisCluster.hdel("uuid-cache", entry.getUuid().toString());
|
||||
} else {
|
||||
nameToUuidMap.put(player.toLowerCase(), entry);
|
||||
uuidToNameMap.put(entry.getUuid(), entry);
|
||||
return entry.getUuid();
|
||||
}
|
||||
}
|
||||
|
||||
// That didn't work. Let's ask Mojang.
|
||||
if (!expensiveLookups || !plugin.isOnlineMode())
|
||||
return null;
|
||||
|
||||
Map<String, UUID> uuidMap1;
|
||||
try {
|
||||
uuidMap1 = new UUIDFetcher(Collections.singletonList(player)).call();
|
||||
} catch (Exception e) {
|
||||
plugin.logFatal("Unable to fetch UUID from Mojang for " + player);
|
||||
return null;
|
||||
}
|
||||
for (Map.Entry<String, UUID> entry : uuidMap1.entrySet()) {
|
||||
if (entry.getKey().equalsIgnoreCase(player)) {
|
||||
persistInfo(entry.getKey(), entry.getValue(), jedisCluster);
|
||||
return entry.getValue();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
// Let's try Redis.
|
||||
try {
|
||||
return redisTask.execute();
|
||||
} catch (JedisException e) {
|
||||
plugin.logFatal("Unable to fetch UUID for " + player);
|
||||
}
|
||||
@ -115,7 +162,7 @@ public final class UUIDTranslator {
|
||||
return null; // Nope, game over!
|
||||
}
|
||||
|
||||
public final String getNameFromUuid(@NonNull UUID player, boolean expensiveLookups) {
|
||||
public String getNameFromUuid(@NonNull UUID player, boolean expensiveLookups) {
|
||||
// If the player is online, give them their UUID.
|
||||
// Remember, local data > remote data.
|
||||
if (plugin.getPlayer(player) != null)
|
||||
@ -130,8 +177,9 @@ public final class UUIDTranslator {
|
||||
uuidToNameMap.remove(player);
|
||||
}
|
||||
|
||||
// Okay, it wasn't locally cached. Let's try Redis.
|
||||
try (Jedis jedis = plugin.getJedisSummoner().requestJedis()) {
|
||||
RedisTask<String> redisTask = new RedisTask<String>(plugin.getApi()) {
|
||||
@Override
|
||||
public String singleJedisTask(Jedis jedis) {
|
||||
String stored = jedis.hget("uuid-cache", player.toString());
|
||||
if (stored != null) {
|
||||
// Found an entry value. Deserialize it.
|
||||
@ -162,29 +210,75 @@ public final class UUIDTranslator {
|
||||
plugin.logFatal("Unable to fetch name from Mojang for " + player);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (name != null) {
|
||||
persistInfo(name, player, jedis);
|
||||
return name;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String clusterJedisTask(JedisCluster jedisCluster) {
|
||||
String stored = jedisCluster.hget("uuid-cache", player.toString());
|
||||
if (stored != null) {
|
||||
// Found an entry value. Deserialize it.
|
||||
CachedUUIDEntry entry = gson.fromJson(stored, CachedUUIDEntry.class);
|
||||
|
||||
// Check for expiry:
|
||||
if (entry.expired()) {
|
||||
jedisCluster.hdel("uuid-cache", player.toString());
|
||||
// Doesn't hurt to also remove the named entry as well.
|
||||
// TODO: Since UUIDs are fixed, we could look up the name and see if the UUID matches.
|
||||
jedisCluster.hdel("uuid-cache", entry.getName());
|
||||
} else {
|
||||
nameToUuidMap.put(entry.getName().toLowerCase(), entry);
|
||||
uuidToNameMap.put(player, entry);
|
||||
return entry.getName();
|
||||
}
|
||||
}
|
||||
|
||||
if (!expensiveLookups || !plugin.isOnlineMode())
|
||||
return null;
|
||||
|
||||
// That didn't work. Let's ask Mojang. This call may fail, because Mojang is insane.
|
||||
String name;
|
||||
try {
|
||||
List<String> nameHist = NameFetcher.nameHistoryFromUuid(player);
|
||||
name = Iterables.getLast(nameHist, null);
|
||||
} catch (Exception e) {
|
||||
plugin.logFatal("Unable to fetch name from Mojang for " + player);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (name != null) {
|
||||
persistInfo(name, player, jedisCluster);
|
||||
return name;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Okay, it wasn't locally cached. Let's try Redis.
|
||||
try {
|
||||
return redisTask.execute();
|
||||
} catch (JedisException e) {
|
||||
plugin.logFatal("Unable to fetch name for " + player);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public final void persistInfo(String name, UUID uuid, Jedis jedis) {
|
||||
public void persistInfo(String name, UUID uuid, Jedis jedis) {
|
||||
addToMaps(name, uuid);
|
||||
String json = gson.toJson(uuidToNameMap.get(uuid));
|
||||
jedis.hmset("uuid-cache", ImmutableMap.of(name.toLowerCase(), json, uuid.toString(), json));
|
||||
}
|
||||
|
||||
public final void persistInfo(String name, UUID uuid, Pipeline jedis) {
|
||||
public void persistInfo(String name, UUID uuid, JedisCluster jedisCluster) {
|
||||
addToMaps(name, uuid);
|
||||
String json = gson.toJson(uuidToNameMap.get(uuid));
|
||||
jedis.hmset("uuid-cache", ImmutableMap.of(name.toLowerCase(), json, uuid.toString(), json));
|
||||
jedisCluster.hmset("uuid-cache", ImmutableMap.of(name.toLowerCase(), json, uuid.toString(), json));
|
||||
}
|
||||
|
||||
private static class CachedUUIDEntry {
|
||||
|
@ -11,7 +11,6 @@ import com.imaginarycode.minecraft.redisbungee.internal.AbstractDataManager;
|
||||
import com.imaginarycode.minecraft.redisbungee.internal.RedisBungeePlugin;
|
||||
import com.imaginarycode.minecraft.redisbungee.events.PubSubMessageEvent;
|
||||
import com.imaginarycode.minecraft.redisbungee.internal.RedisUtil;
|
||||
import com.imaginarycode.minecraft.redisbungee.internal.util.RedisCallable;
|
||||
import net.md_5.bungee.api.AbstractReconnectHandler;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
@ -21,6 +20,7 @@ import net.md_5.bungee.api.plugin.Listener;
|
||||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
import redis.clients.jedis.Jedis;
|
||||
import redis.clients.jedis.JedisCluster;
|
||||
import redis.clients.jedis.Pipeline;
|
||||
|
||||
import java.net.InetAddress;
|
||||
@ -125,6 +125,11 @@ public class RedisBungeeBungeeListener extends AbstractRedisBungeeListener<Login
|
||||
new AbstractDataManager.ServerChangePayload(event.getServer().getInfo().getName(), currentServer))));
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void call(JedisCluster jedisCluster) {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@ import com.imaginarycode.minecraft.redisbungee.events.PlayerChangedServerNetwork
|
||||
import com.imaginarycode.minecraft.redisbungee.events.PlayerJoinedNetworkEvent;
|
||||
import com.imaginarycode.minecraft.redisbungee.events.PubSubMessageEvent;
|
||||
import com.imaginarycode.minecraft.redisbungee.internal.*;
|
||||
import com.imaginarycode.minecraft.redisbungee.internal.summoners.JedisSummoner;
|
||||
import com.imaginarycode.minecraft.redisbungee.internal.summoners.Summoner;
|
||||
import com.imaginarycode.minecraft.redisbungee.internal.summoners.SinglePoolJedisSummoner;
|
||||
import com.imaginarycode.minecraft.redisbungee.internal.util.IOUtil;
|
||||
import com.imaginarycode.minecraft.redisbungee.internal.util.LuaManager;
|
||||
@ -48,7 +48,7 @@ import static com.google.common.base.Preconditions.checkArgument;
|
||||
public class RedisBungeeBungeePlugin extends Plugin implements RedisBungeePlugin<ProxiedPlayer> {
|
||||
private RedisBungeeAPI api;
|
||||
private PubSubListener psl = null;
|
||||
private JedisSummoner jedisSummoner;
|
||||
private Summoner jedisSummoner;
|
||||
private UUIDTranslator uuidTranslator;
|
||||
private RedisBungeeConfiguration configuration;
|
||||
private BungeeDataManager dataManager;
|
||||
@ -503,7 +503,7 @@ public class RedisBungeeBungeePlugin extends Plugin implements RedisBungeePlugin
|
||||
}
|
||||
|
||||
@Override
|
||||
public JedisSummoner getJedisSummoner() {
|
||||
public Summoner getSummoner() {
|
||||
return this.jedisSummoner;
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,6 @@ import com.imaginarycode.minecraft.redisbungee.internal.AbstractDataManager;
|
||||
import com.imaginarycode.minecraft.redisbungee.internal.RedisBungeePlugin;
|
||||
import com.imaginarycode.minecraft.redisbungee.events.PubSubMessageEvent;
|
||||
import com.imaginarycode.minecraft.redisbungee.internal.RedisUtil;
|
||||
import com.imaginarycode.minecraft.redisbungee.internal.util.RedisCallable;
|
||||
import com.velocitypowered.api.event.Continuation;
|
||||
import com.velocitypowered.api.event.PostOrder;
|
||||
import com.velocitypowered.api.event.ResultedEvent;
|
||||
|
@ -13,7 +13,7 @@ import com.imaginarycode.minecraft.redisbungee.events.PlayerChangedServerNetwork
|
||||
import com.imaginarycode.minecraft.redisbungee.events.PlayerJoinedNetworkEvent;
|
||||
import com.imaginarycode.minecraft.redisbungee.events.PubSubMessageEvent;
|
||||
import com.imaginarycode.minecraft.redisbungee.internal.*;
|
||||
import com.imaginarycode.minecraft.redisbungee.internal.summoners.JedisSummoner;
|
||||
import com.imaginarycode.minecraft.redisbungee.internal.summoners.Summoner;
|
||||
import com.imaginarycode.minecraft.redisbungee.internal.summoners.SinglePoolJedisSummoner;
|
||||
import com.imaginarycode.minecraft.redisbungee.internal.util.IOUtil;
|
||||
import com.imaginarycode.minecraft.redisbungee.internal.util.LuaManager;
|
||||
@ -61,7 +61,7 @@ public class RedisBungeeVelocityPlugin implements RedisBungeePlugin<Player> {
|
||||
private final Path dataFolder;
|
||||
private final RedisBungeeAPI api;
|
||||
private final PubSubListener psl;
|
||||
private JedisSummoner jedisSummoner;
|
||||
private Summoner jedisSummoner;
|
||||
private final UUIDTranslator uuidTranslator;
|
||||
private RedisBungeeConfiguration configuration;
|
||||
private final VelocityDataManager dataManager;
|
||||
@ -201,7 +201,7 @@ public class RedisBungeeVelocityPlugin implements RedisBungeePlugin<Player> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public JedisSummoner getJedisSummoner() {
|
||||
public Summoner getSummoner() {
|
||||
return this.jedisSummoner;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user