Improve network error handling for skin servers

This commit is contained in:
Sollace 2019-04-09 13:41:33 +02:00
parent b3f8eee00e
commit 4b1f8beb97
7 changed files with 62 additions and 10 deletions

View file

@ -71,7 +71,7 @@ import javax.annotation.Nullable;
public final class HDSkinManager implements IResourceManagerReloadListener { public final class HDSkinManager implements IResourceManagerReloadListener {
private static final Logger logger = LogManager.getLogger(); public static final Logger logger = LogManager.getLogger();
public static final ExecutorService skinUploadExecutor = Executors.newSingleThreadExecutor(); public static final ExecutorService skinUploadExecutor = Executors.newSingleThreadExecutor();
public static final ExecutorService skinDownloadExecutor = Executors.newFixedThreadPool(8); public static final ExecutorService skinDownloadExecutor = Executors.newFixedThreadPool(8);

View file

@ -17,6 +17,7 @@ import com.mumfrey.liteloader.util.log.LiteLoaderLogger;
import com.voxelmodpack.hdskins.gui.EntityPlayerModel; import com.voxelmodpack.hdskins.gui.EntityPlayerModel;
import com.voxelmodpack.hdskins.gui.Feature; import com.voxelmodpack.hdskins.gui.Feature;
import com.voxelmodpack.hdskins.resources.PreviewTextureManager; import com.voxelmodpack.hdskins.resources.PreviewTextureManager;
import com.voxelmodpack.hdskins.server.HttpException;
import com.voxelmodpack.hdskins.server.SkinServer; import com.voxelmodpack.hdskins.server.SkinServer;
import com.voxelmodpack.hdskins.server.SkinUpload; import com.voxelmodpack.hdskins.server.SkinUpload;
import com.voxelmodpack.hdskins.util.MoreHttpResponses; import com.voxelmodpack.hdskins.util.MoreHttpResponses;
@ -224,6 +225,18 @@ public class SkinUploader implements Closeable {
offline = true; offline = true;
} else if (throwable instanceof AuthenticationException) { } else if (throwable instanceof AuthenticationException) {
throttlingNeck = true; throttlingNeck = true;
} else if (throwable instanceof HttpException) {
HttpException ex = (HttpException)throwable;
HDSkinManager.logger.error(ex.getReasonPhrase(), ex);
int code = ex.getStatusCode();
if (code >= 500) {
setError(String.format("A fatal server error has ocurred (check logs for details): \n%s", ex.getReasonPhrase()));
} else if (code >= 400 && code != 403 && code != 404) {
setError(ex.getReasonPhrase());
}
} else { } else {
setError(throwable.toString()); setError(throwable.toString());
} }

View file

@ -32,7 +32,7 @@ public class BethlehemSkinServer implements SkinServer {
public MinecraftTexturesPayload loadProfileData(GameProfile profile) throws IOException { public MinecraftTexturesPayload loadProfileData(GameProfile profile) throws IOException {
try (MoreHttpResponses response = new NetClient("GET", getPath(profile)).send()) { try (MoreHttpResponses response = new NetClient("GET", getPath(profile)).send()) {
if (!response.ok()) { if (!response.ok()) {
throw new IOException(response.getResponse().getStatusLine().getReasonPhrase()); throw new HttpException(response.getResponse());
} }
return response.json(MinecraftTexturesPayload.class); return response.json(MinecraftTexturesPayload.class);
@ -53,8 +53,9 @@ public class BethlehemSkinServer implements SkinServer {
try (MoreHttpResponses response = client.send()) { try (MoreHttpResponses response = client.send()) {
if (!response.ok()) { if (!response.ok()) {
throw new IOException(response.text()); throw new HttpException(response.getResponse());
} }
return new SkinUploadResponse(response.text()); return new SkinUploadResponse(response.text());
} }
} }

View file

@ -0,0 +1,37 @@
package com.voxelmodpack.hdskins.server;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import java.io.IOException;
public class HttpException extends IOException {
private static final long serialVersionUID = -6168434367054139332L;
private final String reason;
private final int statusCode;
public HttpException(HttpResponse response) {
this(response.getStatusLine());
}
public HttpException(StatusLine status) {
this(status.getReasonPhrase(), status.getStatusCode(), null);
}
public HttpException(String reason, int statusCode, Throwable cause) {
super("(" + statusCode + ") " + reason, cause);
this.reason = reason;
this.statusCode = statusCode;
}
public String getReasonPhrase() {
return reason;
}
public int getStatusCode() {
return statusCode;
}
}

View file

@ -83,7 +83,7 @@ public class LegacySkinServer implements SkinServer {
Map<MinecraftProfileTexture.Type, MinecraftProfileTexture> map = builder.build(); Map<MinecraftProfileTexture.Type, MinecraftProfileTexture> map = builder.build();
if (map.isEmpty()) { if (map.isEmpty()) {
throw new IOException(String.format("No textures found for %s at %s", profile, this.address)); throw new HttpException(String.format("No textures found for %s at %s", profile, this.address), 404, null);
} }
return TexturesPayloadBuilder.createTexturesPayload(profile, map); return TexturesPayloadBuilder.createTexturesPayload(profile, map);
} }
@ -91,7 +91,7 @@ public class LegacySkinServer implements SkinServer {
private MinecraftProfileTexture loadProfileTexture(GameProfile profile, String url) throws IOException { private MinecraftProfileTexture loadProfileTexture(GameProfile profile, String url) throws IOException {
try (MoreHttpResponses resp = MoreHttpResponses.execute(HDSkinManager.httpClient, new HttpHead(url))) { try (MoreHttpResponses resp = MoreHttpResponses.execute(HDSkinManager.httpClient, new HttpHead(url))) {
if (!resp.ok()) { if (!resp.ok()) {
throw new IOException("Bad response code: " + resp.getResponseCode() + ". URL: " + url); throw new HttpException(resp.getResponse());
} }
logger.debug("Found skin for {} at {}", profile.getName(), url); logger.debug("Found skin for {} at {}", profile.getName(), url);
@ -124,14 +124,15 @@ public class LegacySkinServer implements SkinServer {
client.putFile(upload.getType().toString().toLowerCase(Locale.US), "image/png", upload.getImage()); client.putFile(upload.getType().toString().toLowerCase(Locale.US), "image/png", upload.getImage());
} }
String response = client.send().text(); MoreHttpResponses resp = client.send();
String response = resp.text();
if (response.startsWith("ERROR: ")) { if (response.startsWith("ERROR: ")) {
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 HttpException(response, resp.getResponseCode(), null);
} }
return new SkinUploadResponse(response); return new SkinUploadResponse(response);

View file

@ -41,7 +41,7 @@ public interface SkinServer extends Exposable {
* *
* @return The parsed server response as a textures payload. * @return The parsed server response as a textures payload.
* *
* @throws IOException If any authenticaiton or network error occurs. * @throws IOException If any authentication or network error occurs.
*/ */
MinecraftTexturesPayload loadProfileData(GameProfile profile) throws IOException; MinecraftTexturesPayload loadProfileData(GameProfile profile) throws IOException;
@ -52,7 +52,7 @@ public interface SkinServer extends Exposable {
* *
* @return A server response object. * @return A server response object.
* *
* @throws IOException * @throws IOException If any authentication or network error occurs.
* @throws AuthenticationException * @throws AuthenticationException
*/ */
SkinUploadResponse performSkinUpload(SkinUpload upload) throws IOException, AuthenticationException; SkinUploadResponse performSkinUpload(SkinUpload upload) throws IOException, AuthenticationException;

View file

@ -46,7 +46,7 @@ public class ValhallaSkinServer implements SkinServer {
return response.unwrapAsJson(MinecraftTexturesPayload.class); return response.unwrapAsJson(MinecraftTexturesPayload.class);
} }
throw new IOException("Server sent non-ok response code: " + response.getResponseCode()); throw new HttpException(response.getResponse());
} }
} }