diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/HDSkinManager.java b/src/hdskins/java/com/voxelmodpack/hdskins/HDSkinManager.java index 10662436..23eab36b 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/HDSkinManager.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/HDSkinManager.java @@ -51,13 +51,7 @@ import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; -import java.util.Base64; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.UUID; +import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -123,7 +117,14 @@ public final class HDSkinManager implements IResourceManagerReloadListener { for (SkinServer server : skinServers) { try { if (!server.getFeatures().contains(Feature.SYNTHETIC)) { - server.loadProfileData(profile).getTextures().forEach(textureMap::putIfAbsent); + server.loadProfileData(profile).getTextures().forEach((k, v) -> { + try { + Type t = Type.valueOf(k.toUpperCase(Locale.ROOT)); + if (t != null) { + textureMap.put(t, v); + } + } catch (Exception e) {} + }); if (textureMap.size() == Type.values().length) { break; } diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/SkinUploader.java b/src/hdskins/java/com/voxelmodpack/hdskins/SkinUploader.java index 12f82221..1b54a0a6 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/SkinUploader.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/SkinUploader.java @@ -232,7 +232,7 @@ public class SkinUploader implements Closeable { if (throwable instanceof AuthenticationUnavailableException) { offline = true; } else if (throwable instanceof InvalidCredentialsException) { - setError("hdskins.error.session"); + setError("Invalid session: Please try restarting Minecraft"); } else if (throwable instanceof AuthenticationException) { throttlingNeck = true; } else if (throwable instanceof HttpException) { diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/resources/PreviewTextureManager.java b/src/hdskins/java/com/voxelmodpack/hdskins/resources/PreviewTextureManager.java index b4e8500f..c4b5995b 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/resources/PreviewTextureManager.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/resources/PreviewTextureManager.java @@ -2,13 +2,14 @@ package com.voxelmodpack.hdskins.resources; import com.google.common.collect.Maps; import com.mojang.authlib.minecraft.MinecraftProfileTexture; -import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload; import com.voxelmodpack.hdskins.resources.texture.ISkinAvailableCallback; import com.voxelmodpack.hdskins.resources.texture.ImageBufferDownloadHD; +import com.voxelmodpack.hdskins.server.TexturePayload; import net.minecraft.client.resources.SkinManager; import net.minecraft.util.ResourceLocation; +import java.util.Locale; import java.util.Map; import javax.annotation.Nullable; @@ -19,19 +20,22 @@ import javax.annotation.Nullable; */ public class PreviewTextureManager { - private final Map textures; + private final Map textures; - public PreviewTextureManager(MinecraftTexturesPayload payload) { + public PreviewTextureManager(TexturePayload payload) { this.textures = payload.getTextures(); } @Nullable public PreviewTexture getPreviewTexture(ResourceLocation location, MinecraftProfileTexture.Type type, ResourceLocation def, @Nullable SkinManager.SkinAvailableCallback callback) { - if (!textures.containsKey(type)) { + + String key = type.name().toLowerCase(Locale.ROOT); + + if (!textures.containsKey(key)) { return null; } - MinecraftProfileTexture texture = textures.get(type); + MinecraftProfileTexture texture = textures.get(key); ISkinAvailableCallback buff = new ImageBufferDownloadHD(type, () -> { if (callback != null) { callback.skinAvailable(type, location, new MinecraftProfileTexture(texture.getUrl(), Maps.newHashMap())); diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/resources/texture/ThreadDownloadImageETag.java b/src/hdskins/java/com/voxelmodpack/hdskins/resources/texture/ThreadDownloadImageETag.java deleted file mode 100644 index c3a64921..00000000 --- a/src/hdskins/java/com/voxelmodpack/hdskins/resources/texture/ThreadDownloadImageETag.java +++ /dev/null @@ -1,222 +0,0 @@ -package com.voxelmodpack.hdskins.resources.texture; - -import com.voxelmodpack.hdskins.util.MoreHttpResponses; -import net.minecraft.client.renderer.IImageBuffer; -import net.minecraft.client.renderer.texture.SimpleTexture; -import net.minecraft.client.renderer.texture.TextureUtil; -import net.minecraft.client.resources.IResourceManager; -import net.minecraft.util.ResourceLocation; -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.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpHead; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import java.awt.image.BufferedImage; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Collections; -import java.util.concurrent.atomic.AtomicInteger; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import javax.imageio.ImageIO; - -/** - * @deprecated - * Do not use. This will be removed in a later update. - * Now that legacy includes the etag in the hash, it is no longer required to save it to disk. - */ -@Deprecated -public class ThreadDownloadImageETag extends SimpleTexture implements IBufferedTexture { - - private static final Logger LOGGER = LogManager.getLogger(); - private static final AtomicInteger THREAD_ID = new AtomicInteger(0); - private static CloseableHttpClient client = HttpClients.createSystem(); - - @Nonnull - private final Path cacheFile; - private final Path eTagFile; - private final String imageUrl; - @Nullable - private final IImageBuffer imageBuffer; - - @Nullable - private BufferedImage bufferedImage; - @Nullable - private Thread imageThread; - private boolean textureUploaded; - - public ThreadDownloadImageETag(@Nonnull File cacheFileIn, String imageUrlIn, ResourceLocation defLocation, @Nullable IImageBuffer imageBufferIn) { - super(defLocation); - this.cacheFile = cacheFileIn.toPath(); - this.eTagFile = cacheFile.resolveSibling(cacheFile.getFileName() + ".etag"); - this.imageUrl = imageUrlIn; - this.imageBuffer = imageBufferIn; - } - - private void checkTextureUploaded() { - if (!this.textureUploaded) { - if (this.bufferedImage != null) { - if (this.textureLocation != null) { - this.deleteGlTexture(); - } - - TextureUtil.uploadTextureImage(super.getGlTextureId(), this.bufferedImage); - this.textureUploaded = true; - } - } - } - - @Override - public int getGlTextureId() { - this.checkTextureUploaded(); - return super.getGlTextureId(); - } - - private void setBufferedImage(@Nonnull BufferedImage bufferedImageIn) { - this.bufferedImage = bufferedImageIn; - - if (this.imageBuffer != null) { - this.imageBuffer.skinAvailable(); - } - } - - @Override - @Nullable - public BufferedImage getBufferedImage() { - return bufferedImage; - } - - @Override - public void loadTexture(IResourceManager resourceManager) throws IOException { - if (this.bufferedImage == null && this.textureLocation != null) { - super.loadTexture(resourceManager); - } - - if (this.imageThread == null) { - this.imageThread = new Thread(this::loadTexture, "Texture Downloader #" + THREAD_ID.incrementAndGet()); - this.imageThread.setDaemon(true); - this.imageThread.start(); - } - } - - private void loadTexture() { - switch (checkLocalCache()) { - case GONE: - clearCache(); - break; - case OK: - case NOPE: - LOGGER.debug("Loading http texture from local cache ({})", cacheFile); - try { - // e-tag check passed. Load the local file - setLocalCache(); - break; - } catch (IOException e) { - // Nope. Local cache is corrupt. Re-download it. - // fallthrough to load from network - LOGGER.error("Couldn't load skin {}", cacheFile, e); - } - case OUTDATED: - loadTextureFromServer(); - } - } - - - private void setLocalCache() throws IOException { - if (Files.isRegularFile(cacheFile)) { - try (InputStream in = Files.newInputStream(cacheFile)) { - BufferedImage image = ImageIO.read(in); - if (imageBuffer != null) { - image = imageBuffer.parseUserSkin(image); - } - setBufferedImage(image); - } - } - } - - private void clearCache() { - try { - Files.deleteIfExists(this.cacheFile); - Files.deleteIfExists(this.eTagFile); - } catch (IOException e) { - // ignore - } - } - - private enum State { - OUTDATED, - GONE, - NOPE, - OK - } - - private State checkLocalCache() { - try (CloseableHttpResponse response = client.execute(new HttpHead(imageUrl))) { - int code = response.getStatusLine().getStatusCode(); - if (code == HttpStatus.SC_NOT_FOUND) { - return State.GONE; - } - if (code != HttpStatus.SC_OK) { - return State.NOPE; - } - return checkETag(response) ? State.OK : State.OUTDATED; - } catch (IOException e) { - LOGGER.error("Couldn't load skin {} ", imageUrl, e); - return State.NOPE; - } - } - - private boolean checkETag(HttpResponse response) { - try { - if (Files.isRegularFile(cacheFile)) { - String localETag = Files.lines(eTagFile).limit(1).findFirst().orElse(""); - Header remoteETag = response.getFirstHeader(HttpHeaders.ETAG); - // true if no remote etag or does match - return remoteETag == null || localETag.equals(remoteETag.getValue()); - } - return false; - } catch (IOException e) { - // it failed, so re-fetch. - return false; - } - } - - private void loadTextureFromServer() { - LOGGER.debug("Downloading http texture from {} to {}", imageUrl, cacheFile); - try (MoreHttpResponses resp = MoreHttpResponses.execute(client, new HttpGet(imageUrl))) { - if (resp.ok()) { - // write the image to disk - Files.createDirectories(cacheFile.getParent()); - Files.copy(resp.inputStream(), cacheFile); - - try (InputStream in = Files.newInputStream(cacheFile)) { - BufferedImage bufferedimage = ImageIO.read(in); - - // maybe write the etag to disk - Header eTag = resp.response().getFirstHeader(HttpHeaders.ETAG); - if (eTag != null) { - Files.write(eTagFile, Collections.singleton(eTag.getValue())); - } - - if (imageBuffer != null) { - bufferedimage = imageBuffer.parseUserSkin(bufferedimage); - } - setBufferedImage(bufferedimage); - } - } - } catch (Exception exception) { - LOGGER.error("Couldn\'t download http texture", exception); - } - } -} - diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/server/BethlehemSkinServer.java b/src/hdskins/java/com/voxelmodpack/hdskins/server/BethlehemSkinServer.java index c63c73fb..8109d13f 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/server/BethlehemSkinServer.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/server/BethlehemSkinServer.java @@ -6,7 +6,6 @@ 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.yggdrasil.response.MinecraftTexturesPayload; import com.mojang.util.UUIDTypeAdapter; import com.voxelmodpack.hdskins.gui.Feature; import com.voxelmodpack.hdskins.util.IndentedToStringStyle; @@ -43,13 +42,13 @@ public class BethlehemSkinServer implements SkinServer { } @Override - public MinecraftTexturesPayload loadProfileData(GameProfile profile) throws IOException { + public TexturePayload loadProfileData(GameProfile profile) throws IOException { try (MoreHttpResponses response = new NetClient("GET", getPath(profile)).send()) { if (!response.ok()) { throw new HttpException(response.response()); } - return response.unwrapAsJson(MinecraftTexturesPayload.class); + return response.requireOk().json(TexturePayload.class, "Invalid texture payload"); } } @@ -66,9 +65,7 @@ public class BethlehemSkinServer implements SkinServer { } try (MoreHttpResponses response = client.send()) { - if (!response.ok()) { - throw response.exception(); - } + response.requireOk(); } } diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/server/LegacySkinServer.java b/src/hdskins/java/com/voxelmodpack/hdskins/server/LegacySkinServer.java index b8d9d3b0..82e9bd57 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/server/LegacySkinServer.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/server/LegacySkinServer.java @@ -8,13 +8,11 @@ import com.google.gson.annotations.Expose; import com.mojang.authlib.GameProfile; import com.mojang.authlib.exceptions.AuthenticationException; import com.mojang.authlib.minecraft.MinecraftProfileTexture; -import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload; import com.mojang.util.UUIDTypeAdapter; import com.voxelmodpack.hdskins.gui.Feature; import com.voxelmodpack.hdskins.util.IndentedToStringStyle; import com.voxelmodpack.hdskins.util.MoreHttpResponses; import com.voxelmodpack.hdskins.util.NetClient; -import com.voxelmodpack.hdskins.util.TexturesPayloadBuilder; import net.minecraft.client.Minecraft; import org.apache.commons.lang3.StringUtils; import org.apache.http.Header; @@ -53,39 +51,39 @@ public class LegacySkinServer implements SkinServer { } @Override - public MinecraftTexturesPayload getPreviewTextures(GameProfile profile) throws IOException, AuthenticationException { + public TexturePayload getPreviewTextures(GameProfile profile) throws IOException, AuthenticationException { SkinServer.verifyServerConnection(Minecraft.getMinecraft().getSession(), SERVER_ID); if (Strings.isNullOrEmpty(gateway)) { throw gatewayUnsupported(); } - Map map = new EnumMap<>(MinecraftProfileTexture.Type.class); + Map map = new HashMap<>(); for (MinecraftProfileTexture.Type type : MinecraftProfileTexture.Type.values()) { - map.put(type, new MinecraftProfileTexture(getPath(gateway, type, profile), null)); + map.put(type.name(), new MinecraftProfileTexture(getPath(gateway, type, profile), null)); } - return TexturesPayloadBuilder.createTexturesPayload(profile, map); + return new TexturePayload(profile, map); } @Override - public MinecraftTexturesPayload loadProfileData(GameProfile profile) throws IOException { - ImmutableMap.Builder builder = ImmutableMap.builder(); + public TexturePayload loadProfileData(GameProfile profile) throws IOException { + ImmutableMap.Builder builder = ImmutableMap.builder(); for (MinecraftProfileTexture.Type type : MinecraftProfileTexture.Type.values()) { String url = getPath(address, type, profile); try { - builder.put(type, loadProfileTexture(profile, url)); + builder.put(type.name(), loadProfileTexture(profile, url)); } catch (IOException e) { logger.trace("Couldn't find texture for {} at {}. Does it exist?", profile.getName(), url, e); } } - Map map = builder.build(); + Map map = builder.build(); if (map.isEmpty()) { throw new HttpException(String.format("No textures found for %s at %s", profile, this.address), 404, null); } - return TexturesPayloadBuilder.createTexturesPayload(profile, map); + return new TexturePayload(profile, map); } private MinecraftProfileTexture loadProfileTexture(GameProfile profile, String url) throws IOException { @@ -125,7 +123,7 @@ public class LegacySkinServer implements SkinServer { } MoreHttpResponses resp = client.send(); - String response = resp.text(); + String response = resp.reader().readLine(); if (response.startsWith("ERROR: ")) { response = response.substring(7); diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/server/SkinServer.java b/src/hdskins/java/com/voxelmodpack/hdskins/server/SkinServer.java index 0eacd351..2f13dcb5 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/server/SkinServer.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/server/SkinServer.java @@ -3,7 +3,6 @@ package com.voxelmodpack.hdskins.server; import com.mojang.authlib.GameProfile; import com.mojang.authlib.exceptions.AuthenticationException; import com.mojang.authlib.minecraft.MinecraftSessionService; -import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload; import com.mumfrey.liteloader.modconfig.Exposable; import com.voxelmodpack.hdskins.gui.Feature; import net.minecraft.client.Minecraft; @@ -29,7 +28,7 @@ public interface SkinServer extends Exposable { * * @throws IOException If any authentication or network error occurs. */ - MinecraftTexturesPayload loadProfileData(GameProfile profile) throws IOException, AuthenticationException; + TexturePayload loadProfileData(GameProfile profile) throws IOException, AuthenticationException; /** * Synchronously uploads a skin to this server. @@ -51,7 +50,7 @@ public interface SkinServer extends Exposable { * @throws AuthenticationException * @throws IOException */ - default MinecraftTexturesPayload getPreviewTextures(GameProfile profile) throws IOException, AuthenticationException { + default TexturePayload getPreviewTextures(GameProfile profile) throws IOException, AuthenticationException { return loadProfileData(profile); } diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/server/SkinServerSerializer.java b/src/hdskins/java/com/voxelmodpack/hdskins/server/SkinServerSerializer.java index 5f74dd08..443d7847 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/server/SkinServerSerializer.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/server/SkinServerSerializer.java @@ -11,7 +11,6 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; -import com.voxelmodpack.hdskins.HDSkinManager; import java.lang.reflect.Modifier; import java.lang.reflect.Type; diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/server/ValhallaSkinServer.java b/src/hdskins/java/com/voxelmodpack/hdskins/server/ValhallaSkinServer.java index cc0cbed7..17e00bd7 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/server/ValhallaSkinServer.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/server/ValhallaSkinServer.java @@ -6,7 +6,6 @@ import com.google.gson.annotations.Expose; import com.mojang.authlib.GameProfile; import com.mojang.authlib.exceptions.AuthenticationException; import com.mojang.authlib.minecraft.MinecraftProfileTexture; -import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload; import com.mojang.util.UUIDTypeAdapter; import com.voxelmodpack.hdskins.gui.Feature; import com.voxelmodpack.hdskins.util.IndentedToStringStyle; @@ -54,14 +53,9 @@ public class ValhallaSkinServer implements SkinServer { } @Override - public MinecraftTexturesPayload loadProfileData(GameProfile profile) throws IOException, AuthenticationException { + public TexturePayload loadProfileData(GameProfile profile) throws IOException, AuthenticationException { try (MoreHttpResponses response = MoreHttpResponses.execute(HTTP_CLIENT, new HttpGet(getTexturesURI(profile)))) { - - if (response.ok()) { - return response.unwrapAsJson(MinecraftTexturesPayload.class); - } - - throw new HttpException(response.response()); + return response.requireOk().json(TexturePayload.class, "Invalid texture payload"); } } @@ -131,9 +125,7 @@ public class ValhallaSkinServer implements SkinServer { private void upload(HttpUriRequest request) throws IOException { try (MoreHttpResponses response = MoreHttpResponses.execute(HTTP_CLIENT, request)) { - if (!response.ok()) { - throw response.exception(); - } + response.requireOk(); } } @@ -163,7 +155,7 @@ public class ValhallaSkinServer implements SkinServer { .setUri(getHandshakeURI()) .addParameter("name", name) .build())) { - return resp.unwrapAsJson(AuthHandshake.class); + return resp.requireOk().json(AuthHandshake.class, "Invalid handshake response"); } } @@ -173,7 +165,7 @@ public class ValhallaSkinServer implements SkinServer { .addParameter("name", name) .addParameter("verifyToken", String.valueOf(verifyToken)) .build())) { - return resp.unwrapAsJson(AuthResponse.class); + return resp.requireOk().json(AuthResponse.class, "Invalid auth response"); } } diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/server/YggdrasilSkinServer.java b/src/hdskins/java/com/voxelmodpack/hdskins/server/YggdrasilSkinServer.java index 82f6ff4d..eb446ac5 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/server/YggdrasilSkinServer.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/server/YggdrasilSkinServer.java @@ -15,7 +15,6 @@ import com.google.gson.Gson; import com.mojang.authlib.GameProfile; import com.mojang.authlib.exceptions.AuthenticationException; import com.mojang.authlib.minecraft.*; -import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload; import com.mojang.util.UUIDTypeAdapter; import com.voxelmodpack.hdskins.HDSkinManager; import com.voxelmodpack.hdskins.gui.Feature; @@ -53,9 +52,7 @@ public class YggdrasilSkinServer implements SkinServer { } @Override - public MinecraftTexturesPayload loadProfileData(GameProfile profile) throws IOException, AuthenticationException { - - Map textures = new HashMap<>(); + public TexturePayload loadProfileData(GameProfile profile) throws IOException, AuthenticationException { Minecraft client = Minecraft.getMinecraft(); MinecraftSessionService session = client.getSessionService(); @@ -68,13 +65,16 @@ public class YggdrasilSkinServer implements SkinServer { } profile = newProfile; + Map textures = new HashMap<>(); try { - textures.putAll(session.getTextures(profile, requireSecure)); + session.getTextures(profile, requireSecure).forEach((k, v) -> { + textures.put(k.name(), v); + }); } catch (InsecureTextureException e) { HDSkinManager.logger.error(e); } - return TexturesPayloadBuilder.createTexturesPayload(profile, textures); + return new TexturePayload(profile, textures); } @Override diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/util/MoreHttpResponses.java b/src/hdskins/java/com/voxelmodpack/hdskins/util/MoreHttpResponses.java index f27c089a..61e08d87 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/util/MoreHttpResponses.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/util/MoreHttpResponses.java @@ -1,10 +1,10 @@ package com.voxelmodpack.hdskins.util; -import com.google.common.io.ByteStreams; import com.google.common.io.CharStreams; import com.google.gson.*; import com.mojang.util.UUIDTypeAdapter; import com.voxelmodpack.hdskins.HDSkinManager; +import com.voxelmodpack.hdskins.server.HttpException; import org.apache.http.HttpEntity; import org.apache.http.HttpStatus; @@ -17,12 +17,9 @@ import org.apache.http.message.BasicNameValuePair; import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStream; import java.io.InputStreamReader; -import java.lang.reflect.Type; import java.nio.charset.StandardCharsets; import java.util.*; -import java.util.stream.Stream; /** * Utility class for getting different response types from a http response. @@ -33,89 +30,6 @@ public interface MoreHttpResponses extends AutoCloseable { .registerTypeAdapter(UUID.class, new UUIDTypeAdapter()) .create(); - CloseableHttpResponse response(); - - default boolean ok() { - return responseCode() < HttpStatus.SC_MULTIPLE_CHOICES; - } - - default boolean json() { - return "application/json".contentEquals(contentType().getMimeType()); - } - - default int responseCode() { - return response().getStatusLine().getStatusCode(); - } - - default Optional entity() { - return Optional.ofNullable(response().getEntity()); - } - - default ContentType contentType() { - return entity() - .map(ContentType::get) - .orElse(ContentType.DEFAULT_TEXT); - } - - default InputStream inputStream() throws IOException { - return response().getEntity().getContent(); - } - - default BufferedReader reader() throws IOException { - return new BufferedReader(new InputStreamReader(inputStream(), StandardCharsets.UTF_8)); - } - - default byte[] bytes() throws IOException { - try (InputStream input = inputStream()) { - return ByteStreams.toByteArray(input); - } - } - - default String text() throws IOException { - try (BufferedReader reader = reader()) { - return CharStreams.toString(reader); - } - } - - default Stream lines() throws IOException { - try (BufferedReader reader = reader()) { - return reader.lines(); - } - } - - default T json(Class type, String errorMessage) throws IOException { - return json((Type)type, errorMessage); - } - - default T json(Type type, String errorMessage) throws IOException { - if (!json()) { - String text = text(); - HDSkinManager.logger.error(errorMessage, text); - throw new IOException(text); - } - - try (BufferedReader reader = reader()) { - return GSON.fromJson(reader, type); - } - } - - default T unwrapAsJson(Type type) throws IOException { - if (ok()) { - return json(type, "Server returned a non-json response!"); - } - - throw exception(); - } - - default IOException exception() throws IOException { - return new IOException(json(JsonObject.class, "Server error wasn't in json: {}").get("message").getAsString()); - } - - @Override - default void close() throws IOException { - response().close(); - } - static MoreHttpResponses execute(CloseableHttpClient client, HttpUriRequest request) throws IOException { CloseableHttpResponse response = client.execute(request); return () -> response; @@ -128,4 +42,71 @@ public interface MoreHttpResponses extends AutoCloseable { ) .toArray(NameValuePair[]::new); } + + CloseableHttpResponse response(); + + default boolean contentTypeMatches(String contentType) { + return contentType.contentEquals(entity() + .map(ContentType::get) + .orElse(ContentType.DEFAULT_TEXT) + .getMimeType() + ); + } + + default int responseCode() { + return response().getStatusLine().getStatusCode(); + } + + default Optional entity() { + return Optional.ofNullable(response().getEntity()); + } + + default BufferedReader reader() throws IOException { + return new BufferedReader(new InputStreamReader(response().getEntity().getContent(), StandardCharsets.UTF_8)); + } + + default String text() throws IOException { + try (BufferedReader reader = reader()) { + return CharStreams.toString(reader); + } + } + + default T json(Class type, String errorMessage) throws IOException { + + if (!contentTypeMatches("application/json")) { + String text = text(); + HDSkinManager.logger.error(errorMessage, text); + throw new HttpException(text, responseCode(), null); + } + + String text = text(); + + T t = GSON.fromJson(text, type); + if (t == null) { + throw new HttpException(errorMessage + "\n " + text, responseCode(), null); + } + return t; + } + + default boolean ok() { + return responseCode() < HttpStatus.SC_MULTIPLE_CHOICES; + } + + default MoreHttpResponses requireOk() throws IOException { + if (!ok()) { + JsonObject json = json(JsonObject.class, "Server did not respond correctly. Status Code " + responseCode()); + if (json.has("message")) { + throw new HttpException(json.get("message").getAsString(), responseCode(), null); + } else { + throw new HttpException(json.toString(), responseCode(), null); + } + } + return this; + } + + @Override + default void close() throws IOException { + response().close(); + } + } \ No newline at end of file diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/util/TexturesPayloadBuilder.java b/src/hdskins/java/com/voxelmodpack/hdskins/util/TexturesPayloadBuilder.java deleted file mode 100644 index deb6fa35..00000000 --- a/src/hdskins/java/com/voxelmodpack/hdskins/util/TexturesPayloadBuilder.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.voxelmodpack.hdskins.util; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.mojang.authlib.GameProfile; -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; - -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -/** - * Use this to build a {@link MinecraftTexturesPayload} object. This is - * required because it has no useful constructor. This uses reflection - * via Gson to create a new instance and populate the fields. - */ -@SuppressWarnings("unused") -public class TexturesPayloadBuilder { - - private static Gson gson = new GsonBuilder().registerTypeAdapter(UUID.class, new UUIDTypeAdapter()).create(); - - public static MinecraftTexturesPayload createTexturesPayload(GameProfile profile, Map textures) { - // This worked fine as is before I started using sub-classes. - MinecraftTexturesPayload payload = gson.fromJson(gson.toJson(new TexturesPayloadBuilder(profile)), MinecraftTexturesPayload.class); - payload.getTextures().putAll(textures); - return payload; - } - - private long timestamp; - - private UUID profileId; - private String profileName; - - private boolean isPublic; - - private Map textures; - - private TexturesPayloadBuilder(GameProfile profile) { - profileId = profile.getId(); - profileName = profile.getName(); - timestamp = System.currentTimeMillis(); - - isPublic = true; - - this.textures = new HashMap<>(); - } -}