All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.dv8tion.jda.api.sharding.ShardManager Maven / Gradle / Ivy

Go to download

Java wrapper for the popular chat & VOIP service: Discord https://discord.com

There is a newer version: 5.1.0
Show newest version
/*
 * Copyright 2015 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.dv8tion.jda.api.sharding;

import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDA.Status;
import net.dv8tion.jda.api.OnlineStatus;
import net.dv8tion.jda.api.entities.*;
import net.dv8tion.jda.api.entities.channel.Channel;
import net.dv8tion.jda.api.entities.channel.ChannelType;
import net.dv8tion.jda.api.entities.channel.attribute.IGuildChannelContainer;
import net.dv8tion.jda.api.entities.channel.concrete.*;
import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel;
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
import net.dv8tion.jda.api.entities.emoji.RichCustomEmoji;
import net.dv8tion.jda.api.exceptions.InvalidTokenException;
import net.dv8tion.jda.api.requests.GatewayIntent;
import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.requests.Route;
import net.dv8tion.jda.api.utils.MiscUtil;
import net.dv8tion.jda.api.utils.cache.CacheView;
import net.dv8tion.jda.api.utils.cache.ChannelCacheView;
import net.dv8tion.jda.api.utils.cache.ShardCacheView;
import net.dv8tion.jda.api.utils.cache.SnowflakeCacheView;
import net.dv8tion.jda.internal.JDAImpl;
import net.dv8tion.jda.internal.requests.CompletedRestAction;
import net.dv8tion.jda.internal.requests.RestActionImpl;
import net.dv8tion.jda.internal.utils.Checks;
import net.dv8tion.jda.internal.utils.Helpers;
import net.dv8tion.jda.internal.utils.cache.UnifiedChannelCacheView;
import org.jetbrains.annotations.Unmodifiable;

import javax.annotation.CheckReturnValue;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.stream.Collectors;

/**
 * This class acts as a manager for multiple shards.
 * It contains several methods to make your life with sharding easier.
 *
 * 
Custom implementations may not support all methods and throw * {@link java.lang.UnsupportedOperationException UnsupportedOperationExceptions} instead. * * @since 3.4 * @author Aljoscha Grebe */ public interface ShardManager extends IGuildChannelContainer { /** * Adds all provided listeners to the event-listeners that will be used to handle events. * *

Note: when using the {@link net.dv8tion.jda.api.hooks.InterfacedEventManager InterfacedEventListener} (default), * the given listener must be an instance of {@link net.dv8tion.jda.api.hooks.EventListener EventListener}! * * @param listeners * The listener(s) which will react to events. * * @throws java.lang.IllegalArgumentException * If either listeners or one of it's objects is {@code null}. */ default void addEventListener(@Nonnull final Object... listeners) { Checks.noneNull(listeners, "listeners"); this.getShardCache().forEach(jda -> jda.addEventListener(listeners)); } /** * Removes all provided listeners from the event-listeners and no longer uses them to handle events. * * @param listeners * The listener(s) to be removed. * * @throws java.lang.IllegalArgumentException * If either listeners or one of it's objects is {@code null}. */ default void removeEventListener(@Nonnull final Object... listeners) { Checks.noneNull(listeners, "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.api.hooks.InterfacedEventManager InterfacedEventListener} (default), * the given listener must be an instance of {@link net.dv8tion.jda.api.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(@Nonnull 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(@Nonnull 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(@Nonnull IntFunction eventListenerProvider) { } /** * Returns the amount of shards queued for (re)connecting. * * @return The amount of shards queued for (re)connecting. */ int getShardsQueued(); /** * Returns the amount of running shards. * * @return The amount of running shards. */ default int getShardsRunning() { return (int) this.getShardCache().size(); } /** * Returns the amount of shards managed by this {@link net.dv8tion.jda.api.sharding.ShardManager ShardManager}. * This includes shards currently queued for a restart. * * @return The managed amount of shards. */ default int getShardsTotal() { return this.getShardsQueued() + this.getShardsRunning(); } /** * The {@link GatewayIntent GatewayIntents} for the JDA sessions of this shard manager. * * @return {@link EnumSet} of active gateway intents */ @Nonnull default EnumSet getGatewayIntents() { //noinspection ConstantConditions return getShardCache().applyStream((stream) -> stream.map(JDA::getGatewayIntents) .findAny() .orElse(EnumSet.noneOf(GatewayIntent.class))); } /** * Used to access application details of this bot. *
Since this is the same for every shard it picks {@link JDA#retrieveApplicationInfo()} from any shard. * * @throws java.lang.IllegalStateException * If there is no running shard * * @return The Application registry for this bot. */ @Nonnull default RestAction retrieveApplicationInfo() { return this.getShardCache().stream() .findAny() .orElseThrow(() -> new IllegalStateException("no active shards")) .retrieveApplicationInfo(); } /** * The average time in milliseconds between all shards that discord took to respond to our last heartbeat. * This roughly represents the WebSocket ping of this session. If there are no shards running, this will return {@code -1}. * *

{@link net.dv8tion.jda.api.requests.RestAction RestAction} request times do not * correlate to this value! * * @return The average time in milliseconds between heartbeat and the heartbeat ack response */ default double getAverageGatewayPing() { return this.getShardCache() .stream() .mapToLong(JDA::getGatewayPing) .filter(ping -> ping != -1) .average() .orElse(-1D); } /** * {@link net.dv8tion.jda.api.utils.cache.SnowflakeCacheView SnowflakeCacheView} of * all cached {@link net.dv8tion.jda.api.entities.channel.concrete.Category Categories} visible to this ShardManager instance. * * @return {@link net.dv8tion.jda.api.utils.cache.SnowflakeCacheView SnowflakeCacheView} */ @Nonnull default SnowflakeCacheView getCategoryCache() { return CacheView.allSnowflakes(() -> this.getShardCache().stream().map(JDA::getCategoryCache)); } /** * Retrieves a custom emoji matching the specified {@code id} if one is available in our cache. * *

Unicode emojis are not included as {@link RichCustomEmoji}! * * @param id * The id of the requested {@link RichCustomEmoji}. * * @return An {@link RichCustomEmoji} represented by this id or null if none is found in * our cache. */ @Nullable default RichCustomEmoji getEmojiById(final long id) { return this.getEmojiCache().getElementById(id); } /** * Retrieves a custom emoji matching the specified {@code id} if one is available in our cache. * *

Unicode emojis are not included as {@link RichCustomEmoji}! * * @param id * The id of the requested {@link RichCustomEmoji}. * * @throws java.lang.NumberFormatException * If the provided {@code id} cannot be parsed by {@link Long#parseLong(String)} * * @return An {@link RichCustomEmoji} represented by this id or null if none is found in * our cache. */ @Nullable default RichCustomEmoji getEmojiById(@Nonnull final String id) { return this.getEmojiCache().getElementById(id); } /** * Unified {@link net.dv8tion.jda.api.utils.cache.SnowflakeCacheView SnowflakeCacheView} of * all cached {@link RichCustomEmoji RichCustomEmojis} visible to this ShardManager instance. * * @return Unified {@link net.dv8tion.jda.api.utils.cache.SnowflakeCacheView SnowflakeCacheView} */ @Nonnull default SnowflakeCacheView getEmojiCache() { return CacheView.allSnowflakes(() -> this.getShardCache().stream().map(JDA::getEmojiCache)); } /** * A collection of all known custom emojis (managed/restricted included). * *

Hint: To check whether you can use a {@link RichCustomEmoji} in a specific * context you can use {@link RichCustomEmoji#canInteract(net.dv8tion.jda.api.entities.Member)} or {@link * RichCustomEmoji#canInteract(net.dv8tion.jda.api.entities.User, MessageChannel)} * *

Unicode emojis are not included as {@link RichCustomEmoji}! * *

This copies the backing store into a list. This means every call * creates a new list with O(n) complexity. It is recommended to store this into * a local variable or use {@link #getEmojiCache()} and use its more efficient * versions of handling these values. * * @return An immutable list of custom emojis (which may or may not be available to usage). */ @Nonnull @Unmodifiable default List getEmojis() { return this.getEmojiCache().asList(); } /** * An unmodifiable list of all {@link RichCustomEmoji RichCustomEmojis} that have the same name as the one * provided.
If there are no {@link RichCustomEmoji RichCustomEmojis} with the provided name, this will * return an empty list. * *

Unicode emojis are not included as {@link RichCustomEmoji}! * * @param name * The name of the requested {@link RichCustomEmoji RichCustomEmojis}. Without colons. * @param ignoreCase * Whether to ignore case or not when comparing the provided name to each {@link * RichCustomEmoji#getName()}. * * @return Possibly-empty list of all the {@link RichCustomEmoji RichCustomEmojis} that all have the same * name as the provided name. */ @Nonnull @Unmodifiable default List getEmojisByName(@Nonnull final String name, final boolean ignoreCase) { return this.getEmojiCache().getElementsByName(name, ignoreCase); } /** * This returns the {@link net.dv8tion.jda.api.entities.Guild Guild} which has the same id as the one provided. *
If there is no connected guild with an id that matches the provided one, this will return {@code null}. * * @param id * The id of the {@link net.dv8tion.jda.api.entities.Guild Guild}. * * @return Possibly-null {@link net.dv8tion.jda.api.entities.Guild Guild} with matching id. */ @Nullable default Guild getGuildById(final long id) { return getGuildCache().getElementById(id); } /** * This returns the {@link net.dv8tion.jda.api.entities.Guild Guild} which has the same id as the one provided. *
If there is no connected guild with an id that matches the provided one, this will return {@code null}. * * @param id * The id of the {@link net.dv8tion.jda.api.entities.Guild Guild}. * * @return Possibly-null {@link net.dv8tion.jda.api.entities.Guild Guild} with matching id. */ @Nullable default Guild getGuildById(@Nonnull final String id) { return getGuildById(MiscUtil.parseSnowflake(id)); } /** * An unmodifiable list of all {@link net.dv8tion.jda.api.entities.Guild Guilds} that have the same name as the one provided. *
If there are no {@link net.dv8tion.jda.api.entities.Guild Guilds} with the provided name, this will return an empty list. * * @param name * The name of the requested {@link net.dv8tion.jda.api.entities.Guild Guilds}. * @param ignoreCase * Whether to ignore case or not when comparing the provided name to each {@link net.dv8tion.jda.api.entities.Guild#getName()}. * * @return Possibly-empty list of all the {@link net.dv8tion.jda.api.entities.Guild Guilds} that all have the same name as the provided name. */ @Nonnull @Unmodifiable default List getGuildsByName(@Nonnull final String name, final boolean ignoreCase) { return this.getGuildCache().getElementsByName(name, ignoreCase); } /** * {@link net.dv8tion.jda.api.utils.cache.SnowflakeCacheView SnowflakeCacheView} of * all cached {@link net.dv8tion.jda.api.entities.Guild Guilds} visible to this ShardManager instance. * * @return {@link net.dv8tion.jda.api.utils.cache.SnowflakeCacheView SnowflakeCacheView} */ @Nonnull default SnowflakeCacheView getGuildCache() { return CacheView.allSnowflakes(() -> this.getShardCache().stream().map(JDA::getGuildCache)); } /** * An unmodifiable List of all {@link net.dv8tion.jda.api.entities.Guild Guilds} that the logged account is connected to. *
If this account is not connected to any {@link net.dv8tion.jda.api.entities.Guild Guilds}, this will return * an empty list. * *

This copies the backing store into a list. This means every call * creates a new list with O(n) complexity. It is recommended to store this into * a local variable or use {@link #getGuildCache()} and use its more efficient * versions of handling these values. * * @return Possibly-empty list of all the {@link net.dv8tion.jda.api.entities.Guild Guilds} that this account is connected to. */ @Nonnull @Unmodifiable default List getGuilds() { return this.getGuildCache().asList(); } /** * Gets all {@link net.dv8tion.jda.api.entities.Guild Guilds} that contain all given users as their members. * * @param users * The users which all the returned {@link net.dv8tion.jda.api.entities.Guild Guilds} must contain. * * @return Unmodifiable list of all {@link net.dv8tion.jda.api.entities.Guild Guild} instances which have all {@link net.dv8tion.jda.api.entities.User Users} in them. */ @Nonnull @Unmodifiable default List getMutualGuilds(@Nonnull final Collection users) { Checks.noneNull(users, "users"); return this.getGuildCache().stream() .filter(guild -> users.stream() .allMatch(guild::isMember)) .collect(Helpers.toUnmodifiableList()); } /** * Gets all {@link net.dv8tion.jda.api.entities.Guild Guilds} that contain all given users as their members. * * @param users * The users which all the returned {@link net.dv8tion.jda.api.entities.Guild Guilds} must contain. * * @return Unmodifiable list of all {@link net.dv8tion.jda.api.entities.Guild Guild} instances which have all {@link net.dv8tion.jda.api.entities.User Users} in them. */ @Nonnull @Unmodifiable default List getMutualGuilds(@Nonnull final User... users) { Checks.notNull(users, "users"); return this.getMutualGuilds(Arrays.asList(users)); } /** * Attempts to retrieve a {@link net.dv8tion.jda.api.entities.User User} object based on the provided id. *
This first calls {@link #getUserById(long)}, and if the return is {@code null} then a request * is made to the Discord servers. * *

The returned {@link net.dv8tion.jda.api.requests.RestAction RestAction} can encounter the following Discord errors: *

    *
  • {@link net.dv8tion.jda.api.requests.ErrorResponse#UNKNOWN_USER ErrorResponse.UNKNOWN_USER} *
    Occurs when the provided id does not refer to a {@link net.dv8tion.jda.api.entities.User User} * known by Discord. Typically occurs when developers provide an incomplete id (cut short).
  • *
* * @param id * The id of the requested {@link net.dv8tion.jda.api.entities.User User}. * * @throws java.lang.IllegalArgumentException * If the provided id String is not a valid snowflake. * @throws java.lang.IllegalStateException * If there isn't any active shards. * * @return {@link net.dv8tion.jda.api.requests.RestAction RestAction} - Type: {@link net.dv8tion.jda.api.entities.User User} *
On request, gets the User with id matching provided id from Discord. */ @Nonnull @CheckReturnValue default RestAction retrieveUserById(@Nonnull String id) { return retrieveUserById(MiscUtil.parseSnowflake(id)); } /** * Attempts to retrieve a {@link net.dv8tion.jda.api.entities.User User} object based on the provided id. *
This first calls {@link #getUserById(long)}, and if the return is {@code null} then a request * is made to the Discord servers. * *

The returned {@link net.dv8tion.jda.api.requests.RestAction RestAction} can encounter the following Discord errors: *

    *
  • {@link net.dv8tion.jda.api.requests.ErrorResponse#UNKNOWN_USER ErrorResponse.UNKNOWN_USER} *
    Occurs when the provided id does not refer to a {@link net.dv8tion.jda.api.entities.User User} * known by Discord. Typically occurs when developers provide an incomplete id (cut short).
  • *
* * @param id * The id of the requested {@link net.dv8tion.jda.api.entities.User User}. * * @throws java.lang.IllegalStateException * If there isn't any active shards. * * @return {@link net.dv8tion.jda.api.requests.RestAction RestAction} - Type: {@link net.dv8tion.jda.api.entities.User User} *
On request, gets the User with id matching provided id from Discord. */ @Nonnull @CheckReturnValue default RestAction retrieveUserById(long id) { JDA api = null; for (JDA shard : getShardCache()) { api = shard; EnumSet intents = shard.getGatewayIntents(); User user = shard.getUserById(id); boolean isUpdated = intents.contains(GatewayIntent.GUILD_PRESENCES) || intents.contains(GatewayIntent.GUILD_MEMBERS); if (user != null && isUpdated) return new CompletedRestAction<>(shard, user); } if (api == null) throw new IllegalStateException("no shards active"); JDAImpl jda = (JDAImpl) api; Route.CompiledRoute route = Route.Users.GET_USER.compile(Long.toUnsignedString(id)); return new RestActionImpl<>(jda, route, (response, request) -> jda.getEntityBuilder().createUser(response.getObject())); } /** * Searches for the first user that has the matching Discord Tag. *
Format has to be in the form {@code Username#Discriminator} where the * username must be between 2 and 32 characters (inclusive) matching the exact casing and the discriminator * must be exactly 4 digits. * *

This will only check cached users! * *

This only checks users that are known to the currently logged in account (shards). If a user exists * with the tag that is not available in the {@link #getUserCache() User-Cache} it will not be detected. *
Currently Discord does not offer a way to retrieve a user by their discord tag. * * @param tag * The Discord Tag in the format {@code Username#Discriminator} * * @throws java.lang.IllegalArgumentException * If the provided tag is null or not in the described format * * @return The {@link net.dv8tion.jda.api.entities.User} for the discord tag or null if no user has the provided tag */ @Nullable default User getUserByTag(@Nonnull String tag) { return getShardCache().applyStream(stream -> stream.map(jda -> jda.getUserByTag(tag)) .filter(Objects::nonNull) .findFirst() .orElse(null) ); } /** * Searches for the first user that has the matching Discord Tag. *
Format has to be in the form {@code Username#Discriminator} where the * username must be between 2 and 32 characters (inclusive) matching the exact casing and the discriminator * must be exactly 4 digits. * *

This will only check cached users! * *

This only checks users that are known to the currently logged in account (shards). If a user exists * with the tag that is not available in the {@link #getUserCache() User-Cache} it will not be detected. *
Currently Discord does not offer a way to retrieve a user by their discord tag. * * @param username * The name of the user * @param discriminator * The discriminator of the user * * @throws java.lang.IllegalArgumentException * If the provided arguments are null or not in the described format * * @return The {@link net.dv8tion.jda.api.entities.User} for the discord tag or null if no user has the provided tag */ @Nullable default User getUserByTag(@Nonnull String username, @Nonnull String discriminator) { return getShardCache().applyStream(stream -> stream.map(jda -> jda.getUserByTag(username, discriminator)) .filter(Objects::nonNull) .findFirst() .orElse(null) ); } /** * An unmodifiable list of all known {@link net.dv8tion.jda.api.entities.channel.concrete.PrivateChannel PrivateChannels}. * *

This copies the backing store into a list. This means every call * creates a new list with O(n) complexity. It is recommended to store this into * a local variable or use {@link #getPrivateChannelCache()} and use its more efficient * versions of handling these values. * * @return Possibly-empty list of all {@link net.dv8tion.jda.api.entities.channel.concrete.PrivateChannel PrivateChannels}. */ @Nonnull @Unmodifiable default List getPrivateChannels() { return this.getPrivateChannelCache().asList(); } /** * Retrieves the {@link net.dv8tion.jda.api.entities.Role Role} associated to the provided id.
This iterates * over all {@link net.dv8tion.jda.api.entities.Guild Guilds} and check whether a Role from that Guild is assigned * to the specified ID and will return the first that can be found. * * @param id * The id of the searched Role * * @return Possibly-null {@link net.dv8tion.jda.api.entities.Role Role} for the specified ID */ @Nullable default Role getRoleById(final long id) { return this.getRoleCache().getElementById(id); } /** * Retrieves the {@link net.dv8tion.jda.api.entities.Role Role} associated to the provided id.
This iterates * over all {@link net.dv8tion.jda.api.entities.Guild Guilds} and check whether a Role from that Guild is assigned * to the specified ID and will return the first that can be found. * * @param id * The id of the searched Role * * @throws java.lang.NumberFormatException * If the provided {@code id} cannot be parsed by {@link Long#parseLong(String)} * * @return Possibly-null {@link net.dv8tion.jda.api.entities.Role Role} for the specified ID */ @Nullable default Role getRoleById(@Nonnull final String id) { return this.getRoleCache().getElementById(id); } /** * Unified {@link net.dv8tion.jda.api.utils.cache.SnowflakeCacheView SnowflakeCacheView} of * all cached {@link net.dv8tion.jda.api.entities.Role Roles} visible to this ShardManager instance. * * @return Unified {@link net.dv8tion.jda.api.utils.cache.SnowflakeCacheView SnowflakeCacheView} */ @Nonnull default SnowflakeCacheView getRoleCache() { return CacheView.allSnowflakes(() -> this.getShardCache().stream().map(JDA::getRoleCache)); } /** * All {@link net.dv8tion.jda.api.entities.Role Roles} this ShardManager instance can see.
This will iterate over each * {@link net.dv8tion.jda.api.entities.Guild Guild} retrieved from {@link #getGuilds()} and collect its {@link * net.dv8tion.jda.api.entities.Guild#getRoles() Guild.getRoles()}. * *

This copies the backing store into a list. This means every call * creates a new list with O(n) complexity. It is recommended to store this into * a local variable or use {@link #getRoleCache()} and use its more efficient * versions of handling these values. * * @return Immutable List of all visible Roles */ @Nonnull @Unmodifiable default List getRoles() { return this.getRoleCache().asList(); } /** * Retrieves all {@link net.dv8tion.jda.api.entities.Role Roles} visible to this ShardManager instance. *
This simply filters the Roles returned by {@link #getRoles()} with the provided name, either using * {@link String#equals(Object)} or {@link String#equalsIgnoreCase(String)} on {@link net.dv8tion.jda.api.entities.Role#getName()}. * * @param name * The name for the Roles * @param ignoreCase * Whether to use {@link String#equalsIgnoreCase(String)} * * @return Immutable List of all Roles matching the parameters provided. */ @Nonnull @Unmodifiable default List getRolesByName(@Nonnull final String name, final boolean ignoreCase) { return this.getRoleCache().getElementsByName(name, ignoreCase); } /** * This returns the {@link net.dv8tion.jda.api.entities.channel.concrete.PrivateChannel PrivateChannel} which has the same id as the one provided. *
If there is no known {@link net.dv8tion.jda.api.entities.channel.concrete.PrivateChannel PrivateChannel} with an id that matches the provided * one, then this will return {@code null}. * * @param id * The id of the {@link net.dv8tion.jda.api.entities.channel.concrete.PrivateChannel PrivateChannel}. * * @return Possibly-null {@link net.dv8tion.jda.api.entities.channel.concrete.PrivateChannel PrivateChannel} with matching id. */ @Nullable default PrivateChannel getPrivateChannelById(final long id) { return this.getPrivateChannelCache().getElementById(id); } /** * This returns the {@link net.dv8tion.jda.api.entities.channel.concrete.PrivateChannel PrivateChannel} which has the same id as the one provided. *
If there is no known {@link net.dv8tion.jda.api.entities.channel.concrete.PrivateChannel PrivateChannel} with an id that matches the provided * one, this will return {@code null}. * * @param id * The id of the {@link net.dv8tion.jda.api.entities.channel.concrete.PrivateChannel PrivateChannel}. * * @throws java.lang.NumberFormatException * If the provided {@code id} cannot be parsed by {@link Long#parseLong(String)} * * @return Possibly-null {@link net.dv8tion.jda.api.entities.channel.concrete.PrivateChannel PrivateChannel} with matching id. */ @Nullable default PrivateChannel getPrivateChannelById(@Nonnull final String id) { return this.getPrivateChannelCache().getElementById(id); } /** * {@link net.dv8tion.jda.api.utils.cache.SnowflakeCacheView SnowflakeCacheView} of * all cached {@link net.dv8tion.jda.api.entities.channel.concrete.PrivateChannel PrivateChannels} visible to this ShardManager instance. * * @return {@link net.dv8tion.jda.api.utils.cache.SnowflakeCacheView SnowflakeCacheView} */ @Nonnull default SnowflakeCacheView getPrivateChannelCache() { return CacheView.allSnowflakes(() -> this.getShardCache().stream().map(JDA::getPrivateChannelCache)); } @Nullable default GuildChannel getGuildChannelById(long id) { GuildChannel channel; for (JDA shard : getShards()) { channel = shard.getGuildChannelById(id); if (channel != null) return channel; } return null; } @Nullable default GuildChannel getGuildChannelById(@Nonnull ChannelType type, long id) { Checks.notNull(type, "ChannelType"); GuildChannel channel; for (JDA shard : getShards()) { channel = shard.getGuildChannelById(type, id); if (channel != null) return channel; } return null; } @Nonnull default SnowflakeCacheView getTextChannelCache() { return CacheView.allSnowflakes(() -> this.getShardCache().stream().map(JDA::getTextChannelCache)); } @Nonnull default SnowflakeCacheView getVoiceChannelCache() { return CacheView.allSnowflakes(() -> this.getShardCache().stream().map(JDA::getVoiceChannelCache)); } @Nonnull @Override default SnowflakeCacheView getStageChannelCache() { return CacheView.allSnowflakes(() -> this.getShardCache().stream().map(JDA::getStageChannelCache)); } @Nonnull @Override default SnowflakeCacheView getThreadChannelCache() { return CacheView.allSnowflakes(() -> this.getShardCache().stream().map(JDA::getThreadChannelCache)); } @Nonnull @Override default SnowflakeCacheView getNewsChannelCache() { return CacheView.allSnowflakes(() -> this.getShardCache().stream().map(JDA::getNewsChannelCache)); } @Nonnull @Override default SnowflakeCacheView getForumChannelCache() { return CacheView.allSnowflakes(() -> this.getShardCache().stream().map(JDA::getForumChannelCache)); } @Nonnull @Override default SnowflakeCacheView getMediaChannelCache() { return CacheView.allSnowflakes(() -> this.getShardCache().stream().map(JDA::getMediaChannelCache)); } @Nonnull @Override default ChannelCacheView getChannelCache() { return new UnifiedChannelCacheView<>(() -> this.getShardCache().stream().map(JDA::getChannelCache)); } /** * This returns the {@link net.dv8tion.jda.api.JDA JDA} instance which has the same id as the one provided. *
If there is no shard with an id that matches the provided one, this will return {@code null}. * * @param id * The id of the shard. * * @return The {@link net.dv8tion.jda.api.JDA JDA} instance with the given shardId or * {@code null} if no shard has the given id */ @Nullable default JDA getShardById(final int id) { return this.getShardCache().getElementById(id); } /** * This returns the {@link net.dv8tion.jda.api.JDA JDA} instance which has the same id as the one provided. *
If there is no shard with an id that matches the provided one, this will return {@code null}. * * @param id * The id of the shard. * * @return The {@link net.dv8tion.jda.api.JDA JDA} instance with the given shardId or * {@code null} if no shard has the given id */ @Nullable default JDA getShardById(@Nonnull final String id) { return this.getShardCache().getElementById(id); } /** * Unified {@link ShardCacheView ShardCacheView} of * all cached {@link net.dv8tion.jda.api.JDA JDA} bound to this ShardManager instance. * * @return Unified {@link ShardCacheView ShardCacheView} */ @Nonnull ShardCacheView getShardCache(); /** * Gets all {@link net.dv8tion.jda.api.JDA JDA} instances bound to this ShardManager. * *

This copies the backing store into a list. This means every call * creates a new list with O(n) complexity. It is recommended to store this into * a local variable or use {@link #getShardCache()} and use its more efficient * versions of handling these values. * * @return An immutable list of all managed {@link net.dv8tion.jda.api.JDA JDA} instances. */ @Nonnull @Unmodifiable default List getShards() { return this.getShardCache().asList(); } /** * This returns the {@link net.dv8tion.jda.api.JDA.Status JDA.Status} of the shard which has the same id as the one provided. *
If there is no shard with an id that matches the provided one, this will return {@code null}. * * @param shardId * The id of the shard. * * @return The {@link net.dv8tion.jda.api.JDA.Status JDA.Status} of the shard with the given shardId or * {@code null} if no shard has the given id */ @Nullable default JDA.Status getStatus(final int shardId) { final JDA jda = this.getShardCache().getElementById(shardId); return jda == null ? null : jda.getStatus(); } /** * Gets the current {@link net.dv8tion.jda.api.JDA.Status Status} of all shards. * * @return All current shard statuses. */ @Nonnull @Unmodifiable default Map getStatuses() { return Collections.unmodifiableMap(this.getShardCache().stream() .collect(Collectors.toMap(Function.identity(), JDA::getStatus))); } /** * This returns the {@link net.dv8tion.jda.api.entities.User User} which has the same id as the one provided. *
If there is no visible user with an id that matches the provided one, this will return {@code null}. * * @param id * The id of the requested {@link net.dv8tion.jda.api.entities.User User}. * * @return Possibly-null {@link net.dv8tion.jda.api.entities.User User} with matching id. */ @Nullable default User getUserById(final long id) { return this.getUserCache().getElementById(id); } /** * This returns the {@link net.dv8tion.jda.api.entities.User User} which has the same id as the one provided. *
If there is no visible user with an id that matches the provided one, this will return {@code null}. * * @param id * The id of the requested {@link net.dv8tion.jda.api.entities.User User}. * * @return Possibly-null {@link net.dv8tion.jda.api.entities.User User} with matching id. */ @Nullable default User getUserById(@Nonnull final String id) { return this.getUserCache().getElementById(id); } /** * {@link net.dv8tion.jda.api.utils.cache.SnowflakeCacheView SnowflakeCacheView} of * all cached {@link net.dv8tion.jda.api.entities.User Users} visible to this ShardManager instance. * * @return {@link net.dv8tion.jda.api.utils.cache.SnowflakeCacheView SnowflakeCacheView} */ @Nonnull default SnowflakeCacheView getUserCache() { return CacheView.allSnowflakes(() -> this.getShardCache().stream().map(JDA::getUserCache)); } /** * An unmodifiable list of all {@link net.dv8tion.jda.api.entities.User Users} that share a * {@link net.dv8tion.jda.api.entities.Guild Guild} with the currently logged in account. *
This list will never contain duplicates and represents all {@link net.dv8tion.jda.api.entities.User Users} * that JDA can currently see. * *

If the developer is sharding, then only users from guilds connected to the specifically logged in * shard will be returned in the List. * *

This copies the backing store into a list. This means every call * creates a new list with O(n) complexity. It is recommended to store this into * a local variable or use {@link #getUserCache()} and use its more efficient * versions of handling these values. * * @return List of all {@link net.dv8tion.jda.api.entities.User Users} that are visible to JDA. */ @Nonnull @Unmodifiable default List getUsers() { return this.getUserCache().asList(); } /** * Restarts all shards, shutting old ones down first. * *

As all shards need to connect to discord again this will take equally long as the startup of a new ShardManager * (using the 5000ms + backoff as delay between starting new JDA instances). * * @throws java.util.concurrent.RejectedExecutionException * If {@link #shutdown()} has already been invoked */ void restart(); /** * Restarts the shards with the given id only. *
If there is no shard with the given Id, this method acts like {@link #start(int)}. * * @param id * The id of the target shard * * @throws java.lang.IllegalArgumentException * If shardId is negative or higher than maxShardId * @throws java.util.concurrent.RejectedExecutionException * If {@link #shutdown()} has already been invoked */ void restart(int id); /** * Sets the {@link net.dv8tion.jda.api.entities.Activity Activity} for all shards. *
An Activity can be retrieved via {@link net.dv8tion.jda.api.entities.Activity#playing(String)}. * For streams you provide a valid streaming url as second parameter. * *

This will also change the activity for shards that are created in the future. * * @param activity * A {@link net.dv8tion.jda.api.entities.Activity Activity} instance or null to reset * * @see net.dv8tion.jda.api.entities.Activity#playing(String) * @see net.dv8tion.jda.api.entities.Activity#streaming(String, String) */ default void setActivity(@Nullable final Activity activity) { this.setActivityProvider(id -> activity); } /** * Sets provider that provider the {@link net.dv8tion.jda.api.entities.Activity Activity} for all shards. *
A Activity can be retrieved via {@link net.dv8tion.jda.api.entities.Activity#playing(String)}. * For streams you provide a valid streaming url as second parameter. * *

This will also change the provider for shards that are created in the future. * * @param activityProvider * Provider for an {@link net.dv8tion.jda.api.entities.Activity Activity} instance or null to reset * * @see net.dv8tion.jda.api.entities.Activity#playing(String) * @see net.dv8tion.jda.api.entities.Activity#streaming(String, String) */ default void setActivityProvider(@Nullable final IntFunction activityProvider) { this.getShardCache().forEach(jda -> jda.getPresence().setActivity(activityProvider == null ? null : activityProvider.apply(jda.getShardInfo().getShardId()))); } /** * Sets whether all instances should be marked as afk or not * *

This is relevant to client accounts to monitor * whether new messages should trigger mobile push-notifications. * *

This will also change the value for shards that are created in the future. * * @param idle * boolean */ default void setIdle(final boolean idle) { this.setIdleProvider(id -> idle); } /** * Sets the provider that decides for all shards whether they should be marked as afk or not. * *

This will also change the provider for shards that are created in the future. * * @param idleProvider * Provider for a boolean */ default void setIdleProvider(@Nonnull final IntFunction idleProvider) { this.getShardCache().forEach(jda -> jda.getPresence().setIdle(idleProvider.apply(jda.getShardInfo().getShardId()))); } /** * Sets the {@link net.dv8tion.jda.api.OnlineStatus OnlineStatus} and {@link net.dv8tion.jda.api.entities.Activity Activity} for all shards. * *

This will also change the status for shards that are created in the future. * * @param status * The {@link net.dv8tion.jda.api.OnlineStatus OnlineStatus} * to be used (OFFLINE/null {@literal ->} INVISIBLE) * @param activity * A {@link net.dv8tion.jda.api.entities.Activity Activity} instance or null to reset * * @throws java.lang.IllegalArgumentException * If the provided OnlineStatus is {@link net.dv8tion.jda.api.OnlineStatus#UNKNOWN UNKNOWN} * * @see net.dv8tion.jda.api.entities.Activity#playing(String) * @see net.dv8tion.jda.api.entities.Activity#streaming(String, String) */ default void setPresence(@Nullable final OnlineStatus status, @Nullable final Activity activity) { this.setPresenceProvider(id -> status, id -> activity); } /** * Sets the provider that provides the {@link net.dv8tion.jda.api.OnlineStatus OnlineStatus} and * {@link net.dv8tion.jda.api.entities.Activity Activity} for all shards. * *

This will also change the status for shards that are created in the future. * * @param statusProvider * The {@link net.dv8tion.jda.api.OnlineStatus OnlineStatus} * to be used (OFFLINE/null {@literal ->} INVISIBLE) * @param activityProvider * A {@link net.dv8tion.jda.api.entities.Activity Activity} instance or null to reset * * @throws java.lang.IllegalArgumentException * If the provided OnlineStatus is {@link net.dv8tion.jda.api.OnlineStatus#UNKNOWN UNKNOWN} * * @see net.dv8tion.jda.api.entities.Activity#playing(String) * @see net.dv8tion.jda.api.entities.Activity#streaming(String, String) */ default void setPresenceProvider(@Nullable final IntFunction statusProvider, @Nullable final IntFunction activityProvider) { this.getShardCache().forEach(jda -> jda.getPresence().setPresence(statusProvider == null ? null : statusProvider.apply(jda.getShardInfo().getShardId()), activityProvider == null ? null : activityProvider.apply(jda.getShardInfo().getShardId()))); } /** * Sets the {@link net.dv8tion.jda.api.OnlineStatus OnlineStatus} for all shards. * *

This will also change the status for shards that are created in the future. * * @param status * The {@link net.dv8tion.jda.api.OnlineStatus OnlineStatus} * to be used (OFFLINE/null {@literal ->} INVISIBLE) * * @throws java.lang.IllegalArgumentException * If the provided OnlineStatus is {@link net.dv8tion.jda.api.OnlineStatus#UNKNOWN UNKNOWN} */ default void setStatus(@Nullable final OnlineStatus status) { this.setStatusProvider(id -> status); } /** * Sets the provider that provides the {@link net.dv8tion.jda.api.OnlineStatus OnlineStatus} for all shards. * *

This will also change the provider for shards that are created in the future. * * @param statusProvider * The {@link net.dv8tion.jda.api.OnlineStatus OnlineStatus} * to be used (OFFLINE/null {@literal ->} INVISIBLE) * * @throws java.lang.IllegalArgumentException * If the provided OnlineStatus is {@link net.dv8tion.jda.api.OnlineStatus#UNKNOWN UNKNOWN} */ default void setStatusProvider(@Nullable final IntFunction statusProvider) { this.getShardCache().forEach(jda -> jda.getPresence().setStatus(statusProvider == null ? null : statusProvider.apply(jda.getShardInfo().getShardId()))); } /** * Shuts down all JDA shards, closing all their connections. * After this method has been called the ShardManager instance can not be used anymore. * *
This will shutdown the internal queue worker for (re-)starts of shards. * This means {@link #restart(int)}, {@link #restart()}, and {@link #start(int)} will throw * {@link java.util.concurrent.RejectedExecutionException}. * *

This will interrupt the default JDA event thread, due to the gateway connection being interrupted. */ void shutdown(); /** * Shuts down the shard with the given id only. *
If there is no shard with the given id, this will do nothing. * * @param shardId * The id of the shard that should be stopped */ void shutdown(int shardId); /** * Adds a new shard with the given id to this ShardManager and starts it. * * @param shardId * The id of the shard that should be started * * @throws java.util.concurrent.RejectedExecutionException * If {@link #shutdown()} has already been invoked */ void start(int shardId); /** * Initializes and starts all shards. This should only be called once. * * @throws InvalidTokenException * If the provided token is invalid. */ void login(); }