mirror of
https://github.com/proxiodev/RedisBungee.git
synced 2026-06-24 03:46:43 +00:00
RedisBungee 0.3 base code. A lot has changed. There is more to come.
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Copyright © 2013 tuxed <write@imaginarycode.com>
|
||||
* This work is free. You can redistribute it and/or modify it under the
|
||||
* terms of the Do What The Fuck You Want To Public License, Version 2,
|
||||
* as published by Sam Hocevar. See http://www.wtfpl.net/ for more details.
|
||||
*/
|
||||
package com.imaginarycode.minecraft.redisbungee.util;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.imaginarycode.minecraft.redisbungee.RedisBungee;
|
||||
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/* Credits to evilmidget38 for this class. I modified it to use Gson. */
|
||||
public class NameFetcher implements Callable<Map<UUID, String>> {
|
||||
private static final String PROFILE_URL = "https://sessionserver.mojang.com/session/minecraft/profile/";
|
||||
private final List<UUID> uuids;
|
||||
|
||||
public NameFetcher(List<UUID> uuids) {
|
||||
this.uuids = ImmutableList.copyOf(uuids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<UUID, String> call() throws Exception {
|
||||
Map<UUID, String> uuidStringMap = new HashMap<>();
|
||||
for (UUID uuid : uuids) {
|
||||
HttpURLConnection connection = (HttpURLConnection) new URL(PROFILE_URL + uuid.toString().replace("-", "")).openConnection();
|
||||
Map<String, String> response = RedisBungee.getGson().fromJson(new InputStreamReader(connection.getInputStream()), new TypeToken<Map<String, String>>() {
|
||||
}.getType());
|
||||
String name = response.get("name");
|
||||
if (name == null) {
|
||||
continue;
|
||||
}
|
||||
String cause = response.get("cause");
|
||||
String errorMessage = response.get("errorMessage");
|
||||
if (cause != null && cause.length() > 0) {
|
||||
throw new IllegalStateException(errorMessage);
|
||||
}
|
||||
uuidStringMap.put(uuid, name);
|
||||
}
|
||||
return uuidStringMap;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* Copyright © 2013 tuxed <write@imaginarycode.com>
|
||||
* This work is free. You can redistribute it and/or modify it under the
|
||||
* terms of the Do What The Fuck You Want To Public License, Version 2,
|
||||
* as published by Sam Hocevar. See http://www.wtfpl.net/ for more details.
|
||||
*/
|
||||
package com.imaginarycode.minecraft.redisbungee.util;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.imaginarycode.minecraft.redisbungee.RedisBungee;
|
||||
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/* Credits to evilmidget38 for this class. I modified it to use Gson. */
|
||||
public class UUIDFetcher implements Callable<Map<String, UUID>> {
|
||||
private static final double PROFILES_PER_REQUEST = 100;
|
||||
private static final String PROFILE_URL = "https://api.mojang.com/profiles/minecraft";
|
||||
private final List<String> names;
|
||||
private final boolean rateLimiting;
|
||||
|
||||
public UUIDFetcher(List<String> names, boolean rateLimiting) {
|
||||
this.names = ImmutableList.copyOf(names);
|
||||
this.rateLimiting = rateLimiting;
|
||||
}
|
||||
|
||||
public UUIDFetcher(List<String> names) {
|
||||
this(names, true);
|
||||
}
|
||||
|
||||
public Map<String, UUID> call() throws Exception {
|
||||
Map<String, UUID> uuidMap = new HashMap<>();
|
||||
int requests = (int) Math.ceil(names.size() / PROFILES_PER_REQUEST);
|
||||
for (int i = 0; i < requests; i++) {
|
||||
HttpURLConnection connection = createConnection();
|
||||
String body = RedisBungee.getGson().toJson(names.subList(i * 100, Math.min((i + 1) * 100, names.size())));
|
||||
writeBody(connection, body);
|
||||
Profile[] array = RedisBungee.getGson().fromJson(new InputStreamReader(connection.getInputStream()), Profile[].class);
|
||||
for (Profile profile : array) {
|
||||
UUID uuid = UUIDFetcher.getUUID(profile.id);
|
||||
uuidMap.put(profile.name, uuid);
|
||||
}
|
||||
if (rateLimiting && i != requests - 1) {
|
||||
Thread.sleep(100L);
|
||||
}
|
||||
}
|
||||
return uuidMap;
|
||||
}
|
||||
|
||||
private static void writeBody(HttpURLConnection connection, String body) throws Exception {
|
||||
OutputStream stream = connection.getOutputStream();
|
||||
stream.write(body.getBytes());
|
||||
stream.flush();
|
||||
stream.close();
|
||||
}
|
||||
|
||||
private static HttpURLConnection createConnection() throws Exception {
|
||||
URL url = new URL(PROFILE_URL);
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setRequestProperty("Content-Type", "application/json");
|
||||
connection.setUseCaches(false);
|
||||
connection.setDoInput(true);
|
||||
connection.setDoOutput(true);
|
||||
return connection;
|
||||
}
|
||||
|
||||
private static UUID getUUID(String id) {
|
||||
return UUID.fromString(id.substring(0, 8) + "-" + id.substring(8, 12) + "-" + id.substring(12, 16) + "-" + id.substring(16, 20) + "-" + id.substring(20, 32));
|
||||
}
|
||||
|
||||
public static byte[] toBytes(UUID uuid) {
|
||||
ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[16]);
|
||||
byteBuffer.putLong(uuid.getMostSignificantBits());
|
||||
byteBuffer.putLong(uuid.getLeastSignificantBits());
|
||||
return byteBuffer.array();
|
||||
}
|
||||
|
||||
public static UUID fromBytes(byte[] array) {
|
||||
if (array.length != 16) {
|
||||
throw new IllegalArgumentException("Illegal byte array length: " + array.length);
|
||||
}
|
||||
ByteBuffer byteBuffer = ByteBuffer.wrap(array);
|
||||
long mostSignificant = byteBuffer.getLong();
|
||||
long leastSignificant = byteBuffer.getLong();
|
||||
return new UUID(mostSignificant, leastSignificant);
|
||||
}
|
||||
|
||||
public static UUID getUUIDOf(String name) throws Exception {
|
||||
return new UUIDFetcher(Collections.singletonList(name)).call().get(name);
|
||||
}
|
||||
|
||||
private class Profile {
|
||||
String id;
|
||||
String name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* Copyright © 2013 tuxed <write@imaginarycode.com>
|
||||
* This work is free. You can redistribute it and/or modify it under the
|
||||
* terms of the Do What The Fuck You Want To Public License, Version 2,
|
||||
* as published by Sam Hocevar. See http://www.wtfpl.net/ for more details.
|
||||
*/
|
||||
package com.imaginarycode.minecraft.redisbungee.util;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.HashBiMap;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.imaginarycode.minecraft.redisbungee.RedisBungee;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import redis.clients.jedis.Jedis;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class UUIDTranslator {
|
||||
private final RedisBungee plugin;
|
||||
private BiMap<String, UUID> uuidMap = Maps.synchronizedBiMap(HashBiMap.<String, UUID>create());
|
||||
public static final Pattern UUID_PATTERN = Pattern.compile("[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}");
|
||||
|
||||
public UUID getTranslatedUuid(String player) {
|
||||
if (ProxyServer.getInstance().getPlayer(player) != null)
|
||||
return ProxyServer.getInstance().getPlayer(player).getUniqueId();
|
||||
|
||||
UUID uuid = uuidMap.get(player);
|
||||
if (uuid != null)
|
||||
return uuid;
|
||||
|
||||
if (!plugin.getProxy().getConfig().isOnlineMode()) {
|
||||
uuid = UUID.nameUUIDFromBytes(("OfflinePlayer:" + player).getBytes(Charsets.UTF_8));
|
||||
uuidMap.put(player, uuid);
|
||||
return uuid;
|
||||
}
|
||||
|
||||
// Okay, it wasn't locally cached. Let's try Redis.
|
||||
Jedis jedis = plugin.getPool().getResource();
|
||||
try {
|
||||
String stored = jedis.hget("uuids", player);
|
||||
if (stored != null && UUID_PATTERN.matcher(stored).find()) {
|
||||
// This is it!
|
||||
uuid = UUID.fromString(stored);
|
||||
uuidMap.put(stored, UUID.fromString(stored));
|
||||
return uuid;
|
||||
}
|
||||
|
||||
// That didn't work. Let's ask Mojang.
|
||||
uuid = UUIDFetcher.getUUIDOf(player);
|
||||
|
||||
if (uuid != null) {
|
||||
uuidMap.put(stored, uuid);
|
||||
jedis.hset("uuids", player, uuid.toString());
|
||||
}
|
||||
|
||||
return uuid;
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().log(Level.SEVERE, "Unable to fetch UUID for " + player, e);
|
||||
return null;
|
||||
} finally {
|
||||
plugin.getPool().returnResource(jedis);
|
||||
}
|
||||
}
|
||||
|
||||
public String getNameFromUuid(UUID player) {
|
||||
if (ProxyServer.getInstance().getPlayer(player) != null)
|
||||
return ProxyServer.getInstance().getPlayer(player).getName();
|
||||
|
||||
String name = uuidMap.inverse().get(player);
|
||||
|
||||
if (name != null)
|
||||
return name;
|
||||
|
||||
// Okay, it wasn't locally cached. Let's try Redis.
|
||||
Jedis jedis = plugin.getPool().getResource();
|
||||
try {
|
||||
String stored = jedis.hget("player:" + player, "name");
|
||||
if (stored != null) {
|
||||
name = stored;
|
||||
uuidMap.put(name, player);
|
||||
return name;
|
||||
}
|
||||
|
||||
// That didn't work. Let's ask Mojang.
|
||||
name = new NameFetcher(Collections.singletonList(player)).call().get(player);
|
||||
|
||||
if (name != null) {
|
||||
jedis.hset("player:" + player, "name", name);
|
||||
uuidMap.put(name, player);
|
||||
return name;
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().log(Level.SEVERE, "Unable to fetch name for " + player, e);
|
||||
return null;
|
||||
} finally {
|
||||
plugin.getPool().returnResource(jedis);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user