UNPKG

fnbr

Version:

A library to interact with Epic Games' Fortnite HTTP and XMPP services

193 lines 9.53 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const ws_1 = tslib_1.__importDefault(require("ws")); const Base_1 = tslib_1.__importDefault(require("../Base")); const enums_1 = require("../../resources/enums"); const AuthenticationMissingError_1 = tslib_1.__importDefault(require("../exceptions/AuthenticationMissingError")); const Endpoints_1 = tslib_1.__importDefault(require("../../resources/Endpoints")); const ReceivedFriendMessage_1 = tslib_1.__importDefault(require("../structures/friend/ReceivedFriendMessage")); const PartyMessage_1 = tslib_1.__importDefault(require("../structures/party/PartyMessage")); const STOMPConnectionTimeoutError_1 = tslib_1.__importDefault(require("../exceptions/STOMPConnectionTimeoutError")); const STOMPMessage_1 = tslib_1.__importDefault(require("./STOMPMessage")); const STOMPConnectionError_1 = tslib_1.__importDefault(require("../exceptions/STOMPConnectionError")); /** * Represents the client's EOS Connect STOMP manager (i.e. chat messages) */ class STOMP extends Base_1.default { /** * @param client The main client */ constructor(client) { super(client); this.connection = undefined; this.pingInterval = undefined; this.connectionId = undefined; this.connectionRetryCount = 0; } /** * Whether the internal websocket is connected */ get isConnected() { return this.connection && this.connection.readyState === ws_1.default.OPEN; } /** * Connect to the STOMP server * @throws {AuthenticationMissingError} When there is no EOS auth to use for STOMP auth * @throws {STOMPConnectionError} When the connection failed for any reason */ async connect() { if (!this.client.auth.sessions.has(enums_1.AuthSessionStoreKey.FortniteEOS)) { throw new AuthenticationMissingError_1.default(enums_1.AuthSessionStoreKey.FortniteEOS); } this.client.debug('[STOMP] Connecting...'); const connectionStartTime = Date.now(); this.connection = new ws_1.default(`wss://${Endpoints_1.default.EOS_STOMP}`, { headers: { Authorization: `Bearer ${this.client.auth.sessions.get(enums_1.AuthSessionStoreKey.FortniteEOS).accessToken}`, 'Sec-Websocket-Protocol': 'v10.stomp,v11.stomp,v12.stomp', 'Epic-Connect-Device-Id': ' ', 'Epic-Connect-Protocol': 'stomp', }, }); return new Promise((res, rej) => { const connectionTimeout = setTimeout(() => { this.disconnect(); rej(new STOMPConnectionTimeoutError_1.default(this.client.config.stompConnectionTimeout)); }, this.client.config.stompConnectionTimeout); this.connection.once('open', () => { clearTimeout(connectionTimeout); this.sendMessage({ command: 'CONNECT', headers: { 'accept-version': '1.0,1.1,1.2', 'heart-beat': '35000,0', }, }); this.registerEvents(res, rej, connectionStartTime); }); this.connection.once('error', (err) => { this.client.debug(`[STOMP] Connection failed: ${err.message}`); clearTimeout(connectionTimeout); rej(new STOMPConnectionError_1.default(err.message)); }); }); } /** * Registers the events for the STOMP connection */ registerEvents(resolve, reject, connectionStartTime) { this.connection.on('close', async (code, reason) => { this.disconnect(); if (this.connectionRetryCount < 2) { this.client.debug('[STOMP] Disconnected, reconnecting in 5 seconds...'); this.connectionRetryCount += 1; await new Promise((res) => setTimeout(res, 5000)); await this.connect(); } else { this.client.debug('[STOMP] Disconnected, retry limit reached'); this.connectionRetryCount = 0; throw new STOMPConnectionError_1.default(`STOMP WS disconnected, retry limit reached. Reason: ${reason}`, code); } }); this.connection.on('message', async (d) => { var _a; const message = STOMPMessage_1.default.fromString(d.toString()); switch (message.command) { case 'CONNECTED': this.pingInterval = setInterval(() => this.connection.send('\n'), 35000); this.sendMessage({ command: 'SUBSCRIBE', headers: { id: 'sub-0', destination: `${this.client.config.eosDeploymentId}/account/${this.client.user.self.id}`, }, }); break; case 'MESSAGE': { if (!message.body) break; const data = JSON.parse(message.body); switch (data.type) { case 'core.connect.v1.connected': this.client.debug(`[STOMP] Successfully connected (${((Date.now() - connectionStartTime) / 1000).toFixed(2)}s)`); this.connectionId = data.connectionId; this.connectionRetryCount = 0; resolve(); break; case 'core.connect.v1.connect-failed': this.client.debug(`[STOMP] Connection failed: ${data.statusCode} - ${data.message}`); reject(new STOMPConnectionError_1.default(data.message, data.statusCode)); break; case 'social.chat.v1.NEW_WHISPER': { const { senderId, body, time } = data.payload.message; const friend = this.client.friend.list.get(senderId); if (!friend || senderId === this.client.user.self.id) return; const friendMessage = new ReceivedFriendMessage_1.default(this.client, { content: body !== null && body !== void 0 ? body : '', author: friend, id: data.id, sentAt: new Date(time), }); this.client.emit('friend:message', friendMessage); break; } case 'social.chat.v1.NEW_MESSAGE': { if (data.payload.conversation.type !== 'party') return; await this.client.partyLock.wait(); const { conversation: { conversationId }, message: { senderId, body, time } } = data.payload; const partyId = conversationId.replace('p-', ''); if (!this.client.party || this.client.party.id !== partyId || senderId === this.client.user.self.id) { return; } const authorMember = this.client.party.members.get(senderId); if (!authorMember) return; const partyMessage = new PartyMessage_1.default(this.client, { content: body !== null && body !== void 0 ? body : '', author: authorMember, sentAt: new Date(time), id: data.id, party: this.client.party, }); this.client.emit('party:member:message', partyMessage); break; } default: this.client.debug(`[STOMP] Unknown message type: ${data.type} ${message.body}`); } } break; default: this.client.debug(`[STOMP] Unknown command: ${message.command} ${(_a = message.body) !== null && _a !== void 0 ? _a : 'no body'}`); } }); } /** * Disconnects the STOMP client. * Also performs a cleanup */ async disconnect() { if (!this.connection) return; clearInterval(this.pingInterval); this.pingInterval = undefined; this.connection.removeAllListeners(); this.connection.close(); this.connection = undefined; this.connectionId = undefined; } /** * Sends a message to the STOMP server * @param message The message to send */ sendMessage(message) { this.connection.send(new STOMPMessage_1.default(message).toString()); } } exports.default = STOMP; //# sourceMappingURL=STOMP.js.map