Rewrite net code and remove at least some spaghetti

This commit is contained in:
Sollace 2018-07-14 23:18:36 +02:00
parent ab741b5e3a
commit d94f792851
6 changed files with 143 additions and 114 deletions

View file

@ -24,6 +24,7 @@ import com.mumfrey.liteloader.util.log.LiteLoaderLogger;
import com.voxelmodpack.hdskins.gui.GuiSkins; import com.voxelmodpack.hdskins.gui.GuiSkins;
import com.voxelmodpack.hdskins.resource.SkinResourceManager; import com.voxelmodpack.hdskins.resource.SkinResourceManager;
import com.voxelmodpack.hdskins.skins.AsyncCacheLoader; import com.voxelmodpack.hdskins.skins.AsyncCacheLoader;
import com.voxelmodpack.hdskins.skins.BethlehemSkinServer;
import com.voxelmodpack.hdskins.skins.LegacySkinServer; import com.voxelmodpack.hdskins.skins.LegacySkinServer;
import com.voxelmodpack.hdskins.skins.ServerType; import com.voxelmodpack.hdskins.skins.ServerType;
import com.voxelmodpack.hdskins.skins.SkinServer; import com.voxelmodpack.hdskins.skins.SkinServer;
@ -98,6 +99,7 @@ public final class HDSkinManager implements IResourceManagerReloadListener {
// register default skin server types // register default skin server types
addSkinServerType(LegacySkinServer.class); addSkinServerType(LegacySkinServer.class);
addSkinServerType(ValhallaSkinServer.class); addSkinServerType(ValhallaSkinServer.class);
addSkinServerType(BethlehemSkinServer.class);
} }
public void setPrefferedSkinsGuiClass(Class<? extends GuiSkins> clazz) { public void setPrefferedSkinsGuiClass(Class<? extends GuiSkins> clazz) {

View file

@ -1,39 +1,21 @@
package com.voxelmodpack.hdskins.skins; package com.voxelmodpack.hdskins.skins;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URI; import java.net.URI;
import java.net.URL;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import org.apache.commons.io.IOUtils;
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.Logger;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.gson.Gson; import com.google.common.collect.ImmutableMap.Builder;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
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.MinecraftSessionService;
import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type; 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.HDSkinManager;
import com.voxelmodpack.hdskins.upload.ThreadMultipartPostUpload;
import net.minecraft.client.Minecraft;
import net.minecraft.util.Session; import net.minecraft.util.Session;
@ServerType("bethlehem") @ServerType("bethlehem")
@ -41,8 +23,6 @@ public class BethlehemSkinServer implements SkinServer {
private static final String SERVER_ID = "7853dfddc358333843ad55a2c7485c4aa0380a51"; private static final String SERVER_ID = "7853dfddc358333843ad55a2c7485c4aa0380a51";
private static final Logger logger = LogManager.getLogger();
@Expose @Expose
private final String address; private final String address;
@ -50,36 +30,11 @@ public class BethlehemSkinServer implements SkinServer {
this.address = address; this.address = address;
} }
private static final Gson gson = new GsonBuilder().registerTypeAdapter(UUID.class, new UUIDTypeAdapter()).create();
@Override @Override
public Optional<MinecraftTexturesPayload> loadProfileData(GameProfile profile) { public Optional<MinecraftTexturesPayload> loadProfileData(GameProfile profile) {
NetClient client = new NetClient("GET", getPath(profile));
String url = getPath(profile); String json = client.getResponseText();
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
try {
urlConnection = (HttpURLConnection) new URL(url).openConnection(Minecraft.getMinecraft().getProxy());
urlConnection.setDoInput(true);
urlConnection.setDoOutput(false);
urlConnection.connect();
if (urlConnection.getResponseCode() / 100 != 2) {
throw new IOException("Bad response code: " + urlConnection.getResponseCode());
}
reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
StringBuilder builder = new StringBuilder();
int ch;
while ((ch = reader.read()) != -1) {
builder.append((char)ch);
}
String json = builder.toString();
JsonObject s = gson.fromJson(json, JsonObject.class); JsonObject s = gson.fromJson(json, JsonObject.class);
@ -88,70 +43,43 @@ public class BethlehemSkinServer implements SkinServer {
return Optional.ofNullable(gson.fromJson(s, MinecraftTexturesPayload.class)); return Optional.ofNullable(gson.fromJson(s, MinecraftTexturesPayload.class));
} }
} catch (IOException e) {
logger.trace("Couldn't reach skin server for {} at {}", profile.getName(), url, e);
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
IOUtils.closeQuietly(reader);
}
return Optional.empty(); return Optional.empty();
} }
@Override @Override
public CompletableFuture<SkinUploadResponse> uploadSkin(Session session, URI image, Type type, Map<String, String> metadata) { public CompletableFuture<SkinUploadResponse> uploadSkin(Session session, URI image, Type type, Map<String, String> metadata) {
return CallableFutures.asyncFailableFuture(() -> {
SkinServer.verifyServerConnection(session, SERVER_ID);
if (Strings.isNullOrEmpty(address)) { NetClient client = new NetClient("POST", address).putHeaders(createHeaders(session, type, image, metadata));
return CallableFutures.failedFuture(new NullPointerException("gateway url is blank"));
if (image != null) {
client.putFile(type.toString().toLowerCase(Locale.US), "image/png", image);
} }
return CallableFutures.asyncFailableFuture(() -> { return new SkinUploadResponse(client.send(), client.getResponseText());
verifyServerConnection(session, SERVER_ID);
Map<String, ?> data = image == null ? getClearData(session, type) : getUploadData(session, type, metadata.getOrDefault("mode", "default"), image);
ThreadMultipartPostUpload upload = new ThreadMultipartPostUpload(address, data);
String response = upload.uploadMultipart();
return new SkinUploadResponse(response.equalsIgnoreCase("OK"), response);
}, HDSkinManager.skinUploadExecutor); }, HDSkinManager.skinUploadExecutor);
} }
protected static ImmutableMap.Builder<String, Object> getData(Session session, MinecraftProfileTexture.Type type) { protected Map<String, ?> createHeaders(Session session, Type type, URI image, Map<String, String> metadata) {
return ImmutableMap.<String, Object>builder() Builder<String, Object> builder = ImmutableMap.<String, Object>builder()
.put("accessToken", session.getToken()) .put("accessToken", session.getToken())
.put("user", session.getUsername()) .put("user", session.getUsername())
.put("uuid", UUIDTypeAdapter.fromUUID(session.getProfile().getId())) .put("uuid", UUIDTypeAdapter.fromUUID(session.getProfile().getId()))
.put("type", type.toString().toLowerCase(Locale.US)); .put("type", type.toString().toLowerCase(Locale.US));
if (image == null) {
builder.put("clear", "1");
} else {
builder.put("model", metadata.getOrDefault("mode", "default"));
} }
protected static Map<String, ?> getClearData(Session session, MinecraftProfileTexture.Type type) { return builder.build();
return getData(session, type)
.put("clear", "1")
.build();
}
protected static Map<String, ?> getUploadData(Session session, MinecraftProfileTexture.Type type, String model, URI skinFile) {
return getData(session, type)
.put("model", model)
.put(type.toString().toLowerCase(Locale.US), skinFile)
.build();
} }
private String getPath(GameProfile profile) { private String getPath(GameProfile profile) {
return String.format("%s/profile/%s", address, UUIDTypeAdapter.fromUUID(profile.getId()));
String uuid = UUIDTypeAdapter.fromUUID(profile.getId());
return String.format("%s/profile/%s", address, uuid);
}
protected static void verifyServerConnection(Session session, String serverId) throws AuthenticationException {
MinecraftSessionService service = Minecraft.getMinecraft().getSessionService();
service.joinServer(session.getProfile(), session.getToken(), serverId);
} }
@Override @Override

View file

@ -4,14 +4,11 @@ import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
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.MinecraftSessionService;
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.HDSkinManager;
import com.voxelmodpack.hdskins.upload.ThreadMultipartPostUpload; import com.voxelmodpack.hdskins.upload.ThreadMultipartPostUpload;
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;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
@ -100,7 +97,7 @@ public class LegacySkinServer implements SkinServer {
} }
return CallableFutures.asyncFailableFuture(() -> { return CallableFutures.asyncFailableFuture(() -> {
verifyServerConnection(session, SERVER_ID); SkinServer.verifyServerConnection(session, SERVER_ID);
String model = metadata.getOrDefault("model", "default"); String model = metadata.getOrDefault("model", "default");
Map<String, ?> data = image == null ? getClearData(session, type) : getUploadData(session, type, model, image); Map<String, ?> data = image == null ? getClearData(session, type) : getUploadData(session, type, model, image);
ThreadMultipartPostUpload upload = new ThreadMultipartPostUpload(this.gateway, data); ThreadMultipartPostUpload upload = new ThreadMultipartPostUpload(this.gateway, data);
@ -136,11 +133,6 @@ public class LegacySkinServer implements SkinServer {
return String.format("%s/%s/%s.png", address, path, uuid); return String.format("%s/%s/%s.png", address, path, uuid);
} }
private static void verifyServerConnection(Session session, String serverId) throws AuthenticationException {
MinecraftSessionService service = Minecraft.getMinecraft().getSessionService();
service.joinServer(session.getProfile(), session.getToken(), serverId);
}
@Override @Override
public String toString() { public String toString() {
return new ToStringBuilder(this, IndentedToStringStyle.INSTANCE) return new ToStringBuilder(this, IndentedToStringStyle.INSTANCE)

View file

@ -0,0 +1,102 @@
package com.voxelmodpack.hdskins.skins;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.util.Map;
import org.apache.commons.io.IOUtils;
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.HttpClients;
/**
* Ew. Why so many builders? >.<
*/
public class NetClient {
private final RequestBuilder rqBuilder;
private Map<String, ?> headers;
private CloseableHttpResponse response = null;
public NetClient(String method, String uri) {
rqBuilder = RequestBuilder.create(method).setUri(uri);
}
public NetClient putFile(String key, String contentType, URI file) {
File f = new File(file);
HttpEntity entity = MultipartEntityBuilder.create().addBinaryBody(key, f, ContentType.create(contentType), f.getName()).build();
rqBuilder.setEntity(entity);
return this;
}
public NetClient putHeaders(Map<String, ?> headers) {
this.headers = headers;
return this;
}
public boolean send() {
HttpUriRequest request = rqBuilder.build();
for (Map.Entry<String, ?> parameter : headers.entrySet()) {
request.addHeader(parameter.getKey(), parameter.getValue().toString());
}
try {
response = HttpClients.createSystem().execute(request);
return getResponseCode() == HttpStatus.SC_OK;
} catch (IOException e) { }
return false;
}
public int getResponseCode() {
if (response == null) {
send();
}
return response.getStatusLine().getStatusCode();
}
public String getResponseText() {
if (response == null) {
if (!send()) {
return "";
}
}
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
StringBuilder builder = new StringBuilder();
int ch;
while ((ch = reader.read()) != -1) {
builder.append((char)ch);
}
return builder.toString();
} catch (IOException e) {
} finally {
IOUtils.closeQuietly(reader);
}
return "";
}
}

View file

@ -4,11 +4,14 @@ import com.google.common.collect.Lists;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
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.MinecraftSessionService;
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.mumfrey.liteloader.modconfig.Exposable; import com.mumfrey.liteloader.modconfig.Exposable;
import net.minecraft.client.Minecraft;
import net.minecraft.util.Session; import net.minecraft.util.Session;
import java.net.URI; import java.net.URI;
@ -39,4 +42,9 @@ public interface SkinServer extends Exposable {
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 {
MinecraftSessionService service = Minecraft.getMinecraft().getSessionService();
service.joinServer(session.getProfile(), session.getToken(), serverId);
}
} }

View file

@ -45,7 +45,7 @@ public class ValhallaSkinServer implements SkinServer {
@Expose @Expose
private final String address; private final String address;
private String accessToken; private transient String accessToken;
public ValhallaSkinServer(String address) { public ValhallaSkinServer(String address) {
this.address = address; this.address = address;
@ -68,8 +68,7 @@ public class ValhallaSkinServer implements SkinServer {
} }
@Override @Override
public CompletableFuture<SkinUploadResponse> uploadSkin(Session session, @Nullable URI image, public CompletableFuture<SkinUploadResponse> uploadSkin(Session session, @Nullable URI image, MinecraftProfileTexture.Type type, Map<String, String> metadata) {
MinecraftProfileTexture.Type type, Map<String, String> metadata) {
return CallableFutures.asyncFailableFuture(() -> { return CallableFutures.asyncFailableFuture(() -> {
try (CloseableHttpClient client = HttpClients.createSystem()) { try (CloseableHttpClient client = HttpClients.createSystem()) {
authorize(client, session); authorize(client, session);
@ -99,8 +98,7 @@ public class ValhallaSkinServer implements SkinServer {
.build()); .build());
} }
private SkinUploadResponse uploadFile(CloseableHttpClient client, File file, GameProfile profile, MinecraftProfileTexture.Type type, private SkinUploadResponse uploadFile(CloseableHttpClient client, File file, GameProfile profile, MinecraftProfileTexture.Type type, Map<String, String> metadata) throws IOException {
Map<String, String> metadata) throws IOException {
MultipartEntityBuilder b = MultipartEntityBuilder.create(); MultipartEntityBuilder b = MultipartEntityBuilder.create();
b.addBinaryBody("file", file, ContentType.create("image/png"), file.getName()); b.addBinaryBody("file", file, ContentType.create("image/png"), file.getName());
metadata.forEach(b::addTextBody); metadata.forEach(b::addTextBody);
@ -112,8 +110,7 @@ public class ValhallaSkinServer implements SkinServer {
.build()); .build());
} }
private SkinUploadResponse uploadUrl(CloseableHttpClient client, URI uri, GameProfile profile, MinecraftProfileTexture.Type type, private SkinUploadResponse uploadUrl(CloseableHttpClient client, URI uri, GameProfile profile, MinecraftProfileTexture.Type type, Map<String, String> metadata) throws IOException {
Map<String, String> metadata) throws IOException {
return upload(client, RequestBuilder.post() return upload(client, RequestBuilder.post()
.setUri(buildUserTextureUri(profile, type)) .setUri(buildUserTextureUri(profile, type))