mirror of
https://github.com/zDevelopers/ImageOnMap.git
synced 2025-02-15 19:11:35 +01:00
Fixed migration for players who changed names before migrating.
* NEW: UUIDFetcher can now fetch uuids at a specific timestamp. * BUG: Old map files are not loaded twice anymore. * OPT: Reduced minimum time between requests.
This commit is contained in:
parent
90dd9eb24d
commit
6725c15002
@ -23,6 +23,8 @@ import java.io.InputStreamReader;
|
|||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -34,20 +36,72 @@ import org.json.simple.parser.ParseException;
|
|||||||
|
|
||||||
abstract public class UUIDFetcher
|
abstract public class UUIDFetcher
|
||||||
{
|
{
|
||||||
static private final String PROFILE_URL = "https://api.mojang.com/profiles/minecraft"; //The URI of the name->UUID API from Mojang
|
/**
|
||||||
static private final JSONParser jsonParser = new JSONParser();
|
* The maximal amount of usernames to send to mojang per request
|
||||||
|
* This allows not to overload mojang's service with too many usernames at a time
|
||||||
static public Map<String, UUID> fetch(List<String> names) throws IOException
|
*/
|
||||||
|
static private final int MOJANG_USERNAMES_PER_REQUEST = 100;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximal amount of requests to send to Mojang
|
||||||
|
* The time limit for this amount is MOJANG_MAX_REQUESTS_TIME
|
||||||
|
* Read : You can only send MOJANG_MAX_REQUESTS in MOJANG_MAX_REQUESTS_TIME seconds
|
||||||
|
*/
|
||||||
|
static private final int MOJANG_MAX_REQUESTS = 600;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The timeframe for the Mojang request limit (in seconds)
|
||||||
|
*/
|
||||||
|
static private final int MOJANG_MAX_REQUESTS_TIME = 600;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The minimum time between two requests to mojang (in milliseconds)
|
||||||
|
*/
|
||||||
|
static private final int TIME_BETWEEN_REQUESTS = 200;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The (approximative) timestamp of the date when Mojang name changing feature
|
||||||
|
* was announced to be released
|
||||||
|
*/
|
||||||
|
static private final int NAME_CHANGE_TIMESTAMP = 1420844400;
|
||||||
|
|
||||||
|
static private final String PROFILE_URL = "https://api.mojang.com/profiles/minecraft";
|
||||||
|
static private final String TIMED_PROFILE_URL = "https://api.mojang.com/users/profiles/minecraft/";
|
||||||
|
|
||||||
|
static public Map<String, UUID> fetch(List<String> names) throws IOException, InterruptedException
|
||||||
|
{
|
||||||
|
return fetch(names, MOJANG_USERNAMES_PER_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
static public Map<String, UUID> fetch(List<String> names, int limitByRequest) throws IOException, InterruptedException
|
||||||
|
{
|
||||||
|
Map<String, UUID> UUIDs = new HashMap<String, UUID>();
|
||||||
|
int requests = (names.size() / limitByRequest) + 1;
|
||||||
|
|
||||||
|
List<String> tempNames;
|
||||||
|
Map<String, UUID> tempUUIDs;
|
||||||
|
|
||||||
|
for(int i = 0; i < requests; i++)
|
||||||
|
{
|
||||||
|
tempNames = names.subList(limitByRequest * i, Math.min((limitByRequest * (i+1)) - 1, names.size()));
|
||||||
|
tempUUIDs = rawFetch(tempNames);
|
||||||
|
UUIDs.putAll(tempUUIDs);
|
||||||
|
Thread.sleep(TIME_BETWEEN_REQUESTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
return UUIDs;
|
||||||
|
}
|
||||||
|
|
||||||
|
static private Map<String, UUID> rawFetch(List<String> names) throws IOException
|
||||||
{
|
{
|
||||||
Map<String, UUID> uuidMap = new HashMap<String, UUID>();
|
Map<String, UUID> uuidMap = new HashMap<String, UUID>();
|
||||||
HttpURLConnection connection = createConnection();
|
HttpURLConnection connection = getPOSTConnection(PROFILE_URL);
|
||||||
|
|
||||||
writeBody(connection, names);
|
writeBody(connection, names);
|
||||||
|
|
||||||
JSONArray array;
|
JSONArray array;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
array = (JSONArray) jsonParser.parse(new InputStreamReader(connection.getInputStream()));
|
array = (JSONArray) readResponse(connection);
|
||||||
}
|
}
|
||||||
catch(ParseException ex)
|
catch(ParseException ex)
|
||||||
{
|
{
|
||||||
@ -62,33 +116,63 @@ abstract public class UUIDFetcher
|
|||||||
uuidMap.put(name, fromMojangUUID(id));
|
uuidMap.put(name, fromMojangUUID(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return uuidMap;
|
return uuidMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
static public Map<String, UUID> fetch(List<String> names, int limitByRequest) throws IOException, InterruptedException
|
static public void fetchRemaining(Collection<String> names, Map<String, UUID> uuids) throws IOException, InterruptedException
|
||||||
{
|
{
|
||||||
Map<String, UUID> UUIDs = new HashMap<String, UUID>();
|
ArrayList<String> remainingNames = new ArrayList<>();
|
||||||
int requests = (names.size() / limitByRequest) + 1;
|
|
||||||
|
|
||||||
List<String> tempNames;
|
for(String name : names)
|
||||||
Map<String, UUID> tempUUIDs;
|
|
||||||
|
|
||||||
for(int i = 0; i < requests; i++)
|
|
||||||
{
|
{
|
||||||
tempNames = names.subList(limitByRequest * i, Math.min((limitByRequest * (i+1)) - 1, names.size()));
|
if(!uuids.containsKey(name)) remainingNames.add(name);
|
||||||
tempUUIDs = fetch(tempNames);
|
}
|
||||||
UUIDs.putAll(tempUUIDs);
|
|
||||||
Thread.sleep(400);
|
int timeBetweenRequests;
|
||||||
|
if(remainingNames.size() > MOJANG_MAX_REQUESTS)
|
||||||
|
{
|
||||||
|
timeBetweenRequests = (MOJANG_MAX_REQUESTS / MOJANG_MAX_REQUESTS_TIME) * 1000;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
timeBetweenRequests = TIME_BETWEEN_REQUESTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
User user;
|
||||||
|
for(String name : remainingNames)
|
||||||
|
{
|
||||||
|
user = fetchOriginalUUID(name);
|
||||||
|
uuids.put(user.name, user.uuid);
|
||||||
|
Thread.sleep(timeBetweenRequests);
|
||||||
}
|
}
|
||||||
|
|
||||||
return UUIDs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static HttpURLConnection createConnection() throws IOException
|
static private User fetchOriginalUUID(String name) throws IOException
|
||||||
{
|
{
|
||||||
URL url = new URL(PROFILE_URL);
|
HttpURLConnection connection = getGETConnection(TIMED_PROFILE_URL + name + "?at=" + NAME_CHANGE_TIMESTAMP);
|
||||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
sendRequest(connection);
|
||||||
|
|
||||||
|
JSONObject object;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
object = (JSONObject) readResponse(connection);
|
||||||
|
}
|
||||||
|
catch(ParseException ex)
|
||||||
|
{
|
||||||
|
throw new IOException("Invalid response from server, unable to parse received JSON : " + ex.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
User user = new User();
|
||||||
|
user.name = (String) object.get("name");
|
||||||
|
user.uuid = fromMojangUUID((String)object.get("id"));
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
static private HttpURLConnection getPOSTConnection(String url) throws IOException
|
||||||
|
{
|
||||||
|
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
|
||||||
connection.setRequestMethod("POST");
|
connection.setRequestMethod("POST");
|
||||||
connection.setRequestProperty("Content-Type", "application/json");
|
connection.setRequestProperty("Content-Type", "application/json");
|
||||||
connection.setUseCaches(false);
|
connection.setUseCaches(false);
|
||||||
@ -96,7 +180,22 @@ abstract public class UUIDFetcher
|
|||||||
connection.setDoOutput(true);
|
connection.setDoOutput(true);
|
||||||
return connection;
|
return connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static private HttpURLConnection getGETConnection(String url) throws IOException
|
||||||
|
{
|
||||||
|
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
|
||||||
|
connection.setRequestMethod("GET");
|
||||||
|
connection.setUseCaches(false);
|
||||||
|
connection.setDoInput(true);
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
static private void sendRequest(HttpURLConnection connection) throws IOException
|
||||||
|
{
|
||||||
|
OutputStream stream = connection.getOutputStream();
|
||||||
|
stream.flush();
|
||||||
|
stream.close();
|
||||||
|
}
|
||||||
|
|
||||||
private static void writeBody(HttpURLConnection connection, List<String> names) throws IOException
|
private static void writeBody(HttpURLConnection connection, List<String> names) throws IOException
|
||||||
{
|
{
|
||||||
@ -106,7 +205,11 @@ abstract public class UUIDFetcher
|
|||||||
stream.flush();
|
stream.flush();
|
||||||
stream.close();
|
stream.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Object readResponse(HttpURLConnection connection) throws IOException, ParseException
|
||||||
|
{
|
||||||
|
return new JSONParser().parse(new InputStreamReader(connection.getInputStream()));
|
||||||
|
}
|
||||||
|
|
||||||
private static UUID fromMojangUUID(String id) //Mojang sends string UUIDs without dashes ...
|
private static UUID fromMojangUUID(String id) //Mojang sends string UUIDs without dashes ...
|
||||||
{
|
{
|
||||||
@ -114,6 +217,12 @@ abstract public class UUIDFetcher
|
|||||||
id.substring(12, 16) + "-" + id.substring(16, 20) + "-" +
|
id.substring(12, 16) + "-" + id.substring(16, 20) + "-" +
|
||||||
id.substring(20, 32));
|
id.substring(20, 32));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static private class User
|
||||||
|
{
|
||||||
|
public String name;
|
||||||
|
public UUID uuid;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,12 +71,6 @@ public class V3Migrator
|
|||||||
*/
|
*/
|
||||||
static private final String BACKUPS_POSTV3_DIRECTORY_NAME = "backups_post-v3";
|
static private final String BACKUPS_POSTV3_DIRECTORY_NAME = "backups_post-v3";
|
||||||
|
|
||||||
/**
|
|
||||||
* The maximal amount of usernames to send to mojang per request
|
|
||||||
* This allows not to overload mojang's service with too many usernames at a time
|
|
||||||
*/
|
|
||||||
static private final int MOJANG_USERNAMES_PER_REQUEST = 100;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the former images directory of a given plugin
|
* Returns the former images directory of a given plugin
|
||||||
* @param plugin The plugin.
|
* @param plugin The plugin.
|
||||||
@ -167,9 +161,8 @@ public class V3Migrator
|
|||||||
if(checkForExistingBackups()) return;
|
if(checkForExistingBackups()) return;
|
||||||
if(!loadOldFiles()) return;
|
if(!loadOldFiles()) return;
|
||||||
backupMapData();
|
backupMapData();
|
||||||
loadOldFiles();
|
|
||||||
fetchUUIDs();
|
fetchUUIDs();
|
||||||
if(!checkMissingUUIDs()) return;
|
if(!fetchMissingUUIDs()) return;
|
||||||
}
|
}
|
||||||
catch(Exception ex)
|
catch(Exception ex)
|
||||||
{
|
{
|
||||||
@ -341,7 +334,7 @@ public class V3Migrator
|
|||||||
logInfo("Fetching UUIDs from Mojang ...");
|
logInfo("Fetching UUIDs from Mojang ...");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
usersUUIDs = UUIDFetcher.fetch(new ArrayList<String>(userNamesToFetch), MOJANG_USERNAMES_PER_REQUEST);
|
usersUUIDs = UUIDFetcher.fetch(new ArrayList<String>(userNamesToFetch));
|
||||||
}
|
}
|
||||||
catch(IOException ex)
|
catch(IOException ex)
|
||||||
{
|
{
|
||||||
@ -357,14 +350,30 @@ public class V3Migrator
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if any UUID has been retreived.
|
* Fetches the UUIDs that could not be retreived via Mojang's standard API
|
||||||
* @return true if at least one UUID has been retreived, false otherwise
|
* @return true if at least one UUID has been retreived, false otherwise
|
||||||
*/
|
*/
|
||||||
private boolean checkMissingUUIDs()
|
private boolean fetchMissingUUIDs() throws IOException, InterruptedException
|
||||||
{
|
{
|
||||||
if(usersUUIDs.size() == userNamesToFetch.size()) return true;
|
if(usersUUIDs.size() == userNamesToFetch.size()) return true;
|
||||||
logInfo("Mojang did not find UUIDs for all the registered players.");
|
int remainingUsersCount = userNamesToFetch.size() - usersUUIDs.size();
|
||||||
logInfo("This means some of the users do not actually exist, or they have changed names before migrating.");
|
logInfo("Mojang did not find UUIDs for "+remainingUsersCount+" players.");
|
||||||
|
logInfo("The Mojang servers limit requests rate at one per second, this may take some time...");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
UUIDFetcher.fetchRemaining(userNamesToFetch, usersUUIDs);
|
||||||
|
}
|
||||||
|
catch(IOException ex)
|
||||||
|
{
|
||||||
|
logError("An error occured while fetching the UUIDs from Mojang", ex);
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
catch(InterruptedException ex)
|
||||||
|
{
|
||||||
|
logError("The migration worker has been interrupted", ex);
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
|
||||||
if(usersUUIDs.size() <= 0)
|
if(usersUUIDs.size() <= 0)
|
||||||
{
|
{
|
||||||
@ -373,15 +382,6 @@ public class V3Migrator
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String missingUsersList = "";
|
|
||||||
|
|
||||||
for(String user : userNamesToFetch)
|
|
||||||
{
|
|
||||||
if(!usersUUIDs.containsKey(user)) missingUsersList += user + ",";
|
|
||||||
}
|
|
||||||
missingUsersList = missingUsersList.substring(0, missingUsersList.length());
|
|
||||||
|
|
||||||
logInfo("Here are the missing players : " + missingUsersList);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user