Search in sources :

Example 1 with ResumeEvent

use of org.javacord.api.event.connection.ResumeEvent in project Javacord by BtoBastian.

the class DiscordWebSocketAdapter method onTextMessage.

@Override
public void onTextMessage(WebSocket websocket, String text) throws Exception {
    ObjectMapper mapper = api.getObjectMapper();
    JsonNode packet = mapper.readTree(text);
    heart.handlePacket(packet);
    int op = packet.get("op").asInt();
    Optional<GatewayOpcode> opcode = GatewayOpcode.fromCode(op);
    if (!opcode.isPresent()) {
        logger.debug("Received unknown packet (op: {}, content: {})", op, packet);
        return;
    }
    switch(opcode.get()) {
        case DISPATCH:
            lastSeq = packet.get("s").asInt();
            String type = packet.get("t").asText();
            PacketHandler handler = handlers.get(type);
            if (handler != null) {
                handler.handlePacket(packet.get("d"));
            } else {
                logger.debug("Received unknown packet of type {} (packet: {})", type, packet);
            }
            if (type.equals("GUILD_MEMBERS_CHUNK")) {
                lastGuildMembersChunkReceived = System.currentTimeMillis();
            }
            if (type.equals("RESUMED")) {
                reconnectingOrResumingLock.lock();
                try {
                    reconnectAttempt.set(0);
                    finishedReconnectingOrResumingCondition.signalAll();
                } finally {
                    reconnectingOrResumingLock.unlock();
                }
                logger.debug("Received RESUMED packet");
                ResumeEvent resumeEvent = new ResumeEventImpl(api);
                api.getEventDispatcher().dispatchResumeEvent(null, resumeEvent);
            }
            if (type.equals("READY")) {
                reconnectingOrResumingLock.lock();
                try {
                    reconnectAttempt.set(0);
                    finishedReconnectingOrResumingCondition.signalAll();
                } finally {
                    reconnectingOrResumingLock.unlock();
                }
                sessionId = packet.get("d").get("session_id").asText();
                // Discord sends us GUILD_CREATE packets after logging in. We will wait for them.
                api.getThreadPool().getSingleThreadExecutorService("Startup Servers Wait Thread").submit(() -> {
                    boolean allUsersLoaded = false;
                    boolean allServersLoaded = false;
                    int lastUnavailableServerAmount = 0;
                    int sameUnavailableServerCounter = 0;
                    while (api.isWaitingForServersOnStartup() && (!allServersLoaded || !allUsersLoaded)) {
                        if (api.getUnavailableServers().size() == lastUnavailableServerAmount) {
                            sameUnavailableServerCounter++;
                        } else {
                            lastUnavailableServerAmount = api.getUnavailableServers().size();
                            sameUnavailableServerCounter = 0;
                        }
                        allServersLoaded = api.getUnavailableServers().isEmpty();
                        if (allServersLoaded) {
                            allUsersLoaded = !api.hasUserCacheEnabled() || !api.isWaitingForUsersOnStartup() || api.getAllServers().stream().map(ServerImpl.class::cast).noneMatch(server -> server.getMemberCount() != server.getRealMembers().size());
                        }
                        if (sameUnavailableServerCounter > 1000 && lastGuildMembersChunkReceived + 5000 < System.currentTimeMillis()) {
                            // itself has some issues. Let's break the loop!
                            break;
                        }
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException ignored) {
                        }
                    }
                    ReconnectEvent reconnectEvent = new ReconnectEventImpl(api);
                    api.getEventDispatcher().dispatchReconnectEvent(null, reconnectEvent);
                    ready.complete(true);
                });
                logger.debug("Received READY packet");
            }
            break;
        case HEARTBEAT:
            heart.beat();
            break;
        case RECONNECT:
            sendCloseFrame(websocket, WebSocketCloseReason.COMMANDED_RECONNECT.getNumericCloseCode(), WebSocketCloseReason.COMMANDED_RECONNECT.getCloseReason());
            break;
        case INVALID_SESSION:
            if (lastSentFrameWasIdentify.isMarked()) {
                logger.info("Hit identifying rate limit. Retrying in 5 seconds...");
            } else {
                // Invalid session :(
                int oneToFiveSeconds = 1000 + (int) (Math.random() * 4000);
                logger.info("Could not resume session. Reconnecting in {}.{} seconds...", () -> oneToFiveSeconds / 1000, () -> oneToFiveSeconds / 100 % 10);
                try {
                    Thread.sleep(oneToFiveSeconds);
                } catch (InterruptedException e) {
                    logger.error("Interrupted while delaying reconnect!");
                    return;
                }
            }
            api.getGatewayIdentifyRatelimiter().requestQuota();
            sendIdentify(websocket);
            break;
        case HELLO:
            logger.debug("Received HELLO packet");
            JsonNode data = packet.get("d");
            int heartbeatInterval = data.get("heartbeat_interval").asInt();
            // calculate reserved places for heartbeats
            webSocketFrameSendingLimit.set(WEB_SOCKET_FRAME_SENDING_RATELIMIT - 1 - (60_000 / heartbeatInterval));
            heart.startBeating(heartbeatInterval);
            if (sessionId == null) {
                sendIdentify(websocket);
            } else {
                sendResume(websocket);
            }
            break;
        case HEARTBEAT_ACK:
            // Handled by the heart
            break;
        default:
            logger.debug("Received unknown packet (op: {}, content: {})", op, packet);
            break;
    }
}
Also used : ReconnectEvent(org.javacord.api.event.connection.ReconnectEvent) JsonNode(com.fasterxml.jackson.databind.JsonNode) ResumeEvent(org.javacord.api.event.connection.ResumeEvent) RestEndpoint(org.javacord.core.util.rest.RestEndpoint) ResumeEventImpl(org.javacord.core.event.connection.ResumeEventImpl) ReconnectEventImpl(org.javacord.core.event.connection.ReconnectEventImpl) ObjectMapper(com.fasterxml.jackson.databind.ObjectMapper)

Aggregations

JsonNode (com.fasterxml.jackson.databind.JsonNode)1 ObjectMapper (com.fasterxml.jackson.databind.ObjectMapper)1 ReconnectEvent (org.javacord.api.event.connection.ReconnectEvent)1 ResumeEvent (org.javacord.api.event.connection.ResumeEvent)1 ReconnectEventImpl (org.javacord.core.event.connection.ReconnectEventImpl)1 ResumeEventImpl (org.javacord.core.event.connection.ResumeEventImpl)1 RestEndpoint (org.javacord.core.util.rest.RestEndpoint)1