Skip to content

Commit

Permalink
Add retrieveMembersByPrefix (#1276)
Browse files Browse the repository at this point in the history
* Add retrieveMemberByPrefix
* Add event pool configuration
* Fix javadoc errors
* Rename chunkSyncQueue -> chunkQueue
  • Loading branch information
MinnDevelopment committed May 5, 2020
1 parent 6ba908c commit da82e2d
Show file tree
Hide file tree
Showing 19 changed files with 595 additions and 170 deletions.
44 changes: 44 additions & 0 deletions src/main/java/net/dv8tion/jda/api/JDABuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ public class JDABuilder
protected boolean shutdownMainWsPool = true;
protected ExecutorService callbackPool = null;
protected boolean shutdownCallbackPool = true;
protected ExecutorService eventPool = null;
protected boolean shutdownEventPool = true;
protected EnumSet<CacheFlag> cacheFlags = EnumSet.allOf(CacheFlag.class);
protected ConcurrentMap<String, String> contextMap = null;
protected SessionController controller = null;
Expand Down Expand Up @@ -1025,6 +1027,47 @@ public JDABuilder setCallbackPool(@Nullable ExecutorService executor, boolean au
return this;
}

/**
* Sets the {@link ExecutorService ExecutorService} that should be used by the
* event proxy to schedule events. This will be done on the calling thread by default.
*
* <p>The executor will not be shutdown automatically when JDA is shutdown.
* To shut it down automatically use {@link #setEventPool(ExecutorService, boolean)}.
*
* @param executor
* The executor for the event proxy, or null to use calling thread
*
* @return The JDABuilder instance. Useful for chaining.
*
* @since 4.2.0
*/
@Nonnull
public JDABuilder setEventPool(@Nullable ExecutorService executor)
{
return setEventPool(executor, executor == null);
}

/**
* Sets the {@link ExecutorService ExecutorService} that should be used by the
* event proxy to schedule events. This will be done on the calling thread by default.
*
* @param executor
* The executor for the event proxy, or null to use calling thread
* @param automaticShutdown
* True, if the executor should be shutdown when JDA shuts down
*
* @return The JDABuilder instance. Useful for chaining.
*
* @since 4.2.0
*/
@Nonnull
public JDABuilder setEventPool(@Nullable ExecutorService executor, boolean automaticShutdown)
{
this.eventPool = executor;
this.shutdownEventPool = automaticShutdown;
return this;
}

/**
* If enabled, JDA will separate the bulk delete event into individual delete events, but this isn't as efficient as
* handling a single event would be. It is recommended that BulkDelete Splitting be disabled and that the developer
Expand Down Expand Up @@ -1710,6 +1753,7 @@ public JDA build() throws LoginException
threadingConfig.setCallbackPool(callbackPool, shutdownCallbackPool);
threadingConfig.setGatewayPool(mainWsPool, shutdownMainWsPool);
threadingConfig.setRateLimitPool(rateLimitPool, shutdownRateLimitPool);
threadingConfig.setEventPool(eventPool, shutdownEventPool);
SessionConfig sessionConfig = new SessionConfig(controller, httpClient, wsFactory, voiceDispatchInterceptor, flags, maxReconnectDelay, largeThreshold);
MetaConfig metaConfig = new MetaConfig(maxBufferSize, contextMap, cacheFlags, flags);

Expand Down
48 changes: 41 additions & 7 deletions src/main/java/net/dv8tion/jda/api/entities/Guild.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import net.dv8tion.jda.api.utils.cache.MemberCacheView;
import net.dv8tion.jda.api.utils.cache.SnowflakeCacheView;
import net.dv8tion.jda.api.utils.cache.SortedSnowflakeCacheView;
import net.dv8tion.jda.api.utils.concurrent.Task;
import net.dv8tion.jda.internal.requests.DeferredRestAction;
import net.dv8tion.jda.internal.requests.Route;
import net.dv8tion.jda.internal.requests.restaction.AuditableRestActionImpl;
Expand All @@ -50,6 +51,7 @@
import javax.annotation.Nullable;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;

/**
* Represents a Discord {@link net.dv8tion.jda.api.entities.Guild Guild}.
Expand Down Expand Up @@ -842,7 +844,7 @@ default List<Member> getMembers()
*
* @return Possibly-empty immutable list of all Members with the same name as the name provided.
*
* @see #retrieveMembersByName(String)
* @see #retrieveMembersByPrefix(String, int)
*/
@Nonnull
default List<Member> getMembersByName(@Nonnull String name, boolean ignoreCase)
Expand All @@ -863,6 +865,8 @@ default List<Member> getMembersByName(@Nonnull String name, boolean ignoreCase)
* Determines if the comparison ignores case when comparing. True - case insensitive.
*
* @return Possibly-empty immutable list of all Members with the same nickname as the nickname provided.
*
* @see #retrieveMembersByPrefix(String, int)
*/
@Nonnull
default List<Member> getMembersByNickname(@Nullable String nickname, boolean ignoreCase)
Expand All @@ -886,6 +890,8 @@ default List<Member> getMembersByNickname(@Nullable String nickname, boolean ign
* If the provided name is null
*
* @return Possibly-empty immutable list of all Members with the same effective name as the name provided.
*
* @see #retrieveMembersByPrefix(String, int)
*/
@Nonnull
default List<Member> getMembersByEffectiveName(@Nonnull String name, boolean ignoreCase)
Expand Down Expand Up @@ -2182,6 +2188,9 @@ default RestAction<Ban> retrieveBan(@Nonnull User bannedUser)
*
* <p>Calling {@link CompletableFuture#cancel(boolean)} will not cancel the chunking process.
*
* <p><b>You MUST NOT use blocking operations such as {@link CompletableFuture#join()} or {@link Future#get()}!</b>
* The response handling happens on the event thread by default.
*
* @return {@link CompletableFuture} representing the chunking task
*
* @see #pruneMemberCache()
Expand Down Expand Up @@ -2469,12 +2478,37 @@ default RestAction<Member> retrieveOwner(boolean update)
return retrieveMemberById(getOwnerIdLong(), update);
}

// TODO: Wait for a "done" payload to be added to the api
// TODO: Without that we cannot make a good UX since we would be required to use a timeout instead.
//
// @Nonnull
// @CheckReturnValue
// CompletableFuture<List<Member>> retrieveMembersByName(@Nonnull String prefix, int limit);
/**
* Queries a list of members using a radix tree based on the provided name prefix.
* <br>This will check both the username and the nickname of the members.
* Additional filtering may be required. If no members with the specified prefix exist, the list will be empty.
*
* <p>The requests automatically timeout after {@code 10} seconds.
* When the timeout occurs a {@link java.util.concurrent.TimeoutException TimeoutException} will be used to complete exceptionally.
*
* <p><b>You MUST NOT use blocking operations such as {@link Task#get()}!</b>
* The response handling happens on the event thread by default.
*
* @param prefix
* The case-insensitive name prefix
* @param limit
* The max amount of members to retrieve (1-100)
*
* @throws IllegalArgumentException
* <ul>
* <li>If the provided prefix is null or empty.</li>
* <li>If the provided limit is not in the range of [1, 100]</li>
* </ul>
*
* @return {@link Task} handle for the request
*
* @see #getMembersByName(String, boolean)
* @see #getMembersByNickname(String, boolean)
* @see #getMembersByEffectiveName(String, boolean)
*/
@Nonnull
@CheckReturnValue
Task<List<Member>> retrieveMembersByPrefix(@Nonnull String prefix, int limit);

/* From GuildController */

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2310,6 +2310,7 @@ default ReactionPaginationAction retrieveReactionUsersById(long messageId, @Nonn
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#UNKNOWN_MESSAGE UNKNOWN_MESSAGE}
* <br>The provided {@code messageId} is unknown in this MessageChannel, either due to the id being invalid, or
* the message it referred to has already been deleted.</li>
* </ul>
*
* @param messageId
* The messageId to retrieve the users from.
Expand Down Expand Up @@ -2360,6 +2361,7 @@ default ReactionPaginationAction retrieveReactionUsersById(@Nonnull String messa
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#UNKNOWN_MESSAGE UNKNOWN_MESSAGE}
* <br>The provided {@code messageId} is unknown in this MessageChannel, either due to the id being invalid, or
* the message it referred to has already been deleted.</li>
* </ul>
*
* @param messageId
* The messageId to retrieve the users from.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -492,12 +492,17 @@ protected JDAImpl buildInstance(final int shardId) throws LoginException, Interr
ExecutorService callbackPool = callbackPair.executor;
boolean shutdownCallbackPool = callbackPair.automaticShutdown;

ExecutorPair<ExecutorService> eventPair = resolveExecutor(threadingConfig.getEventPoolProvider(), shardId);
ExecutorService eventPool = eventPair.executor;
boolean shutdownEventPool = eventPair.automaticShutdown;

AuthorizationConfig authConfig = new AuthorizationConfig(token);
SessionConfig sessionConfig = this.sessionConfig.toSessionConfig(httpClient);
ThreadingConfig threadingConfig = new ThreadingConfig();
threadingConfig.setRateLimitPool(rateLimitPool, shutdownRateLimitPool);
threadingConfig.setGatewayPool(gatewayPool, shutdownGatewayPool);
threadingConfig.setCallbackPool(callbackPool, shutdownCallbackPool);
threadingConfig.setEventPool(eventPool, shutdownEventPool);
MetaConfig metaConfig = new MetaConfig(this.metaConfig.getMaxBufferSize(), this.metaConfig.getContextMap(shardId), this.metaConfig.getCacheFlags(), this.sessionConfig.getFlags());
final JDAImpl jda = new JDAImpl(authConfig, sessionConfig, threadingConfig, metaConfig);
jda.setMemberCachePolicy(shardingConfig.getMemberCachePolicy());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ public class DefaultShardManagerBuilder
protected ThreadPoolProvider<? extends ScheduledExecutorService> rateLimitPoolProvider = null;
protected ThreadPoolProvider<? extends ScheduledExecutorService> gatewayPoolProvider = null;
protected ThreadPoolProvider<? extends ExecutorService> callbackPoolProvider = null;
protected ThreadPoolProvider<? extends ExecutorService> eventPoolProvider = null;
protected Collection<Integer> shards = null;
protected OkHttpClient.Builder httpClientBuilder = null;
protected OkHttpClient httpClient = null;
Expand Down Expand Up @@ -1485,6 +1486,70 @@ public DefaultShardManagerBuilder setCallbackPoolProvider(@Nullable ThreadPoolPr
return this;
}

/**
* Sets the {@link ExecutorService ExecutorService} that should be used by the
* event proxy to schedule events. This will be done on the calling thread by default.
*
* <p>The executor will not be shutdown automatically when the shard is shutdown.
* To shut it down automatically use {@link #setEventPool(ExecutorService, boolean)}.
*
* @param executor
* The executor for the event proxy, or null to use calling thread
*
* @return The DefaultShardManagerBuilder instance. Useful for chaining.
*
* @since 4.2.0
*/
@Nonnull
public DefaultShardManagerBuilder setEventPool(@Nullable ExecutorService executor)
{
return setEventPool(executor, executor == null);
}

/**
* Sets the {@link ExecutorService ExecutorService} that should be used by the
* event proxy to schedule events. This will be done on the calling thread by default.
*
* @param executor
* The executor for the event proxy, or null to use calling thread
* @param automaticShutdown
* True, if the executor should be shutdown when JDA shuts down
*
* @return The DefaultShardManagerBuilder instance. Useful for chaining.
*
* @since 4.2.0
*/
@Nonnull
public DefaultShardManagerBuilder setEventPool(@Nullable ExecutorService executor, boolean automaticShutdown)
{
return setEventPoolProvider(executor == null ? null : new ThreadPoolProviderImpl<>(executor, automaticShutdown));
}

/**
* Sets the {@link ExecutorService ExecutorService} that should be used in
* the JDA callback handler which mostly consists of {@link net.dv8tion.jda.api.requests.RestAction RestAction} callbacks.
* By default JDA will use {@link ForkJoinPool#commonPool()}
* <br><b>Only change this pool if you know what you're doing.</b>
*
* <p>This is used to handle callbacks of {@link RestAction#queue()}, similarly it is used to
* finish {@link RestAction#submit()} and {@link RestAction#complete()} tasks which build on queue.
*
* <p>Default: {@link ForkJoinPool#commonPool()}
*
* @param provider
* The thread-pool provider to use for callback handling
*
* @return The DefaultShardManagerBuilder instance. Useful for chaining.
*
* @since 4.2.0
*/
@Nonnull
public DefaultShardManagerBuilder setEventPoolProvider(@Nullable ThreadPoolProvider<? extends ExecutorService> provider)
{
this.eventPoolProvider = provider;
return this;
}

/**
* Sets the maximum amount of time that JDA will back off to wait when attempting to reconnect the MainWebsocket.
* <br>Provided value must be 32 or greater.
Expand Down Expand Up @@ -2066,7 +2131,7 @@ public ShardManager build() throws LoginException, IllegalArgumentException
presenceConfig.setActivityProvider(activityProvider);
presenceConfig.setStatusProvider(statusProvider);
presenceConfig.setIdleProvider(idleProvider);
final ThreadingProviderConfig threadingConfig = new ThreadingProviderConfig(rateLimitPoolProvider, gatewayPoolProvider, callbackPoolProvider, threadFactory);
final ThreadingProviderConfig threadingConfig = new ThreadingProviderConfig(rateLimitPoolProvider, gatewayPoolProvider, callbackPoolProvider, eventPoolProvider, threadFactory);
final ShardingSessionConfig sessionConfig = new ShardingSessionConfig(sessionController, voiceDispatchInterceptor, httpClient, httpClientBuilder, wsFactory, audioSendFactory, flags, shardingFlags, maxReconnectDelay, largeThreshold);
final ShardingMetaConfig metaConfig = new ShardingMetaConfig(maxBufferSize, contextProvider, cacheFlags, flags, compression);
final DefaultShardManager manager = new DefaultShardManager(this.token, this.shards, shardingConfig, eventConfig, presenceConfig, threadingConfig, sessionConfig, metaConfig, chunkingFilter);
Expand Down
89 changes: 89 additions & 0 deletions src/main/java/net/dv8tion/jda/api/utils/concurrent/Task.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* Copyright 2015-2020 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.utils.concurrent;

import javax.annotation.Nonnull;
import java.util.function.Consumer;

/**
* Represents an asynchronous task.
* <br>Note: The underlying task may already be started.
*
* @param <T>
* The result type
*/
public interface Task<T>
{
/**
* Whether this task has started.
*
* @return True, if this task has already started.
*/
boolean isStarted();

/**
* Provide a callback for exception handling.
* <br>This is an asynchronous operation.
*
* <p>The error will be logged regardless of your callback, this only exists to handle
* failures for other purposes.
*
* @param callback
* The error callback
*
* @throws IllegalArgumentException
* If null is provided
*
* @return The current Task instance for chaining
*/
Task<T> onError(@Nonnull Consumer<? super Throwable> callback);

/**
* Provide a callback for success handling.
* <br>This is an asynchronous operation.
*
* @param callback
* The success callback
*
* @throws IllegalArgumentException
* If null is provided
*
* @return The current Task instance for chaining
*/
Task<T> onSuccess(@Nonnull Consumer<? super T> callback);

/**
* Blocks the current thread until the result is ready.
* <br>This will not work on the default JDA event thread because it might depend on other events to be processed,
* which could lead to a deadlock.
*
* @throws UnsupportedOperationException
* If this is called on the default JDA event thread
* @throws java.util.concurrent.CompletionException
* If some exception occurred (such as {@link java.util.concurrent.TimeoutException}).
* @throws java.util.concurrent.CancellationException
* If the request was cancelled
*
* @return The result value
*/
T get();

/**
* Cancels the task and will emit a {@link java.util.concurrent.CancellationException CancellationException}.
*/
void cancel();
}
Loading

0 comments on commit da82e2d

Please sign in to comment.