diff --git a/pom.xml b/pom.xml index b9c1da9..e439c49 100644 --- a/pom.xml +++ b/pom.xml @@ -57,6 +57,7 @@ com.jagrosh Vortex-Pro 0.2 + runtime diff --git a/src/main/java/com/jagrosh/vortex/automod/AutoMod.java b/src/main/java/com/jagrosh/vortex/automod/AutoMod.java index 7de7ca3..32eb1fd 100644 --- a/src/main/java/com/jagrosh/vortex/automod/AutoMod.java +++ b/src/main/java/com/jagrosh/vortex/automod/AutoMod.java @@ -20,7 +20,8 @@ import com.jagrosh.vortex.database.managers.AutomodManager; import com.jagrosh.vortex.database.managers.AutomodManager.AutomodSettings; import com.jagrosh.vortex.logging.MessageCache.CachedMessage; -import com.jagrosh.vortex.pro.URLResolver; +import com.jagrosh.vortex.pro.api.URLResolver; +import com.jagrosh.vortex.pro.VortexPro; import com.jagrosh.vortex.utils.FixedCache; import com.jagrosh.vortex.utils.OtherUtil; import java.time.OffsetDateTime; @@ -73,7 +74,7 @@ public AutoMod(Vortex vortex, String url, String secret) { this.vortex = vortex; - urlResolver = new URLResolver(url, secret); + urlResolver = VortexPro.from(URLResolver.class, url, secret); loadCopypastas(); loadReferralDomains(); } diff --git a/src/main/java/com/jagrosh/vortex/logging/BasicLogger.java b/src/main/java/com/jagrosh/vortex/logging/BasicLogger.java index 5d9842f..b0bea51 100644 --- a/src/main/java/com/jagrosh/vortex/logging/BasicLogger.java +++ b/src/main/java/com/jagrosh/vortex/logging/BasicLogger.java @@ -15,9 +15,10 @@ */ package com.jagrosh.vortex.logging; -import com.jagrosh.vortex.pro.AvatarUtil; import com.jagrosh.vortex.Vortex; import com.jagrosh.vortex.logging.MessageCache.CachedMessage; +import com.jagrosh.vortex.pro.api.AvatarUtil; +import com.jagrosh.vortex.pro.VortexPro; import com.jagrosh.vortex.utils.FormatUtil; import com.jagrosh.vortex.utils.LogUtil; import java.awt.Color; @@ -291,6 +292,9 @@ public void logAvatarChange(UserUpdateAvatarEvent event) { + AvatarUtil avatarUtil = VortexPro.from(AvatarUtil.class); + if(avatarUtil == null) + return; List logs = event.getUser().getMutualGuilds().stream() .map(guild -> vortex.getDatabase().settings.getSettings(guild).getAvatarLogChannel(guild)) .filter(tc -> tc!=null) @@ -300,7 +304,7 @@ OffsetDateTime now = OffsetDateTime.now(); vortex.getThreadpool().execute(() -> { - byte[] im = AvatarUtil.makeAvatarImage(event.getUser(), event.getOldAvatarUrl(), event.getOldAvatarId()); + byte[] im = avatarUtil.makeAvatarImage(event.getUser(), event.getOldAvatarUrl(), event.getOldAvatarId()); if(im!=null) logs.forEach(tc -> logFile(now, tc, AVATAR, FormatUtil.formatFullUser(event.getUser())+" has changed avatars" +(event.getUser().getAvatarId()!=null && event.getUser().getAvatarId().startsWith("a_") ? " <:gif:314068430624129039>" : "") diff --git a/src/main/java/com/jagrosh/vortex/pro/ProFeature.java b/src/main/java/com/jagrosh/vortex/pro/ProFeature.java new file mode 100644 index 0000000..1b349b4 --- /dev/null +++ b/src/main/java/com/jagrosh/vortex/pro/ProFeature.java @@ -0,0 +1,15 @@ +package com.jagrosh.vortex.pro; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface ProFeature +{ + String value(); + + Class mock() default Object.class; +} diff --git a/src/main/java/com/jagrosh/vortex/pro/VortexPro.java b/src/main/java/com/jagrosh/vortex/pro/VortexPro.java new file mode 100644 index 0000000..bd615d0 --- /dev/null +++ b/src/main/java/com/jagrosh/vortex/pro/VortexPro.java @@ -0,0 +1,70 @@ +package com.jagrosh.vortex.pro; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +public class VortexPro +{ + private static final Map, Object> IMPLS = new HashMap<>(); + + @SuppressWarnings("unchecked") + public static T from(Class apiClass, Object... args) + { + if(IMPLS.containsKey(apiClass)) + { + return (T) IMPLS.get(apiClass); + } + ProFeature anno = apiClass.getAnnotation(ProFeature.class); + Class implClass = null; + try + { + Class tmpClass = Class.forName(anno.value()); + if(!apiClass.isAssignableFrom(tmpClass) || tmpClass.isInterface()) + { + throw new IllegalStateException("Class " + tmpClass.getName() + " can't be converted to a instance of " + apiClass.getName()); + } + implClass = (Class) tmpClass; + } + catch(ClassNotFoundException ignored) {} + if(implClass == null) + { + if(anno.mock() != Object.class) + { + if(!apiClass.isAssignableFrom(anno.mock()) || anno.mock().isInterface()) + { + throw new IllegalStateException("Class " + anno.mock().getName() + " can't be converted to a instance of " + apiClass.getName()); + } + implClass = (Class) anno.mock(); + } + } + try + { + T instance = null; + if(implClass != null) + { + Set> constructors = Arrays.stream(implClass.getConstructors()) + .filter(c -> c.getParameterCount() == args.length) + .map(c -> (Constructor) c) + .collect(Collectors.toSet()); + if(constructors.size() != 1) + { + throw new IllegalArgumentException("Could not find a Constructor with matching amount of arguments. Arguments provided: " + Arrays.toString(args)); + } + instance = constructors.iterator().next().newInstance(args); + } + IMPLS.put(apiClass, instance); + return instance; + } + catch(InvocationTargetException | InstantiationException | IllegalAccessException e) + { + throw new IllegalStateException("Can not instanciate class "+implClass.getName()+". Does it have a public no-arg constructor?", e); + } + } + + private VortexPro() {} +} diff --git a/src/main/java/com/jagrosh/vortex/pro/api/AvatarUtil.java b/src/main/java/com/jagrosh/vortex/pro/api/AvatarUtil.java new file mode 100644 index 0000000..384e011 --- /dev/null +++ b/src/main/java/com/jagrosh/vortex/pro/api/AvatarUtil.java @@ -0,0 +1,10 @@ +package com.jagrosh.vortex.pro.api; + +import com.jagrosh.vortex.pro.ProFeature; +import net.dv8tion.jda.core.entities.User; + +@ProFeature("com.jagrosh.vortex.pro.AvatarUtil") +public interface AvatarUtil +{ + byte[] makeAvatarImage(User user, String oldAvatarUrl, String oldAvatarId); +} diff --git a/src/main/java/com/jagrosh/vortex/pro/api/URLResolver.java b/src/main/java/com/jagrosh/vortex/pro/api/URLResolver.java new file mode 100644 index 0000000..1903932 --- /dev/null +++ b/src/main/java/com/jagrosh/vortex/pro/api/URLResolver.java @@ -0,0 +1,14 @@ +package com.jagrosh.vortex.pro.api; + +import com.jagrosh.vortex.pro.ProFeature; +import com.jagrosh.vortex.pro.api.mocks.URLResolverMock; + +import java.util.List; + +@ProFeature(value = "com.jagrosh.vortex.pro.URLResolver", mock = URLResolverMock.class) +public interface URLResolver +{ + void loadSafeDomains(); + + List findRedirects(String link); +} diff --git a/src/main/java/com/jagrosh/vortex/pro/api/mocks/URLResolverMock.java b/src/main/java/com/jagrosh/vortex/pro/api/mocks/URLResolverMock.java new file mode 100644 index 0000000..3224d28 --- /dev/null +++ b/src/main/java/com/jagrosh/vortex/pro/api/mocks/URLResolverMock.java @@ -0,0 +1,20 @@ +package com.jagrosh.vortex.pro.api.mocks; + +import com.jagrosh.vortex.pro.api.URLResolver; + +import java.util.Collections; +import java.util.List; + +public class URLResolverMock implements URLResolver +{ + public URLResolverMock(String url, String secret){} + + @Override + public void loadSafeDomains(){} + + @Override + public List findRedirects(String link) + { + return Collections.emptyList(); + } +}