Skip to content

Commit

Permalink
Experimental Session Checkpointing
Browse files Browse the repository at this point in the history
  • Loading branch information
MrPowerGamerBR committed Oct 5, 2024
1 parent d3eaf94 commit 4235406
Show file tree
Hide file tree
Showing 7 changed files with 840 additions and 5 deletions.
646 changes: 646 additions & 0 deletions src/examples/java/SessionCheckpointAndGatewayResumeExample.kt

Large diffs are not rendered by default.

28 changes: 28 additions & 0 deletions src/main/java/net/dv8tion/jda/api/JDA.java
Original file line number Diff line number Diff line change
Expand Up @@ -1952,6 +1952,20 @@ default RestAction<ApplicationEmoji> retrieveApplicationEmojiById(long emojiId)
*/
void shutdown();

/**
* Shuts down this JDA instance, closing all its connections.
* After this command is issued the JDA Instance can not be used anymore.
* Already enqueued {@link net.dv8tion.jda.api.requests.RestAction RestActions} are still going to be executed.
*
* <p>If you want this instance to shutdown without executing, use {@link #shutdownNow() shutdownNow()}
*
* <p>This will interrupt the default JDA event thread, due to the gateway connection being interrupted.
*
* @param closeCode the WebSocket close code that will be used when closing the connection, depending on the close code used, the gateway session may still be available for resume
* @see #shutdownNow()
*/
void shutdown(int closeCode);

/**
* Shuts down this JDA instance instantly, closing all its connections.
* After this command is issued the JDA Instance can not be used anymore.
Expand All @@ -1965,6 +1979,20 @@ default RestAction<ApplicationEmoji> retrieveApplicationEmojiById(long emojiId)
*/
void shutdownNow();

/**
* Shuts down this JDA instance instantly, closing all its connections.
* After this command is issued the JDA Instance can not be used anymore.
* This will also cancel all queued {@link net.dv8tion.jda.api.requests.RestAction RestActions}.
*
* <p>If you want this instance to shutdown without cancelling enqueued RestActions use {@link #shutdown() shutdown()}
*
* <p>This will interrupt the default JDA event thread, due to the gateway connection being interrupted.
*
* @param closeCode the WebSocket close code that will be used when closing the connection, depending on the close code used, such as code 1012, the gateway session may still be available for resume
* @see #shutdown()
*/
void shutdownNow(int closeCode);

///**
// * Installs an auxiliary cable into the given port of your system.
// *
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/net/dv8tion/jda/api/entities/sticker/Sticker.java
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,16 @@ enum StickerFormat
this.extension = extension;
}

/**
* The raw key used to identify types within the api.
*
* @return Raw id for this StickerFormat
*/
public int getId()
{
return id;
}

