use of net.dv8tion.jda.internal.JDAImpl in project JDA by DV8FromTheWorld.
the class AudioWebSocket method handleCallbackError.
@Override
public void handleCallbackError(WebSocket websocket, Throwable cause) {
LOG.error("There was some audio websocket error", cause);
JDAImpl api = getJDA();
api.handleEvent(new ExceptionEvent(api, cause, true));
}
use of net.dv8tion.jda.internal.JDAImpl in project JDA by DV8FromTheWorld.
the class DefaultShardManager method buildInstance.
protected JDAImpl buildInstance(final int shardId) throws LoginException {
OkHttpClient httpClient = sessionConfig.getHttpClient();
if (httpClient == null) {
// httpClient == null implies we have a builder
// noinspection ConstantConditions
httpClient = sessionConfig.getHttpBuilder().build();
}
// imagine if we had macros or closures or destructuring :)
ExecutorPair<ScheduledExecutorService> rateLimitPair = resolveExecutor(threadingConfig.getRateLimitPoolProvider(), shardId);
ScheduledExecutorService rateLimitPool = rateLimitPair.executor;
boolean shutdownRateLimitPool = rateLimitPair.automaticShutdown;
ExecutorPair<ScheduledExecutorService> gatewayPair = resolveExecutor(threadingConfig.getGatewayPoolProvider(), shardId);
ScheduledExecutorService gatewayPool = gatewayPair.executor;
boolean shutdownGatewayPool = gatewayPair.automaticShutdown;
ExecutorPair<ExecutorService> callbackPair = resolveExecutor(threadingConfig.getCallbackPoolProvider(), shardId);
ExecutorService callbackPool = callbackPair.executor;
boolean shutdownCallbackPool = callbackPair.automaticShutdown;
ExecutorPair<ExecutorService> eventPair = resolveExecutor(threadingConfig.getEventPoolProvider(), shardId);
ExecutorService eventPool = eventPair.executor;
boolean shutdownEventPool = eventPair.automaticShutdown;
ExecutorPair<ScheduledExecutorService> audioPair = resolveExecutor(threadingConfig.getAudioPoolProvider(), shardId);
ScheduledExecutorService audioPool = audioPair.executor;
boolean shutdownAudioPool = audioPair.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);
threadingConfig.setAudioPool(audioPool, shutdownAudioPool);
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());
threadingConfig.init(jda::getIdentifierString);
// We can only do member chunking with the GUILD_MEMBERS intent
if ((shardingConfig.getIntents() & GatewayIntent.GUILD_MEMBERS.getRawValue()) == 0)
jda.setChunkingFilter(ChunkingFilter.NONE);
else
jda.setChunkingFilter(chunkingFilter);
jda.setShardManager(this);
if (eventConfig.getEventManagerProvider() != null)
jda.setEventManager(this.eventConfig.getEventManagerProvider().apply(shardId));
if (this.sessionConfig.getAudioSendFactory() != null)
jda.setAudioSendFactory(this.sessionConfig.getAudioSendFactory());
this.eventConfig.getListeners().forEach(jda::addEventListener);
this.eventConfig.getListenerProviders().forEach(provider -> jda.addEventListener(provider.apply(shardId)));
// Set the presence information before connecting to have the correct information ready when sending IDENTIFY
PresenceImpl presence = ((PresenceImpl) jda.getPresence());
if (presenceConfig.getActivityProvider() != null)
presence.setCacheActivity(presenceConfig.getActivityProvider().apply(shardId));
if (presenceConfig.getIdleProvider() != null)
presence.setCacheIdle(presenceConfig.getIdleProvider().apply(shardId));
if (presenceConfig.getStatusProvider() != null)
presence.setCacheStatus(presenceConfig.getStatusProvider().apply(shardId));
if (this.gatewayURL == null) {
try {
SessionController.ShardedGateway gateway = jda.getShardedGateway();
this.sessionConfig.getSessionController().setConcurrency(gateway.getConcurrency());
this.gatewayURL = gateway.getUrl();
if (this.gatewayURL == null)
LOG.error("Acquired null gateway url from SessionController");
else
LOG.info("Login Successful!");
if (getShardsTotal() == -1) {
shardingConfig.setShardsTotal(gateway.getShardTotal());
this.shards = new ShardCacheViewImpl(getShardsTotal());
synchronized (queue) {
for (int i = 0; i < getShardsTotal(); i++) queue.add(i);
}
}
} catch (CompletionException e) {
if (e.getCause() instanceof LoginException)
// complete() can't throw this because its a checked-exception so we have to unwrap it first
throw (LoginException) e.getCause();
throw e;
}
}
final JDA.ShardInfo shardInfo = new JDA.ShardInfo(shardId, getShardsTotal());
// Initialize SelfUser instance before logging in
SelfUser selfUser = getShardCache().applyStream(s -> // this should never throw!
s.map(JDA::getSelfUser).findFirst().orElse(null));
// Copy from other JDA instance or do initial fetch
if (selfUser == null)
selfUser = retrieveSelfUser(jda);
else
selfUser = SelfUserImpl.copyOf((SelfUserImpl) selfUser, jda);
jda.setSelfUser(selfUser);
// This is already set by JDA internally, but this is to make sure the listeners catch it.
jda.setStatus(JDA.Status.INITIALIZED);
final int shardTotal = jda.login(this.gatewayURL, shardInfo, this.metaConfig.getCompression(), false, shardingConfig.getIntents(), this.metaConfig.getEncoding());
if (getShardsTotal() == -1)
shardingConfig.setShardsTotal(shardTotal);
return jda;
}
use of net.dv8tion.jda.internal.JDAImpl in project JDA by DV8FromTheWorld.
the class DefaultShardManager method login.
@Override
public void login() throws LoginException {
// building the first one in the current thread ensures that LoginException and IllegalArgumentException can be thrown on login
JDAImpl jda = null;
try {
final int shardId = this.queue.isEmpty() ? 0 : this.queue.peek();
jda = this.buildInstance(shardId);
try (UnlockHook hook = this.shards.writeLock()) {
this.shards.getMap().put(shardId, jda);
}
synchronized (queue) {
this.queue.remove(shardId);
}
} catch (final Exception e) {
if (jda != null) {
if (shardingConfig.isUseShutdownNow())
jda.shutdownNow();
else
jda.shutdown();
}
throw e;
}
runQueueWorker();
if (this.shutdownHook != null)
Runtime.getRuntime().addShutdownHook(this.shutdownHook);
}
use of net.dv8tion.jda.internal.JDAImpl in project JDA by DV8FromTheWorld.
the class ShardManager method retrieveUserById.
/**
* Attempts to retrieve a {@link net.dv8tion.jda.api.entities.User User} object based on the provided id.
* <br>This first calls {@link #getUserById(long)}, and if the return is {@code null} then a request
* is made to the Discord servers.
*
* <p>The returned {@link net.dv8tion.jda.api.requests.RestAction RestAction} can encounter the following Discord errors:
* <ul>
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#UNKNOWN_USER ErrorResponse.UNKNOWN_USER}
* <br>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).</li>
* </ul>
*
* @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}
* <br>On request, gets the User with id matching provided id from Discord.
*/
@Nonnull
@CheckReturnValue
default RestAction<User> retrieveUserById(long id) {
JDA api = null;
for (JDA shard : getShardCache()) {
api = shard;
EnumSet<GatewayIntent> 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()));
}
use of net.dv8tion.jda.internal.JDAImpl in project JDA by DV8FromTheWorld.
the class AudioConnection method setupReceiveThread.
private synchronized void setupReceiveThread() {
if (receiveThread == null) {
receiveThread = new Thread(() -> {
getJDA().setContext();
try {
udpSocket.setSoTimeout(1000);
} catch (SocketException e) {
LOG.error("Couldn't set SO_TIMEOUT for UDP socket", e);
}
while (!udpSocket.isClosed() && !Thread.currentThread().isInterrupted()) {
DatagramPacket receivedPacket = new DatagramPacket(new byte[1920], 1920);
try {
udpSocket.receive(receivedPacket);
boolean shouldDecode = receiveHandler != null && (receiveHandler.canReceiveUser() || receiveHandler.canReceiveCombined());
boolean canReceive = receiveHandler != null && (receiveHandler.canReceiveUser() || receiveHandler.canReceiveCombined() || receiveHandler.canReceiveEncoded());
if (canReceive && webSocket.getSecretKey() != null) {
if (!couldReceive) {
couldReceive = true;
sendSilentPackets();
}
AudioPacket decryptedPacket = AudioPacket.decryptAudioPacket(webSocket.encryption, receivedPacket, webSocket.getSecretKey());
if (decryptedPacket == null)
continue;
int ssrc = decryptedPacket.getSSRC();
final long userId = ssrcMap.get(ssrc);
Decoder decoder = opusDecoders.get(ssrc);
if (userId == ssrcMap.getNoEntryValue()) {
ByteBuffer audio = decryptedPacket.getEncodedAudio();
// and as such, we haven't yet received information to pair the SSRC with the UserId.
if (!audio.equals(silenceBytes))
LOG.debug("Received audio data with an unknown SSRC id. Ignoring");
continue;
}
if (decoder == null) {
if (AudioNatives.ensureOpus()) {
opusDecoders.put(ssrc, decoder = new Decoder(ssrc));
} else if (!receiveHandler.canReceiveEncoded()) {
LOG.error("Unable to decode audio due to missing opus binaries!");
break;
}
}
OpusPacket opusPacket = new OpusPacket(decryptedPacket, userId, decoder);
if (receiveHandler.canReceiveEncoded())
receiveHandler.handleEncodedAudio(opusPacket);
if (!shouldDecode || !opusPacket.canDecode())
continue;
User user = getJDA().getUserById(userId);
if (user == null) {
LOG.warn("Received audio data with a known SSRC, but the userId associate with the SSRC is unknown to JDA!");
continue;
}
short[] decodedAudio = opusPacket.decode();
// If decodedAudio is null, then the Opus decode failed, so throw away the packet.
if (decodedAudio == null) {
// decoder error logged in method
continue;
}
if (receiveHandler.canReceiveUser()) {
receiveHandler.handleUserAudio(new UserAudio(user, decodedAudio));
}
if (receiveHandler.canReceiveCombined() && receiveHandler.includeUserInCombinedAudio(user)) {
Queue<AudioData> queue = combinedQueue.get(user);
if (queue == null) {
queue = new ConcurrentLinkedQueue<>();
combinedQueue.put(user, queue);
}
queue.add(new AudioData(decodedAudio));
}
} else if (couldReceive) {
couldReceive = false;
sendSilentPackets();
}
} catch (SocketTimeoutException e) {
// Ignore. We set a low timeout so that we wont block forever so we can properly shutdown the loop.
} catch (SocketException e) {
// The socket was closed while we were listening for the next packet.
// This is expected. Ignore the exception. The thread will exit during the next while
// iteration because the udpSocket.isClosed() will return true.
} catch (Exception e) {
LOG.error("There was some random exception while waiting for udp packets", e);
}
}
});
receiveThread.setUncaughtExceptionHandler((thread, throwable) -> {
LOG.error("There was some uncaught exception in the audio receive thread", throwable);
JDAImpl api = getJDA();
api.handleEvent(new ExceptionEvent(api, throwable, true));
});
receiveThread.setDaemon(true);
receiveThread.setName(threadIdentifier + " Receiving Thread");
receiveThread.start();
}
if (receiveHandler.canReceiveCombined()) {
setupCombinedExecutor();
}
}
Aggregations