upstox-js-sdk
Version:
The official Node Js client for communicating with the Upstox API
151 lines (146 loc) • 5.18 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.MarketDataFeeder = void 0;
var _ws = _interopRequireDefault(require("ws"));
var _protobufjs = _interopRequireDefault(require("protobufjs"));
var _path = _interopRequireDefault(require("path"));
var _uuid = _interopRequireDefault(require("uuid4"));
var _ApiClient = require("../ApiClient");
var _Feeder = _interopRequireDefault(require("./Feeder"));
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
class MarketDataFeeder extends _Feeder.default {
constructor(instrumentKeys = [], mode = this.Mode.FULL) {
super();
//Required enums
_defineProperty(this, "Mode", Object.freeze({
LTPC: "ltpc",
FULL: "full"
}));
_defineProperty(this, "Method", Object.freeze({
SUBSCRIBE: "sub",
CHANGE_METHOD: "change_mode",
UNSUBSCRIBE: "unsub"
}));
_defineProperty(this, "ws", null);
_defineProperty(this, "instrumentKeys", []);
_defineProperty(this, "mode", "");
_defineProperty(this, "userClosedWebSocket", false);
_defineProperty(this, "closingCode", -1);
_defineProperty(this, "protobufRoot", null);
this.apiClient = _ApiClient.ApiClient.instance;
this.instrumentKeys = instrumentKeys;
this.mode = mode;
this.initProtobuf();
}
async connect() {
// Skip if its already connected
if (this.ws && (this.ws.readyState == ws.CONNECTING || ws.readyState == ws.OPEN)) return;
this.ws = await this.connectWebSocket(`wss://api.upstox.com/v2/feed/market-data-feed`, this.apiClient.authentications["OAUTH2"].accessToken);
this.onOpen();
this.onMessage();
this.onClose();
this.onError();
}
shouldReconnect() {
return this.ws === null || !this.userClosedWebSocket && this.ws.readyState !== _ws.default.OPEN;
}
onOpen() {
this.ws.on("open", () => {
this.emit("open");
});
}
onMessage() {
this.ws.on("message", data => {
const decodedData = this.decodeProtobuf(data);
this.push(JSON.stringify(decodedData));
});
}
onClose() {
this.ws.on("close", code => {
this.push(null);
this.closingCode = code;
if (code === 1000) {
this.userClosedWebSocket = true;
}
});
}
onError() {
this.ws.on("error", e => {
this.emit("error", e);
});
}
disconnect() {
this.ws.close(1000);
}
subscribe(instrumentKeys, mode) {
if (this.ws && this.ws.readyState === _ws.default.OPEN) {
this.ws.send(this.buildRequest(instrumentKeys, this.Method.SUBSCRIBE, mode));
} else {
throw new Error("Failed to subscribe: WebSocket is not open.");
}
}
unsubscribe(instrumentKeys) {
if (this.ws && this.ws.readyState === _ws.default.OPEN) {
this.ws.send(this.buildRequest(instrumentKeys, this.Method.UNSUBSCRIBE));
}
}
changeMode(instrumentKeys, newMode) {
if (this.ws && this.ws.readyState === _ws.default.OPEN) {
this.ws.send(this.buildRequest(instrumentKeys, this.Method.SUBSCRIBE, newMode));
} else {
throw new Error("Failed to changeMode: WebSocket is not open.");
}
}
// Function to establish WebSocket connection
async connectWebSocket(wsUrl, accessToken) {
return new Promise(resolve => {
const ws = new _ws.default(wsUrl, {
headers: {
Authorization: `Bearer ${accessToken}`
},
followRedirects: true
});
resolve(ws);
});
}
// Function to initialize the protobuf part
async initProtobuf() {
const protoPath = _path.default.resolve(__dirname, "./proto/MarketDataFeed.proto");
_protobufjs.default.load(protoPath, (error, root) => {
if (error) {
console.error("Error loading .proto file", error);
return;
}
this.protobufRoot = root;
});
}
// Function to decode protobuf message
decodeProtobuf(buffer) {
if (!this.protobufRoot) {
console.warn("Protobuf part not initialized yet!");
return null;
}
const FeedResponse = this.protobufRoot.lookupType("com.upstox.marketdatafeeder.rpc.proto.FeedResponse");
return FeedResponse.decode(buffer);
}
buildRequest(instrumentKeys, method, mode) {
const requestObj = {
guid: (0, _uuid.default)(),
method,
data: {
instrumentKeys
}
};
// Only add 'mode' to 'data' if it is not undefined
if (mode !== undefined) {
requestObj.data.mode = mode;
}
return Buffer.from(JSON.stringify(requestObj));
}
}
exports.MarketDataFeeder = MarketDataFeeder;