diff --git a/src/main/java/net/dv8tion/jda/bot/sharding/DefaultShardManager.java b/src/main/java/net/dv8tion/jda/bot/sharding/DefaultShardManager.java index 4b5f568b0a..fc346227d7 100644 --- a/src/main/java/net/dv8tion/jda/bot/sharding/DefaultShardManager.java +++ b/src/main/java/net/dv8tion/jda/bot/sharding/DefaultShardManager.java @@ -103,6 +103,11 @@ public class DefaultShardManager implements ShardManager */ protected final List listeners; + /** + * The event listener providers for new and restarted JDA instances. + */ + protected final List> listenerProviders; + /** * The maximum amount of time that JDA will back off to wait when attempting to reconnect the MainWebsocket. */ @@ -213,6 +218,9 @@ public class DefaultShardManager implements ShardManager * The {@link net.dv8tion.jda.core.utils.SessionController SessionController} * @param listeners * The event listeners for new JDA instances. + * @param listenerProviders + * Providers of event listeners for JDA instances. Each will have the shard id applied to them upon + * shard creation (including shard restarts) and must return an event listener * @param token * The token * @param eventManager @@ -257,6 +265,7 @@ public class DefaultShardManager implements ShardManager */ protected DefaultShardManager(final int shardsTotal, final Collection shardIds, final SessionController controller, final List listeners, + final List> listenerProviders, final String token, final IEventManager eventManager, final IAudioSendFactory audioSendFactory, final IntFunction gameProvider, final IntFunction statusProvider, final OkHttpClient.Builder httpClientBuilder, final WebSocketFactory wsFactory, @@ -269,6 +278,7 @@ protected DefaultShardManager(final int shardsTotal, final Collection s { this.shardsTotal = shardsTotal; this.listeners = listeners; + this.listenerProviders = listenerProviders; this.token = token; this.eventManager = eventManager; this.audioSendFactory = audioSendFactory; @@ -326,6 +336,19 @@ public void removeEventListener(final Object... listeners) this.listeners.removeAll(Arrays.asList(listeners)); } + @Override + public void addEventListeners(IntFunction eventListenerProvider) + { + ShardManager.super.addEventListeners(eventListenerProvider); + this.listenerProviders.add(eventListenerProvider); + } + + @Override + public void removeEventListenerProvider(IntFunction eventListenerProvider) + { + this.listenerProviders.remove(eventListenerProvider); + } + @Override public int getShardsQueued() { @@ -563,6 +586,7 @@ protected JDAImpl buildInstance(final int shardId) throws LoginException, Interr jda.setAudioSendFactory(this.audioSendFactory); this.listeners.forEach(jda::addEventListener); + this.listenerProviders.forEach(provider -> jda.addEventListener(provider.apply(shardId))); jda.setStatus(JDA.Status.INITIALIZED); //This is already set by JDA internally, but this is to make sure the listeners catch it. // Set the presence information before connecting to have the correct information ready when sending IDENTIFY diff --git a/src/main/java/net/dv8tion/jda/bot/sharding/DefaultShardManagerBuilder.java b/src/main/java/net/dv8tion/jda/bot/sharding/DefaultShardManagerBuilder.java index a94b14fad3..2c9fd69053 100644 --- a/src/main/java/net/dv8tion/jda/bot/sharding/DefaultShardManagerBuilder.java +++ b/src/main/java/net/dv8tion/jda/bot/sharding/DefaultShardManagerBuilder.java @@ -29,6 +29,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ThreadFactory; @@ -47,6 +48,7 @@ public class DefaultShardManagerBuilder { protected final List listeners = new ArrayList<>(); + protected final List> listenerProviders = new ArrayList<>(); protected SessionController sessionController = null; protected IntFunction> contextProvider = null; protected boolean enableContext = true; @@ -220,6 +222,82 @@ public DefaultShardManagerBuilder removeEventListeners(final Collection return this; } + /** + * Adds the provided listener provider to the list of listener providers that will be used to create listeners. + * On shard creation (including shard restarts) the provider will have the shard id applied and must return a listener, + * which will be used, along all other listeners, to populate the listeners of the JDA object of that shard. + * + *
This uses the {@link net.dv8tion.jda.core.hooks.InterfacedEventManager InterfacedEventListener} by default. + *
To switch to the {@link net.dv8tion.jda.core.hooks.AnnotatedEventManager AnnotatedEventManager}, + * use {@link #setEventManager(net.dv8tion.jda.core.hooks.IEventManager) setEventManager(new AnnotatedEventManager())}. + * + *

Note: When using the {@link net.dv8tion.jda.core.hooks.InterfacedEventManager InterfacedEventListener} (default), + * given listener(s) must be instance of {@link net.dv8tion.jda.core.hooks.EventListener EventListener}! + * + * @param listenerProvider + * The listener provider to add to the list of listener providers. + * + * @return The {@link net.dv8tion.jda.bot.sharding.DefaultShardManagerBuilder DefaultShardManagerBuilder} instance. Useful for chaining. + */ + public DefaultShardManagerBuilder addEventListenerProvider(final IntFunction listenerProvider) + { + return this.addEventListenerProviders(Collections.singleton(listenerProvider)); + } + + /** + * Adds the provided listener providers to the list of listener providers that will be used to create listeners. + * On shard creation (including shard restarts) each provider will have the shard id applied and must return a listener, + * which will be used, along all other listeners, to populate the listeners of the JDA object of that shard. + * + *
This uses the {@link net.dv8tion.jda.core.hooks.InterfacedEventManager InterfacedEventListener} by default. + *
To switch to the {@link net.dv8tion.jda.core.hooks.AnnotatedEventManager AnnotatedEventManager}, + * use {@link #setEventManager(net.dv8tion.jda.core.hooks.IEventManager) setEventManager(new AnnotatedEventManager())}. + * + *

Note: When using the {@link net.dv8tion.jda.core.hooks.InterfacedEventManager InterfacedEventListener} (default), + * given listener(s) must be instance of {@link net.dv8tion.jda.core.hooks.EventListener EventListener}! + * + * @param listenerProviders + * The listener provider to add to the list of listener providers. + * + * @return The {@link net.dv8tion.jda.bot.sharding.DefaultShardManagerBuilder DefaultShardManagerBuilder} instance. Useful for chaining. + */ + public DefaultShardManagerBuilder addEventListenerProviders(final Collection> listenerProviders) + { + Checks.noneNull(listenerProviders, "listener providers"); + + this.listenerProviders.addAll(listenerProviders); + return this; + } + + /** + * Removes the provided listener provider from the list of listener providers. + * + * @param listenerProvider + * The listener provider to remove from the list of listener providers. + * + * @return The {@link net.dv8tion.jda.bot.sharding.DefaultShardManagerBuilder DefaultShardManagerBuilder} instance. Useful for chaining. + */ + public DefaultShardManagerBuilder removeEventListenerProvider(final IntFunction listenerProvider) + { + return this.removeEventListenerProviders(Collections.singleton(listenerProvider)); + } + + /** + * Removes all provided listener providers from the list of listener providers. + * + * @param listenerProviders + * The listener provider(s) to remove from the list of listener providers. + * + * @return The {@link net.dv8tion.jda.bot.sharding.DefaultShardManagerBuilder DefaultShardManagerBuilder} instance. Useful for chaining. + */ + public DefaultShardManagerBuilder removeEventListenerProviders(final Collection> listenerProviders) + { + Checks.noneNull(listenerProviders, "listener providers"); + + this.listenerProviders.removeAll(listenerProviders); + return this; + } + /** * Enables/Disables Voice functionality. *
This is useful, if your current system doesn't support Voice and you do not need it. @@ -761,7 +839,7 @@ public ShardManager build() throws LoginException, IllegalArgumentException { final DefaultShardManager manager = new DefaultShardManager( this.shardsTotal, this.shards, this.sessionController, - this.listeners, this.token, this.eventManager, + this.listeners, this.listenerProviders, this.token, this.eventManager, this.audioSendFactory, this.gameProvider, this.statusProvider, this.httpClientBuilder, this.wsFactory, this.threadFactory, this.shardedRateLimiter, this.maxReconnectDelay, this.corePoolSize, this.enableVoice, this.enableShutdownHook, this.enableBulkDeleteSplitting, diff --git a/src/main/java/net/dv8tion/jda/bot/sharding/ShardManager.java b/src/main/java/net/dv8tion/jda/bot/sharding/ShardManager.java index cd46d613b0..f953dc4edc 100644 --- a/src/main/java/net/dv8tion/jda/bot/sharding/ShardManager.java +++ b/src/main/java/net/dv8tion/jda/bot/sharding/ShardManager.java @@ -76,6 +76,66 @@ default void removeEventListener(final Object... listeners) this.getShardCache().forEach(jda -> jda.removeEventListener(listeners)); } + /** + * Adds listeners provided by the listener provider to each shard to the event-listeners that will be used to handle events. + * The listener provider gets a shard id applied and is expected to return a listener. + * + *

Note: when using the {@link net.dv8tion.jda.core.hooks.InterfacedEventManager InterfacedEventListener} (default), + * given listener must be instance of {@link net.dv8tion.jda.core.hooks.EventListener EventListener}! + * + * @param eventListenerProvider + * The provider of listener(s) which will react to events. + * + * @throws java.lang.IllegalArgumentException + * If the provided listener provider or any of the listeners or provides are {@code null}. + */ + default void addEventListeners(final IntFunction eventListenerProvider) + { + Checks.notNull(eventListenerProvider, "event listener provider"); + this.getShardCache().forEach(jda -> + { + Object listener = eventListenerProvider.apply(jda.getShardInfo().getShardId()); + if (listener != null) jda.addEventListener(listener); + }); + } + + /** + * Remove listeners from shards by their id. + * The provider takes shard ids, and returns a collection of listeners that shall be removed from the respective + * shards. + * + * @param eventListenerProvider + * gets shard ids applied and is expected to return a collection of listeners that shall be removed from + * the respective shards + * + * @throws java.lang.IllegalArgumentException + * If the provided event listeners provider is {@code null}. + */ + default void removeEventListeners(final IntFunction> eventListenerProvider) + { + Checks.notNull(eventListenerProvider, "event listener provider"); + this.getShardCache().forEach(jda -> + jda.removeEventListener(eventListenerProvider.apply(jda.getShardInfo().getShardId())) + ); + } + + /** + * Remove a listener provider. This will stop further created / restarted shards from getting a listener added by + * that provider. + * + * Default is a no-op for backwards compatibility, see implementations like + * {@link DefaultShardManager#removeEventListenerProvider(IntFunction)} for actual code + * + * @param eventListenerProvider + * The provider of listeners that shall be removed. + * + * @throws java.lang.IllegalArgumentException + * If the provided listener provider is {@code null}. + */ + default void removeEventListenerProvider(IntFunction eventListenerProvider) + { + } + /** * Returns the amount of shards queued for (re)connecting. *