Split off the boilerplate code

This commit is contained in:
Sollace 2018-08-08 14:55:17 +02:00
parent 018a0dd141
commit a815d13912
8 changed files with 212 additions and 262 deletions

View file

@ -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;
}

View file

@ -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) {

View file

@ -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;
}
} }

View file

@ -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();
} }
} }

View file

@ -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;
}
}
} }

View file

@ -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);

View file

@ -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;
} }
} }

View file

@ -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);
}
}
}