mirror of
https://github.com/MineLittlePony/MineLittlePony.git
synced 2024-12-02 08:48:00 +01:00
Split off the boilerplate code
This commit is contained in:
parent
018a0dd141
commit
a815d13912
8 changed files with 212 additions and 262 deletions
|
@ -0,0 +1,47 @@
|
||||||
|
package com.voxelmodpack.hdskins.skins;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.mojang.authlib.GameProfile;
|
||||||
|
import com.mojang.authlib.exceptions.AuthenticationException;
|
||||||
|
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
|
||||||
|
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
|
||||||
|
import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload;
|
||||||
|
import com.voxelmodpack.hdskins.HDSkinManager;
|
||||||
|
|
||||||
|
import net.minecraft.util.Session;
|
||||||
|
|
||||||
|
public abstract class AbstractSkinServer implements SkinServer {
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final Optional<MinecraftTexturesPayload> loadProfileData(GameProfile profile) {
|
||||||
|
return Optional.ofNullable(getProfileData(profile));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<Type, MinecraftProfileTexture> getPreviewTextures(GameProfile profile) {
|
||||||
|
return loadProfileData(profile)
|
||||||
|
.map(MinecraftTexturesPayload::getTextures)
|
||||||
|
.orElse(Collections.emptyMap());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final CompletableFuture<SkinUploadResponse> uploadSkin(Session session, @Nullable URI image, Type type, Map<String, String> metadata) {
|
||||||
|
return CallableFutures.asyncFailableFuture(() -> {
|
||||||
|
return doUpload(session, image, type, metadata);
|
||||||
|
}, HDSkinManager.skinUploadExecutor);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract MinecraftTexturesPayload getProfileData(GameProfile profile);
|
||||||
|
|
||||||
|
protected abstract SkinUploadResponse doUpload(Session session, URI image, Type type, Map<String, String> metadata) throws AuthenticationException, IOException;
|
||||||
|
|
||||||
|
}
|
|
@ -1,26 +1,24 @@
|
||||||
package com.voxelmodpack.hdskins.skins;
|
package com.voxelmodpack.hdskins.skins;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
|
||||||
import com.google.common.collect.ImmutableMap.Builder;
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import com.google.gson.annotations.Expose;
|
|
||||||
import com.mojang.authlib.GameProfile;
|
|
||||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
|
|
||||||
import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload;
|
|
||||||
import com.mojang.util.UUIDTypeAdapter;
|
|
||||||
import com.voxelmodpack.hdskins.HDSkinManager;
|
|
||||||
import net.minecraft.util.Session;
|
|
||||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.common.collect.ImmutableMap.Builder;
|
||||||
|
import com.google.gson.annotations.Expose;
|
||||||
|
import com.mojang.authlib.GameProfile;
|
||||||
|
import com.mojang.authlib.exceptions.AuthenticationException;
|
||||||
|
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
|
||||||
|
import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload;
|
||||||
|
import com.mojang.util.UUIDTypeAdapter;
|
||||||
|
|
||||||
|
import net.minecraft.util.Session;
|
||||||
|
|
||||||
@ServerType("bethlehem")
|
@ServerType("bethlehem")
|
||||||
public class BethlehemSkinServer implements SkinServer {
|
public class BethlehemSkinServer extends AbstractSkinServer {
|
||||||
|
|
||||||
private static final String SERVER_ID = "7853dfddc358333843ad55a2c7485c4aa0380a51";
|
private static final String SERVER_ID = "7853dfddc358333843ad55a2c7485c4aa0380a51";
|
||||||
|
|
||||||
|
@ -32,28 +30,24 @@ public class BethlehemSkinServer implements SkinServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<MinecraftTexturesPayload> loadProfileData(GameProfile profile) {
|
protected MinecraftTexturesPayload getProfileData(GameProfile profile) {
|
||||||
NetClient client = new NetClient("GET", getPath(profile));
|
try (NetClient client = new NetClient("GET", getPath(profile))) {
|
||||||
|
if (!client.send()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
String json = client.getResponseText();
|
return gson.fromJson(client.getResponseText(), MinecraftTexturesPayload.class);
|
||||||
|
} catch (IOException e) {
|
||||||
JsonObject s = gson.fromJson(json, JsonObject.class);
|
return null;
|
||||||
|
|
||||||
if (s.has("success") && s.get("success").getAsBoolean()) {
|
|
||||||
s = s.get("data").getAsJsonObject();
|
|
||||||
|
|
||||||
return Optional.ofNullable(gson.fromJson(s, MinecraftTexturesPayload.class));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<SkinUploadResponse> uploadSkin(Session session, URI image, Type type, Map<String, String> metadata) {
|
protected SkinUploadResponse doUpload(Session session, URI image, Type type, Map<String, String> metadata) throws AuthenticationException, IOException {
|
||||||
return CallableFutures.asyncFailableFuture(() -> {
|
SkinServer.verifyServerConnection(session, SERVER_ID);
|
||||||
SkinServer.verifyServerConnection(session, SERVER_ID);
|
|
||||||
|
|
||||||
NetClient client = new NetClient("POST", address).putHeaders(createHeaders(session, type, image, metadata));
|
try (NetClient client = new NetClient("POST", address)) {
|
||||||
|
client.putHeaders(createHeaders(session, type, image, metadata));
|
||||||
|
|
||||||
if (image != null) {
|
if (image != null) {
|
||||||
client.putFile(type.toString().toLowerCase(Locale.US), "image/png", image);
|
client.putFile(type.toString().toLowerCase(Locale.US), "image/png", image);
|
||||||
|
@ -64,7 +58,7 @@ public class BethlehemSkinServer implements SkinServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
return new SkinUploadResponse(client.getResponseText());
|
return new SkinUploadResponse(client.getResponseText());
|
||||||
}, HDSkinManager.skinUploadExecutor);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Map<String, ?> createHeaders(Session session, Type type, URI image, Map<String, String> metadata) {
|
protected Map<String, ?> createHeaders(Session session, Type type, URI image, Map<String, String> metadata) {
|
||||||
|
|
|
@ -17,10 +17,4 @@ public class CallableFutures {
|
||||||
});
|
});
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> CompletableFuture<T> failedFuture(Exception e) {
|
|
||||||
CompletableFuture<T> ret = new CompletableFuture<>();
|
|
||||||
ret.completeExceptionally(e);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,33 +2,30 @@ package com.voxelmodpack.hdskins.skins;
|
||||||
|
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.common.collect.ImmutableMap.Builder;
|
||||||
import com.google.gson.annotations.Expose;
|
import com.google.gson.annotations.Expose;
|
||||||
import com.mojang.authlib.GameProfile;
|
import com.mojang.authlib.GameProfile;
|
||||||
|
import com.mojang.authlib.exceptions.AuthenticationException;
|
||||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
|
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
|
||||||
|
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
|
||||||
import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload;
|
import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload;
|
||||||
import com.mojang.util.UUIDTypeAdapter;
|
import com.mojang.util.UUIDTypeAdapter;
|
||||||
import com.voxelmodpack.hdskins.HDSkinManager;
|
|
||||||
import com.voxelmodpack.hdskins.upload.ThreadMultipartPostUpload;
|
|
||||||
import net.minecraft.util.Session;
|
import net.minecraft.util.Session;
|
||||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URL;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.EnumMap;
|
import java.util.EnumMap;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@ServerType("legacy")
|
@ServerType("legacy")
|
||||||
public class LegacySkinServer implements SkinServer {
|
public class LegacySkinServer extends AbstractSkinServer {
|
||||||
|
|
||||||
private static final String SERVER_ID = "7853dfddc358333843ad55a2c7485c4aa0380a51";
|
private static final String SERVER_ID = "7853dfddc358333843ad55a2c7485c4aa0380a51";
|
||||||
|
|
||||||
|
@ -36,6 +33,7 @@ public class LegacySkinServer implements SkinServer {
|
||||||
|
|
||||||
@Expose
|
@Expose
|
||||||
private final String address;
|
private final String address;
|
||||||
|
|
||||||
@Expose
|
@Expose
|
||||||
private final String gateway;
|
private final String gateway;
|
||||||
|
|
||||||
|
@ -45,28 +43,33 @@ public class LegacySkinServer implements SkinServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<MinecraftProfileTexture.Type, MinecraftProfileTexture> getPreviewTextures(GameProfile profile) {
|
public Map<Type, MinecraftProfileTexture> getPreviewTextures(GameProfile profile) {
|
||||||
if (Strings.isNullOrEmpty(this.gateway)) {
|
if (Strings.isNullOrEmpty(gateway)) {
|
||||||
return Collections.emptyMap();
|
return Collections.emptyMap();
|
||||||
}
|
}
|
||||||
Map<MinecraftProfileTexture.Type, MinecraftProfileTexture> map = new EnumMap<>(MinecraftProfileTexture.Type.class);
|
|
||||||
for (MinecraftProfileTexture.Type type : MinecraftProfileTexture.Type.values()) {
|
Map<Type, MinecraftProfileTexture> map = new EnumMap<>(Type.class);
|
||||||
|
|
||||||
|
for (Type type : Type.values()) {
|
||||||
map.put(type, new MinecraftProfileTexture(getPath(gateway, type, profile), null));
|
map.put(type, new MinecraftProfileTexture(getPath(gateway, type, profile), null));
|
||||||
}
|
}
|
||||||
|
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
@Override
|
@Override
|
||||||
public Optional<MinecraftTexturesPayload> loadProfileData(GameProfile profile) {
|
protected MinecraftTexturesPayload getProfileData(GameProfile profile) {
|
||||||
ImmutableMap.Builder<MinecraftProfileTexture.Type, MinecraftProfileTexture> builder = ImmutableMap.builder();
|
ImmutableMap.Builder<Type, MinecraftProfileTexture> builder = ImmutableMap.builder();
|
||||||
for (MinecraftProfileTexture.Type type : MinecraftProfileTexture.Type.values()) {
|
|
||||||
|
|
||||||
String url = getPath(this.address, type, profile);
|
for (Type type : Type.values()) {
|
||||||
try {
|
String url = getPath(address, type, profile);
|
||||||
HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection();
|
|
||||||
if (urlConnection.getResponseCode() / 100 != 2) {
|
try (NetClient client = new NetClient("GET", url)) {
|
||||||
throw new IOException("Bad response code: " + urlConnection.getResponseCode());
|
if (!client.send()) {
|
||||||
|
throw new IOException("Bad response code: " + client.getResponseCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.put(type, new MinecraftProfileTexture(url, null));
|
builder.put(type, new MinecraftProfileTexture(url, null));
|
||||||
logger.debug("Found skin for {} at {}", profile.getName(), url);
|
logger.debug("Found skin for {} at {}", profile.getName(), url);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -74,66 +77,67 @@ public class LegacySkinServer implements SkinServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<MinecraftProfileTexture.Type, MinecraftProfileTexture> map = builder.build();
|
Map<Type, MinecraftProfileTexture> map = builder.build();
|
||||||
|
|
||||||
if (map.isEmpty()) {
|
if (map.isEmpty()) {
|
||||||
logger.debug("No textures found for {} at {}", profile, this.address);
|
logger.debug("No textures found for {} at {}", profile, address);
|
||||||
return Optional.empty();
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Optional.of(TexturesPayloadBuilder.createTexturesPayload(profile, map));
|
return TexturesPayloadBuilder.createTexturesPayload(profile, map);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<SkinUploadResponse> uploadSkin(Session session, @Nullable URI image, MinecraftProfileTexture.Type type, Map<String, String> metadata) {
|
protected SkinUploadResponse doUpload(Session session, URI image, Type type, Map<String, String> metadata) throws AuthenticationException, IOException {
|
||||||
if (Strings.isNullOrEmpty(this.gateway)) {
|
SkinServer.verifyServerConnection(session, SERVER_ID);
|
||||||
return CallableFutures.failedFuture(new NullPointerException("gateway url is blank"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return CallableFutures.asyncFailableFuture(() -> {
|
try (NetClient client = new NetClient("POST", address)) {
|
||||||
SkinServer.verifyServerConnection(session, SERVER_ID);
|
client.putHeaders(createHeaders(session, type, image, metadata));
|
||||||
String model = metadata.getOrDefault("model", "default");
|
|
||||||
Map<String, ?> data = image == null ? getClearData(session, type) : getUploadData(session, type, model, image);
|
if (image != null) {
|
||||||
ThreadMultipartPostUpload upload = new ThreadMultipartPostUpload(this.gateway, data);
|
client.putFile(type.toString().toLowerCase(Locale.US), "image/png", image);
|
||||||
String response = upload.uploadMultipart();
|
}
|
||||||
if (response.startsWith("ERROR: ")) {
|
|
||||||
|
String response = client.getResponseText();
|
||||||
|
|
||||||
|
if (response.startsWith("ERROR: ")) { // lol @ "ERROR: OK"
|
||||||
response = response.substring(7);
|
response = response.substring(7);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!response.equalsIgnoreCase("OK") && !response.endsWith("OK"))
|
if (!response.equalsIgnoreCase("OK") && !response.endsWith("OK"))
|
||||||
throw new IOException(response);
|
throw new IOException(response);
|
||||||
return new SkinUploadResponse(response);
|
return new SkinUploadResponse(response);
|
||||||
|
}
|
||||||
}, HDSkinManager.skinUploadExecutor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<String, ?> getData(Session session, MinecraftProfileTexture.Type type, String model, String param, Object val) {
|
|
||||||
return ImmutableMap.of(
|
protected Map<String, ?> createHeaders(Session session, Type type, URI image, Map<String, String> metadata) {
|
||||||
"user", session.getUsername(),
|
Builder<String, Object> builder = ImmutableMap.<String, Object>builder()
|
||||||
"uuid", UUIDTypeAdapter.fromUUID(session.getProfile().getId()),
|
.put("user", session.getUsername())
|
||||||
"type", type.toString().toLowerCase(Locale.US),
|
.put("uuid", UUIDTypeAdapter.fromUUID(session.getProfile().getId()))
|
||||||
"model", model,
|
.put("type", type.toString().toLowerCase(Locale.US));
|
||||||
param, val);
|
|
||||||
|
if (image == null) {
|
||||||
|
builder.put("clear", "1");
|
||||||
|
} else {
|
||||||
|
builder.put("model", metadata.getOrDefault("mode", "default"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<String, ?> getClearData(Session session, MinecraftProfileTexture.Type type) {
|
private static String getPath(String address, Type type, GameProfile profile) {
|
||||||
return getData(session, type, "default", "clear", "1");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Map<String, ?> getUploadData(Session session, MinecraftProfileTexture.Type type, String model, URI skinFile) {
|
|
||||||
return getData(session, type, model, type.toString().toLowerCase(Locale.US), skinFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getPath(String address, MinecraftProfileTexture.Type type, GameProfile profile) {
|
|
||||||
String uuid = UUIDTypeAdapter.fromUUID(profile.getId());
|
String uuid = UUIDTypeAdapter.fromUUID(profile.getId());
|
||||||
String path = type.toString().toLowerCase() + "s";
|
String path = type.toString().toLowerCase() + "s";
|
||||||
|
|
||||||
return String.format("%s/%s/%s.png", address, path, uuid);
|
return String.format("%s/%s/%s.png", address, path, uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return new ToStringBuilder(this, IndentedToStringStyle.INSTANCE)
|
return new ToStringBuilder(this, IndentedToStringStyle.INSTANCE)
|
||||||
.append("address", this.address)
|
.append("address", address)
|
||||||
.append("gateway", this.gateway)
|
.append("gateway", gateway)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package com.voxelmodpack.hdskins.skins;
|
package com.voxelmodpack.hdskins.skins;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
|
import java.io.Closeable;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
@ -15,21 +16,36 @@ import org.apache.http.client.methods.HttpUriRequest;
|
||||||
import org.apache.http.client.methods.RequestBuilder;
|
import org.apache.http.client.methods.RequestBuilder;
|
||||||
import org.apache.http.entity.ContentType;
|
import org.apache.http.entity.ContentType;
|
||||||
import org.apache.http.entity.mime.MultipartEntityBuilder;
|
import org.apache.http.entity.mime.MultipartEntityBuilder;
|
||||||
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
import org.apache.http.impl.client.HttpClients;
|
import org.apache.http.impl.client.HttpClients;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ew. Why so many builders? >.<
|
* Ew. Why so many builders? >.<
|
||||||
*/
|
*/
|
||||||
public class NetClient {
|
public class NetClient implements Closeable {
|
||||||
|
|
||||||
private final RequestBuilder rqBuilder;
|
private CloseableHttpClient client;
|
||||||
|
|
||||||
|
private RequestBuilder rqBuilder;
|
||||||
|
|
||||||
private Map<String, ?> headers;
|
private Map<String, ?> headers;
|
||||||
|
|
||||||
private CloseableHttpResponse response = null;
|
private CloseableHttpResponse response = null;
|
||||||
|
|
||||||
public NetClient(String method, String uri) {
|
public NetClient(String method, String uri) {
|
||||||
|
start(method, uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NetClient start(String method, String uri) {
|
||||||
rqBuilder = RequestBuilder.create(method).setUri(uri);
|
rqBuilder = RequestBuilder.create(method).setUri(uri);
|
||||||
|
headers = null;
|
||||||
|
|
||||||
|
if (response != null) {
|
||||||
|
IOUtils.closeQuietly(response);
|
||||||
|
response = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public NetClient putFile(String key, String contentType, URI file) {
|
public NetClient putFile(String key, String contentType, URI file) {
|
||||||
|
@ -50,12 +66,18 @@ public class NetClient {
|
||||||
public boolean send() {
|
public boolean send() {
|
||||||
HttpUriRequest request = rqBuilder.build();
|
HttpUriRequest request = rqBuilder.build();
|
||||||
|
|
||||||
for (Map.Entry<String, ?> parameter : headers.entrySet()) {
|
if (headers != null) {
|
||||||
request.addHeader(parameter.getKey(), parameter.getValue().toString());
|
for (Map.Entry<String, ?> parameter : headers.entrySet()) {
|
||||||
|
request.addHeader(parameter.getKey(), parameter.getValue().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client == null) {
|
||||||
|
client = HttpClients.createSystem();
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
response = HttpClients.createSystem().execute(request);
|
response = client.execute(request);
|
||||||
|
|
||||||
return getResponseCode() == HttpStatus.SC_OK;
|
return getResponseCode() == HttpStatus.SC_OK;
|
||||||
} catch (IOException e) { }
|
} catch (IOException e) { }
|
||||||
|
@ -78,11 +100,7 @@ public class NetClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BufferedReader reader = null;
|
try (BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()))) {
|
||||||
|
|
||||||
try {
|
|
||||||
reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
|
|
||||||
|
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
|
|
||||||
int ch;
|
int ch;
|
||||||
|
@ -93,10 +111,21 @@ public class NetClient {
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|
||||||
} finally {
|
|
||||||
IOUtils.closeQuietly(reader);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
if (response != null) {
|
||||||
|
IOUtils.closeQuietly(response);
|
||||||
|
response = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client != null) {
|
||||||
|
IOUtils.closeQuietly(client);
|
||||||
|
client = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@ import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.util.Session;
|
import net.minecraft.util.Session;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
@ -36,13 +35,10 @@ public interface SkinServer extends Exposable {
|
||||||
|
|
||||||
Optional<MinecraftTexturesPayload> loadProfileData(GameProfile profile);
|
Optional<MinecraftTexturesPayload> loadProfileData(GameProfile profile);
|
||||||
|
|
||||||
default Map<MinecraftProfileTexture.Type, MinecraftProfileTexture> getPreviewTextures(GameProfile profile) {
|
Map<MinecraftProfileTexture.Type, MinecraftProfileTexture> getPreviewTextures(GameProfile profile);
|
||||||
return loadProfileData(profile).map(MinecraftTexturesPayload::getTextures).orElse(Collections.emptyMap());
|
|
||||||
}
|
|
||||||
|
|
||||||
CompletableFuture<SkinUploadResponse> uploadSkin(Session session, @Nullable URI image, MinecraftProfileTexture.Type type, Map<String, String> metadata);
|
CompletableFuture<SkinUploadResponse> uploadSkin(Session session, @Nullable URI image, MinecraftProfileTexture.Type type, Map<String, String> metadata);
|
||||||
|
|
||||||
|
|
||||||
public static void verifyServerConnection(Session session, String serverId) throws AuthenticationException {
|
public static void verifyServerConnection(Session session, String serverId) throws AuthenticationException {
|
||||||
MinecraftSessionService service = Minecraft.getMinecraft().getSessionService();
|
MinecraftSessionService service = Minecraft.getMinecraft().getSessionService();
|
||||||
service.joinServer(session.getProfile(), session.getToken(), serverId);
|
service.joinServer(session.getProfile(), session.getToken(), serverId);
|
||||||
|
|
|
@ -6,9 +6,12 @@ import com.google.gson.annotations.Expose;
|
||||||
import com.mojang.authlib.GameProfile;
|
import com.mojang.authlib.GameProfile;
|
||||||
import com.mojang.authlib.exceptions.AuthenticationException;
|
import com.mojang.authlib.exceptions.AuthenticationException;
|
||||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
|
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
|
||||||
|
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type;
|
||||||
import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload;
|
import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload;
|
||||||
import com.mojang.util.UUIDTypeAdapter;
|
import com.mojang.util.UUIDTypeAdapter;
|
||||||
import com.voxelmodpack.hdskins.HDSkinManager;
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.util.Session;
|
import net.minecraft.util.Session;
|
||||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
|
@ -34,14 +37,10 @@ import java.io.Reader;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
@ServerType("valhalla")
|
@ServerType("valhalla")
|
||||||
public class ValhallaSkinServer implements SkinServer {
|
public class ValhallaSkinServer extends AbstractSkinServer {
|
||||||
|
|
||||||
@Expose
|
@Expose
|
||||||
private final String address;
|
private final String address;
|
||||||
|
@ -53,44 +52,39 @@ public class ValhallaSkinServer implements SkinServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<MinecraftTexturesPayload> loadProfileData(GameProfile profile) {
|
protected MinecraftTexturesPayload getProfileData(GameProfile profile) {
|
||||||
|
|
||||||
try (CloseableHttpClient client = HttpClients.createSystem();
|
try (CloseableHttpClient client = HttpClients.createSystem();
|
||||||
CloseableHttpResponse response = client.execute(new HttpGet(getTexturesURI(profile)))) {
|
CloseableHttpResponse response = client.execute(new HttpGet(getTexturesURI(profile)))) {
|
||||||
|
|
||||||
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
|
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
|
||||||
|
return readJson(response, MinecraftTexturesPayload.class);
|
||||||
return Optional.of(readJson(response, MinecraftTexturesPayload.class));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
return Optional.empty();
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<SkinUploadResponse> uploadSkin(Session session, @Nullable URI image, MinecraftProfileTexture.Type type, Map<String, String> metadata) {
|
protected SkinUploadResponse doUpload(Session session, URI image, Type type, Map<String, String> metadata) throws AuthenticationException, IOException {
|
||||||
return CallableFutures.asyncFailableFuture(() -> {
|
try (CloseableHttpClient client = HttpClients.createSystem()) {
|
||||||
try (CloseableHttpClient client = HttpClients.createSystem()) {
|
authorize(client, session);
|
||||||
authorize(client, session);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
return upload(client, session, image, type, metadata);
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (e.getMessage().equals("Authorization failed")) {
|
||||||
|
accessToken = null;
|
||||||
|
authorize(client, session);
|
||||||
return upload(client, session, image, type, metadata);
|
return upload(client, session, image, type, metadata);
|
||||||
} catch (IOException e) {
|
|
||||||
if (e.getMessage().equals("Authorization failed")) {
|
|
||||||
accessToken = null;
|
|
||||||
authorize(client, session);
|
|
||||||
return upload(client, session, image, type, metadata);
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
}
|
||||||
|
throw e;
|
||||||
}
|
}
|
||||||
}, HDSkinManager.skinUploadExecutor);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private SkinUploadResponse upload(CloseableHttpClient client, Session session, @Nullable URI image,
|
private SkinUploadResponse upload(CloseableHttpClient client, Session session, @Nullable URI image, MinecraftProfileTexture.Type type, Map<String, String> metadata) throws IOException {
|
||||||
MinecraftProfileTexture.Type type, Map<String, String> metadata)
|
|
||||||
throws IOException {
|
|
||||||
GameProfile profile = session.getProfile();
|
GameProfile profile = session.getProfile();
|
||||||
|
|
||||||
if (image == null) {
|
if (image == null) {
|
||||||
|
@ -128,7 +122,6 @@ public class ValhallaSkinServer implements SkinServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private SkinUploadResponse uploadUrl(CloseableHttpClient client, URI uri, GameProfile profile, MinecraftProfileTexture.Type type, Map<String, String> metadata) throws IOException {
|
private SkinUploadResponse uploadUrl(CloseableHttpClient client, URI uri, GameProfile profile, MinecraftProfileTexture.Type type, Map<String, String> metadata) throws IOException {
|
||||||
|
|
||||||
return upload(client, RequestBuilder.post()
|
return upload(client, RequestBuilder.post()
|
||||||
.setUri(buildUserTextureUri(profile, type))
|
.setUri(buildUserTextureUri(profile, type))
|
||||||
.addHeader(HttpHeaders.AUTHORIZATION, this.accessToken)
|
.addHeader(HttpHeaders.AUTHORIZATION, this.accessToken)
|
||||||
|
@ -147,11 +140,12 @@ public class ValhallaSkinServer implements SkinServer {
|
||||||
|
|
||||||
|
|
||||||
private void authorize(CloseableHttpClient client, Session session) throws IOException, AuthenticationException {
|
private void authorize(CloseableHttpClient client, Session session) throws IOException, AuthenticationException {
|
||||||
if (this.accessToken != null) {
|
if (accessToken != null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GameProfile profile = session.getProfile();
|
GameProfile profile = session.getProfile();
|
||||||
String token = session.getToken();
|
|
||||||
AuthHandshake handshake = authHandshake(client, profile.getName());
|
AuthHandshake handshake = authHandshake(client, profile.getName());
|
||||||
|
|
||||||
if (handshake.offline) {
|
if (handshake.offline) {
|
||||||
|
@ -159,17 +153,19 @@ public class ValhallaSkinServer implements SkinServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// join the session server
|
// join the session server
|
||||||
Minecraft.getMinecraft().getSessionService().joinServer(profile, token, handshake.serverId);
|
Minecraft.getMinecraft().getSessionService().joinServer(profile, session.getToken(), handshake.serverId);
|
||||||
|
|
||||||
AuthResponse response = authResponse(client, profile.getName(), handshake.verifyToken);
|
AuthResponse response = authResponse(client, profile.getName(), handshake.verifyToken);
|
||||||
if (!response.userId.equals(profile.getId())) {
|
if (!response.userId.equals(profile.getId())) {
|
||||||
throw new IOException("UUID mismatch!"); // probably won't ever throw
|
throw new IOException("UUID mismatch!"); // probably won't ever throw
|
||||||
}
|
}
|
||||||
this.accessToken = response.accessToken;
|
|
||||||
|
accessToken = response.accessToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T> T readJson(HttpResponse resp, Class<T> cl) throws IOException {
|
private <T> T readJson(HttpResponse resp, Class<T> cl) throws IOException {
|
||||||
String type = resp.getEntity().getContentType().getValue();
|
String type = resp.getEntity().getContentType().getValue();
|
||||||
|
|
||||||
if (!"application/json".equals(type)) {
|
if (!"application/json".equals(type)) {
|
||||||
try {
|
try {
|
||||||
throw new IOException("Server returned a non-json response!");
|
throw new IOException("Server returned a non-json response!");
|
||||||
|
@ -177,11 +173,13 @@ public class ValhallaSkinServer implements SkinServer {
|
||||||
EntityUtils.consumeQuietly(resp.getEntity());
|
EntityUtils.consumeQuietly(resp.getEntity());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try (Reader r = new InputStreamReader(resp.getEntity().getContent())) {
|
try (Reader r = new InputStreamReader(resp.getEntity().getContent())) {
|
||||||
if (resp.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
|
if (resp.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
|
||||||
// TODO specific error handling
|
// TODO specific error handling
|
||||||
throw new IOException(gson.fromJson(r, JsonObject.class).get("message").getAsString());
|
throw new IOException(gson.fromJson(r, JsonObject.class).get("message").getAsString());
|
||||||
}
|
}
|
||||||
|
|
||||||
return gson.fromJson(r, cl);
|
return gson.fromJson(r, cl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -208,27 +206,27 @@ public class ValhallaSkinServer implements SkinServer {
|
||||||
private URI buildUserTextureUri(GameProfile profile, MinecraftProfileTexture.Type textureType) {
|
private URI buildUserTextureUri(GameProfile profile, MinecraftProfileTexture.Type textureType) {
|
||||||
String user = UUIDTypeAdapter.fromUUID(profile.getId());
|
String user = UUIDTypeAdapter.fromUUID(profile.getId());
|
||||||
String skinType = textureType.name().toLowerCase(Locale.US);
|
String skinType = textureType.name().toLowerCase(Locale.US);
|
||||||
return URI.create(String.format("%s/user/%s/%s", this.address, user, skinType));
|
return URI.create(String.format("%s/user/%s/%s", address, user, skinType));
|
||||||
}
|
}
|
||||||
|
|
||||||
private URI getTexturesURI(GameProfile profile) {
|
private URI getTexturesURI(GameProfile profile) {
|
||||||
Preconditions.checkNotNull(profile.getId(), "profile id required for skins");
|
Preconditions.checkNotNull(profile.getId(), "profile id required for skins");
|
||||||
return URI.create(String.format("%s/user/%s", this.address, UUIDTypeAdapter.fromUUID(profile.getId())));
|
return URI.create(String.format("%s/user/%s", address, UUIDTypeAdapter.fromUUID(profile.getId())));
|
||||||
}
|
}
|
||||||
|
|
||||||
private URI getHandshakeURI() {
|
private URI getHandshakeURI() {
|
||||||
return URI.create(String.format("%s/auth/handshake", this.address));
|
return URI.create(String.format("%s/auth/handshake", address));
|
||||||
}
|
}
|
||||||
|
|
||||||
private URI getResponseURI() {
|
private URI getResponseURI() {
|
||||||
return URI.create(String.format("%s/auth/response", this.address));
|
return URI.create(String.format("%s/auth/response", address));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return new ToStringBuilder(this, IndentedToStringStyle.INSTANCE)
|
return new ToStringBuilder(this, IndentedToStringStyle.INSTANCE)
|
||||||
.append("address", this.address)
|
.append("address", address)
|
||||||
.toString();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
|
@ -244,6 +242,5 @@ public class ValhallaSkinServer implements SkinServer {
|
||||||
|
|
||||||
private String accessToken;
|
private String accessToken;
|
||||||
private UUID userId;
|
private UUID userId;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,111 +0,0 @@
|
||||||
package com.voxelmodpack.hdskins.upload;
|
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
import java.net.URI;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Uploader for Multipart form data
|
|
||||||
*
|
|
||||||
* @author Adam Mummery-Smith
|
|
||||||
* @deprecated Use httpmime multipart upload
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class ThreadMultipartPostUpload {
|
|
||||||
protected final Map<String, ?> sourceData;
|
|
||||||
|
|
||||||
protected final String method;
|
|
||||||
|
|
||||||
protected final String authorization;
|
|
||||||
|
|
||||||
protected final String urlString;
|
|
||||||
|
|
||||||
protected HttpURLConnection httpClient;
|
|
||||||
|
|
||||||
protected static final String CRLF = "\r\n";
|
|
||||||
|
|
||||||
protected static final String twoHyphens = "--";
|
|
||||||
|
|
||||||
protected static final String boundary = "----------AaB03x";
|
|
||||||
|
|
||||||
public String response;
|
|
||||||
|
|
||||||
public ThreadMultipartPostUpload(String method, String url, Map<String, ?> sourceData, @Nullable String authorization) {
|
|
||||||
this.method = method;
|
|
||||||
this.urlString = url;
|
|
||||||
this.sourceData = sourceData;
|
|
||||||
this.authorization = authorization;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ThreadMultipartPostUpload(String url, Map<String, ?> sourceData) {
|
|
||||||
this("POST", url, sourceData, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String uploadMultipart() throws IOException {
|
|
||||||
// open a URL connection
|
|
||||||
URL url = new URL(this.urlString);
|
|
||||||
|
|
||||||
// Open a HTTP connection to the URL
|
|
||||||
this.httpClient = (HttpURLConnection) url.openConnection();
|
|
||||||
this.httpClient.setDoOutput(true);
|
|
||||||
this.httpClient.setUseCaches(false);
|
|
||||||
|
|
||||||
this.httpClient.setRequestMethod(this.method);
|
|
||||||
this.httpClient.setRequestProperty("Connection", "Close");
|
|
||||||
this.httpClient.addRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)"); // For CloudFlare
|
|
||||||
|
|
||||||
if (this.sourceData.size() > 0) {
|
|
||||||
this.httpClient.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.authorization != null) {
|
|
||||||
this.httpClient.addRequestProperty("Authorization", this.authorization);
|
|
||||||
}
|
|
||||||
|
|
||||||
try (DataOutputStream outputStream = new DataOutputStream(this.httpClient.getOutputStream())) {
|
|
||||||
|
|
||||||
for (Entry<String, ?> data : this.sourceData.entrySet()) {
|
|
||||||
outputStream.writeBytes(twoHyphens + boundary + CRLF);
|
|
||||||
|
|
||||||
String paramName = data.getKey();
|
|
||||||
Object paramData = data.getValue();
|
|
||||||
|
|
||||||
if (paramData instanceof URI) {
|
|
||||||
Path uploadPath = Paths.get((URI) paramData);
|
|
||||||
|
|
||||||
outputStream.writeBytes("Content-Disposition: form-data; name=\"" + paramName + "\"; filename=\"" + uploadPath.getFileName() + "\"" + CRLF);
|
|
||||||
outputStream.writeBytes("Content-Type: image/png" + CRLF + CRLF);
|
|
||||||
|
|
||||||
|
|
||||||
Files.copy(uploadPath, outputStream);
|
|
||||||
} else {
|
|
||||||
outputStream.writeBytes("Content-Disposition: form-data; name=\"" + paramName + "\"" + CRLF + CRLF);
|
|
||||||
|
|
||||||
outputStream.writeBytes(paramData.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
outputStream.writeBytes(ThreadMultipartPostUpload.CRLF);
|
|
||||||
}
|
|
||||||
|
|
||||||
outputStream.writeBytes(twoHyphens + boundary + twoHyphens + CRLF);
|
|
||||||
}
|
|
||||||
|
|
||||||
try (InputStream input = this.httpClient.getInputStream()) {
|
|
||||||
return IOUtils.toString(input, StandardCharsets.UTF_8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in a new issue