/**
* The file extension used for the sticker asset.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* 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.events;

import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.utils.data.DataObject;

import javax.annotation.Nonnull;

/**
* Wrapper for the raw event received from discord.
* <br>This provides the raw structure of a gateway event through a {@link DataObject}
* instance containing:
* <ul>
* <li>d: The payload of the package (DataObject)</li>
* <li>t: The type of the package (String)</li>
* <li>op: The opcode of the package, always 0 for dispatch (int)</li>
* <li>s: The sequence number, equivalent to {@link #getResponseNumber()} (long)</li>
* </ul>
*
* <p>Sent after derived events. This is disabled by default and can be enabled through either
* the {@link net.dv8tion.jda.api.JDABuilder#setRawEventsEnabled(boolean) JDABuilder}
* or {@link net.dv8tion.jda.api.sharding.DefaultShardManagerBuilder#setRawEventsEnabled(boolean) DefaultShardManagerBuilder}.
*
* @see net.dv8tion.jda.api.JDABuilder#setRawEventsEnabled(boolean) JDABuilder.setRawEventsEnabled(boolean)
* @see net.dv8tion.jda.api.sharding.DefaultShardManagerBuilder#setRawEventsEnabled(boolean) DefaultShardManagerBuilder.setRawEventsEnabled(boolean)
* @see <a href="https://discord.com/developers/docs/topics/gateway" target="_blank">Gateway Documentation</a>
*/
public class PreProcessedRawGatewayEvent extends Event
{
private final DataObject data;
private boolean isCancelled = false;

public PreProcessedRawGatewayEvent(@Nonnull JDA api, long responseNumber, @Nonnull DataObject data)
{
super(api, responseNumber);
this.data = data;
}

/**
* The raw gateway package including sequence and type.
*
* <ul>
* <li>d: The payload of the package (DataObject)</li>
* <li>t: The type of the package (String)</li>
* <li>op: The opcode of the package, always 0 for dispatch (int)</li>
* <li>s: The sequence number, equivalent to {@link #getResponseNumber()} (long)</li>
* </ul>
*
* @return The data object
*/
@Nonnull
public DataObject getPackage()
{
return data;
}

/**
* The payload of the package.
*
* @return The payload as a {@link DataObject} instance
*/
@Nonnull
public DataObject getPayload()
{
return data.getObject("d");
}

/**
* The type of event.
*
* @return The type of event.
*/
@Nonnull
public String getType()
{
return data.getString("t");
}

public void setCancelled(boolean cancelled)
{
isCancelled = cancelled;
}

public boolean isCancelled()
{
return isCancelled;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ public abstract class ListenerAdapter implements EventListener
public void onGenericEvent(@Nonnull GenericEvent event) {}
public void onGenericUpdate(@Nonnull UpdateEvent<?, ?> event) {}
public void onRawGateway(@Nonnull RawGatewayEvent event) {}
public void onPreProcessedRawGateway(@Nonnull PreProcessedRawGatewayEvent event) {}
public void onGatewayPing(@Nonnull GatewayPingEvent event) {}

//Session Events
Expand Down
16 changes: 14 additions & 2 deletions src/main/java/net/dv8tion/jda/internal/JDAImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -914,14 +914,26 @@ public SelfUser getSelfUser()

@Override
public synchronized void shutdownNow()
{
shutdownNow(1000);
}

@Override
public synchronized void shutdownNow(int closeCode)
{
requester.stop(true, this::shutdownRequester); // stop all requests
shutdown();
shutdown(closeCode);
threadConfig.shutdownNow();
}

@Override
public synchronized void shutdown()
{
shutdown(1000);
}

@Override
public synchronized void shutdown(int closeCode)
{
Status status = getStatus();
if (status == Status.SHUTDOWN || status == Status.SHUTTING_DOWN)
Expand All @@ -933,7 +945,7 @@ public synchronized void shutdown()
if (client != null)
{
client.getChunkManager().shutdown();
client.shutdown();
client.shutdown(closeCode);
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.channel.middleman.AudioChannel;
import net.dv8tion.jda.api.events.ExceptionEvent;
import net.dv8tion.jda.api.events.PreProcessedRawGatewayEvent;
import net.dv8tion.jda.api.events.RawGatewayEvent;
import net.dv8tion.jda.api.events.session.*;
import net.dv8tion.jda.api.exceptions.ParsingException;
Expand Down Expand Up @@ -57,6 +58,7 @@
import org.slf4j.MDC;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.ref.SoftReference;
Expand Down Expand Up @@ -186,6 +188,25 @@ public MemberChunkManager getChunkManager()
return chunkManager;
}

public void setSessionId(String sessionId) {
this.sessionId = sessionId;
}

@Nullable
public String getSessionId() {
return sessionId;
}

public void setResumeUrl(String resumeUrl) {
this.resumeUrl = resumeUrl;
}

@Nullable
public String getResumeUrl() {
return resumeUrl;
}


public void ready()
{
if (initiating)
Expand Down Expand Up @@ -336,6 +357,10 @@ public void close(int code, String reason)

public void shutdown()
{
shutdown(1000);
}

public synchronized void shutdown(int closeCode) {
boolean callOnShutdown = MiscUtil.locked(reconnectLock, () -> {
if (shutdown)
return false;
Expand All @@ -344,13 +369,13 @@ public void shutdown()
if (connectNode != null)
api.getSessionController().removeSession(connectNode);
boolean wasConnected = connected;
close(1000, "Shutting down");
close(closeCode, "Shutting down");
reconnectCondvar.signalAll(); // signal reconnect attempts to stop
return !wasConnected;
});

if (callOnShutdown)
onShutdown(1000);
onShutdown(closeCode);
}


Expand Down Expand Up @@ -863,7 +888,7 @@ protected List<DataObject> convertPresencesReplace(long responseTotal, DataArray
return output;
}

protected void handleEvent(DataObject content)
public void handleEvent(DataObject content)
{
try
{
Expand All @@ -879,6 +904,14 @@ protected void handleEvent(DataObject content)
protected void onEvent(DataObject content)
{
WS_THREAD.set(true);
if (api.isRawEvents())
{
PreProcessedRawGatewayEvent event = new PreProcessedRawGatewayEvent(api, api.getResponseTotal(), content);
api.handleEvent(event);
if (event.isCancelled())
return;
}

int opCode = content.getInt("op");

if (!content.isNull("s"))
Expand Down Expand Up @@ -973,6 +1006,8 @@ protected void onDispatch(DataObject raw)
api.setStatus(JDA.Status.LOADING_SUBSYSTEMS);
processingReady = true;
handleIdentifyRateLimit = false;
// Required to avoid the WebSocketSendingThread stalling forever when sending a fake READY request
sentAuthInfo = true;
// first handle the ready payload before applying the session id
// this prevents a possible race condition with the cache of the guild setup controller
// otherwise the audio connection requests that are currently pending might be removed in the process
Expand Down

0 comments on commit 4235406

Please sign in to comment.