2
0
mirror of https://github.com/proxiodev/RedisBungee.git synced 2026-05-03 11:40:29 +00:00

21 Commits

Author SHA1 Message Date
0f0f707ef7 bump version 2023-03-17 12:23:46 +04:00
441a12bb36 fix error being thrown getServerFor in Bungeecord/Velocity in the api closes #64
when plugins messing around with proxy internals (eg: limboapi) the field server in redis data of the player set to null which can become problematic for velocity due checking of null in velocity but i applied the same stuff to the bungeecord version aswell and document it in the javadocs
2023-03-17 12:15:10 +04:00
冰砚炽
0534970368 Fix PlayerList not returning server name when it is not ALL (#62) 2023-01-31 12:40:06 +04:00
20f9143ea5 bump version 2022-12-31 07:26:05 +04:00
1a2459b64e deprecated NameFetcher api 2022-12-31 07:23:35 +04:00
AlessioDP
c3888c8f65 Fix NullPointerException due plugin instance for jedis tasks in UUIDTranslator/AbstractDataManager (#57) 2022-12-25 06:26:53 +04:00
c8362a44ec add config option to restore old kick behavior pre 0.9.0 2022-11-27 12:29:13 +04:00
31e461a11c change url of big uuid cache 2022-11-27 12:10:29 +04:00
a9ea04c2c0 missed location were it wasn't using the constant 2022-11-24 01:41:47 +04:00
ddfc689c2d expose CachedUUIDEntry Class 2022-11-16 11:32:20 +04:00
ae6961ef24 bump version 2022-11-16 08:22:57 +04:00
8318bcd1bf update some logs in configloader 2022-11-16 08:22:30 +04:00
0b9fd6d7ff Make sure server field is withen map than calling redis seperatly 2022-11-14 08:45:55 +04:00
a526298d1c change one of the comments in PlayerUtils 2022-11-14 08:42:54 +04:00
c69b1e214e add missing final keyword to PROXY_TIMEOUT var 2022-11-14 08:40:46 +04:00
e5f0075a58 add messages config, change some jedis/redis depercated apis, bump to 0.9.0, new logging from another locations handling. 2022-11-11 20:30:16 +04:00
748bc13568 Fix ssl connections on PooledConnections
useSSL in configloader wasn't passing it to the ConnectionProvider
2022-11-05 15:44:51 +04:00
5e3ce725de Include some changes to ssl notes
and little change for compatiblity pool
2022-11-05 15:43:23 +04:00
92bb0030de move PlayerUtils code from platforms to the api 2022-11-02 08:38:25 +04:00
d8c21edc7a Bump version to 0.8.1 2022-11-02 07:58:13 +04:00
87a2b93537 update jitpack location 2022-11-01 10:13:36 +04:00
28 changed files with 291 additions and 188 deletions

View File

@@ -47,11 +47,11 @@ SpigotMC resource page: [click](https://www.spigotmc.org/resources/redisbungee.8
| 7.x.x | ✔ |
## Implementing RedisBungee in your plugin: [![RedisBungee Build](https://github.com/proxiodev/RedisBungee/actions/workflows/maven.yml/badge.svg)](https://github.com/Limework/RedisBungee/actions/workflows/maven.yml) [![](https://jitpack.io/v/limework/redisbungee.svg)](https://jitpack.io/#limework/redisbungee)
## Implementing RedisBungee in your plugin: [![RedisBungee Build](https://github.com/proxiodev/RedisBungee/actions/workflows/maven.yml/badge.svg)](https://github.com/Limework/RedisBungee/actions/workflows/maven.yml) [![](https://jitpack.io/v/ProxioDev/redisbungee.svg)](https://jitpack.io/#ProxioDev/redisbungee)
RedisBungee is distributed as a [maven](https://maven.apache.org) project.
By using jitpack [![](https://jitpack.io/v/limework/redisbungee.svg)](https://jitpack.io/#limework/redisbungee)
By using jitpack [![](https://jitpack.io/v/ProxioDev/redisbungee.svg)](https://jitpack.io/#ProxioDev/redisbungee)
## Setup jitpack repository
```xml
@@ -66,7 +66,7 @@ By using jitpack [![](https://jitpack.io/v/limework/redisbungee.svg)](https://ji
add this in your project dependencies
```xml
<dependency>
<groupId>com.github.limework.redisbungee</groupId>
<groupId>com.github.proxiodev.redisbungee</groupId>
<artifactId>RedisBungee-Bungee</artifactId>
<version>VERSION</version>
<scope>provided</scope>
@@ -86,7 +86,7 @@ depends: [ RedisBungee ]
## [Velocity](https://github.com/PaperMC/Velocity)
```xml
<dependency>
<groupId>com.github.limework.redisbungee</groupId>
<groupId>com.github.proxiodev.redisbungee</groupId>
<artifactId>RedisBungee-Velocity</artifactId>
<version>VERSION</version>
<scope>provided</scope>

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>RedisBungee</artifactId>
<groupId>com.imaginarycode.minecraft</groupId>
<version>0.8.0-SNAPSHOT</version>
<version>0.10.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -20,6 +20,7 @@ import com.imaginarycode.minecraft.redisbungee.api.summoners.JedisClusterSummone
import com.imaginarycode.minecraft.redisbungee.api.summoners.JedisPooledSummoner;
import com.imaginarycode.minecraft.redisbungee.api.summoners.Summoner;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPool;
@@ -81,8 +82,9 @@ public abstract class AbstractRedisBungeeAPI {
* as well, and will return local information on them.
*
* @param player a player uuid
* @return a String name for the server the player is on.
* @return a String name for the server the player is on. Can be Null if plugins is doing weird stuff to the proxy internals
*/
@Nullable
public final String getServerNameFor(@NonNull UUID player) {
return plugin.getDataManager().getServer(player);
}

View File

@@ -59,7 +59,7 @@ public abstract class AbstractDataManager<P, PL, PD, PS> {
return plugin.isPlayerOnAServer(player) ? plugin.getPlayerServerName(player) : null;
try {
return serverCache.get(uuid, new RedisTask<String>(plugin.getAbstractRedisBungeeApi()) {
return serverCache.get(uuid, new RedisTask<String>(plugin) {
@Override
public String unifiedJedisTask(UnifiedJedis unifiedJedis) {
return Objects.requireNonNull(unifiedJedis.hget("player:" + uuid, "server"), "user not found");
@@ -82,7 +82,7 @@ public abstract class AbstractDataManager<P, PL, PD, PS> {
return plugin.getConfiguration().getProxyId();
try {
return proxyCache.get(uuid, new RedisTask<String>(plugin.getAbstractRedisBungeeApi()) {
return proxyCache.get(uuid, new RedisTask<String>(plugin) {
@Override
public String unifiedJedisTask(UnifiedJedis unifiedJedis) {
return Objects.requireNonNull(unifiedJedis.hget("player:" + uuid, "proxy"), "user not found");
@@ -103,7 +103,7 @@ public abstract class AbstractDataManager<P, PL, PD, PS> {
return plugin.getPlayerIp(player);
try {
return ipCache.get(uuid, new RedisTask<InetAddress>(plugin.getAbstractRedisBungeeApi()) {
return ipCache.get(uuid, new RedisTask<InetAddress>(plugin) {
@Override
public InetAddress unifiedJedisTask(UnifiedJedis unifiedJedis) {
String result = unifiedJedis.hget("player:" + uuid, "ip");
@@ -127,7 +127,7 @@ public abstract class AbstractDataManager<P, PL, PD, PS> {
return 0;
try {
return lastOnlineCache.get(uuid, new RedisTask<Long>(plugin.getAbstractRedisBungeeApi()) {
return lastOnlineCache.get(uuid, new RedisTask<Long>(plugin) {
@Override
public Long unifiedJedisTask(UnifiedJedis unifiedJedis) {

View File

@@ -23,10 +23,6 @@ import java.util.Map;
public abstract class AbstractRedisBungeeListener<LE, PLE, PD, SC, PP, PM, PS> {
protected static final String ALREADY_LOGGED_IN = "§cYou are already logged on to this server. \n\nIt may help to try logging in again in a few minutes.\nIf this does not resolve your issue, please contact staff.";
protected static final String ONLINE_MODE_RECONNECT = "§cWhoops! You need to reconnect\n\nWe found someone online using your username. They were kicked and you may reconnect.\nIf this does not work, please contact staff.";
protected final RedisBungeePlugin<?> plugin;
protected final List<InetAddress> exemptAddresses;
protected final Gson gson = new Gson();

View File

@@ -67,7 +67,7 @@ public interface RedisBungeePlugin<P> extends EventsPlatform {
String v = stringStringEntry.getValue();
long heartbeatTime = Long.parseLong(v);
if (heartbeatTime + 30 >= redisTime) {
if (heartbeatTime + RedisUtil.PROXY_TIMEOUT >= redisTime) {
total = total + unifiedJedis.scard("proxy:" + k + ":usersOnline");
}
}

View File

@@ -11,6 +11,8 @@
package com.imaginarycode.minecraft.redisbungee.api.config;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.reflect.TypeToken;
import com.imaginarycode.minecraft.redisbungee.api.RedisBungeeMode;
import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin;
@@ -39,11 +41,6 @@ public interface ConfigLoader {
loadConfig(plugin, dataFolder.toPath());
}
// There currently a problem with the SSL/TLS connections
// looking into the Jedis source code you can pass some form of
// Domain Validation, SSL factory from javax packages
// todo: create Domain valdiation
// todo: add new config options for ssl certs locations
default void loadConfig(RedisBungeePlugin<?> plugin, Path dataFolder) throws IOException {
Path configFile = createConfigFile(dataFolder);
final YAMLConfigurationLoader yamlConfigurationFileLoader = YAMLConfigurationLoader.builder().setPath(configFile).build();
@@ -55,7 +52,8 @@ public interface ConfigLoader {
final boolean useSSL = node.getNode("useSSL").getBoolean(false);
final boolean overrideBungeeCommands = node.getNode("override-bungee-commands").getBoolean(false);
final boolean registerLegacyCommands = node.getNode("register-legacy-commands").getBoolean(false);
String redisPassword = node.getNode("redis-password").getString(null);
final boolean restoreOldKickBehavior = node.getNode("disable-kick-when-online").getBoolean(false);
String redisPassword = node.getNode("redis-password").getString("");
String proxyId = node.getNode("proxy-id").getString("test-1");
final int maxConnections = node.getNode("max-redis-connections").getInt(10);
List<String> exemptAddresses;
@@ -66,15 +64,12 @@ public interface ConfigLoader {
}
// check redis password
if (redisPassword != null && (redisPassword.isEmpty() || redisPassword.equals("none"))) {
if ((redisPassword.isEmpty() || redisPassword.equals("none"))) {
redisPassword = null;
plugin.logWarn("INSECURE setup was detected Please set password for your redis instance.");
plugin.logWarn("password is empty");
}
if (redisPassword == null) {
plugin.logWarn("INSECURE setup was detected Please set password for your redis instance.");
}
if (!useSSL) {
plugin.logWarn("INSECURE setup was detected Please setup ssl for your redis instance.");
if (useSSL) {
plugin.logInfo("Using ssl");
}
// Configuration sanity checks.
if (proxyId == null || proxyId.isEmpty()) {
@@ -87,7 +82,7 @@ public interface ConfigLoader {
} else {
plugin.logInfo("Loaded proxy id " + proxyId);
}
RedisBungeeConfiguration configuration = new RedisBungeeConfiguration(proxyId, exemptAddresses, registerLegacyCommands, overrideBungeeCommands);
RedisBungeeConfiguration configuration = new RedisBungeeConfiguration(proxyId, exemptAddresses, registerLegacyCommands, overrideBungeeCommands, getMessagesFromPath(createMessagesFile(dataFolder)), restoreOldKickBehavior);
Summoner<?> summoner;
RedisBungeeMode redisBungeeMode;
if (node.getNode("cluster-mode-enabled").getBoolean(false)) {
@@ -126,7 +121,7 @@ public interface ConfigLoader {
GenericObjectPoolConfig<Connection> poolConfig = new GenericObjectPoolConfig<>();
poolConfig.setMaxTotal(maxConnections);
poolConfig.setBlockWhenExhausted(true);
summoner = new JedisPooledSummoner(new PooledConnectionProvider(new ConnectionFactory(new HostAndPort(redisServer, redisPort), DefaultJedisClientConfig.builder().timeoutMillis(5000).password(redisPassword).build()), poolConfig), jedisPool);
summoner = new JedisPooledSummoner(new PooledConnectionProvider(new ConnectionFactory(new HostAndPort(redisServer, redisPort), DefaultJedisClientConfig.builder().timeoutMillis(5000).ssl(useSSL).password(redisPassword).build()), poolConfig), jedisPool);
redisBungeeMode = RedisBungeeMode.SINGLE;
}
plugin.logInfo("Successfully connected to Redis.");
@@ -135,6 +130,30 @@ public interface ConfigLoader {
void onConfigLoad(RedisBungeeConfiguration configuration, Summoner<?> summoner, RedisBungeeMode mode);
default ImmutableMap<RedisBungeeConfiguration.MessageType, String> getMessagesFromPath(Path path) throws IOException {
final YAMLConfigurationLoader yamlConfigurationFileLoader = YAMLConfigurationLoader.builder().setPath(path).build();
ConfigurationNode node = yamlConfigurationFileLoader.load();
HashMap<RedisBungeeConfiguration.MessageType, String> messages = new HashMap<>();
messages.put(RedisBungeeConfiguration.MessageType.LOGGED_IN_OTHER_LOCATION, node.getNode("logged-in-other-location").getString("§cLogged in from another location."));
messages.put(RedisBungeeConfiguration.MessageType.ALREADY_LOGGED_IN, node.getNode("already-logged-in").getString("§cYou are already logged in!"));
return ImmutableMap.copyOf(messages);
}
default Path createMessagesFile(Path dataFolder) throws IOException {
if (Files.notExists(dataFolder)) {
Files.createDirectory(dataFolder);
}
Path file = dataFolder.resolve("messages.yml");
if (Files.notExists(file)) {
try (InputStream in = getClass().getClassLoader().getResourceAsStream("messages.yml")) {
Files.createFile(file);
assert in != null;
Files.copy(in, file, StandardCopyOption.REPLACE_EXISTING);
}
}
return file;
}
default Path createConfigFile(Path dataFolder) throws IOException {
if (Files.notExists(dataFolder)) {
Files.createDirectory(dataFolder);
@@ -158,8 +177,6 @@ public interface ConfigLoader {
Path oldConfigPath = dataFolder.resolve("config.yml");
Files.move(oldConfigPath, oldConfigFolder.resolve(UUID.randomUUID() + "_config.yml"));
createConfigFile(dataFolder);
}
}

View File

@@ -11,23 +11,33 @@
package com.imaginarycode.minecraft.redisbungee.api.config;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.net.InetAddresses;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.List;
public class RedisBungeeConfiguration {
public enum MessageType {
LOGGED_IN_OTHER_LOCATION,
ALREADY_LOGGED_IN
}
private final ImmutableMap<MessageType, String> messages;
public static final int CONFIG_VERSION = 1;
private final String proxyId;
private final List<InetAddress> exemptAddresses;
private final boolean registerLegacyCommands;
private final boolean overrideBungeeCommands;
public RedisBungeeConfiguration(String proxyId, List<String> exemptAddresses, boolean registerLegacyCommands, boolean overrideBungeeCommands) {
this.proxyId = proxyId;
private final boolean restoreOldKickBehavior;
public RedisBungeeConfiguration(String proxyId, List<String> exemptAddresses, boolean registerLegacyCommands, boolean overrideBungeeCommands, ImmutableMap<MessageType, String> messages, boolean restoreOldKickBehavior) {
this.proxyId = proxyId;
this.messages = messages;
ImmutableList.Builder<InetAddress> addressBuilder = ImmutableList.builder();
for (String s : exemptAddresses) {
addressBuilder.add(InetAddresses.forString(s));
@@ -35,8 +45,8 @@ public class RedisBungeeConfiguration {
this.exemptAddresses = addressBuilder.build();
this.registerLegacyCommands = registerLegacyCommands;
this.overrideBungeeCommands = overrideBungeeCommands;
this.restoreOldKickBehavior = restoreOldKickBehavior;
}
public String getProxyId() {
return proxyId;
}
@@ -52,4 +62,12 @@ public class RedisBungeeConfiguration {
public boolean doOverrideBungeeCommands() {
return overrideBungeeCommands;
}
public ImmutableMap<MessageType, String> getMessages() {
return messages;
}
public boolean restoreOldKickBehavior() {
return restoreOldKickBehavior;
}
}

View File

@@ -40,7 +40,7 @@ public class InitialUtils {
}
long uuidCacheSize = unifiedJedis.hlen("uuid-cache");
if (uuidCacheSize > 750000) {
plugin.logInfo("Looks like you have a really big UUID cache! Run https://www.spigotmc.org/resources/redisbungeecleaner.8505/ as soon as possible.");
plugin.logInfo("Looks like you have a really big UUID cache! Run https://github.com/ProxioDev/Brains");
}
break;
}

View File

@@ -4,7 +4,7 @@ import com.google.common.annotations.VisibleForTesting;
@VisibleForTesting
public class RedisUtil {
public static int PROXY_TIMEOUT = 30;
public final static int PROXY_TIMEOUT = 30;
public static boolean isRedisVersionRight(String redisVersion) {
String[] args = redisVersion.split("\\.");
if (args.length < 2) {

View File

@@ -3,19 +3,55 @@ package com.imaginarycode.minecraft.redisbungee.api.util.player;
import com.imaginarycode.minecraft.redisbungee.AbstractRedisBungeeAPI;
import redis.clients.jedis.UnifiedJedis;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import static com.imaginarycode.minecraft.redisbungee.api.util.payload.PayloadUtils.playerJoinPayload;
import static com.imaginarycode.minecraft.redisbungee.api.util.payload.PayloadUtils.playerQuitPayload;
public class PlayerUtils {
public static void cleanUpPlayer(String uuid, UnifiedJedis rsc, boolean firePayload) {
final long timestamp = System.currentTimeMillis();
final boolean isKickedFromOtherLocation = isKickedOtherLocation(uuid, rsc);
rsc.srem("proxy:" + AbstractRedisBungeeAPI.getAbstractRedisBungeeAPI().getProxyId() + ":usersOnline", uuid);
rsc.hdel("player:" + uuid, "server", "ip", "proxy");
long timestamp = System.currentTimeMillis();
rsc.hset("player:" + uuid, "online", String.valueOf(timestamp));
if (firePayload) {
if (!isKickedFromOtherLocation) {
rsc.hdel("player:" + uuid, "server", "ip", "proxy");
rsc.hset("player:" + uuid, "online", String.valueOf(timestamp));
}
if (firePayload && !isKickedFromOtherLocation) {
playerQuitPayload(uuid, rsc, timestamp);
}
}
public static void setKickedOtherLocation(String uuid, UnifiedJedis unifiedJedis) {
// set anything for sake of exists check. then expire it after 2 seconds. should be great?
unifiedJedis.set("kicked-other-location::" + uuid, "0");
unifiedJedis.expire("kicked-other-location::" + uuid, 2);
}
public static boolean isKickedOtherLocation(String uuid, UnifiedJedis unifiedJedis) {
return unifiedJedis.exists("kicked-other-location::" + uuid);
}
public static void createPlayer(UUID uuid, UnifiedJedis unifiedJedis, String currentServer, InetAddress hostname, boolean fireEvent) {
final boolean isKickedFromOtherLocation = isKickedOtherLocation(uuid.toString(), unifiedJedis);
Map<String, String> playerData = new HashMap<>(4);
playerData.put("online", "0");
playerData.put("ip", hostname.getHostName());
playerData.put("proxy", AbstractRedisBungeeAPI.getAbstractRedisBungeeAPI().getProxyId());
if (currentServer != null) {
playerData.put("server", currentServer);
}
unifiedJedis.sadd("proxy:" + AbstractRedisBungeeAPI.getAbstractRedisBungeeAPI().getProxyId() + ":usersOnline", uuid.toString());
unifiedJedis.hset("player:" + uuid, playerData);
if (fireEvent && !isKickedFromOtherLocation) {
playerJoinPayload(uuid, unifiedJedis, hostname);
}
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (c) 2013-present RedisBungee contributors
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*/
package com.imaginarycode.minecraft.redisbungee.api.util.uuid;
import java.util.Calendar;
import java.util.UUID;
public class CachedUUIDEntry {
private final String name;
private final UUID uuid;
private final Calendar expiry;
public CachedUUIDEntry(String name, UUID uuid, Calendar expiry) {
this.name = name;
this.uuid = uuid;
this.expiry = expiry;
}
public String getName() {
return name;
}
public UUID getUuid() {
return uuid;
}
public Calendar getExpiry() {
return expiry;
}
public boolean expired() {
return Calendar.getInstance().after(expiry);
}
}

View File

@@ -1,3 +1,13 @@
/*
* Copyright (c) 2013-present RedisBungee contributors
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*/
package com.imaginarycode.minecraft.redisbungee.api.util.uuid;
import com.google.gson.Gson;
@@ -11,32 +21,38 @@ import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@Deprecated
public class NameFetcher {
private static OkHttpClient httpClient;
private static final Gson gson = new Gson();
@Deprecated
public static void setHttpClient(OkHttpClient httpClient) {
NameFetcher.httpClient = httpClient;
throw new UnsupportedOperationException("Due mojang disabled the Names API NameFetcher no longer functions and has been disabled");
// NameFetcher.httpClient = httpClient;
}
@Deprecated
public static List<String> nameHistoryFromUuid(UUID uuid) throws IOException {
String url = "https://api.mojang.com/user/profiles/" + uuid.toString().replace("-", "") + "/names";
Request request = new Request.Builder().url(url).get().build();
ResponseBody body = httpClient.newCall(request).execute().body();
String response = body.string();
body.close();
Type listType = new TypeToken<List<Name>>() {
}.getType();
List<Name> names = gson.fromJson(response, listType);
List<String> humanNames = new ArrayList<>();
for (Name name : names) {
humanNames.add(name.name);
}
return humanNames;
throw new UnsupportedOperationException("Due mojang disabled the Names API NameFetcher no longer functions and has been disabled");
// String url = "https://api.mojang.com/user/profiles/" + uuid.toString().replace("-", "") + "/names";
// Request request = new Request.Builder().url(url).get().build();
// ResponseBody body = httpClient.newCall(request).execute().body();
// String response = body.string();
// body.close();
//
// Type listType = new TypeToken<List<Name>>() {
// }.getType();
// List<Name> names = gson.fromJson(response, listType);
//
// List<String> humanNames = new ArrayList<>();
// for (Name name : names) {
// humanNames.add(name.name);
// }
// return humanNames;
}
@Deprecated
public static class Name {
private String name;
private long changedToAt;

View File

@@ -1,3 +1,13 @@
/*
* Copyright (c) 2013-present RedisBungee contributors
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*/
package com.imaginarycode.minecraft.redisbungee.api.util.uuid;
import com.google.common.collect.ImmutableList;

View File

@@ -1,3 +1,13 @@
/*
* Copyright (c) 2013-present RedisBungee contributors
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*/
package com.imaginarycode.minecraft.redisbungee.api.util.uuid;
import com.google.common.base.Charsets;
@@ -70,7 +80,7 @@ public final class UUIDTranslator {
if (!plugin.isOnlineMode()) {
return UUID.nameUUIDFromBytes(("OfflinePlayer:" + player).getBytes(Charsets.UTF_8));
}
RedisTask<UUID> redisTask = new RedisTask<UUID>(plugin.getAbstractRedisBungeeApi()) {
RedisTask<UUID> redisTask = new RedisTask<UUID>(plugin) {
@Override
public UUID unifiedJedisTask(UnifiedJedis unifiedJedis) {
String stored = unifiedJedis.hget("uuid-cache", player.toLowerCase());
@@ -135,7 +145,7 @@ public final class UUIDTranslator {
uuidToNameMap.remove(player);
}
RedisTask<String> redisTask = new RedisTask<String>(plugin.getAbstractRedisBungeeApi()) {
RedisTask<String> redisTask = new RedisTask<String>(plugin) {
@Override
public String unifiedJedisTask(UnifiedJedis unifiedJedis) {
String stored = unifiedJedis.hget("uuid-cache", player.toString());
@@ -160,10 +170,14 @@ public final class UUIDTranslator {
return null;
// That didn't work. Let's ask Mojang. This call may fail, because Mojang is insane.
//
// UPDATE: Mojang has removed the API somewhere in september/2022 due privacy issues
// this is expected to fail now, so we will keep logging it until we figure out something or remove name fetching completely
// Name fetching class was deprecated as result
String name;
try {
List<String> nameHist = NameFetcher.nameHistoryFromUuid(player);
name = Iterables.getLast(nameHist, null);
plugin.logFatal("Due Mojang removing the naming API, we were unable to fetch player names.");
name = Iterables.getLast(NameFetcher.nameHistoryFromUuid(player));
} catch (Exception e) {
plugin.logFatal("Unable to fetch name from Mojang for " + player);
return null;
@@ -191,34 +205,8 @@ public final class UUIDTranslator {
public void persistInfo(String name, UUID uuid, UnifiedJedis unifiedJedis) {
addToMaps(name, uuid);
String json = gson.toJson(uuidToNameMap.get(uuid));
unifiedJedis.hmset("uuid-cache", ImmutableMap.of(name.toLowerCase(), json, uuid.toString(), json));
unifiedJedis.hset("uuid-cache", ImmutableMap.of(name.toLowerCase(), json, uuid.toString(), json));
}
private static class CachedUUIDEntry {
private final String name;
private final UUID uuid;
private final Calendar expiry;
public CachedUUIDEntry(String name, UUID uuid, Calendar expiry) {
this.name = name;
this.uuid = uuid;
this.expiry = expiry;
}
public String getName() {
return name;
}
public UUID getUuid() {
return uuid;
}
public Calendar getExpiry() {
return expiry;
}
public boolean expired() {
return Calendar.getInstance().after(expiry);
}
}
}

View File

@@ -32,15 +32,15 @@ redis-password: ""
# inefficient plugins or a lot of players.
max-redis-connections: 10
# since redis can support ssl by version 6 you can use ssl in redis bungee too!
# since redis can support ssl by version 6 you can use ssl / tls in redis bungee too!
# but there is more configuration needed to work see https://github.com/ProxioDev/RedisBungee/issues/18
# in cluster mode using ssl without password is ignored due fact is not supported in Jedis lib
# Keep note that SSL/TLS connections will decrease redis performance so use it when needed.
useSSL: false
# An identifier for this BungeeCord / Velocity instance. Will randomly generate if leaving it blank.
proxy-id: "test-1"
# In version 0.8.0 Internally now uses JedisPooled instead of Jedis, JedisPool.
# since version 0.8.0 Internally now uses JedisPooled instead of Jedis, JedisPool.
# which will break compatibility with old plugins that uses RedisBungee JedisPool
# so to mitigate this issue, we will instruct RedisBungee to init an JedisPool for compatibility reasons.
# enabled by default
@@ -68,5 +68,10 @@ override-bungee-commands: false
# restart scripts.
exempt-ip-addresses: []
# restore old login when online behavior before 0.9.0 update
# uncomment to enable it
# disable-kick-when-online: true
# Config version DO NOT CHANGE!!!!
config-version: 1

View File

@@ -0,0 +1,2 @@
logged-in-other-location: "§cYou logged in from another location!"
already-logged-in: "§cYou are already logged in!"

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>RedisBungee</artifactId>
<groupId>com.imaginarycode.minecraft</groupId>
<version>0.8.0-SNAPSHOT</version>
<version>0.10.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -10,37 +10,19 @@
package com.imaginarycode.minecraft.redisbungee;
import com.imaginarycode.minecraft.redisbungee.api.util.player.PlayerUtils;
import net.md_5.bungee.api.connection.PendingConnection;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import redis.clients.jedis.UnifiedJedis;
import java.util.HashMap;
import java.util.Map;
import static com.imaginarycode.minecraft.redisbungee.api.util.payload.PayloadUtils.playerJoinPayload;
public class BungeePlayerUtils {
public static void createPlayer(ProxiedPlayer player, UnifiedJedis unifiedJedis, boolean fireEvent) {
createPlayer(player.getPendingConnection(), unifiedJedis, fireEvent);
if (player.getServer() != null)
unifiedJedis.hset("player:" + player.getUniqueId().toString(), "server", player.getServer().getInfo().getName());
}
public static void createPlayer(PendingConnection connection, UnifiedJedis unifiedJedis, boolean fireEvent) {
Map<String, String> playerData = new HashMap<>(4);
playerData.put("online", "0");
playerData.put("ip", connection.getAddress().getAddress().getHostAddress());
playerData.put("proxy", RedisBungeeAPI.getRedisBungeeApi().getProxyId());
unifiedJedis.sadd("proxy:" + RedisBungeeAPI.getRedisBungeeApi().getProxyId() + ":usersOnline", connection.getUniqueId().toString());
unifiedJedis.hmset("player:" + connection.getUniqueId().toString(), playerData);
if (fireEvent) {
playerJoinPayload(connection.getUniqueId(), unifiedJedis, connection.getAddress().getAddress());
public static void createBungeePlayer(ProxiedPlayer player, UnifiedJedis unifiedJedis, boolean fireEvent) {
String serverName = null;
if (player.getServer() != null) {
serverName = player.getServer().getInfo().getName();
}
PendingConnection pendingConnection = player.getPendingConnection();
PlayerUtils.createPlayer(player.getUniqueId(), unifiedJedis, serverName, pendingConnection.getAddress().getAddress(), fireEvent);
}
}

View File

@@ -222,7 +222,7 @@ public class RedisBungee extends Plugin implements RedisBungeePlugin<ProxiedPlay
httpClient = new OkHttpClient();
Dispatcher dispatcher = new Dispatcher(getExecutorService());
httpClient.setDispatcher(dispatcher);
NameFetcher.setHttpClient(httpClient);
//NameFetcher.setHttpClient(httpClient);
UUIDFetcher.setHttpClient(httpClient);
InitialUtils.checkRedisVersion(this);
// check if this proxy is recovering from a crash and start heart the beat.
@@ -243,7 +243,7 @@ public class RedisBungee extends Plugin implements RedisBungeePlugin<ProxiedPlay
if (proxiedPlayer == null)
return; // We'll deal with it later.
BungeePlayerUtils.createPlayer(proxiedPlayer, unifiedJedis, false);
BungeePlayerUtils.createBungeePlayer(proxiedPlayer, unifiedJedis, false);
}
};

View File

@@ -14,6 +14,7 @@ import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.plugin.Plugin;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.UUID;
@@ -43,8 +44,11 @@ public class RedisBungeeAPI extends AbstractRedisBungeeAPI {
* @return {@link ServerInfo} Can be null if proxy can't find it.
* @see #getServerNameFor(UUID)
*/
@Nullable
public final ServerInfo getServerFor(@NonNull UUID player) {
return ((Plugin) this.plugin).getProxy().getServerInfo(this.getServerNameFor(player));
String serverName = this.getServerNameFor(player);
if (serverName == null) return null;
return ((Plugin) this.plugin).getProxy().getServerInfo(serverName);
}
/**

View File

@@ -17,6 +17,7 @@ import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
import com.imaginarycode.minecraft.redisbungee.api.AbstractRedisBungeeListener;
import com.imaginarycode.minecraft.redisbungee.api.config.RedisBungeeConfiguration;
import com.imaginarycode.minecraft.redisbungee.api.util.player.PlayerUtils;
import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin;
import com.imaginarycode.minecraft.redisbungee.api.tasks.RedisTask;
@@ -47,7 +48,7 @@ public class RedisBungeeBungeeListener extends AbstractRedisBungeeListener<Login
}
@Override
@EventHandler (priority = HIGHEST)
@EventHandler(priority = HIGHEST)
public void onLogin(LoginEvent event) {
event.registerIntent((Plugin) plugin);
plugin.executeAsync(new RedisTask<Void>(plugin) {
@@ -57,27 +58,17 @@ public class RedisBungeeBungeeListener extends AbstractRedisBungeeListener<Login
if (event.isCancelled()) {
return null;
}
// We make sure they aren't trying to use an existing player's name.
// This is problematic for online-mode servers as they always disconnect old clients.
if (plugin.isOnlineMode()) {
ProxiedPlayer player = (ProxiedPlayer) plugin.getPlayer(event.getConnection().getName());
if (player != null) {
event.setCancelled(true);
// TODO: Make it accept a BaseComponent[] like everything else.
event.setCancelReason(ONLINE_MODE_RECONNECT);
return null;
}
}
for (String s : plugin.getProxiesIds()) {
if (unifiedJedis.sismember("proxy:" + s + ":usersOnline", event.getConnection().getUniqueId().toString())) {
event.setCancelled(true);
// TODO: Make it accept a BaseComponent[] like everything else.
event.setCancelReason(ALREADY_LOGGED_IN);
return null;
if (plugin.getConfiguration().restoreOldKickBehavior()) {
for (String s : plugin.getProxiesIds()) {
if (unifiedJedis.sismember("proxy:" + s + ":usersOnline", event.getConnection().getUniqueId().toString())) {
event.setCancelled(true);
event.setCancelReason(plugin.getConfiguration().getMessages().get(RedisBungeeConfiguration.MessageType.ALREADY_LOGGED_IN));
return null;
}
}
} else if (api.isPlayerOnline(event.getConnection().getUniqueId())) {
PlayerUtils.setKickedOtherLocation(event.getConnection().getUniqueId().toString(), unifiedJedis);
api.kickPlayer(event.getConnection().getUniqueId(), plugin.getConfiguration().getMessages().get(RedisBungeeConfiguration.MessageType.LOGGED_IN_OTHER_LOCATION));
}
return null;
} finally {
@@ -94,7 +85,7 @@ public class RedisBungeeBungeeListener extends AbstractRedisBungeeListener<Login
@Override
public Void unifiedJedisTask(UnifiedJedis unifiedJedis) {
plugin.getUuidTranslator().persistInfo(event.getPlayer().getName(), event.getPlayer().getUniqueId(), unifiedJedis);
BungeePlayerUtils.createPlayer(event.getPlayer(), unifiedJedis, true);
BungeePlayerUtils.createBungeePlayer(event.getPlayer(), unifiedJedis, true);
return null;
}
});
@@ -165,6 +156,7 @@ public class RedisBungeeBungeeListener extends AbstractRedisBungeeListener<Login
out.writeUTF("ALL");
original = plugin.getPlayers();
} else {
out.writeUTF(type);
try {
original = plugin.getAbstractRedisBungeeApi().getPlayersOnServer(type);
} catch (IllegalArgumentException ignored) {

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>RedisBungee</artifactId>
<groupId>com.imaginarycode.minecraft</groupId>
<version>0.8.0-SNAPSHOT</version>
<version>0.10.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -14,6 +14,7 @@ import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.proxy.server.ServerInfo;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.UUID;
@@ -44,8 +45,11 @@ public class RedisBungeeAPI extends AbstractRedisBungeeAPI {
* @return {@link ServerInfo} Can be null if proxy can't find it.
* @see #getServerNameFor(UUID)
*/
@Nullable
public final ServerInfo getServerFor(@NonNull UUID player) {
return ((RedisBungeeVelocityPlugin) this.plugin).getProxy().getServer(this.getServerNameFor(player)).map((RegisteredServer::getServerInfo)).orElse(null);
String serverName = this.getServerNameFor(player);
if (serverName == null) return null;
return ((RedisBungeeVelocityPlugin) this.plugin).getProxy().getServer(serverName).map((RegisteredServer::getServerInfo)).orElse(null);
}
/**

View File

@@ -17,6 +17,7 @@ import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
import com.imaginarycode.minecraft.redisbungee.api.AbstractRedisBungeeListener;
import com.imaginarycode.minecraft.redisbungee.api.config.RedisBungeeConfiguration;
import com.imaginarycode.minecraft.redisbungee.api.util.player.PlayerUtils;
import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin;
import com.imaginarycode.minecraft.redisbungee.api.tasks.RedisTask;
@@ -36,6 +37,7 @@ import com.velocitypowered.api.event.proxy.ProxyPingEvent;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ServerConnection;
import com.velocitypowered.api.proxy.server.ServerPing;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import redis.clients.jedis.UnifiedJedis;
@@ -54,7 +56,7 @@ public class RedisBungeeVelocityListener extends AbstractRedisBungeeListener<Log
super(plugin, exemptAddresses);
}
@Subscribe (order = PostOrder.LAST)
@Subscribe(order = PostOrder.LAST)
public void onLogin(LoginEvent event, Continuation continuation) {
plugin.executeAsync(new RedisTask<Void>(plugin) {
@Override
@@ -63,23 +65,18 @@ public class RedisBungeeVelocityListener extends AbstractRedisBungeeListener<Log
if (!event.getResult().isAllowed()) {
return null;
}
if (plugin.getConfiguration().restoreOldKickBehavior()) {
// We make sure they aren't trying to use an existing player's name.
// This is problematic for online-mode servers as they always disconnect old clients.
if (plugin.isOnlineMode()) {
Player player = (Player) plugin.getPlayer(event.getPlayer().getUsername());
if (player != null) {
event.setResult(ResultedEvent.ComponentResult.denied(serializer.deserialize(ONLINE_MODE_RECONNECT)));
return null;
for (String s : plugin.getProxiesIds()) {
if (unifiedJedis.sismember("proxy:" + s + ":usersOnline", event.getPlayer().getUniqueId().toString())) {
event.setResult(ResultedEvent.ComponentResult.denied(serializer.deserialize(plugin.getConfiguration().getMessages().get(RedisBungeeConfiguration.MessageType.ALREADY_LOGGED_IN))));
return null;
}
}
}
for (String s : plugin.getProxiesIds()) {
if (unifiedJedis.sismember("proxy:" + s + ":usersOnline", event.getPlayer().getUniqueId().toString())) {
event.setResult(ResultedEvent.ComponentResult.denied(serializer.deserialize(ALREADY_LOGGED_IN)));
return null;
}
} else if (api.isPlayerOnline(event.getPlayer().getUniqueId())) {
PlayerUtils.setKickedOtherLocation(event.getPlayer().getUniqueId().toString(), unifiedJedis);
api.kickPlayer(event.getPlayer().getUniqueId(), plugin.getConfiguration().getMessages().get(RedisBungeeConfiguration.MessageType.LOGGED_IN_OTHER_LOCATION));
}
return null;
} finally {
@@ -97,7 +94,7 @@ public class RedisBungeeVelocityListener extends AbstractRedisBungeeListener<Log
@Override
public Void unifiedJedisTask(UnifiedJedis unifiedJedis) {
plugin.getUuidTranslator().persistInfo(event.getPlayer().getUsername(), event.getPlayer().getUniqueId(), unifiedJedis);
VelocityPlayerUtils.createPlayer(event.getPlayer(), unifiedJedis, true);
VelocityPlayerUtils.createVelocityPlayer(event.getPlayer(), unifiedJedis, true);
return null;
}
});
@@ -146,7 +143,7 @@ public class RedisBungeeVelocityListener extends AbstractRedisBungeeListener<Log
@Override
@Subscribe
public void onPluginMessage(PluginMessageEvent event) {
if(!(event.getSource() instanceof ServerConnection) || !RedisBungeeVelocityPlugin.IDENTIFIERS.contains(event.getIdentifier())) {
if (!(event.getSource() instanceof ServerConnection) || !RedisBungeeVelocityPlugin.IDENTIFIERS.contains(event.getIdentifier())) {
return;
}
@@ -168,14 +165,15 @@ public class RedisBungeeVelocityListener extends AbstractRedisBungeeListener<Log
out.writeUTF("ALL");
original = plugin.getPlayers();
} else {
out.writeUTF(type);
try {
original = plugin.getAbstractRedisBungeeApi().getPlayersOnServer(type);
} catch (IllegalArgumentException ignored) {
}
}
Set<String> players = original.stream()
.map(uuid -> plugin.getUuidTranslator().getNameFromUuid(uuid, false))
.collect(Collectors.toSet());
.map(uuid -> plugin.getUuidTranslator().getNameFromUuid(uuid, false))
.collect(Collectors.toSet());
out.writeUTF(Joiner.on(',').join(players));
break;
case "PlayerCount":
@@ -246,7 +244,7 @@ public class RedisBungeeVelocityListener extends AbstractRedisBungeeListener<Log
((ServerConnection) event.getSource()).sendPluginMessage(event.getIdentifier(), out.toByteArray());
});
}
@@ -258,7 +256,7 @@ public class RedisBungeeVelocityListener extends AbstractRedisBungeeListener<Log
if (message.startsWith("/"))
message = message.substring(1);
plugin.logInfo("Invoking command via PubSub: /" + message);
((RedisBungeeVelocityPlugin)plugin).getProxy().getCommandManager().executeAsync(RedisBungeeCommandSource.getSingleton(), message);
((RedisBungeeVelocityPlugin) plugin).getProxy().getCommandManager().executeAsync(RedisBungeeCommandSource.getSingleton(), message);
}
}

View File

@@ -109,7 +109,7 @@ public class RedisBungeeVelocityPlugin implements RedisBungeePlugin<Player>, Con
this.httpClient = new OkHttpClient();
Dispatcher dispatcher = new Dispatcher(Executors.newFixedThreadPool(6));
this.httpClient.setDispatcher(dispatcher);
NameFetcher.setHttpClient(httpClient);
//NameFetcher.setHttpClient(httpClient);
UUIDFetcher.setHttpClient(httpClient);
}
@@ -259,7 +259,7 @@ public class RedisBungeeVelocityPlugin implements RedisBungeePlugin<Player>, Con
Player playerProxied = getProxy().getPlayer(UUID.fromString(player)).orElse(null);
if (playerProxied == null)
return; // We'll deal with it later.
VelocityPlayerUtils.createPlayer(playerProxied, unifiedJedis, false);
VelocityPlayerUtils.createVelocityPlayer(playerProxied, unifiedJedis, false);
}
};
integrityCheck = getProxy().getScheduler().buildTask(this, integrityCheckTask::execute).repeat(30, TimeUnit.SECONDS).schedule();

View File

@@ -10,31 +10,22 @@
package com.imaginarycode.minecraft.redisbungee;
import com.imaginarycode.minecraft.redisbungee.api.util.player.PlayerUtils;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ServerConnection;
import redis.clients.jedis.UnifiedJedis;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import static com.imaginarycode.minecraft.redisbungee.api.util.payload.PayloadUtils.playerJoinPayload;
public class VelocityPlayerUtils {
protected static void createPlayer(Player player, UnifiedJedis unifiedJedis, boolean fireEvent) {
Optional<ServerConnection> server = player.getCurrentServer();
server.ifPresent(serverConnection -> unifiedJedis.hset("player:" + player.getUniqueId().toString(), "server", serverConnection.getServerInfo().getName()));
Map<String, String> playerData = new HashMap<>(4);
playerData.put("online", "0");
playerData.put("ip", player.getRemoteAddress().getHostName());
playerData.put("proxy", AbstractRedisBungeeAPI.getAbstractRedisBungeeAPI().getProxyId());
unifiedJedis.sadd("proxy:" + AbstractRedisBungeeAPI.getAbstractRedisBungeeAPI().getProxyId() + ":usersOnline", player.getUniqueId().toString());
unifiedJedis.hmset("player:" + player.getUniqueId().toString(), playerData);
if (fireEvent) {
playerJoinPayload(player.getUniqueId(), unifiedJedis, player.getRemoteAddress().getAddress());
protected static void createVelocityPlayer(Player player, UnifiedJedis unifiedJedis, boolean fireEvent) {
Optional<ServerConnection> optionalServerConnection = player.getCurrentServer();
String serverName = null;
if (optionalServerConnection.isPresent()) {
serverName = optionalServerConnection.get().getServerInfo().getName();
}
PlayerUtils.createPlayer(player.getUniqueId(), unifiedJedis, serverName, player.getRemoteAddress().getAddress(), fireEvent);
}
}

View File

@@ -7,7 +7,7 @@
<groupId>com.imaginarycode.minecraft</groupId>
<artifactId>RedisBungee</artifactId>
<packaging>pom</packaging>
<version>0.8.0-SNAPSHOT</version>
<version>0.10.2-SNAPSHOT</version>
<build>
<plugins>
<plugin>