diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/HDSkinManager.java b/src/hdskins/java/com/voxelmodpack/hdskins/HDSkinManager.java index 16346b16..2b6ebc5d 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/HDSkinManager.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/HDSkinManager.java @@ -9,8 +9,7 @@ import com.google.common.collect.HashBiMap; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import com.google.common.util.concurrent.ListeningExecutorService; -import com.google.common.util.concurrent.MoreExecutors; + import com.mojang.authlib.GameProfile; import com.mojang.authlib.minecraft.MinecraftProfileTexture; import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type; @@ -58,10 +57,10 @@ import javax.annotation.Nonnull; public final class HDSkinManager implements IResourceManagerReloadListener { - private static final ResourceLocation LOADING = new ResourceLocation("LOADING"); + public static final ExecutorService skinUploadExecutor = Executors.newSingleThreadExecutor(); + public static final ExecutorService skinDownloadExecutor = Executors.newFixedThreadPool(8); - private static final ExecutorService skinDownloadExecutor = Executors.newFixedThreadPool(8); - public static final ListeningExecutorService skinUploadExecutor = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor()); + private static final ResourceLocation LOADING = new ResourceLocation("LOADING"); public static final HDSkinManager INSTANCE = new HDSkinManager(); diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/PreviewTextureManager.java b/src/hdskins/java/com/voxelmodpack/hdskins/PreviewTextureManager.java index 0b55f3a4..1e04c028 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/PreviewTextureManager.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/PreviewTextureManager.java @@ -3,7 +3,6 @@ package com.voxelmodpack.hdskins; import com.google.common.collect.Maps; import com.mojang.authlib.GameProfile; import com.mojang.authlib.minecraft.MinecraftProfileTexture; -import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type; import com.voxelmodpack.hdskins.skins.CallableFutures; import net.minecraft.client.renderer.IImageBuffer; @@ -23,20 +22,20 @@ public class PreviewTextureManager { private final GameProfile profile; - private Map textures = null; + private Map textures = null; PreviewTextureManager(GameProfile profile) { this.profile = profile; } - public CompletableFuture getPreviewTexture(ResourceLocation location, Type type, ResourceLocation def, @Nullable SkinAvailableCallback callback) { + public CompletableFuture getPreviewTexture(ResourceLocation location, MinecraftProfileTexture.Type type, ResourceLocation def, @Nullable SkinAvailableCallback callback) { return CallableFutures.asyncFailableFuture(() -> loadPreviewTexture(location, type, def, callback) , HDSkinManager.skinUploadExecutor); } @Nullable - private PreviewTexture loadPreviewTexture(ResourceLocation location, Type type, ResourceLocation def, @Nullable SkinAvailableCallback callback) { + private PreviewTexture loadPreviewTexture(ResourceLocation location, MinecraftProfileTexture.Type type, ResourceLocation def, @Nullable SkinAvailableCallback callback) { if (textures == null) { textures = HDSkinManager.INSTANCE.getGatewayServer().getProfileTextures(profile); } @@ -47,7 +46,7 @@ public class PreviewTextureManager { MinecraftProfileTexture texture = textures.get(type); - IImageBuffer buffer = type != Type.SKIN ? null : new ImageBufferDownloadHD().withCallback(() -> { + IImageBuffer buffer = type != MinecraftProfileTexture.Type.SKIN ? null : new ImageBufferDownloadHD().withCallback(() -> { if (callback != null) { callback.skinAvailable(type, location, new MinecraftProfileTexture(texture.getUrl(), Maps.newHashMap())); } diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/ThreadDownloadImageETag.java b/src/hdskins/java/com/voxelmodpack/hdskins/ThreadDownloadImageETag.java index 6f8a20b6..f9f8693a 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/ThreadDownloadImageETag.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/ThreadDownloadImageETag.java @@ -2,6 +2,7 @@ package com.voxelmodpack.hdskins; import com.google.common.base.Charsets; import com.google.common.io.Files; +import com.voxelmodpack.hdskins.skins.MoreHttpResponses; import com.voxelmodpack.hdskins.skins.NetClient; import net.minecraft.client.renderer.IImageBuffer; @@ -12,9 +13,7 @@ import net.minecraft.util.ResourceLocation; import org.apache.commons.io.FileUtils; import org.apache.http.Header; import org.apache.http.HttpHeaders; -import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; -import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -97,9 +96,9 @@ public class ThreadDownloadImageETag extends SimpleTexture { private void loadTexture() { try (NetClient client = new NetClient("GET", imageUrl)) { - CloseableHttpResponse response = client.getResponse(); + MoreHttpResponses response = client.getResponse(); - if (client.getResponseCode() == HttpStatus.SC_NOT_FOUND) { + if (client.getResponse().getResponseCode() == HttpStatus.SC_NOT_FOUND) { // delete the cache files in case we can't connect in the future clearCache(); } else if (checkETag(response)) { @@ -147,11 +146,11 @@ public class ThreadDownloadImageETag extends SimpleTexture { FileUtils.deleteQuietly(eTagFile); } - private boolean checkETag(HttpResponse response) { + private boolean checkETag(MoreHttpResponses response) { try { if (cacheFile.isFile()) { String localETag = Files.readFirstLine(eTagFile, Charsets.UTF_8); - Header remoteETag = response.getFirstHeader(HttpHeaders.ETAG); + Header remoteETag = response.getResponse().getFirstHeader(HttpHeaders.ETAG); // true if no remote etag or does match return remoteETag == null || localETag.equals(remoteETag.getValue()); @@ -163,18 +162,18 @@ public class ThreadDownloadImageETag extends SimpleTexture { return false; // it failed, so re-fetch. } - private void loadTextureFromServer(HttpResponse response) { + private void loadTextureFromServer(MoreHttpResponses response) { LOGGER.debug("Downloading http texture from {} to {}", imageUrl, cacheFile); try { - if (response.getStatusLine().getStatusCode() / 100 == 2) { + if (response.getResponseCode() / 100 == 2) { BufferedImage bufferedimage; // write the image to disk - FileUtils.copyInputStreamToFile(response.getEntity().getContent(), cacheFile); + FileUtils.copyInputStreamToFile(response.getInputStream(), cacheFile); bufferedimage = ImageIO.read(cacheFile); // maybe write the etag to disk - Header eTag = response.getFirstHeader(HttpHeaders.ETAG); + Header eTag = response.getResponse().getFirstHeader(HttpHeaders.ETAG); if (eTag != null) { FileUtils.write(eTagFile, eTag.getValue(), Charsets.UTF_8); } diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/gui/EntityPlayerModel.java b/src/hdskins/java/com/voxelmodpack/hdskins/gui/EntityPlayerModel.java index a86af574..c7f52a25 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/gui/EntityPlayerModel.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/gui/EntityPlayerModel.java @@ -8,6 +8,7 @@ import com.voxelmodpack.hdskins.HDSkinManager; import com.voxelmodpack.hdskins.LocalTexture; import com.voxelmodpack.hdskins.LocalTexture.IBlankSkinSupplier; import com.voxelmodpack.hdskins.PreviewTextureManager; + import net.minecraft.client.Minecraft; import net.minecraft.client.resources.SkinManager; import net.minecraft.entity.EntityLivingBase; @@ -19,6 +20,7 @@ import net.minecraft.util.ResourceLocation; import java.io.File; import java.util.Map; + @SuppressWarnings("EntityConstructor") public class EntityPlayerModel extends EntityLivingBase implements IBlankSkinSupplier { diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/gui/GuiSkins.java b/src/hdskins/java/com/voxelmodpack/hdskins/gui/GuiSkins.java index f1d981f1..091b2e6d 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/gui/GuiSkins.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/gui/GuiSkins.java @@ -16,6 +16,7 @@ import com.mojang.authlib.minecraft.MinecraftProfileTexture; import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type; import com.mumfrey.liteloader.util.log.LiteLoaderLogger; import com.voxelmodpack.hdskins.HDSkinManager; +import com.voxelmodpack.hdskins.skins.SkinUpload; import com.voxelmodpack.hdskins.skins.SkinUploadResponse; import com.voxelmodpack.hdskins.upload.awt.ThreadOpenFilePNG; @@ -544,7 +545,7 @@ public class GuiSkins extends GameGui { btnUpload.enabled = canUpload(); HDSkinManager.INSTANCE.getGatewayServer() - .uploadSkin(mc.getSession(), path, textureType, getMetadata()) + .uploadSkin(mc.getSession(), new SkinUpload(textureType, path, getMetadata())) .thenAccept(this::onUploadComplete) .exceptionally(this::onUploadFailure); } diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/skins/AbstractSkinServer.java b/src/hdskins/java/com/voxelmodpack/hdskins/skins/AbstractSkinServer.java index 2b8cb9bd..664bd085 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/skins/AbstractSkinServer.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/skins/AbstractSkinServer.java @@ -1,13 +1,10 @@ package com.voxelmodpack.hdskins.skins; import java.io.IOException; -import java.net.URI; import java.util.Collections; import java.util.Map; import java.util.concurrent.CompletableFuture; -import javax.annotation.Nullable; - import org.apache.logging.log4j.util.Strings; import com.google.gson.JsonParseException; @@ -32,19 +29,23 @@ public abstract class AbstractSkinServer implements SkinServer { @Override public Map getProfileTextures(GameProfile profile) { - MinecraftTexturesPayload payload = getProfileData(profile); + try { + MinecraftTexturesPayload payload = getProfileData(profile); + + if (payload != null && payload.getTextures() != null) { + return payload.getTextures(); + } + } catch (IOException ignored) { - if (payload != null && payload.getTextures() != null) { - return payload.getTextures(); } return Collections.emptyMap(); } @Override - public final CompletableFuture uploadSkin(Session session, @Nullable URI image, Type type, Map metadata) { + public CompletableFuture uploadSkin(Session session, SkinUpload upload) { return CallableFutures.asyncFailableFuture(() -> { - return doUpload(session, image, type, metadata); + return doUpload(session, upload); }, HDSkinManager.skinUploadExecutor); } @@ -55,7 +56,9 @@ public abstract class AbstractSkinServer implements SkinServer { } } - protected abstract SkinUploadResponse doUpload(Session session, URI image, Type type, Map metadata) throws AuthenticationException, IOException; + protected abstract MinecraftTexturesPayload getProfileData(GameProfile profile) throws IOException; + + protected abstract SkinUploadResponse doUpload(Session session, SkinUpload upload) throws AuthenticationException, IOException; @Override public String toString() { diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/skins/BethlehemSkinServer.java b/src/hdskins/java/com/voxelmodpack/hdskins/skins/BethlehemSkinServer.java index eb6f235c..5d061f8e 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/skins/BethlehemSkinServer.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/skins/BethlehemSkinServer.java @@ -1,16 +1,13 @@ package com.voxelmodpack.hdskins.skins; import java.io.IOException; -import java.net.URI; import java.util.Locale; import java.util.Map; -import org.apache.http.HttpStatus; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap.Builder; 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; @@ -26,47 +23,45 @@ public class BethlehemSkinServer extends AbstractSkinServer { } @Override - public MinecraftTexturesPayload getProfileData(GameProfile profile) { + public MinecraftTexturesPayload getProfileData(GameProfile profile) throws IOException { try (NetClient client = new NetClient("GET", getPath(profile))) { - if (client.getResponseCode() == HttpStatus.SC_OK) { - return gson.fromJson(client.getResponseText(), MinecraftTexturesPayload.class); + if (client.getResponse().ok()) { + return client.getResponse().json(MinecraftTexturesPayload.class); } - } catch (IOException e) { - } return null; } @Override - protected SkinUploadResponse doUpload(Session session, URI image, Type type, Map metadata) throws AuthenticationException, IOException { + protected SkinUploadResponse doUpload(Session session, SkinUpload upload) throws AuthenticationException, IOException { SkinServer.verifyServerConnection(session, SERVER_ID); try (NetClient client = new NetClient("POST", address)) { - client.putHeaders(createHeaders(session, type, image, metadata)); + client.putHeaders(createHeaders(session, upload)); - if (image != null) { - client.putFile(type.toString().toLowerCase(Locale.US), "image/png", image); + if (upload.getImage() != null) { + client.putFile(upload.getType().toString().toLowerCase(Locale.US), "image/png", upload.getImage()); } - if (client.getResponseCode() == HttpStatus.SC_OK) { - return new SkinUploadResponse(client.getResponseText()); + if (client.getResponse().ok()) { + return new SkinUploadResponse(client.getResponse().text()); } - throw new IOException(client.getResponseText()); + throw new IOException(client.getResponse().text()); } } - protected Map createHeaders(Session session, Type type, URI image, Map metadata) { + protected Map createHeaders(Session session, SkinUpload upload) { Builder builder = ImmutableMap.builder() .put("accessToken", session.getToken()) .put("user", session.getUsername()) .put("uuid", UUIDTypeAdapter.fromUUID(session.getProfile().getId())) - .put("type", type.toString().toLowerCase(Locale.US)); + .put("type", upload.getType().toString().toLowerCase(Locale.US)); - if (image == null) { + if (upload.getImage() == null) { builder.put("clear", "1"); } else { - builder.put("model", metadata.getOrDefault("mode", "default")); + builder.put("model", upload.getMetadata().getOrDefault("mode", "default")); } return builder.build(); diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/skins/LegacySkinServer.java b/src/hdskins/java/com/voxelmodpack/hdskins/skins/LegacySkinServer.java index 1780b31e..f464c70c 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/skins/LegacySkinServer.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/skins/LegacySkinServer.java @@ -11,16 +11,18 @@ import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload; import com.mojang.util.UUIDTypeAdapter; import net.minecraft.util.Session; -import org.apache.http.HttpStatus; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.util.Strings; import java.io.IOException; +import java.net.HttpURLConnection; import java.net.URI; +import java.net.URL; import java.util.EnumMap; import java.util.Locale; import java.util.Map; + import javax.annotation.Nullable; @ServerType("legacy") @@ -49,21 +51,14 @@ public class LegacySkinServer extends AbstractSkinServer { return map; } - @SuppressWarnings("deprecation") @Override - public MinecraftTexturesPayload getProfileData(GameProfile profile) { + public MinecraftTexturesPayload getProfileData(GameProfile profile) throws IOException { ImmutableMap.Builder builder = ImmutableMap.builder(); - for (Type type : Type.values()) { + String url = getPath(address, type, profile); - - try (NetClient client = new NetClient("GET", url)) { - if (client.getResponseCode() != HttpStatus.SC_OK) { - throw new IOException("Bad response code: " + client.getResponseCode()); - } - - builder.put(type, new MinecraftProfileTexture(url, null)); - logger.debug("Found skin for {} at {}", profile.getName(), url); + try { + builder.put(type, loadProfileTexture(profile, url)); } catch (IOException e) { logger.trace("Couldn't find texture for {} at {}. Does it exist?", profile.getName(), url, e); } @@ -72,25 +67,32 @@ public class LegacySkinServer extends AbstractSkinServer { Map map = builder.build(); if (map.isEmpty()) { - logger.debug("No textures found for {} at {}", profile, address); - return null; + throw new IOException(String.format("No textures found for %s at %s", profile, address)); } - return TexturesPayloadBuilder.createTexturesPayload(profile, map); } + private MinecraftProfileTexture loadProfileTexture(GameProfile profile, String url) throws IOException { + HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection(); + if (urlConnection.getResponseCode() / 100 != 2) { + throw new IOException("Bad response code: " + urlConnection.getResponseCode() + ". URL: " + url); + } + logger.debug("Found skin for {} at {}", profile.getName(), url); + return new MinecraftProfileTexture(url, null); + } + @Override - protected SkinUploadResponse doUpload(Session session, URI image, Type type, Map metadata) throws AuthenticationException, IOException { + protected SkinUploadResponse doUpload(Session session, SkinUpload skin) throws AuthenticationException, IOException { SkinServer.verifyServerConnection(session, SERVER_ID); try (NetClient client = new NetClient("POST", address)) { - client.putHeaders(createHeaders(session, type, image, metadata)); + client.putHeaders(createHeaders(session, skin.getType(), skin.getImage(), skin.getMetadata())); - if (image != null) { - client.putFile(type.toString().toLowerCase(Locale.US), "image/png", image); + if (skin.getImage() != null) { + client.putFile(skin.getType().toString().toLowerCase(Locale.US), "image/png", skin.getImage()); } - String response = client.getResponseText(); + String response = client.getResponse().text(); if (response.startsWith("ERROR: ")) { // lol @ "ERROR: OK" response = response.substring(7); @@ -104,7 +106,6 @@ public class LegacySkinServer extends AbstractSkinServer { } } - protected Map createHeaders(Session session, Type type, URI image, Map metadata) { Builder builder = ImmutableMap.builder() .put("user", session.getUsername()) diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/skins/MoreHttpResponses.java b/src/hdskins/java/com/voxelmodpack/hdskins/skins/MoreHttpResponses.java new file mode 100644 index 00000000..3b7be207 --- /dev/null +++ b/src/hdskins/java/com/voxelmodpack/hdskins/skins/MoreHttpResponses.java @@ -0,0 +1,75 @@ +package com.voxelmodpack.hdskins.skins; + +import com.google.common.io.CharStreams; +import org.apache.http.HttpStatus; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.impl.client.CloseableHttpClient; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.lang.reflect.Type; +import java.nio.charset.StandardCharsets; +import java.util.stream.Stream; + +/** + * Utility class for getting different response types from a http response. + */ +@FunctionalInterface +public interface MoreHttpResponses extends AutoCloseable { + + CloseableHttpResponse getResponse(); + + default boolean ok() { + return getResponseCode() == HttpStatus.SC_OK; + } + + default int getResponseCode() { + return getResponse().getStatusLine().getStatusCode(); + } + + default InputStream getInputStream() throws IOException { + return getResponse().getEntity().getContent(); + } + + default BufferedReader getReader() throws IOException { + return new BufferedReader(new InputStreamReader(getInputStream(), StandardCharsets.UTF_8)); + } + + default String text() throws IOException { + try (BufferedReader reader = getReader()) { + return CharStreams.toString(reader); + } + } + + default Stream lines() throws IOException { + try (BufferedReader reader = getReader()) { + return reader.lines(); + } + } + + default T json(Class type) throws IOException { + try (Reader reader = new InputStreamReader(getResponse().getEntity().getContent())) { + return SkinServer.gson.fromJson(reader, type); + } + } + + default T json(Type type) throws IOException { + try (Reader reader = new InputStreamReader(getResponse().getEntity().getContent())) { + return SkinServer.gson.fromJson(reader, type); + } + } + + @Override + default void close() throws IOException { + this.getResponse().close(); + } + + static MoreHttpResponses execute(CloseableHttpClient client, HttpUriRequest request) throws IOException { + CloseableHttpResponse response = client.execute(request); + return () -> response; + } +} diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/skins/NetClient.java b/src/hdskins/java/com/voxelmodpack/hdskins/skins/NetClient.java index a982f647..d5a621bf 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/skins/NetClient.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/skins/NetClient.java @@ -1,23 +1,19 @@ package com.voxelmodpack.hdskins.skins; -import java.io.BufferedReader; import java.io.Closeable; import java.io.File; import java.io.IOException; -import java.io.InputStreamReader; import java.net.URI; import java.util.Map; import org.apache.http.HttpEntity; -import org.apache.http.HttpStatus; -import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.methods.RequestBuilder; import org.apache.http.entity.ContentType; 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.util.EntityUtils; /** * Ew. Why so many builders? >.< @@ -26,11 +22,19 @@ public class NetClient implements Closeable { private static CloseableHttpClient client = null; + public static CloseableHttpClient nativeClient() { + if (client == null) { + client = HttpClients.createSystem(); + } + + return client; + } + private RequestBuilder rqBuilder; private Map headers; - private CloseableHttpResponse response = null; + private MoreHttpResponses response; public NetClient(String method, String uri) { start(method, uri); @@ -49,7 +53,9 @@ public class NetClient implements Closeable { headers = null; if (response != null) { - EntityUtils.consumeQuietly(response.getEntity()); + try { + response.close(); + } catch (IOException ignored) {} response = null; } @@ -97,17 +103,13 @@ public class NetClient implements Closeable { } } - if (client == null) { - client = HttpClients.createSystem(); - } - - response = client.execute(request); + response = MoreHttpResponses.execute(nativeClient(), request); } /** * Gets or obtains the http response body. */ - public CloseableHttpResponse getResponse() throws IOException { + public MoreHttpResponses getResponse() throws IOException { if (response == null) { send(); } @@ -115,33 +117,6 @@ public class NetClient implements Closeable { return response; } - /** - * Gets or obtains a response status code. - */ - public int getResponseCode() throws IOException { - return getResponse().getStatusLine().getStatusCode(); - } - - /** - * Consumes and returns the entire response body. - */ - public String getResponseText() throws IOException { - if (getResponse().getEntity() == null) { - return ""; - } - - try (BufferedReader reader = new BufferedReader(new InputStreamReader(getResponse().getEntity().getContent()))) { - StringBuilder builder = new StringBuilder(); - - int ch; - while ((ch = reader.read()) != -1) { - builder.append((char)ch); - } - - return builder.toString(); - } - } - @Override public void close() throws IOException { try { diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/skins/SkinServer.java b/src/hdskins/java/com/voxelmodpack/hdskins/skins/SkinServer.java index a08a4905..725b65c4 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/skins/SkinServer.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/skins/SkinServer.java @@ -8,21 +8,16 @@ import com.mojang.authlib.GameProfile; import com.mojang.authlib.exceptions.AuthenticationException; import com.mojang.authlib.minecraft.MinecraftProfileTexture; import com.mojang.authlib.minecraft.MinecraftSessionService; -import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload; import com.mojang.util.UUIDTypeAdapter; import com.mumfrey.liteloader.modconfig.Exposable; - import net.minecraft.client.Minecraft; import net.minecraft.util.Session; -import java.net.URI; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.CompletableFuture; -import javax.annotation.Nullable; - public interface SkinServer extends Exposable { Gson gson = new GsonBuilder() @@ -33,15 +28,13 @@ public interface SkinServer extends Exposable { "http://skins.voxelmodpack.com", "http://skinmanager.voxelmodpack.com")); - MinecraftTexturesPayload getProfileData(GameProfile profile); - Map getProfileTextures(GameProfile profile); - CompletableFuture uploadSkin(Session session, @Nullable URI image, MinecraftProfileTexture.Type type, Map metadata); + CompletableFuture uploadSkin(Session session, SkinUpload upload); void validate() throws JsonParseException; - public static void verifyServerConnection(Session session, String serverId) throws AuthenticationException { + static void verifyServerConnection(Session session, String serverId) throws AuthenticationException { MinecraftSessionService service = Minecraft.getMinecraft().getSessionService(); service.joinServer(session.getProfile(), session.getToken(), serverId); } diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/skins/SkinUpload.java b/src/hdskins/java/com/voxelmodpack/hdskins/skins/SkinUpload.java new file mode 100644 index 00000000..2ff82e6a --- /dev/null +++ b/src/hdskins/java/com/voxelmodpack/hdskins/skins/SkinUpload.java @@ -0,0 +1,34 @@ +package com.voxelmodpack.hdskins.skins; + +import com.mojang.authlib.minecraft.MinecraftProfileTexture; + +import java.net.URI; +import java.util.Map; + +import javax.annotation.Nullable; + +public class SkinUpload { + + private final URI image; + private final Map metadata; + private final MinecraftProfileTexture.Type type; + + public SkinUpload(MinecraftProfileTexture.Type type, @Nullable URI image, Map metadata) { + this.image = image; + this.metadata = metadata; + this.type = type; + } + + @Nullable + public URI getImage() { + return image; + } + + public Map getMetadata() { + return metadata; + } + + public MinecraftProfileTexture.Type getType() { + return type; + } +} diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/skins/ValhallaSkinServer.java b/src/hdskins/java/com/voxelmodpack/hdskins/skins/ValhallaSkinServer.java index 8870c999..8327e6a2 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/skins/ValhallaSkinServer.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/skins/ValhallaSkinServer.java @@ -5,7 +5,6 @@ import com.google.gson.JsonObject; 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.mojang.util.UUIDTypeAdapter; @@ -14,24 +13,16 @@ import javax.annotation.Nullable; import net.minecraft.client.Minecraft; import net.minecraft.util.Session; import org.apache.http.HttpHeaders; -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; import org.apache.http.NameValuePair; -import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.methods.RequestBuilder; import org.apache.http.entity.ContentType; 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.message.BasicNameValuePair; -import org.apache.http.util.EntityUtils; import java.io.File; import java.io.IOException; -import java.io.InputStreamReader; -import java.io.Reader; import java.net.URI; import java.util.Locale; import java.util.Map; @@ -46,79 +37,81 @@ public class ValhallaSkinServer extends AbstractSkinServer { super(address); } - @Override - public MinecraftTexturesPayload getProfileData(GameProfile profile) { - try (CloseableHttpClient client = HttpClients.createSystem()) { - try (CloseableHttpResponse response = client.execute(new HttpGet(getTexturesURI(profile)))) { - if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { - return readJson(response, MinecraftTexturesPayload.class); - } - } + @Override + public MinecraftTexturesPayload getProfileData(GameProfile profile) throws IOException { + + try (MoreHttpResponses response = MoreHttpResponses.execute(NetClient.nativeClient(), new HttpGet(getTexturesURI(profile)))) { + + if (response.ok()) { + return readJson(response, MinecraftTexturesPayload.class); + } + throw new IOException("Server sent non-ok response code: " + response.getResponseCode()); + } + } + + @Override + protected SkinUploadResponse doUpload(Session session, SkinUpload skin) throws AuthenticationException, IOException { + URI image = skin.getImage(); + Map metadata = skin.getMetadata(); + MinecraftProfileTexture.Type type = skin.getType(); + + authorize(session); + + try { + return upload(session, image, type, metadata); } catch (IOException e) { - e.printStackTrace(); - } - - return null; - } - - @Override - protected SkinUploadResponse doUpload(Session session, URI image, Type type, Map metadata) throws AuthenticationException, IOException { - try (CloseableHttpClient client = HttpClients.createSystem()) { - authorize(client, session); - - 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); - } - throw e; + if (e.getMessage().equals("Authorization failed")) { + accessToken = null; + authorize(session); + return upload(session, image, type, metadata); } + throw e; } } - private SkinUploadResponse upload(CloseableHttpClient client, Session session, @Nullable URI image, MinecraftProfileTexture.Type type, Map metadata) throws IOException { + private SkinUploadResponse upload(Session session, @Nullable URI image, + MinecraftProfileTexture.Type type, Map metadata) + throws IOException { GameProfile profile = session.getProfile(); if (image == null) { - return resetSkin(client, profile, type); + return resetSkin(profile, type); } switch (image.getScheme()) { case "file": - return uploadFile(client, new File(image), profile, type, metadata); + return uploadFile(new File(image), profile, type, metadata); case "http": case "https": - return uploadUrl(client, image, profile, type, metadata); + return uploadUrl(image, profile, type, metadata); default: throw new IOException("Unsupported URI scheme: " + image.getScheme()); } } - private SkinUploadResponse resetSkin(CloseableHttpClient client, GameProfile profile, MinecraftProfileTexture.Type type) throws IOException { - return upload(client, RequestBuilder.delete() + private SkinUploadResponse resetSkin(GameProfile profile, MinecraftProfileTexture.Type type) throws IOException { + return upload(RequestBuilder.delete() .setUri(buildUserTextureUri(profile, type)) .addHeader(HttpHeaders.AUTHORIZATION, this.accessToken) .build()); } - private SkinUploadResponse uploadFile(CloseableHttpClient client, File file, GameProfile profile, MinecraftProfileTexture.Type type, Map metadata) throws IOException { + private SkinUploadResponse uploadFile(File file, GameProfile profile, MinecraftProfileTexture.Type type, Map metadata) throws IOException { MultipartEntityBuilder b = MultipartEntityBuilder.create(); b.addBinaryBody("file", file, ContentType.create("image/png"), file.getName()); metadata.forEach(b::addTextBody); - return upload(client, RequestBuilder.put() + return upload(RequestBuilder.put() .setUri(buildUserTextureUri(profile, type)) .addHeader(HttpHeaders.AUTHORIZATION, this.accessToken) .setEntity(b.build()) .build()); } - private SkinUploadResponse uploadUrl(CloseableHttpClient client, URI uri, GameProfile profile, MinecraftProfileTexture.Type type, Map metadata) throws IOException { - return upload(client, RequestBuilder.post() + private SkinUploadResponse uploadUrl(URI uri, GameProfile profile, MinecraftProfileTexture.Type type, Map metadata) throws IOException { + + return upload(RequestBuilder.post() .setUri(buildUserTextureUri(profile, type)) .addHeader(HttpHeaders.AUTHORIZATION, this.accessToken) .addParameter("file", uri.toString()) @@ -128,21 +121,20 @@ public class ValhallaSkinServer extends AbstractSkinServer { .build()); } - private SkinUploadResponse upload(CloseableHttpClient client, HttpUriRequest request) throws IOException { - try (CloseableHttpResponse response = client.execute(request)) { + private SkinUploadResponse upload(HttpUriRequest request) throws IOException { + try (MoreHttpResponses response = MoreHttpResponses.execute(NetClient.nativeClient(), request)) { return readJson(response, SkinUploadResponse.class); } } - - private void authorize(CloseableHttpClient client, Session session) throws IOException, AuthenticationException { - if (accessToken != null) { + private void authorize(Session session) throws IOException, AuthenticationException { + if (this.accessToken != null) { return; } GameProfile profile = session.getProfile(); - AuthHandshake handshake = authHandshake(client, profile.getName()); + AuthHandshake handshake = authHandshake(profile.getName()); if (handshake.offline) { return; @@ -151,7 +143,7 @@ public class ValhallaSkinServer extends AbstractSkinServer { // join the session server Minecraft.getMinecraft().getSessionService().joinServer(profile, session.getToken(), handshake.serverId); - AuthResponse response = authResponse(client, profile.getName(), handshake.verifyToken); + AuthResponse response = authResponse(profile.getName(), handshake.verifyToken); if (!response.userId.equals(profile.getId())) { throw new IOException("UUID mismatch!"); // probably won't ever throw } @@ -159,29 +151,21 @@ public class ValhallaSkinServer extends AbstractSkinServer { accessToken = response.accessToken; } - private T readJson(HttpResponse resp, Class cl) throws IOException { - String type = resp.getEntity().getContentType().getValue(); - + private T readJson(MoreHttpResponses resp, Class cl) throws IOException { + String type = resp.getResponse().getEntity().getContentType().getValue(); if (!"application/json".equals(type)) { - try { - throw new IOException("Server returned a non-json response!"); - } finally { - EntityUtils.consumeQuietly(resp.getEntity()); - } + throw new IOException("Server returned a non-json response!"); } - try (Reader r = new InputStreamReader(resp.getEntity().getContent())) { - if (resp.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { - // TODO specific error handling - throw new IOException(gson.fromJson(r, JsonObject.class).get("message").getAsString()); - } - - return gson.fromJson(r, cl); + if (resp.ok()) { + return resp.json(cl); } + throw new IOException(resp.json(JsonObject.class).get("message").getAsString()); + } - private AuthHandshake authHandshake(CloseableHttpClient client, String name) throws IOException { - try (CloseableHttpResponse resp = client.execute(RequestBuilder.post() + private AuthHandshake authHandshake(String name) throws IOException { + try (MoreHttpResponses resp = MoreHttpResponses.execute(NetClient.nativeClient(), RequestBuilder.post() .setUri(getHandshakeURI()) .addParameter("name", name) .build())) { @@ -189,8 +173,8 @@ public class ValhallaSkinServer extends AbstractSkinServer { } } - private AuthResponse authResponse(CloseableHttpClient client, String name, long verifyToken) throws IOException { - try (CloseableHttpResponse resp = client.execute(RequestBuilder.post() + private AuthResponse authResponse(String name, long verifyToken) throws IOException { + try (MoreHttpResponses resp = MoreHttpResponses.execute(NetClient.nativeClient(), RequestBuilder.post() .setUri(getResponseURI()) .addParameter("name", name) .addParameter("verifyToken", String.valueOf(verifyToken)) diff --git a/src/main/java/com/minelittlepony/render/layer/LayerPonyCustomHead.java b/src/main/java/com/minelittlepony/render/layer/LayerPonyCustomHead.java index f5900193..9b906e47 100644 --- a/src/main/java/com/minelittlepony/render/layer/LayerPonyCustomHead.java +++ b/src/main/java/com/minelittlepony/render/layer/LayerPonyCustomHead.java @@ -101,7 +101,7 @@ public class LayerPonyCustomHead implements LayerRen } private ModelWrapper getModel() { - return ((IRenderPony) renderer).getModelWrapper(); + return ((IRenderPony) renderer).getModelWrapper(); } @Override