941 lines
34 KiB
TypeScript
941 lines
34 KiB
TypeScript
// Metro module 12692 (f12693).
|
|
import _slicedToArray from "../../_bundle/_slicedToArray";
|
|
import DeveloperOptionsStore from "../../stores/DeveloperOptionsStore";
|
|
import { Endpoints, AnalyticEvents } from "../../Constants";
|
|
import Logger from "../debug/Logger";
|
|
import GatewayEncoding from "./GatewayEncoding";
|
|
import createWebSocket_android from "./createWebSocket.android";
|
|
import Durations from "../../utils/Durations";
|
|
import GatewaySocketOpCodes, { Opcode } from "./GatewaySocketOpCodes";
|
|
import Backoff from "../../_bundle/Backoff";
|
|
import AltGatewayTracker from "./AltGatewayTracker";
|
|
import GatewaySocketDispatcher from "./GatewaySocketDispatcher";
|
|
import ConnectionState from "./ConnectionState";
|
|
import { getCompressionHandler } from "./GatewayCompressionHandler";
|
|
import { getIsPaused } from "./PauseGatewaySocket";
|
|
import Module10 from "../../_bundle/Module10";
|
|
import TTITracker from "../tti_analytics/TTITracker";
|
|
import CrossPlatformNativeUtils_native from "../../utils/CrossPlatformNativeUtils.native";
|
|
import { getConnectionPath, logGatewayConnected, createResumeAnalytics } from "./GatewaySocketAnalytics";
|
|
import { isIOS } from "../../utils/PlatformUtils";
|
|
import { HTTP } from "../../_bundle/sendRequest";
|
|
import AnalyticsUtils from "../../utils/AnalyticsUtils";
|
|
import Module38 from "../../_bundle/Module38";
|
|
import Module589 from "../../_bundle/Module589";
|
|
import { isCacheEnabled } from "../cache/isCacheEnabled.native";
|
|
import GuildVersions from "../app_database/modules/GuildVersions";
|
|
import NonGuildVersions from "../app_database/modules/NonGuildVersions";
|
|
import KvCacheVersion from "../app_database/modules/KvCacheVersion";
|
|
import { getClientCapabilities } from "./GatewayCapabilities";
|
|
import { isChannelMetadataObfuscationEnabled } from "./PrivateChannelHidingExperiment";
|
|
import { deflate } from "../../_bundle/Module12711";
|
|
import { usesClientMods } from "../../_bundle/Module667";
|
|
import MonitoringAgent from "../monitoring/MonitoringAgent";
|
|
import { MetricEvents } from "../../_bundle/Module5872";
|
|
import SentryUtils_native from "../../utils/SentryUtils.native";
|
|
import Dispatcher from "../../Dispatcher";
|
|
let byteSize, c8746_9, c8746_10, c8746_13, c8746_14, c8746_15, c8746_16, GATEWAY_ENDPOINT, c8746_19;
|
|
let env8746 = {};
|
|
const noop = function noop() {};
|
|
byteSize = function byteSize(a0) {
|
|
return a0 == null ? 0 : typeof a0 === "string" ? a0.length : a0.byteLength;
|
|
};
|
|
c8746_9 = new Logger("GatewaySocket");
|
|
c8746_10 = new GatewayEncoding();
|
|
env8746[11] = null;
|
|
c8746_13 = 4004;
|
|
c8746_14 = 30 * Durations.Millis.SECOND;
|
|
c8746_15 = 3 * Durations.Millis.MINUTE;
|
|
c8746_16 = 1 * Durations.Millis.MINUTE;
|
|
GATEWAY_ENDPOINT = window.GLOBAL_ENV.GATEWAY_ENDPOINT;
|
|
class GatewaySocket extends GatewaySocketOpCodes {
|
|
dispatchExceptionBackoff = new Backoff(1000, c8746_16);
|
|
dispatchSuccessTimer = 0;
|
|
didForceClearGuildHashes = false;
|
|
identifyUncompressedByteSize = 0;
|
|
identifyCompressedByteSize = 0;
|
|
analytics = {};
|
|
identifyCount = 0;
|
|
resumeUrl = null;
|
|
iosGoingAwayEventCount = 0;
|
|
altGateway = new AltGatewayTracker();
|
|
failedConnectAttempts = 0;
|
|
receivedHelloThisAttempt = false;
|
|
heartbeatQOSState = {
|
|
currentPayload: null,
|
|
upcomingState: null
|
|
};
|
|
send = (a0, a1, a2) => {
|
|
if (DeveloperOptionsStore.isLoggingGatewayEvents) {
|
|
c8746_9.verboseDangerously("~>", a0, Opcode[a0], a1);
|
|
}
|
|
const r24 = c8746_10.pack({
|
|
op: a0,
|
|
d: a1
|
|
});
|
|
if (a2 && !this.isSessionEstablished()) {
|
|
c8746_9.warn(`Attempted to send while not being in a connected state opcode: ${a0}`);
|
|
} else {
|
|
try {
|
|
if (this.webSocket != null) {
|
|
this.webSocket.send(r24);
|
|
}
|
|
} catch ($e) {}
|
|
}
|
|
};
|
|
dispatcher = new GatewaySocketDispatcher(this);
|
|
gatewayBackoff = new Backoff(1000, 60000);
|
|
connectionState_ = ConnectionState.CLOSED;
|
|
webSocket = null;
|
|
seq = 0;
|
|
sessionId = null;
|
|
token = null;
|
|
initialHeartbeatTimeout = null;
|
|
expeditedHeartbeatTimeout = null;
|
|
lastHeartbeatTime = null;
|
|
lastHeartbeatAckTime = null;
|
|
helloTimeout = null;
|
|
heartbeatInterval = null;
|
|
heartbeater = null;
|
|
heartbeatAck = true;
|
|
connectionStartTime = 0;
|
|
firstConnectAttemptStartTime = 0;
|
|
identifyStartTime = 0;
|
|
nextReconnectIsImmediate = false;
|
|
compressionHandler = getCompressionHandler(c8746_10);
|
|
hasConnectedOnce = false;
|
|
isFastConnect = false;
|
|
constructor() {
|
|
super();
|
|
this.identifyCount = 0;
|
|
this.iosGoingAwayEventCount = 0;
|
|
this.failedConnectAttempts = 0;
|
|
this.receivedHelloThisAttempt = false;
|
|
}
|
|
get connectionState() {
|
|
return this.connectionState_;
|
|
}
|
|
set connectionState(a0) {
|
|
c8746_9.verbose(`Setting connection state to ${a0}`);
|
|
this.connectionState_ = a0;
|
|
}
|
|
addAnalytics(a0) {
|
|
this.analytics = {
|
|
...this.analytics,
|
|
...a0
|
|
};
|
|
}
|
|
setResumeUrl(a0) {
|
|
const resumeUrl = a0 != null && a0.endsWith("/") ? a0.substring(0, a0.length - 1) : a0;
|
|
if (resumeUrl !== null) {
|
|
c8746_9.verbose(`Updating resume url to ${resumeUrl}`);
|
|
}
|
|
this.resumeUrl = resumeUrl;
|
|
}
|
|
handleActiveStateChange(a0) {
|
|
const active = this.heartbeatQOSState.currentPayload?.active;
|
|
let r7 = !active;
|
|
if (this.heartbeatQOSState.currentPayload == null) {
|
|
this.heartbeatQOSState.currentPayload = a0;
|
|
}
|
|
const currentPayload = this.heartbeatQOSState.currentPayload;
|
|
if (a0.active) {
|
|
currentPayload.active = true;
|
|
currentPayload.reasons = [...new Set([...currentPayload.reasons, ...a0.reasons])].sort();
|
|
if (!active) {
|
|
r7 = this.isSessionEstablished();
|
|
}
|
|
if (r7) {
|
|
this._sendHeartbeat();
|
|
}
|
|
}
|
|
this.heartbeatQOSState.upcomingState = a0;
|
|
}
|
|
handleUpdateTimeSpentSessionId(a0, a1, a2) {
|
|
if (this.connectionState_ === ConnectionState.SESSION_ESTABLISHED) {
|
|
this.send(Opcode.UPDATE_TIME_SPENT_SESSION_ID, {
|
|
initialization_timestamp: a0,
|
|
session_id: a1,
|
|
client_launch_id: a2
|
|
});
|
|
this._sendHeartbeat();
|
|
}
|
|
}
|
|
_connect() {
|
|
let env19967 = {
|
|
$parent: env8746
|
|
};
|
|
env19967[1] = this;
|
|
if (this.willReconnect()) {
|
|
if (getIsPaused()) {
|
|
c8746_9.info("Skipping _connect because socket is paused");
|
|
} else {
|
|
this.connectionState = ConnectionState.CONNECTING;
|
|
this.nextReconnectIsImmediate = false;
|
|
const algorithm = this.compressionHandler.getAlgorithm();
|
|
const name = c8746_10.getName();
|
|
const r12 = this._getGatewayUrl();
|
|
const API_VERSION = window.GLOBAL_ENV.API_VERSION;
|
|
this.receivedHelloThisAttempt = false;
|
|
Module10.mark("🌐", "Socket._connect");
|
|
let r24 = algorithm;
|
|
if (r24 == null) {
|
|
r24 = "none";
|
|
}
|
|
c8746_9.info(`[CONNECT] ${r12}, encoding: ${name}, version: ${API_VERSION}, compression: ${r24}`);
|
|
if (this.webSocket !== null) {
|
|
c8746_9.error("_connect called with already existing websocket");
|
|
this._cleanup((a0) => a0.close(4000));
|
|
}
|
|
this.connectionStartTime = Date.now();
|
|
if (this.firstConnectAttemptStartTime === 0) {
|
|
this.firstConnectAttemptStartTime = this.connectionStartTime;
|
|
}
|
|
this.helloTimeout = setTimeout(() => {
|
|
const r5 = Date.now();
|
|
const r9 = env19967[1];
|
|
r9._handleClose(false, 0, `The connection timed out after ${r5 - r9.connectionStartTime} ms - did not receive OP_HELLO in time.`);
|
|
r9.setResumeUrl(null);
|
|
}, c8746_14);
|
|
const uRL = new URL(r12);
|
|
env19967[0] = uRL;
|
|
uRL.searchParams.append("encoding", name);
|
|
uRL.searchParams.append("v", API_VERSION.toString());
|
|
if (algorithm != null) {
|
|
uRL.searchParams.append("compress", algorithm);
|
|
}
|
|
let c19968_3, c19968_4;
|
|
let onOpen2, identify;
|
|
const r22 = uRL.toString();
|
|
const compressionHandler2 = this.compressionHandler;
|
|
const r104 = this._handleClose.bind(this);
|
|
const compressionHandler = compressionHandler2;
|
|
let c19968_2 = (a0, a1) => {
|
|
const r17 = Date.now();
|
|
const r26 = c8746_10.unpack(a0);
|
|
const { op, s: seq, t: r9, d: r7 } = r26;
|
|
if (op !== Opcode.DISPATCH) {
|
|
Module10.mark("🌐", `GatewaySocket.onMessage ${op} ${Opcode[op]}`);
|
|
}
|
|
if (DeveloperOptionsStore.isLoggingGatewayEvents) {
|
|
const r43 = [op];
|
|
if (op === Opcode.DISPATCH) {
|
|
r43.push(r9);
|
|
}
|
|
r43.push(r7);
|
|
c8746_9.verboseDangerously.apply(c8746_9, ["<~", ...r43]);
|
|
}
|
|
const unpack_duration_ms = Date.now() - r17;
|
|
const r3 = r9 === "READY";
|
|
if (r3) {
|
|
TTITracker.parseReady.set(r17, unpack_duration_ms);
|
|
} else if (r9 === "READY_SUPPLEMENTAL") {
|
|
TTITracker.parseReadySupplemental.set(r17, unpack_duration_ms);
|
|
} else if (unpack_duration_ms > 10) {
|
|
Module10.mark("🌐", "Parse " + r9, unpack_duration_ms);
|
|
}
|
|
if (seq != null) {
|
|
env19967[1].seq = seq;
|
|
}
|
|
if (Opcode.HELLO === op) {
|
|
const r145 = env19967[1];
|
|
r145._clearHelloTimeout();
|
|
r145._handleHello(r7);
|
|
} else if (Opcode.RECONNECT === op) {
|
|
env19967[1]._handleReconnect();
|
|
} else if (Opcode.INVALID_SESSION === op) {
|
|
env19967[1]._handleInvalidSession(r7);
|
|
} else if (Opcode.HEARTBEAT === op) {
|
|
env19967[1]._handleHeartbeatReceive();
|
|
} else if (Opcode.HEARTBEAT_ACK === op) {
|
|
env19967[1]._handleHeartbeatAck(r7);
|
|
} else if (Opcode.DISPATCH === op) {
|
|
const r119 = env19967[1];
|
|
r119._handleDispatch(r7, r9, r3 ? {
|
|
compressed_byte_size: a1,
|
|
uncompressed_byte_size: a0 == null ? 0 : typeof a0 === "string" ? a0.length : a0.byteLength,
|
|
compression_algorithm: r119.compressionHandler.getAlgorithm(),
|
|
packing_algorithm: c8746_10.getName(),
|
|
unpack_duration_ms
|
|
} : null);
|
|
} else {
|
|
c8746_9.info(`Unhandled op ${op}`);
|
|
}
|
|
env19967[1]._sendHeartbeatIfDue();
|
|
};
|
|
c19968_4 = void 0;
|
|
c19968_3 = 0;
|
|
compressionHandler.dataReady((a0) => {
|
|
try {
|
|
c19968_2(a0, c19968_3);
|
|
} catch (r7) {
|
|
c19968_3 = 0;
|
|
throw r7;
|
|
}
|
|
c19968_3 = 0;
|
|
});
|
|
c19968_4 = false;
|
|
onOpen2 = (a0) => {};
|
|
identify = void 0;
|
|
c8746_9.enableNativeLogger(true);
|
|
const _ws = window._ws;
|
|
identify = false;
|
|
window._ws = null;
|
|
const r117 = _ws != null;
|
|
let r118 = null;
|
|
let isFastConnect = false;
|
|
let r120 = false;
|
|
let webSocket = void 0;
|
|
if (r117) {
|
|
const ws = _ws.ws;
|
|
const userId = _ws.state.userId;
|
|
const r124 = userId != null && env8746[11] != null && userId !== env8746[11];
|
|
if (_ws.state.gateway !== r22) {
|
|
c8746_9.verbose(`[FAST CONNECT] gatewayURL mismatch: ${_ws.state.gateway} !== ${r22}`);
|
|
ws.close(1000);
|
|
r118 = null;
|
|
isFastConnect = false;
|
|
r120 = false;
|
|
webSocket = null;
|
|
} else if (r124) {
|
|
c8746_9.log(`[FAST CONNECT] refusing to adopt socket: identified user ${userId} does not match switch target ${env8746[11]}`);
|
|
ws.close(1000);
|
|
r118 = null;
|
|
isFastConnect = false;
|
|
r120 = false;
|
|
webSocket = null;
|
|
} else {
|
|
const r129 = {
|
|
..._ws.state
|
|
};
|
|
if (r129.messages != null) {
|
|
r129.messages = r129.messages.map((message) => message.data != null ? typeof message.data === "string" ? {
|
|
...message,
|
|
data: message.data.substring(0, 100)
|
|
} : message : message);
|
|
}
|
|
c8746_9.log("[FAST CONNECT] successfully took over websocket, state:", {
|
|
...r129,
|
|
messages: r129.messages?.length
|
|
});
|
|
r120 = _ws.state.open;
|
|
const identify2 = _ws.state.identify;
|
|
identify = identify2;
|
|
r118 = _ws.state.messages;
|
|
_ws.state.clientState;
|
|
isFastConnect = identify2;
|
|
webSocket = ws;
|
|
}
|
|
}
|
|
if (webSocket == null) {
|
|
const webSocket_android = createWebSocket_android(r22);
|
|
webSocket_android.binaryType = "arraybuffer";
|
|
webSocket = webSocket_android;
|
|
}
|
|
this.webSocket = webSocket;
|
|
this.compressionHandler.bindWebSocket(webSocket);
|
|
if (r120) {
|
|
Module10.mark("🌐", `GatewaySocket.onOpen ${isFastConnect}`);
|
|
const r192 = Date.now() - this.connectionStartTime;
|
|
c8746_9.info(`[CONNECTED] ${uRL.toString()} in ${r192} ms`);
|
|
this.isFastConnect = isFastConnect;
|
|
if (isFastConnect) {
|
|
this._doFastConnectIdentify();
|
|
} else {
|
|
this._doResumeOrIdentify();
|
|
}
|
|
}
|
|
const onmessage = (a0) => {
|
|
const data = a0.data;
|
|
if (a0.raw_length != null) {
|
|
c19968_3 = c19968_3 + a0.raw_length;
|
|
} else {
|
|
c19968_3 = c19968_3 + byteSize(data);
|
|
}
|
|
try {
|
|
compressionHandler.feed(data);
|
|
} catch (r18) {
|
|
if (!c19968_4) {
|
|
c19968_4 = true;
|
|
this(false, 0, "A decompression error occurred");
|
|
}
|
|
throw r18;
|
|
}
|
|
};
|
|
if (r118 != null) {
|
|
r118.forEach(onmessage);
|
|
}
|
|
const onError = () => {
|
|
const r5 = env19967[1];
|
|
r5.setResumeUrl(null);
|
|
CrossPlatformNativeUtils_native.flushDNSCache();
|
|
r5._handleClose(false, 0, "An error with the websocket occurred");
|
|
};
|
|
const onClose = (a0) => env19967[1]._handleClose(a0.wasClean, a0.code, a0.reason);
|
|
webSocket.onopen = () => {
|
|
Module10.mark("🌐", `GatewaySocket.onOpen ${identify}`);
|
|
const r26 = Date.now();
|
|
const r27 = env19967[1];
|
|
const r12 = r26 - r27.connectionStartTime;
|
|
c8746_9.info(`[CONNECTED] ${env19967[0].toString()} in ${r12} ms`);
|
|
r27.isFastConnect = identify;
|
|
if (identify) {
|
|
r27._doFastConnectIdentify();
|
|
} else {
|
|
r27._doResumeOrIdentify();
|
|
}
|
|
};
|
|
webSocket.onmessage = onmessage;
|
|
webSocket.onclose = onClose;
|
|
webSocket.onerror = onError;
|
|
}
|
|
} else {
|
|
c8746_9.verbose("Skipping _connect because willReconnect is false");
|
|
}
|
|
}
|
|
_handleHello(a0) {
|
|
const heartbeat_interval = a0.heartbeat_interval;
|
|
this.heartbeatInterval = heartbeat_interval;
|
|
const now = Date.now();
|
|
const r18 = now - this.connectionStartTime;
|
|
c8746_9.verbose(`[HELLO] via ${getConnectionPath(a0)}, heartbeat interval: ${heartbeat_interval}, took ${r18} ms`);
|
|
logGatewayConnected({
|
|
socket: this,
|
|
altGateway: this.altGateway,
|
|
gatewayUrl: this._getGatewayUrl(),
|
|
now
|
|
});
|
|
this.receivedHelloThisAttempt = true;
|
|
this.failedConnectAttempts = 0;
|
|
this.firstConnectAttemptStartTime = 0;
|
|
this._startHeartbeater();
|
|
}
|
|
_handleReconnect() {
|
|
c8746_9.verbose("[RECONNECT] gateway requested I reconnect.");
|
|
this._cleanup((a0) => a0.close(4000));
|
|
this.connectionState = ConnectionState.WILL_RECONNECT;
|
|
this._connect();
|
|
}
|
|
_handleInvalidSession(a0) {
|
|
c8746_9.info("[INVALID_SESSION]" + (a0 ? " can resume)" : ""));
|
|
if (a0) {
|
|
this._doResumeOrIdentify();
|
|
} else {
|
|
this._doIdentify();
|
|
}
|
|
}
|
|
_handleDispatch(a0, a1, a2) {
|
|
const r15 = Date.now() - this.connectionStartTime;
|
|
if (a1 === "READY") {
|
|
const session_id = a0.session_id;
|
|
this.sessionId = session_id;
|
|
const connectionPath = getConnectionPath(a0);
|
|
Module10.setServerTrace(connectionPath);
|
|
c8746_9.info(`[READY] took ${r15}ms, as ${session_id}`);
|
|
c8746_9.verbose(`${connectionPath}`);
|
|
this.connectionState = ConnectionState.SESSION_ESTABLISHED;
|
|
this.gatewayBackoff.succeed();
|
|
this.iosGoingAwayEventCount = 0;
|
|
this.altGateway.recordSuccess();
|
|
this.setResumeUrl(a0.resume_gateway_url);
|
|
} else if (a1 === "READY_SUPPLEMENTAL") {
|
|
c8746_9.info(`[READY_SUPPLEMENTAL] took ${r15}ms`);
|
|
this.connectionState = ConnectionState.SESSION_ESTABLISHED;
|
|
this.gatewayBackoff.succeed();
|
|
this.iosGoingAwayEventCount = 0;
|
|
this.altGateway.recordSuccess();
|
|
} else if (a1 === "RESUMED") {
|
|
c8746_9.verbose(getConnectionPath(a0));
|
|
this.connectionState = ConnectionState.SESSION_ESTABLISHED;
|
|
this.gatewayBackoff.succeed();
|
|
this.iosGoingAwayEventCount = 0;
|
|
this.altGateway.recordSuccess();
|
|
}
|
|
this.dispatcher.receiveDispatch(a0, a1, a2);
|
|
}
|
|
handleResumeDispatched() {
|
|
c8746_9.info(`[RESUMED] took ${Date.now() - this.connectionStartTime}ms, replayed ${this.dispatcher.resumeAnalytics.numEvents} events, new seq: ${this.seq}`);
|
|
}
|
|
handleReadyDispatched() {
|
|
this.didForceClearGuildHashes = false;
|
|
this.hasConnectedOnce = true;
|
|
}
|
|
_getGatewayUrl() {
|
|
let resumeUrl;
|
|
if (this.resumeUrl != null) {
|
|
resumeUrl = this.resumeUrl;
|
|
} else {
|
|
resumeUrl = this.altGateway.getAltGatewayUrl();
|
|
if (resumeUrl == null) {
|
|
resumeUrl = GATEWAY_ENDPOINT;
|
|
}
|
|
}
|
|
return resumeUrl;
|
|
}
|
|
_maybeFallBackFromAltGateway() {
|
|
if (this.altGateway.shouldUseAltGateway()) {
|
|
this.altGateway.recordFailure();
|
|
if (!this.altGateway.shouldUseAltGateway()) {
|
|
this.gatewayBackoff.succeed();
|
|
this.setResumeUrl(null);
|
|
c8746_9.warn("[ALT GATEWAY] 3 consecutive failures, falling back to default URL for this session.");
|
|
}
|
|
}
|
|
}
|
|
_handleHeartbeatReceive() {
|
|
this._sendHeartbeat();
|
|
if (this.heartbeater != null && this.heartbeatInterval != null) {
|
|
clearInterval(this.heartbeater);
|
|
this.heartbeater = setInterval(this._doHeartbeatInterval.bind(this), this.heartbeatInterval);
|
|
}
|
|
}
|
|
_handleHeartbeatAck() {
|
|
this.lastHeartbeatAckTime = Date.now();
|
|
this.heartbeatAck = true;
|
|
if (this.expeditedHeartbeatTimeout !== null) {
|
|
clearTimeout(this.expeditedHeartbeatTimeout);
|
|
this.expeditedHeartbeatTimeout = null;
|
|
c8746_9.verbose("Expedited heartbeat succeeded");
|
|
}
|
|
}
|
|
_handleHeartbeatTimeout() {
|
|
this._cleanup((a0) => a0.close(4000));
|
|
this.connectionState = ConnectionState.WILL_RECONNECT;
|
|
this._maybeFallBackFromAltGateway();
|
|
c8746_9.warn(`[ACK TIMEOUT] reconnecting in ${(this.gatewayBackoff.fail(() => this._connect()) / 1000).toFixed(2)} seconds.`);
|
|
}
|
|
_handleClose(a0, a1, a2) {
|
|
const r6 = a0 ? a0 : false;
|
|
this._cleanup();
|
|
this.emit("close", {
|
|
code: a1,
|
|
reason: a2
|
|
});
|
|
if (a1 === c8746_13) {
|
|
this.connectionState = ConnectionState.CLOSED;
|
|
c8746_9.warn("[WS CLOSED] because of authentication failure, marking as closed.");
|
|
return this._reset(r6, a1, a2);
|
|
}
|
|
this._tryDetectInvalidIOSToken(a1, a2, r6);
|
|
this.connectionState = ConnectionState.WILL_RECONNECT;
|
|
if (!this.receivedHelloThisAttempt) {
|
|
this.failedConnectAttempts = this.failedConnectAttempts + 1;
|
|
}
|
|
this._maybeFallBackFromAltGateway();
|
|
if (this.nextReconnectIsImmediate) {
|
|
c8746_9.info(`[WS CLOSED] (${r6.toString()}, ${a1}, ${a2}) retrying immediately.`);
|
|
this._connect();
|
|
} else {
|
|
const r46 = this.gatewayBackoff.fail(() => this._connect());
|
|
c8746_9.info(`[WS CLOSED] (${r6.toString()}, ${a1}, ${a2}) retrying in ${(r46 / 1000).toFixed(2)} seconds.`);
|
|
if (this.gatewayBackoff.fails > 4) {
|
|
this._reset(r6, a1, a2);
|
|
}
|
|
}
|
|
}
|
|
_tryDetectInvalidIOSToken(a0, a1, c19972_0) {
|
|
if (isIOS() && this.token != null && a0 === 1001 && a1 === "Stream end encountered") {
|
|
this.iosGoingAwayEventCount = this.iosGoingAwayEventCount + 1;
|
|
if (this.iosGoingAwayEventCount === 3) {
|
|
HTTP.get({
|
|
url: Endpoints.ME,
|
|
headers: {
|
|
authorization: this.token
|
|
},
|
|
rejectWithError: false
|
|
}).then((result) => {
|
|
AnalyticsUtils.track(AnalyticEvents.IOS_INVALID_TOKEN_WORKAROUND_TRIGGERED, {
|
|
api_status_code: result.status
|
|
});
|
|
}, ({ status }) => {
|
|
if (status === 401) {
|
|
this.connectionState = ConnectionState.CLOSED;
|
|
c8746_9.warn("[WS CLOSED] because of manual authentication failure, marking as closed.");
|
|
this._reset(c19972_0, c8746_13, "invalid token manually detected");
|
|
}
|
|
AnalyticsUtils.track(AnalyticEvents.IOS_INVALID_TOKEN_WORKAROUND_TRIGGERED, {
|
|
api_status_code: status
|
|
});
|
|
});
|
|
}
|
|
}
|
|
}
|
|
_reset(a0, a1, a2) {
|
|
this.sessionId = null;
|
|
this.seq = 0;
|
|
c8746_9.warn(`[RESET] (${a0.toString()}, ${a1}, ${a2})`);
|
|
this.emit("disconnect", {
|
|
wasClean: a0,
|
|
code: a1,
|
|
reason: a2
|
|
});
|
|
}
|
|
_sendHeartbeatIfDue() {
|
|
if (this.heartbeatInterval != null && this.heartbeater != null) {
|
|
const lastHeartbeatTime = this.lastHeartbeatTime;
|
|
if (lastHeartbeatTime != null && Date.now() - lastHeartbeatTime > this.heartbeatInterval + 5000) {
|
|
this._sendHeartbeat();
|
|
}
|
|
}
|
|
}
|
|
_doHeartbeatInterval() {
|
|
if (this.heartbeatAck) {
|
|
this.heartbeatAck = false;
|
|
this._sendHeartbeat();
|
|
} else if (this.expeditedHeartbeatTimeout === null) {
|
|
this._handleHeartbeatTimeout();
|
|
}
|
|
}
|
|
_startHeartbeater() {
|
|
const heartbeatInterval = this.heartbeatInterval;
|
|
Module38(heartbeatInterval != null, "GatewaySocket: Heartbeat interval should never null here.");
|
|
if (this.initialHeartbeatTimeout !== null) {
|
|
clearTimeout(this.initialHeartbeatTimeout);
|
|
}
|
|
if (this.heartbeater !== null) {
|
|
clearInterval(this.heartbeater);
|
|
this.heartbeater = null;
|
|
}
|
|
this.initialHeartbeatTimeout = setTimeout(() => {
|
|
this.initialHeartbeatTimeout = null;
|
|
this.heartbeatAck = true;
|
|
this.heartbeater = setInterval(this._doHeartbeatInterval.bind(this), heartbeatInterval);
|
|
this._doHeartbeatInterval();
|
|
}, Math.floor(Math.random() * heartbeatInterval));
|
|
}
|
|
_stopHeartbeater() {
|
|
if (this.heartbeater !== null) {
|
|
clearInterval(this.heartbeater);
|
|
this.heartbeater = null;
|
|
}
|
|
if (this.initialHeartbeatTimeout !== null) {
|
|
clearTimeout(this.initialHeartbeatTimeout);
|
|
this.initialHeartbeatTimeout = null;
|
|
}
|
|
if (this.expeditedHeartbeatTimeout !== null) {
|
|
clearTimeout(this.expeditedHeartbeatTimeout);
|
|
this.expeditedHeartbeatTimeout = null;
|
|
}
|
|
}
|
|
_clearHelloTimeout() {
|
|
if (this.helloTimeout != null) {
|
|
clearTimeout(this.helloTimeout);
|
|
this.helloTimeout = null;
|
|
}
|
|
}
|
|
_cleanup(a0) {
|
|
Module589.Emitter.resume();
|
|
this._stopHeartbeater();
|
|
this._clearHelloTimeout();
|
|
const webSocket = this.webSocket;
|
|
this.webSocket = null;
|
|
if (webSocket != null) {
|
|
webSocket.onopen = noop;
|
|
webSocket.onmessage = noop;
|
|
webSocket.onerror = noop;
|
|
webSocket.onclose = noop;
|
|
if (a0 != null) {
|
|
a0(webSocket);
|
|
}
|
|
}
|
|
this.gatewayBackoff.cancel();
|
|
this.compressionHandler.close();
|
|
this.compressionHandler = getCompressionHandler(c8746_10);
|
|
}
|
|
_doResume() {
|
|
this.connectionState = ConnectionState.RESUMING;
|
|
this.dispatcher.resumeAnalytics = createResumeAnalytics(Date.now() - this.connectionStartTime);
|
|
let sessionId = this.sessionId;
|
|
if (sessionId == null) {
|
|
sessionId = "";
|
|
}
|
|
c8746_9.info(`[RESUME] resuming session ${sessionId}, seq: ${this.seq}`);
|
|
this.send(Opcode.RESUME, {
|
|
token: this.token,
|
|
session_id: this.sessionId,
|
|
seq: this.seq
|
|
}, false);
|
|
}
|
|
async _doIdentify() {
|
|
const _this = this;
|
|
let c27352_1;
|
|
let c30572_0, c30572_1, c30572_2, c30572_3, c30572_4, c30572_5, c30572_6, c30572_7, c30572_8, c30572_9, c30572_10, c30572_11, c30572_12;
|
|
L31: {
|
|
c27352_1 = void 0;
|
|
c30572_0 = void 0;
|
|
c30572_1 = void 0;
|
|
c30572_2 = void 0;
|
|
c30572_3 = void 0;
|
|
c30572_4 = void 0;
|
|
c30572_5 = void 0;
|
|
c30572_6 = void 0;
|
|
c30572_7 = void 0;
|
|
c30572_8 = void 0;
|
|
c30572_9 = void 0;
|
|
c30572_10 = void 0;
|
|
c30572_11 = void 0;
|
|
c30572_12 = void 0;
|
|
_this.seq = 0;
|
|
_this.sessionId = null;
|
|
const r35 = _this.handleIdentify();
|
|
c30572_0 = r35;
|
|
if (r35 !== null) {
|
|
_this.connectionState = ConnectionState.IDENTIFYING;
|
|
const identifyStartTime = Date.now();
|
|
c30572_1 = identifyStartTime;
|
|
_this.identifyStartTime = identifyStartTime;
|
|
c30572_2 = await Promise.all([isCacheEnabled() ? GuildVersions.getCommittedVersions() : {}, isCacheEnabled() ? NonGuildVersions.getCommittedVersions() : {}, !!isCacheEnabled() && KvCacheVersion.canUseGuildVersions()]);
|
|
c30572_3 = (0, _slicedToArray)(c30572_2, 3);
|
|
c30572_4 = c30572_3[0];
|
|
c30572_5 = c30572_3[1];
|
|
c30572_6 = c30572_3[2] ? {
|
|
guild_versions: c30572_4,
|
|
highest_last_message_id: c30572_5.highest_last_message_id,
|
|
read_state_version: c30572_5.read_state_version,
|
|
user_guild_settings_version: c30572_5.user_guild_settings_version,
|
|
user_settings_version: c30572_5.user_settings_version,
|
|
private_channels_version: c30572_5.private_channels_version,
|
|
api_code_version: c30572_5.api_code_version,
|
|
initial_guild_id: c30572_5.initial_guild_id
|
|
} : {
|
|
guild_versions: {}
|
|
};
|
|
if (_this.connectionState === ConnectionState.IDENTIFYING && _this.identifyStartTime === c30572_1) {
|
|
c30572_7 = c30572_0.token;
|
|
c30572_8 = c30572_0.properties;
|
|
c30572_9 = c30572_8 === void 0 ? {} : c30572_8;
|
|
c30572_10 = c30572_0.presence;
|
|
_this.token = c30572_7;
|
|
c8746_9.verbose("[IDENTIFY]");
|
|
c30572_11 = {
|
|
token: c30572_7,
|
|
capabilities: getClientCapabilities({
|
|
useChannelObfuscation: isChannelMetadataObfuscationEnabled("GatewaySocket")
|
|
}),
|
|
properties: c30572_9,
|
|
presence: c30572_10,
|
|
compress: _this.compressionHandler.usesLegacyCompression(),
|
|
client_state: c30572_6
|
|
};
|
|
c30572_12 = JSON.stringify(c30572_11);
|
|
_this.identifyUncompressedByteSize = c30572_12.length;
|
|
_this.identifyCompressedByteSize = deflate(c30572_12).length;
|
|
_this.identifyCount = _this.identifyCount + 1;
|
|
_this.send(Opcode.IDENTIFY, c30572_11, false);
|
|
AnalyticsUtils.track(AnalyticEvents.SESSION_START_CLIENT, {});
|
|
break L31;
|
|
}
|
|
c8746_9.warn("Skipping identify because connectionState or identifyStartTime has changed");
|
|
break L31;
|
|
}
|
|
_this._handleClose(true, c8746_13, "No connection info provided");
|
|
return void 0;
|
|
}
|
|
}
|
|
_doFastConnectIdentify() {
|
|
this.seq = 0;
|
|
this.sessionId = null;
|
|
const r8 = this.handleIdentify();
|
|
if (r8 !== null) {
|
|
this.token = r8.token;
|
|
this.connectionState = ConnectionState.IDENTIFYING;
|
|
this.identifyStartTime = Date.now();
|
|
this.identifyCount = this.identifyCount + 1;
|
|
c8746_9.verbose("[IDENTIFY, fast-connect]");
|
|
this._updateLastHeartbeatAckTime();
|
|
} else {
|
|
this._handleClose(true, c8746_13, "No connection info provided");
|
|
}
|
|
}
|
|
_doResumeOrIdentify() {
|
|
L5: {
|
|
L3: {
|
|
const r4 = Date.now();
|
|
if (this.sessionId !== null) {
|
|
if (this.lastHeartbeatAckTime != null && !(r4 - this.lastHeartbeatAckTime <= c8746_15)) {
|
|
break L3;
|
|
}
|
|
this._doResume();
|
|
break L5;
|
|
}
|
|
}
|
|
this._doIdentify();
|
|
}
|
|
this._updateLastHeartbeatAckTime();
|
|
}
|
|
_updateLastHeartbeatAckTime() {
|
|
this.lastHeartbeatAckTime = Date.now();
|
|
}
|
|
_consumeQOSPayload() {
|
|
const currentPayload = this.heartbeatQOSState.currentPayload;
|
|
const heartbeatQOSState = this.heartbeatQOSState;
|
|
let upcomingState = this.heartbeatQOSState.upcomingState;
|
|
if (upcomingState == null) {
|
|
upcomingState = this.heartbeatQOSState.currentPayload;
|
|
}
|
|
heartbeatQOSState.currentPayload = upcomingState;
|
|
this.heartbeatQOSState.upcomingState = null;
|
|
return currentPayload;
|
|
}
|
|
_sendHeartbeat() {
|
|
this.send(Opcode.QOS_HEARTBEAT, {
|
|
seq: this.seq,
|
|
qos: this._consumeQOSPayload()
|
|
}, false);
|
|
this.lastHeartbeatTime = Date.now();
|
|
}
|
|
getLogger() {
|
|
return c8746_9;
|
|
}
|
|
willReconnect() {
|
|
return this.connectionState === ConnectionState.WILL_RECONNECT;
|
|
}
|
|
isClosed() {
|
|
return this.connectionState === ConnectionState.CLOSED;
|
|
}
|
|
isSessionEstablished() {
|
|
return this.connectionState === ConnectionState.SESSION_ESTABLISHED || this.connectionState === ConnectionState.RESUMING;
|
|
}
|
|
isConnected() {
|
|
return this.connectionState === ConnectionState.IDENTIFYING || this.connectionState === ConnectionState.RESUMING || this.connectionState === ConnectionState.SESSION_ESTABLISHED;
|
|
}
|
|
connect() {
|
|
let r1;
|
|
if (this.isClosed()) {
|
|
this.altGateway.reset();
|
|
c8746_9.verbose(".connect() called, new state is WILL_RECONNECT");
|
|
this.connectionState = ConnectionState.WILL_RECONNECT;
|
|
this.firstConnectAttemptStartTime = 0;
|
|
this._connect();
|
|
r1 = true;
|
|
} else {
|
|
c8746_9.error("Cannot start a new connection, connection state is not closed");
|
|
r1 = false;
|
|
}
|
|
return r1;
|
|
}
|
|
resetSocketAndClearCacheOnError(a0) {
|
|
const { action, error } = a0;
|
|
let metricAction = a0.metricAction;
|
|
c8746_9.error(`resetSocketAndClearCacheOnError during ${action}: ${error.message}`, error.stack);
|
|
const has_client_mods = usesClientMods();
|
|
if (metricAction == null) {
|
|
metricAction = action;
|
|
}
|
|
MonitoringAgent.increment({
|
|
name: MetricEvents.SOCKET_CRASHED,
|
|
tags: [`action:${metricAction}`, `modded_client:${has_client_mods}`]
|
|
}, true);
|
|
if (a0.sentry !== false) {
|
|
SentryUtils_native.captureException(error, {
|
|
tags: {
|
|
socketCrashedAction: action
|
|
}
|
|
});
|
|
}
|
|
AnalyticsUtils.track(AnalyticEvents.GATEWAY_SOCKET_RESET, {
|
|
error_message: error.message,
|
|
error_stack: error.stack,
|
|
has_client_mods,
|
|
action
|
|
});
|
|
this._cleanup((a0) => a0.close());
|
|
this._reset(true, 1000, "Resetting socket due to error.");
|
|
this.dispatcher.clear();
|
|
this.connectionState = ConnectionState.WILL_RECONNECT;
|
|
this.dispatchExceptionBackoff.cancel();
|
|
if (this.dispatchExceptionBackoff._fails === 0) {
|
|
c8746_9.verbose("Triggering fast reconnect");
|
|
this.dispatchExceptionBackoff.fail(() => {});
|
|
setTimeout(() => this._connect(), 0);
|
|
} else {
|
|
this.dispatchExceptionBackoff.fail(() => this._connect());
|
|
}
|
|
this.didForceClearGuildHashes = true;
|
|
Dispatcher.dispatch({
|
|
type: "CLEAR_CACHES",
|
|
reason: `Socket reset during ${action}`
|
|
});
|
|
Dispatcher.dispatch({
|
|
type: "LIBDISCORE_RESET"
|
|
});
|
|
clearTimeout(this.dispatchSuccessTimer);
|
|
this.dispatchSuccessTimer = setTimeout(() => this.dispatchExceptionBackoff.succeed(), 2 * c8746_16);
|
|
}
|
|
resetSocketOnDispatchError(a0) {
|
|
this.resetSocketAndClearCacheOnError({
|
|
...a0,
|
|
sentry: !(a0.error.message != null && a0.error.message.indexOf("Guild data was missing from store") >= 0)
|
|
});
|
|
}
|
|
close(r3 = false) {
|
|
const isClosed2 = this.isClosed();
|
|
if (isClosed2) {
|
|
c8746_9.verbose("close() called, but socket is already closed.");
|
|
if (!r3) {
|
|
this.sessionId = null;
|
|
this.token = null;
|
|
}
|
|
return void 0;
|
|
}
|
|
c8746_9.info(`Closing connection, current state is ${this.connectionState}`);
|
|
let c19976_0 = r3 ? 4000 : void 0;
|
|
this._cleanup((a0) => a0.close(c19976_0));
|
|
this.connectionState = ConnectionState.CLOSED;
|
|
if (!r3) {
|
|
this.sessionId = null;
|
|
this.token = null;
|
|
setImmediate(() => {
|
|
this._reset(true, 1000, "Disconnect requested by user");
|
|
});
|
|
}
|
|
}
|
|
networkStateChange(a0, a1, r6 = true) {
|
|
this.expeditedHeartbeat(a0, a1, r6, false);
|
|
}
|
|
expeditedHeartbeat(a0, r10 = "", r7 = true, r9 = true) {
|
|
if (this.isClosed()) {
|
|
return void 0;
|
|
}
|
|
if (this.isConnected()) {
|
|
c8746_9.verbose("Performing an expedited heartbeat " + (r10 != null ? r10 !== "" ? "reason: " + r10 : "" : ""));
|
|
this.heartbeatAck = false;
|
|
this._sendHeartbeat();
|
|
if (this.expeditedHeartbeatTimeout !== null) {
|
|
clearTimeout(this.expeditedHeartbeatTimeout);
|
|
}
|
|
this.expeditedHeartbeatTimeout = setTimeout(() => {
|
|
this.expeditedHeartbeatTimeout = null;
|
|
if (this.heartbeatAck === false) {
|
|
this._handleHeartbeatTimeout();
|
|
}
|
|
}, a0);
|
|
} else if (r7) {
|
|
this.resetBackoff(r10, r9);
|
|
} else {
|
|
c8746_9.verbose(`Expedited heartbeat requested, but, connection state is ${this.connectionState} and reconnectImmediately was not requested ${r10 != null ? r10 !== "" ? "reason: " + r10 : "" : ""}`);
|
|
}
|
|
}
|
|
resetBackoff(r6 = "", r4 = true) {
|
|
c8746_9.verbose("Connection has reset backoff" + (r6 != null ? r6 !== "" ? " for reason: " + r6 : "" : ""));
|
|
this.gatewayBackoff.succeed();
|
|
this.iosGoingAwayEventCount = 0;
|
|
this.nextReconnectIsImmediate = true;
|
|
if (this.willReconnect()) {
|
|
this._connect();
|
|
} else {
|
|
if (r4) {
|
|
r4 = this.connectionState !== ConnectionState.SESSION_ESTABLISHED;
|
|
}
|
|
if (r4) {
|
|
this._handleClose(true, 0, r6);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
c8746_19 = GatewaySocket;
|
|
export default GatewaySocket;
|
|
export function setAccountSwitchUserId(a0) {
|
|
env8746[11] = a0;
|
|
}
|