2
0
mirror of https://github.com/proxiodev/RedisBungee.git synced 2026-04-08 16:10:26 +00:00

Implement network kick

This commit is contained in:
2022-07-19 15:30:45 +04:00
parent f722b8c9d3
commit c848126aa7
13 changed files with 255 additions and 105 deletions

View File

@@ -333,6 +333,30 @@ public class RedisBungeeAPI {
return plugin.getUuidTranslator().getTranslatedUuid(name, expensiveLookups);
}
/**
* Kicks a player from the network
*
* @param playerName player name
* @param message kick message that player will see on kick
* @since 0.8.0
*/
public void kickPlayer(String playerName, String message) {
plugin.kickPlayer(playerName, message);
}
/**
* Kicks a player from the network
*
* @param playerUUID player name
* @param message kick message that player will see on kick
* @since 0.8.0
*/
public void kickPlayer(UUID playerUUID, String message) {
plugin.kickPlayer(playerUUID, message);
}
/**
* This gives you instance of Jedis
*

View File

@@ -25,7 +25,7 @@ import java.util.concurrent.TimeUnit;
* @since 0.3.3
*/
public abstract class AbstractDataManager<P, PL, PD, PS> {
private final RedisBungeePlugin<P> plugin;
protected final RedisBungeePlugin<P> plugin;
private final Cache<UUID, String> serverCache = createCache();
private final Cache<UUID, String> proxyCache = createCache();
private final Cache<UUID, InetAddress> ipCache = createCache();
@@ -44,8 +44,6 @@ public abstract class AbstractDataManager<P, PL, PD, PS> {
.build();
}
private final JsonParser parser = new JsonParser();
public String getServer(final UUID uuid) {
P player = plugin.getPlayer(uuid);
@@ -174,14 +172,16 @@ public abstract class AbstractDataManager<P, PL, PD, PS> {
public abstract void onPubSubMessage(PS event);
public abstract boolean handleKick(UUID target, String message);
protected void handlePubSubMessage(String channel, String message) {
if (!channel.equals("redisbungee-data"))
return;
// Partially deserialize the message so we can look at the action
JsonObject jsonObject = parser.parse(message).getAsJsonObject();
JsonObject jsonObject = JsonParser.parseString(message).getAsJsonObject();
String source = jsonObject.get("source").getAsString();
final String source = jsonObject.get("source").getAsString();
if (source.equals(plugin.getConfiguration().getProxyId()))
return;
@@ -190,24 +190,20 @@ public abstract class AbstractDataManager<P, PL, PD, PS> {
switch (action) {
case JOIN:
final DataManagerMessage<LoginPayload> message1 = gson.fromJson(jsonObject, new TypeToken<DataManagerMessage<LoginPayload>>() {
}.getType());
final DataManagerMessage<LoginPayload> message1 = gson.fromJson(jsonObject, new TypeToken<DataManagerMessage<LoginPayload>>() {}.getType());
proxyCache.put(message1.getTarget(), message1.getSource());
lastOnlineCache.put(message1.getTarget(), (long) 0);
ipCache.put(message1.getTarget(), message1.getPayload().getAddress());
plugin.executeAsync(new Runnable() {
@Override
public void run() {
Object event;
try {
event = plugin.getNetworkJoinEventClass().getDeclaredConstructor(UUID.class).newInstance(message1.getTarget());
} catch (InstantiationException | IllegalAccessException | InvocationTargetException |
NoSuchMethodException e) {
throw new RuntimeException("unable to dispatch an network join event", e);
}
plugin.callEvent(event);
plugin.executeAsync(() -> {
Object event;
try {
event = plugin.getNetworkJoinEventClass().getDeclaredConstructor(UUID.class).newInstance(message1.getTarget());
} catch (InstantiationException | IllegalAccessException | InvocationTargetException |
NoSuchMethodException e) {
throw new RuntimeException("unable to dispatch an network join event", e);
}
plugin.callEvent(event);
});
break;
case LEAVE:
@@ -215,42 +211,40 @@ public abstract class AbstractDataManager<P, PL, PD, PS> {
}.getType());
invalidate(message2.getTarget());
lastOnlineCache.put(message2.getTarget(), message2.getPayload().getTimestamp());
plugin.executeAsync(new Runnable() {
@Override
public void run() {
Object event;
try {
event = plugin.getNetworkQuitEventClass().getDeclaredConstructor(UUID.class).newInstance(message2.getTarget());
} catch (InstantiationException | IllegalAccessException | InvocationTargetException |
NoSuchMethodException e) {
throw new RuntimeException("unable to dispatch an network quit event", e);
}
plugin.callEvent(event);
plugin.executeAsync(() -> {
Object event;
try {
event = plugin.getNetworkQuitEventClass().getDeclaredConstructor(UUID.class).newInstance(message2.getTarget());
} catch (InstantiationException | IllegalAccessException | InvocationTargetException |
NoSuchMethodException e) {
throw new RuntimeException("unable to dispatch an network quit event", e);
}
plugin.callEvent(event);
});
break;
case SERVER_CHANGE:
final DataManagerMessage<ServerChangePayload> message3 = gson.fromJson(jsonObject, new TypeToken<DataManagerMessage<ServerChangePayload>>() {
}.getType());
final DataManagerMessage<ServerChangePayload> message3 = gson.fromJson(jsonObject, new TypeToken<DataManagerMessage<ServerChangePayload>>() {}.getType());
serverCache.put(message3.getTarget(), message3.getPayload().getServer());
plugin.executeAsync(new Runnable() {
@Override
public void run() {
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) {
throw new RuntimeException("unable to dispatch an server change event", e);
}
plugin.callEvent(event);
plugin.executeAsync(() -> {
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) {
throw new RuntimeException("unable to dispatch an server change event", e);
}
plugin.callEvent(event);
});
break;
case KICK:
final DataManagerMessage<KickPayload> kickPayload = gson.fromJson(jsonObject, new TypeToken<DataManagerMessage<KickPayload>>() {}.getType());
plugin.executeAsync(() -> handleKick(kickPayload.target, kickPayload.payload.message));
break;
}
}
public static class DataManagerMessage<T> {
public static class DataManagerMessage<T extends Payload> {
private final UUID target;
private final String source;
private final Action action; // for future use!
@@ -282,11 +276,27 @@ public abstract class AbstractDataManager<P, PL, PD, PS> {
public enum Action {
JOIN,
LEAVE,
KICK,
SERVER_CHANGE
}
}
public static class LoginPayload {
public static abstract class Payload {}
public static class KickPayload extends Payload {
private final String message;
public KickPayload(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}
public static class LoginPayload extends Payload{
private final InetAddress address;
public LoginPayload(InetAddress address) {
@@ -298,7 +308,7 @@ public abstract class AbstractDataManager<P, PL, PD, PS> {
}
}
public static class ServerChangePayload {
public static class ServerChangePayload extends Payload{
private final String server;
private final String oldServer;
@@ -317,7 +327,7 @@ public abstract class AbstractDataManager<P, PL, PD, PS> {
}
public static class LogoutPayload {
public static class LogoutPayload extends Payload{
private final long timestamp;
public LogoutPayload(long timestamp) {

View File

@@ -67,4 +67,6 @@ public abstract class AbstractRedisBungeeListener<LE, PLE, PD, SC, PP, PM, PS> {
}
public abstract void onPubSubMessage(PS event);
}

View File

@@ -94,6 +94,10 @@ public interface RedisBungeePlugin<P> extends EventsPlatform {
void loadConfig() throws Exception;
void kickPlayer(UUID playerUniqueId, String message);
void kickPlayer(String playerName, String message);
RedisBungeeMode getRedisBungeeMode();
Long getRedisClusterTime();

View File

@@ -1,48 +1,9 @@
package com.imaginarycode.minecraft.redisbungee.api.util;
import com.google.common.annotations.VisibleForTesting;
import com.google.gson.Gson;
import com.imaginarycode.minecraft.redisbungee.RedisBungeeAPI;
import com.imaginarycode.minecraft.redisbungee.api.AbstractDataManager;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.Pipeline;
import java.util.UUID;
@VisibleForTesting
public class RedisUtil {
private static final Gson gson = new Gson();
public static void cleanUpPlayer(String player, Jedis rsc) {
rsc.srem("proxy:" + RedisBungeeAPI.getRedisBungeeApi().getProxyId() + ":usersOnline", player);
rsc.hdel("player:" + player, "server", "ip", "proxy");
long timestamp = System.currentTimeMillis();
rsc.hset("player:" + player, "online", String.valueOf(timestamp));
rsc.publish("redisbungee-data", gson.toJson(new AbstractDataManager.DataManagerMessage<>(
UUID.fromString(player), RedisBungeeAPI.getRedisBungeeApi().getProxyId(), AbstractDataManager.DataManagerMessage.Action.LEAVE,
new AbstractDataManager.LogoutPayload(timestamp))));
}
public static void cleanUpPlayer(String player, Pipeline rsc) {
rsc.srem("proxy:" + RedisBungeeAPI.getRedisBungeeApi().getProxyId() + ":usersOnline", player);
rsc.hdel("player:" + player, "server", "ip", "proxy");
long timestamp = System.currentTimeMillis();
rsc.hset("player:" + player, "online", String.valueOf(timestamp));
rsc.publish("redisbungee-data", gson.toJson(new AbstractDataManager.DataManagerMessage<>(
UUID.fromString(player), RedisBungeeAPI.getRedisBungeeApi().getProxyId(), AbstractDataManager.DataManagerMessage.Action.LEAVE,
new AbstractDataManager.LogoutPayload(timestamp))));
}
public static void cleanUpPlayer(String player, JedisCluster rsc) {
rsc.srem("proxy:" + RedisBungeeAPI.getRedisBungeeApi().getProxyId() + ":usersOnline", player);
rsc.hdel("player:" + player, "server", "ip", "proxy");
long timestamp = System.currentTimeMillis();
rsc.hset("player:" + player, "online", String.valueOf(timestamp));
rsc.publish("redisbungee-data", gson.toJson(new AbstractDataManager.DataManagerMessage<>(
UUID.fromString(player), RedisBungeeAPI.getRedisBungeeApi().getProxyId(), AbstractDataManager.DataManagerMessage.Action.LEAVE,
new AbstractDataManager.LogoutPayload(timestamp))));
}
public static boolean isRedisVersionRight(String redisVersion) {
String[] args = redisVersion.split("\\.");
if (args.length < 2) {

View File

@@ -0,0 +1,65 @@
package com.imaginarycode.minecraft.redisbungee.api.util.payload;
import com.google.gson.Gson;
import com.imaginarycode.minecraft.redisbungee.RedisBungeeAPI;
import com.imaginarycode.minecraft.redisbungee.api.AbstractDataManager;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.Pipeline;
import java.util.UUID;
public class PayloadUtils {
private static final Gson gson = new Gson();
public static void cleanUpPlayer(String uuid, Jedis rsc) {
rsc.srem("proxy:" + RedisBungeeAPI.getRedisBungeeApi().getProxyId() + ":usersOnline", uuid);
rsc.hdel("player:" + uuid, "server", "ip", "proxy");
long timestamp = System.currentTimeMillis();
rsc.hset("player:" + uuid, "online", String.valueOf(timestamp));
rsc.publish("redisbungee-data", gson.toJson(new AbstractDataManager.DataManagerMessage<>(
UUID.fromString(uuid), RedisBungeeAPI.getRedisBungeeApi().getProxyId(), AbstractDataManager.DataManagerMessage.Action.LEAVE,
new AbstractDataManager.LogoutPayload(timestamp))));
}
public static void cleanUpPlayer(String uuid, Pipeline rsc) {
rsc.srem("proxy:" + RedisBungeeAPI.getRedisBungeeApi().getProxyId() + ":usersOnline", uuid);
rsc.hdel("player:" + uuid, "server", "ip", "proxy");
long timestamp = System.currentTimeMillis();
rsc.hset("player:" + uuid, "online", String.valueOf(timestamp));
rsc.publish("redisbungee-data", gson.toJson(new AbstractDataManager.DataManagerMessage<>(
UUID.fromString(uuid), RedisBungeeAPI.getRedisBungeeApi().getProxyId(), AbstractDataManager.DataManagerMessage.Action.LEAVE,
new AbstractDataManager.LogoutPayload(timestamp))));
}
public static void cleanUpPlayer(String uuid, JedisCluster rsc) {
rsc.srem("proxy:" + RedisBungeeAPI.getRedisBungeeApi().getProxyId() + ":usersOnline", uuid);
rsc.hdel("player:" + uuid, "server", "ip", "proxy");
long timestamp = System.currentTimeMillis();
rsc.hset("player:" + uuid, "online", String.valueOf(timestamp));
rsc.publish("redisbungee-data", gson.toJson(new AbstractDataManager.DataManagerMessage<>(
UUID.fromString(uuid), RedisBungeeAPI.getRedisBungeeApi().getProxyId(), AbstractDataManager.DataManagerMessage.Action.LEAVE,
new AbstractDataManager.LogoutPayload(timestamp))));
}
public static void kickPlayer(UUID uuid, String message, Pipeline pipeline) {
System.out.println(uuid);
pipeline.publish("redisbungee-data", gson.toJson(new AbstractDataManager.DataManagerMessage<>(
uuid, RedisBungeeAPI.getRedisBungeeApi().getProxyId(), AbstractDataManager.DataManagerMessage.Action.KICK,
new AbstractDataManager.KickPayload(message))));
}
public static void kickPlayer(UUID uuid, String message, Jedis jedis) {
System.out.println(uuid);
jedis.publish("redisbungee-data", gson.toJson(new AbstractDataManager.DataManagerMessage<>(
uuid, RedisBungeeAPI.getRedisBungeeApi().getProxyId(), AbstractDataManager.DataManagerMessage.Action.KICK,
new AbstractDataManager.KickPayload(message))));
}
public static void kickPlayer(UUID uuid, String message, JedisCluster jedisCluster) {
System.out.println(uuid);
jedisCluster.publish("redisbungee-data", gson.toJson(new AbstractDataManager.DataManagerMessage<>(
uuid, RedisBungeeAPI.getRedisBungeeApi().getProxyId(), AbstractDataManager.DataManagerMessage.Action.KICK,
new AbstractDataManager.KickPayload(message))));
}
}