UNPKG

@sharplygroup/xtb-api-js

Version:

A module for interacting with the XTB API

177 lines 6.26 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.WebSocketManager = void 0; const ws_1 = __importDefault(require("ws")); const XtbLoginError_1 = require("../errors/XtbLoginError"); const XtbConnectionError_1 = require("../errors/XtbConnectionError"); class WebSocketManager { mainSocket = null; streamSocket = null; pingInterval = null; streamSessionId = null; getStreamSessionId() { return this.streamSessionId; } credentials; isDemo; constructor(credentials) { this.credentials = credentials; this.isDemo = credentials.demo; } getMainSocketUrl() { const host = "wss://ws.xapi.pro"; return this.isDemo ? `${host}/demo` : `${host}/real`; } getStreamSocketUrl() { const host = "wss://ws.xapi.pro"; return this.isDemo ? `${host}/demoStream` : `${host}/realStream`; } async connect() { try { // Connect main socket const mainSocket = new ws_1.default(this.getMainSocketUrl()); this.mainSocket = mainSocket; await this.waitForConnection(mainSocket); // Login const loginResponse = await this.login(); if (!loginResponse.status) { throw new XtbLoginError_1.XtbLoginError(loginResponse.errorDescr || "Login failed", loginResponse.errorCode); } this.streamSessionId = loginResponse.streamSessionId || null; // Connect stream socket if we have streamSessionId if (this.streamSessionId) { const streamSocket = new ws_1.default(this.getStreamSocketUrl()); this.streamSocket = streamSocket; await this.waitForConnection(streamSocket); } // Start ping interval this.startPingInterval(); } catch (error) { await this.disconnect(); throw error; } } waitForConnection(socket) { return new Promise((resolve, reject) => { const timeout = setTimeout(() => { reject(new XtbConnectionError_1.XtbConnectionError("Connection timeout")); }, 30000); socket.once("open", () => { clearTimeout(timeout); resolve(); }); socket.once("error", (error) => { clearTimeout(timeout); reject(new XtbConnectionError_1.XtbConnectionError(error.message)); }); }); } async login() { const command = { command: "login", arguments: { userId: this.credentials.userId, password: this.credentials.password, }, }; return this.sendCommand(command); } startPingInterval() { // Send ping every 10 minutes to keep connection alive this.pingInterval = setInterval(async () => { try { await this.sendCommand({ command: "ping", arguments: {} }); } catch (error) { // Handle ping error - maybe reconnect console.error("Ping failed:", error); } }, 10 * 60 * 1000); // 10 minutes } async sendCommand(command) { if (!this.mainSocket || this.mainSocket.readyState !== 1) { // 1 = OPEN throw new Error("Main socket not connected"); } return new Promise((resolve, reject) => { const timeout = setTimeout(() => { reject(new Error("Command timeout")); }, 30000); const messageHandler = (data) => { try { const response = JSON.parse(data.toString()); this.mainSocket?.removeListener("message", messageHandler); clearTimeout(timeout); resolve(response); } catch (error) { this.mainSocket?.removeListener("message", messageHandler); clearTimeout(timeout); reject(error); } }; if (this.mainSocket) { this.mainSocket.on("message", messageHandler); this.mainSocket.send(JSON.stringify(command)); } else { reject(new Error("Socket is not initialized")); } }); } async sendStreamCommand(command) { if (!this.streamSocket || this.streamSocket.readyState !== 1) { // 1 = OPEN throw new Error("Stream socket not connected"); } if (!this.streamSessionId) { throw new Error("No stream session ID available"); } const streamCommand = { ...command, streamSessionId: this.streamSessionId, }; this.streamSocket.send(JSON.stringify(streamCommand)); } onStreamMessage(callback) { if (!this.streamSocket) { throw new Error("Stream socket not connected"); } this.streamSocket.on("message", (data) => { try { const message = JSON.parse(data.toString()); callback(message); } catch (error) { console.error("Error parsing stream message:", error); } }); } async disconnect() { if (this.pingInterval) { clearInterval(this.pingInterval); this.pingInterval = null; } if (this.mainSocket) { try { await this.sendCommand({ command: "logout", arguments: {} }); } catch { // Ignore logout errors } this.mainSocket.close(); this.mainSocket = null; } if (this.streamSocket) { this.streamSocket.close(); this.streamSocket = null; } this.streamSessionId = null; } } exports.WebSocketManager = WebSocketManager; //# sourceMappingURL=WebSocketManager.js.map