2
0
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:
Tux
2014-04-20 01:12:28 -04:00
parent d3a6170e78
commit 1362739b27
17 changed files with 692 additions and 222 deletions
@@ -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);
}
}
}