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 extends T> 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 extends T>) 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 extends T>) anno.mock();
+ }
+ }
+ try
+ {
+ T instance = null;
+ if(implClass != null)
+ {
+ Set> constructors = Arrays.stream(implClass.getConstructors())
+ .filter(c -> c.getParameterCount() == args.length)
+ .map(c -> (Constructor extends T>) 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();
+ }
+}