mirror of
https://github.com/Suiranoil/SkinRestorer.git
synced 2026-01-16 04:42:12 +00:00
add caching to skin providers
This commit is contained in:
@@ -118,7 +118,7 @@ public final class SkinRestorer {
|
||||
boolean save
|
||||
) {
|
||||
return CompletableFuture.supplyAsync(
|
||||
() -> SkinRestorer.getProvider(context.name()).map(provider -> provider.getSkin(context.argument(), context.variant()))
|
||||
() -> SkinRestorer.getProvider(context.name()).map(provider -> provider.fetchSkin(context.argument(), context.variant()))
|
||||
)
|
||||
.thenApplyAsync(result -> {
|
||||
if (result.isEmpty())
|
||||
|
||||
@@ -73,7 +73,7 @@ public abstract class ServerLoginPacketListenerImplMixin {
|
||||
SkinRestorer.LOGGER.debug("fetching {}'s skin", profile.getName());
|
||||
|
||||
var result = SkinRestorer.getProvider(context.name()).map(
|
||||
provider -> provider.getSkin(context.argument(), context.variant())
|
||||
provider -> provider.fetchSkin(context.argument(), context.variant())
|
||||
).orElseGet(() -> Result.error(new IllegalArgumentException("skin provider is not registered: " + context.name())));
|
||||
|
||||
if (!result.isError()) {
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package net.lionarius.skinrestorer.skin.provider;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.properties.Property;
|
||||
import com.mojang.authlib.yggdrasil.response.MinecraftProfilePropertiesResponse;
|
||||
@@ -9,12 +12,15 @@ import net.lionarius.skinrestorer.util.PlayerUtils;
|
||||
import net.lionarius.skinrestorer.util.Result;
|
||||
import net.lionarius.skinrestorer.util.WebUtils;
|
||||
import net.minecraft.util.StringUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public final class ElyBySkinProvider implements SkinProvider {
|
||||
|
||||
@@ -22,12 +28,23 @@ public final class ElyBySkinProvider implements SkinProvider {
|
||||
|
||||
private static final URI API_URI;
|
||||
|
||||
private static final LoadingCache<String, Optional<Property>> SKIN_CACHE;
|
||||
|
||||
static {
|
||||
try {
|
||||
API_URI = new URI("http://skinsystem.ely.by");
|
||||
} catch (URISyntaxException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
|
||||
SKIN_CACHE = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(60, TimeUnit.SECONDS)
|
||||
.build(new CacheLoader<>() {
|
||||
@Override
|
||||
public @NotNull Optional<Property> load(@NotNull String key) throws Exception {
|
||||
return ElyBySkinProvider.loadSkin(key);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -41,20 +58,25 @@ public final class ElyBySkinProvider implements SkinProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Optional<Property>, Exception> getSkin(String username, SkinVariant variant) {
|
||||
if (!StringUtil.isValidPlayerName(username))
|
||||
return Result.error(new IllegalArgumentException("invalid username"));
|
||||
|
||||
public Result<Optional<Property>, Exception> fetchSkin(String username, SkinVariant variant) {
|
||||
try {
|
||||
var profile = ElyBySkinProvider.getElyByProfile(username);
|
||||
var textures = PlayerUtils.getPlayerSkin(profile);
|
||||
if (!StringUtil.isValidPlayerName(username))
|
||||
throw new IllegalArgumentException("invalid username");
|
||||
|
||||
return Result.ofNullable(textures);
|
||||
var usernameLowerCase = username.toLowerCase(Locale.ROOT);
|
||||
return Result.success(SKIN_CACHE.get(usernameLowerCase));
|
||||
} catch (Exception e) {
|
||||
return Result.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Optional<Property> loadSkin(String username) throws Exception {
|
||||
var profile = ElyBySkinProvider.getElyByProfile(username);
|
||||
var textures = PlayerUtils.getPlayerSkin(profile);
|
||||
|
||||
return Optional.ofNullable(textures);
|
||||
}
|
||||
|
||||
private static GameProfile getElyByProfile(String username) throws IOException {
|
||||
var request = HttpRequest.newBuilder()
|
||||
.uri(ElyBySkinProvider.API_URI
|
||||
|
||||
@@ -21,11 +21,11 @@ public final class EmptySkinProvider implements SkinProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Optional<Property>, Exception> getSkin(String argument, SkinVariant variant) {
|
||||
return this.getSkin();
|
||||
public Result<Optional<Property>, Exception> fetchSkin(String argument, SkinVariant variant) {
|
||||
return this.fetchSkin();
|
||||
}
|
||||
|
||||
public Result<Optional<Property>, Exception> getSkin() {
|
||||
public Result<Optional<Property>, Exception> fetchSkin() {
|
||||
return Result.ofNullable(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,24 @@
|
||||
package net.lionarius.skinrestorer.skin.provider;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.mojang.authlib.properties.Property;
|
||||
import it.unimi.dsi.fastutil.Pair;
|
||||
import net.lionarius.skinrestorer.skin.SkinVariant;
|
||||
import net.lionarius.skinrestorer.util.JsonUtils;
|
||||
import net.lionarius.skinrestorer.util.PlayerUtils;
|
||||
import net.lionarius.skinrestorer.util.Result;
|
||||
import net.lionarius.skinrestorer.util.WebUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public final class MineskinSkinProvider implements SkinProvider {
|
||||
|
||||
@@ -20,12 +26,23 @@ public final class MineskinSkinProvider implements SkinProvider {
|
||||
|
||||
private static final URI API_URI;
|
||||
|
||||
private static final LoadingCache<Pair<URI, SkinVariant>, Optional<Property>> SKIN_CACHE;
|
||||
|
||||
static {
|
||||
try {
|
||||
API_URI = new URI("https://api.mineskin.org");
|
||||
} catch (URISyntaxException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
|
||||
SKIN_CACHE = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(300, TimeUnit.SECONDS)
|
||||
.build(new CacheLoader<>() {
|
||||
@Override
|
||||
public @NotNull Optional<Property> load(@NotNull Pair<URI, SkinVariant> key) throws Exception {
|
||||
return MineskinSkinProvider.loadSkin(key.first(), key.second());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -39,20 +56,24 @@ public final class MineskinSkinProvider implements SkinProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Optional<Property>, Exception> getSkin(String url, SkinVariant variant) {
|
||||
public Result<Optional<Property>, Exception> fetchSkin(String url, SkinVariant variant) {
|
||||
try {
|
||||
var uri = new URI(url);
|
||||
|
||||
var result = MineskinSkinProvider.uploadToMineskin(uri, variant);
|
||||
var texture = result.getAsJsonObject("data").getAsJsonObject("texture");
|
||||
var textures = new Property(PlayerUtils.TEXTURES_KEY, texture.get("value").getAsString(), texture.get("signature").getAsString());
|
||||
|
||||
return Result.ofNullable(textures);
|
||||
return Result.success(SKIN_CACHE.get(Pair.of(uri, variant)));
|
||||
} catch (Exception e) {
|
||||
return Result.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Optional<Property> loadSkin(URI uri, SkinVariant variant) throws Exception {
|
||||
var result = MineskinSkinProvider.uploadToMineskin(uri, variant);
|
||||
var texture = result.getAsJsonObject("data").getAsJsonObject("texture");
|
||||
var textures = new Property(PlayerUtils.TEXTURES_KEY, texture.get("value").getAsString(), texture.get("signature").getAsString());
|
||||
|
||||
return Optional.of(textures);
|
||||
}
|
||||
|
||||
private static JsonObject uploadToMineskin(URI url, SkinVariant variant) throws IOException {
|
||||
var body = ("{\"variant\":\"%s\",\"name\":\"%s\",\"visibility\":%d,\"url\":\"%s\"}")
|
||||
.formatted(variant.toString(), "none", 0, url);
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package net.lionarius.skinrestorer.skin.provider;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.properties.Property;
|
||||
import com.mojang.authlib.yggdrasil.response.MinecraftProfilePropertiesResponse;
|
||||
@@ -12,6 +15,7 @@ import net.lionarius.skinrestorer.util.Result;
|
||||
import net.lionarius.skinrestorer.util.WebUtils;
|
||||
import net.minecraft.server.players.GameProfileCache;
|
||||
import net.minecraft.util.StringUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
@@ -19,6 +23,7 @@ import java.net.URISyntaxException;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public final class MojangSkinProvider implements SkinProvider {
|
||||
|
||||
@@ -27,9 +32,11 @@ public final class MojangSkinProvider implements SkinProvider {
|
||||
private static final URI API_URI;
|
||||
private static final URI SESSION_SERVER_URI;
|
||||
|
||||
public static final String CACHE_FILENAME = "mojang_profile_cache.json";
|
||||
public static final String PROFILE_CACHE_FILENAME = "mojang_profile_cache.json";
|
||||
private static final GameProfileCache PROFILE_CACHE;
|
||||
|
||||
private static final LoadingCache<UUID, Optional<Property>> SKIN_CACHE;
|
||||
|
||||
static {
|
||||
try {
|
||||
API_URI = new URI("https://api.mojang.com");
|
||||
@@ -47,7 +54,16 @@ public final class MojangSkinProvider implements SkinProvider {
|
||||
callback.onProfileLookupFailed(name, e);
|
||||
}
|
||||
}
|
||||
}, SkinRestorer.getConfigDir().resolve(CACHE_FILENAME).toFile());
|
||||
}, SkinRestorer.getConfigDir().resolve(PROFILE_CACHE_FILENAME).toFile());
|
||||
|
||||
SKIN_CACHE = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(60, TimeUnit.SECONDS)
|
||||
.build(new CacheLoader<>() {
|
||||
@Override
|
||||
public @NotNull Optional<Property> load(@NotNull UUID key) throws Exception {
|
||||
return MojangSkinProvider.loadSkin(key);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static SkinProviderContext skinProviderContextFromProfile(GameProfile gameProfile) {
|
||||
@@ -65,24 +81,28 @@ public final class MojangSkinProvider implements SkinProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Optional<Property>, Exception> getSkin(String username, SkinVariant variant) {
|
||||
if (!StringUtil.isValidPlayerName(username))
|
||||
return Result.error(new IllegalArgumentException("invalid username"));
|
||||
|
||||
public Result<Optional<Property>, Exception> fetchSkin(String username, SkinVariant variant) {
|
||||
try {
|
||||
if (!StringUtil.isValidPlayerName(username))
|
||||
throw new IllegalArgumentException("invalid username");
|
||||
|
||||
var cachedProfile = MojangSkinProvider.PROFILE_CACHE.get(username);
|
||||
if (cachedProfile.isEmpty())
|
||||
throw new IllegalArgumentException("no profile found for " + username);
|
||||
|
||||
var profile = MojangSkinProvider.getProfileWithProperties(cachedProfile.get().getId());
|
||||
var textures = PlayerUtils.getPlayerSkin(profile);
|
||||
|
||||
return Result.ofNullable(textures);
|
||||
return Result.success(SKIN_CACHE.get(cachedProfile.get().getId()));
|
||||
} catch (Exception e) {
|
||||
return Result.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Optional<Property> loadSkin(UUID uuid) throws Exception {
|
||||
var profile = MojangSkinProvider.getProfileWithProperties(uuid);
|
||||
var textures = PlayerUtils.getPlayerSkin(profile);
|
||||
|
||||
return Optional.ofNullable(textures);
|
||||
}
|
||||
|
||||
private static GameProfile getProfile(final String name) throws IOException {
|
||||
var request = HttpRequest.newBuilder()
|
||||
.uri(MojangSkinProvider.API_URI
|
||||
|
||||
@@ -16,5 +16,5 @@ public interface SkinProvider {
|
||||
|
||||
boolean hasVariantSupport();
|
||||
|
||||
Result<Optional<Property>, Exception> getSkin(String argument, SkinVariant variant);
|
||||
Result<Optional<Property>, Exception> fetchSkin(String argument, SkinVariant variant);
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ public final class FileUtils {
|
||||
return Files.isRegularFile(file)
|
||||
&& !name.startsWith(Translation.LEGACY_TRANSLATION_FILENAME)
|
||||
&& !name.startsWith(Config.CONFIG_FILENAME)
|
||||
&& !name.startsWith(MojangSkinProvider.CACHE_FILENAME)
|
||||
&& !name.startsWith(MojangSkinProvider.PROFILE_CACHE_FILENAME)
|
||||
&& name.endsWith(SkinIO.FILE_EXTENSION);
|
||||
}).toList();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user