fyers-api-v3 1.1.1 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1276 @@
1
+ let HSWebSocket = require('../HSM_Package/hslib.js');
2
+ let mapdata = require("./mapper.js");
3
+ let ErrorHandler = require("../errorHandler/errorHandler.js");
4
+ let axios = require("axios")
5
+ let Logger = require("../logger/log.js")
6
+ let { Config } = require("../config/config");
7
+ let jwt = require('jsonwebtoken');
8
+
9
+ const floatkeys = ["ltp", "op", "c", "lo", "h", "cng", "nc", "yh", "yl", "ap", "to", "lcl", "ucl", "bp", "sp", "mul", "prec", "openingPrice", "lowPrice", "highPrice", "ic", "iv","bp1","bp2","bp3","bp4","sp1","sp2","sp3","sp4"]
10
+ const intkeys = ["ltq", "v", "tbq", "tsq", "oi", "bq", "bs","bq1","bq2","bq3","bq4","bs1","bs2","bs3","bs4","bno1","bno2","bno3","bno4","bno5","sno1","sno2","sno3","sno4","sno5"]
11
+ const datekeys = ["ltt", "fdtm","tvalue"]
12
+ const exchmapping = { "1010": 'nse_cm', "1011": 'nse_fo', "1120": 'mcx_fo', "1210": 'bse_cm', "1012": 'cde_fo', "1211": 'bse_fo' ,"1020": 'nse_com', "1212": 'bcs_fo'}
13
+ var fulldata = {};
14
+
15
+ /**
16
+ * returns the overall count of symbol subscribed across all channels.
17
+ * @param {Object} symbolcounter - symbolcounter object which has subscription type as keys and values as object having key as channel number and values as list of exchange token of symbols subscribed on channel.
18
+ * @returns {Number} number of symbols subscribed over all channels.
19
+ */
20
+ function countValues(symbolcounter) {
21
+ return Object.values(symbolcounter).reduce((count, innerObject) => {
22
+ return count + Object.values(innerObject).reduce((sum, list) => {
23
+ return sum + list.length;
24
+ }, 0);
25
+ }, 0);
26
+ }
27
+
28
+ /**
29
+ * used to send http request to quotes api to get FYtoken.
30
+ * @param {Array} urls - premade urls with querys.
31
+ * @param {string} AuthrizationToken - AccessToken of user.
32
+ * @param {Function} callback - the callback function.
33
+ * @param {Logger} logger - logger class.
34
+ * @returns {Object} with key as symbol ticker and value as fytoken
35
+ */
36
+ async function sendRequests(urls, AuthrizationToken, callback, logger) {
37
+ var funcname = "sendRequests"
38
+ var symboltokenmap = {}
39
+ var resp = undefined
40
+ for (const url of urls) {
41
+ try {
42
+ const response = await axios.get((url), {
43
+ headers: {
44
+ Authorization: AuthrizationToken,
45
+ }
46
+ });
47
+ resp = response.data
48
+ } catch (error) {
49
+ var err = new ErrorHandler(error).getError()
50
+ logger.error("error fetching symbol token", err, funcname)
51
+ err['type'] = "sub"
52
+ callback(err)
53
+ resp = { 'd': [] }
54
+ }
55
+ resp = resp.d
56
+ resp.forEach(function (element) {//make a object with symbol as key and fytoken as value
57
+ if (element.s === 'ok') {
58
+ symboltokenmap[element.n] = element.v.fyToken
59
+ } else {
60
+ callback({ "code": element.v.code, "type": "sub", "message": element.v.errmsg, "s": element.v.s, "symbol": element.n })
61
+ logger.error("error fetching symbol token for specific symbol", element, funcname)
62
+ }
63
+ })
64
+ }
65
+ return symboltokenmap
66
+ }
67
+ /**
68
+ * used to send http request to quotes api to get FYtoken.
69
+ * @param {Array} urls - premade urls with querys.
70
+ * @param {string} AuthrizationToken - AccessToken of user.
71
+ * @param {Function} callback - the callback function.
72
+ * @param {Logger} logger - logger class.
73
+ * @returns {Object} with key as symbol ticker and value as fytoken
74
+ */
75
+ async function getFyToken(url , AuthrizationToken , bodies , logger ,callback) {
76
+ var resp = null;
77
+ var returnResponse = {}
78
+ const funcname = "getFyToken";
79
+ for (const body of bodies){
80
+ var requestBody = JSON.stringify(body)
81
+ try {
82
+ const response = await axios.post((url),requestBody, {
83
+ headers: {
84
+ Authorization: AuthrizationToken,
85
+ }
86
+ });
87
+ resp = response.data
88
+ for (key in resp['validSymbol']){
89
+ returnResponse[key] = resp['validSymbol'][key]
90
+ }
91
+
92
+ } catch (error) {
93
+ var err = new ErrorHandler(error).getError()
94
+ logger.error("error fetching symbol token", err, funcname)
95
+ err['type'] = "sub"
96
+ callback(err)
97
+ resp = { 'd': [] }
98
+ }
99
+ }
100
+ return returnResponse
101
+ }
102
+
103
+ /**
104
+ * function called to check if one single symbol is not subscribed on multiple channels before deleting its in-memory object.
105
+ * @param {Object} obj - premade urls with querys.
106
+ * @param {string} value - AccessToken of user.
107
+ * @returns {boolean} true if symbol found subscribed on multiple channels
108
+ */
109
+ function checkValueInLists(obj, value) {
110
+ let count = 0;
111
+ let foundMultiple = false;
112
+
113
+ for (const key in obj) {
114
+ if (Array.isArray(obj[key]) && obj[key].includes(value)) {
115
+ count++;
116
+ if (count > 1) {
117
+ foundMultiple = true;
118
+ break;
119
+ }
120
+ }
121
+ }
122
+
123
+ return !foundMultiple;
124
+ }
125
+
126
+ /**
127
+ * appends data to Array dropping duplicates
128
+ * @param {Array} mainList - array to which value is to be appened.
129
+ * @param {any} valueToAppend - value to be appended to array.
130
+ * @returns {Array} Appened array.
131
+ */
132
+ function appendToList(mainList, valueToAppend) {
133
+ if (!mainList.includes(valueToAppend)) {
134
+ mainList.push(valueToAppend);
135
+ }
136
+ return mainList;
137
+ }
138
+
139
+ /**
140
+ * return array dropping value passed in channelnumber from default channel list or whatever array passed
141
+ * @param {any} channelnumber - value to be dropped from array.
142
+ * @param {Array} channellist - array from which valued to be dropped.
143
+ * @returns {Array} array dropping the value.
144
+ */
145
+ function returnstopchannelarray(channelnumber, channellist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]) {
146
+ for (var i = 0; i < channellist.length; i++) {
147
+
148
+ if (channellist[i] === channelnumber) {
149
+
150
+ channellist.splice(i, 1);
151
+ }
152
+ }
153
+ return channellist
154
+ }
155
+
156
+ /**
157
+ * return array as array of arrays splitting input array to length of limit
158
+ * @param {Array} array - array to be split.
159
+ * @param {Number} limit - array length limit.
160
+ * @returns {Array<Array<any>>} array dropping the value.
161
+ */
162
+ function splitArray(array, limit) {
163
+ const result = [];
164
+ let currentArray = [];
165
+
166
+ for (const item of array) {
167
+ currentArray.push(item);
168
+
169
+ if (currentArray.length === limit) {
170
+ result.push(currentArray);
171
+ currentArray = [];
172
+ }
173
+ }
174
+
175
+ if (currentArray.length > 0) {
176
+ result.push(currentArray);
177
+ }
178
+
179
+ return result;
180
+ }
181
+
182
+ /**
183
+ * return array as array of arrays splitting input array to length of limit
184
+ * @param {string} datestring - datestring to convert to epoch time.
185
+ * @returns {Number} epoch time.
186
+ */
187
+ function DateTimeStringToEpoch(datestring) {
188
+ process.env.TZ = 'Asia/Kolkata';
189
+ // Parse the date string into its components
190
+ const [day, month, year, hours, minutes, seconds] = datestring.match(/\d+/g);
191
+ // Create a new Date object with the components (months are zero-based)
192
+ const date = new Date(year, month - 1, day, hours, minutes, seconds);
193
+ // Get the epoch time in seconds by dividing by 1000 and flooring the result
194
+ const epochTimeSec = Math.floor(date.getTime() / 1000);
195
+ return epochTimeSec
196
+ }
197
+ /**
198
+ * Class to make a queue datatype object(makes a first in first out system using array).
199
+ * @class
200
+ */
201
+ class Queuesystem {
202
+ constructor() {
203
+ this.queue = [];
204
+ }
205
+ /**
206
+ * used to add data to queue
207
+ * @param {Object | Object[]} data - data to be sent to queue.
208
+ */
209
+ send(data) {
210
+ this.queue.push(data);
211
+ }
212
+
213
+ /**
214
+ * used to add data to queue
215
+ * @returns {Promise} A promise that resolves and send data out of queue or undefined in case queue is empty
216
+ */
217
+ async receive() {
218
+ if (this.queue.length > 0) {
219
+ return this.queue.shift();
220
+ } else {
221
+ return undefined;
222
+ }
223
+ }
224
+ /**
225
+ * clears the queue
226
+ */
227
+ clear() {
228
+ this.queue = []
229
+ }
230
+ }
231
+
232
+ /**
233
+ * function to rename keys of the object
234
+ * @param {Object} obj - object in which key is to be replaced.
235
+ * @param {string} oldKey - the key which is to be renamed.
236
+ * @param {string} newKey - new key name.
237
+ */
238
+ function renameObjectKey(obj, oldKey, newKey) {
239
+ if (oldKey !== newKey && obj.hasOwnProperty(oldKey)) {
240
+ obj[newKey] = obj[oldKey];
241
+ delete obj[oldKey];
242
+ }
243
+ }
244
+
245
+ /**
246
+ * maps data from HSM fromat to our format based on channel mode(full/lite) Note:it deletes key if mapping is not found in mapper object.
247
+ * @param {Object} hsminputdata - data from HSM.
248
+ * @param {Boolean} islitemode - true if channel in lite mode else false.
249
+ */
250
+ function Mapper(hsminputdata, islitemode) {
251
+ var datatobemapped = { ...hsminputdata }
252
+ var feed_type = datatobemapped.name
253
+ if (feed_type === undefined) {
254
+ feed_type = "confirmationmapper"
255
+ }
256
+ if (islitemode) {
257
+ var mode = "lite"
258
+ } else {
259
+ var mode = "full"
260
+ }
261
+ for (const key in datatobemapped) {
262
+ if (!(mapdata[feed_type] === undefined)) {
263
+ if (!(mapdata[feed_type][mode][key] === undefined)) {
264
+ renameObjectKey(datatobemapped, key, mapdata[feed_type][mode][key]);
265
+ if (feed_type=='sf' && mode=='full') {
266
+ datatobemapped['lower_ckt']=0
267
+ datatobemapped['upper_ckt']=0
268
+ }
269
+ }
270
+ else if (key != "symbol") {
271
+ delete datatobemapped[key]
272
+ }
273
+ }
274
+ }
275
+ return datatobemapped
276
+ }
277
+
278
+ Array.prototype.contains = function (obj) {
279
+ var i = this.length;
280
+ while (i--) {
281
+ if (this[i] === obj) {
282
+ return true;
283
+ }
284
+ }
285
+ return false;
286
+ }
287
+
288
+ let reviver = function (key, value) {
289
+ if (floatkeys.contains(key)) {
290
+ return parseFloat(value)
291
+ } else if (intkeys.contains(key)) {
292
+ return parseInt(value)
293
+ } else if (datekeys.contains(key)) {
294
+ return DateTimeStringToEpoch(value)
295
+ } else {
296
+ return value
297
+ }
298
+ }
299
+
300
+ function decodeJWTAndExtractHSMKey(AccessToken,Logger) {
301
+ const funcname="decodeJWTAndExtractHSMKey"
302
+ try {
303
+ const tokenParts = AccessToken.split(':');
304
+ const jwtToken = tokenParts[tokenParts.length - 1];
305
+ const decodedToken = jwt.decode(jwtToken);
306
+
307
+ if (!decodedToken || !decodedToken.hsm_key) {
308
+ Logger.error("HSM key not found in token", decodedToken, funcname)
309
+ throw new Error('Invalid JWT: "hsm_key" missing or token is invalid.');
310
+ }
311
+ if (decodedToken.exp && Date.now() >= decodedToken.exp * 1000) {
312
+ Logger.error("Token expired", decodedToken, funcname)
313
+ throw new Error('You are passing an expired token');
314
+ }
315
+ return decodedToken.hsm_key;
316
+ } catch (error) {
317
+ Logger.error("HSM key not found in token", error.message, funcname)
318
+ throw new Error(`Failed to decode JWT: ${error.message}`);
319
+ }
320
+ }
321
+
322
+ const _receiver = Symbol('receiver');
323
+ const _recurssivesend = Symbol('recursivesend');
324
+
325
+ const DataSocket = (() => {
326
+ /**
327
+ * The current channel being used.
328
+ * @private
329
+ * @type {Number}
330
+ */
331
+ let currentchannel = undefined;
332
+
333
+ /**
334
+ * @typedef {object} symbolcounterobj
335
+ * @property {number} channel - The number of channel.
336
+ * @property {Array} symbols - symbols subscribed on channel.
337
+ */
338
+ /**
339
+ * The symbol subscribed on a particular channel by subsciption type(dp-depth,if-index,sf-equity & FNO).
340
+ * @private
341
+ * @type {symbolcounterobj}
342
+ */
343
+ let symbolcounter = {
344
+ "if": { 1: [], 2: [], 3: [], 4: [], 5: [], 6: [], 7: [], 8: [], 9: [], 10: [], 11: [], 12: [], 13: [], 14: [], 15: [], 16: [], 17: [], 18: [], 19: [], 20: [], 21: [], 22: [], 23: [], 24: [], 25: [], 26: [], 27: [], 28: [], 29: [], 30: [] },
345
+ "sf": { 1: [], 2: [], 3: [], 4: [], 5: [], 6: [], 7: [], 8: [], 9: [], 10: [], 11: [], 12: [], 13: [], 14: [], 15: [], 16: [], 17: [], 18: [], 19: [], 20: [], 21: [], 22: [], 23: [], 24: [], 25: [], 26: [], 27: [], 28: [], 29: [], 30: [] },
346
+ "dp": { 1: [], 2: [], 3: [], 4: [], 5: [], 6: [], 7: [], 8: [], 9: [], 10: [], 11: [], 12: [], 13: [], 14: [], 15: [], 16: [], 17: [], 18: [], 19: [], 20: [], 21: [], 22: [], 23: [], 24: [], 25: [], 26: [], 27: [], 28: [], 29: [], 30: [] }
347
+ };
348
+
349
+ /**
350
+ * @typedef {object} litemodestatusobj
351
+ * @property {number} channel - The number of channel.
352
+ * @property {Boolean} litemode - true if channel in lite mode.
353
+ */
354
+ /**
355
+ * object stating if the channel is in lite mode or not.
356
+ * @private
357
+ * @type {litemodestatusobj}
358
+ */
359
+ let litemodestatus = {
360
+ 1: true, 2: true, 3: true, 4: true, 5: true, 6: true, 7: true, 8: true, 9: true, 10: true, 11: false, 12: false, 13: false, 14: false, 15: false, 16: false, 17: false, 18: false, 19: false, 20: false, 21: false, 22: false, 23: false, 24: false, 25: false, 26: false, 27: false, 28: false, 29: false, 30: false
361
+ };
362
+
363
+ /**
364
+ * AccessToken of user.
365
+ * @private
366
+ * @type {String}
367
+ */
368
+ let AccessToken = undefined
369
+
370
+ /**
371
+ * HSMtoken of user.
372
+ * @private
373
+ * @type {String}
374
+ */
375
+ let HSMToken = undefined
376
+
377
+ /**
378
+ * WebsocketURL.
379
+ * @private
380
+ * @type {String}
381
+ */
382
+ let wsURL = Config['HSM_SOCKET'];
383
+
384
+ /**
385
+ * number of max reconnections allowed.
386
+ * @private
387
+ * @type {Number}
388
+ */
389
+ let maxreconnectiontries = 0;
390
+
391
+ let reconnectiontries = 0;
392
+ /**
393
+ * count of number of request sent to socket in a second reset to zero every second.
394
+ * @private
395
+ * @type {Number}
396
+ */
397
+ let secondcounter = 0;
398
+
399
+ /**
400
+ * HSM websocket object.
401
+ * @private
402
+ * @type {HSWebSocket}
403
+ */
404
+ let hsSocket = new HSWebSocket();
405
+
406
+ /**
407
+ * makes a queue variable to push data to send to websocket.
408
+ * @private
409
+ * @type {Queuesystem}
410
+ */
411
+ let queue = new Queuesystem();
412
+
413
+ /**
414
+ * Class to access symboldata websocket.
415
+ * @class
416
+ */
417
+ class DataSocket {
418
+
419
+ /**
420
+ * Create a new DataSocket object to acess symboldata websocket.
421
+ * @constructor
422
+ * @param {Object} params - The parameters for initializing the DataSocket.
423
+ * @param {string} Token - The access token for authentication.
424
+ * @param {string} [path] - The path for log files.
425
+ */
426
+ constructor(Token,path,loggingFlag=true) {
427
+
428
+ if (DataSocket.instance) {
429
+ throw new Error("Only one instance of DataSocket is allowed. Use getInstance() instead.");
430
+ }
431
+ var self = this;
432
+
433
+ /**
434
+ * variable to be passed to make channel run in full mode.
435
+ * @type {string}
436
+ */
437
+ self.FullMode = "ful"
438
+
439
+ /**
440
+ * filepath where are logs are to be saved.
441
+ * @type {string}
442
+ */
443
+ self.LogPath = path;
444
+
445
+ /**
446
+ * Flag to enable or disable logging.
447
+ * @type {boolean}
448
+ */
449
+ self.LoggingFlag = loggingFlag;
450
+
451
+ /**
452
+ * object used to write logs.
453
+ * @type {Logger}
454
+ */
455
+ self.Logger = new Logger(this.LogPath,this.LoggingFlag)
456
+
457
+ /**
458
+ * variable to be passed to make channel run in lite mode.
459
+ * @type {string}
460
+ */
461
+ self.LiteMode = "lit"
462
+ AccessToken = Token;
463
+ HSMToken = decodeJWTAndExtractHSMKey(AccessToken,self.Logger);
464
+
465
+ /**
466
+ * saves the final onopen function after adding necessary changes to callback function provided by user.
467
+ * @type {Function}
468
+ */
469
+ self.socketonOpen = undefined;
470
+
471
+ /**
472
+ * saves the final onmessage function after adding necessary changes to callback function provided by user.
473
+ * @type {Function}
474
+ */
475
+ self.onticks = undefined;
476
+
477
+ /**
478
+ * saves the final onerror function after adding necessary changes to callback function provided by user.
479
+ * @type {Function}
480
+ */
481
+ self.socketonerror = undefined;
482
+
483
+ /**
484
+ * saves the final onclose function after adding necessary changes to callback function provided by user.
485
+ * @type {Function}
486
+ */
487
+ self.socketonclose = undefined;
488
+
489
+ /**
490
+ * saves the raw on message function provided by user.
491
+ * @type {Function}
492
+ */
493
+ self.callbackfunction = function (message) { console.log({ "SocketMessage": message }) };
494
+
495
+ //resets second counter every second.
496
+ self.secondcountertimer= setInterval(() => {
497
+ secondcounter = 0;
498
+ }, 1000);
499
+
500
+ /**
501
+ * saves set interval timer that runs pushing data out of the queue(wont push data out if ratelimit is breached) to send it to socket.
502
+ * @type {NodeJS.Timer}
503
+ */
504
+ self.interval = undefined
505
+
506
+ /**
507
+ * saves set interval timer that runs autoreconnect mechanism in case user has enabled auto reconnect.
508
+ * @type {NodeJS.Timer}
509
+ */
510
+ self.autreconnecttimer = undefined
511
+
512
+ self.autoreconnectflag = false
513
+
514
+ self.isUserClosed = false
515
+
516
+ DataSocket.instance = this;
517
+ }
518
+ /**
519
+ * @returns {DataSocket}
520
+ */
521
+
522
+ static getInstance(Token,path,loggingFlag=true) {
523
+ if (!DataSocket.instance) {
524
+ DataSocket.instance = new DataSocket(Token,path,loggingFlag);
525
+
526
+ }
527
+ return DataSocket.instance;
528
+ }
529
+
530
+ /**
531
+ * pushes data out of queue.
532
+ * @returns {Promise<void>} - A promise that resolves when data is recieved from queue.
533
+ */
534
+ async[_receiver]() {
535
+ const data = await queue.receive();
536
+ return data
537
+ }
538
+
539
+ /**
540
+ * interval variable of class runs this function to send data to socket that is pushed out of queue.
541
+ */
542
+ [_recurssivesend]() {
543
+ const funcname = "recurssivesend"
544
+ const logger = this.Logger
545
+ try {
546
+ if (secondcounter > 10 || !(hsSocket.isConnected())) {//if second ratelimit is breached
547
+ return
548
+ } else {
549
+ this[_receiver]().then(async (response) => {//pushes data out of queue and recieves
550
+ if (response === undefined) {
551
+ return
552
+ } else {
553
+ if (response.constructor === Array) {//if pushed data is array iterate over array and send over socket(some request grouped as array to stop race condition as whenever subscribed to a new channel it is resumed and rest of channels are paused multiple subscribe or unsubscibe at a time raised resuming of unrequired channel)
554
+ response.forEach(async element => {
555
+ if (element.type === 'ifs' || element.type === 'ifu' || element.type === 'mws' || element.type === 'mwu' || element.type === 'dps' || element.type === 'dpu') {//whenever any subscribe unsubscribe request made make its channel as current channel
556
+ currentchannel = element.channelnum
557
+ }
558
+ await this.waitFor(500)
559
+ hsSocket.send(JSON.stringify(element))
560
+ secondcounter++
561
+ });
562
+ }
563
+ else {
564
+ if (response.type === 'ifs' || response.type === 'ifu' || response.type === 'mws' || response.type === 'mwu' || response.type === 'dps' || response.type === 'dpu') {//whenever any subscribe unsubscribe request made make its channel as current channel
565
+ currentchannel = response.channelnum
566
+ }
567
+ await this.waitFor(500)
568
+ hsSocket.send(JSON.stringify(response))
569
+ secondcounter++
570
+ }
571
+ }
572
+ });
573
+ }
574
+ }
575
+ catch (error) {
576
+ logger.error("error in recurrsivefunction", error, funcname)
577
+ }
578
+ }
579
+
580
+ waitFor = function wait(ms){
581
+ return new Promise(resolve => {
582
+ setTimeout(resolve, ms);
583
+ });
584
+ }
585
+
586
+ /**
587
+ * used to define onmessage,onerror,onopen,onclose for websocket.
588
+ * @param {string} onwhat - defines for what the callback function is.
589
+ * @param {Function} callback - the callback function.
590
+ * @throws error message if onwhat is not valid.
591
+ */
592
+ on = function (onwhat, callback) {
593
+ const funcname = "on"
594
+ const logger = this.Logger
595
+ try {
596
+ var que = queue
597
+ if (onwhat === "connect") {
598
+ var akstkn = HSMToken
599
+ this.socketonOpen = function () {
600
+ reconnectiontries = 0 //resets reconnection count if reconnected
601
+ que.send({ "type": "cn", "sessionid": akstkn, "mode": "P" })//sends message on queue to authorize user
602
+ callback()
603
+ }
604
+ hsSocket.onOpen = this.socketonOpen//set classes socketonOpen varibale to hssocket.onOpen
605
+ }
606
+ else if (onwhat === "message") {
607
+
608
+ this.callbackfunction = callback
609
+ var errorcallback = this.socketonerror
610
+ this.onticks = function (message) {
611
+ try {
612
+ var Objmessage = JSON.parse(message, reviver) // parses incoming data as object
613
+ logger.debug("HSM raw data", Objmessage, "conversion")
614
+ Objmessage.forEach(function (element) {
615
+ if (element.stat === undefined) {
616
+ if (element.tk != "") {
617
+ delete element.ts // deleteing symbol provided by HSM as we are mapping our own format symbol
618
+ fulldata[element.tk][element.name] = Object.assign({}, fulldata[element.tk][element.name], element)//updates data to fulldata variable which has full tick data stored in memory
619
+ var ouptput_to_be_sent = Mapper(fulldata[element.tk][element.name], litemodestatus[currentchannel])//Maps data from HSM format to our format and format data according to full/lite mode
620
+ callback(ouptput_to_be_sent)
621
+ }
622
+ } else {
623
+
624
+ var returnmessage = Mapper(JSON.parse(message)[0], litemodestatus[currentchannel])//format success/error response to our format from HSM
625
+ if (returnmessage["s"] === 'Ok') {
626
+ returnmessage["s"] = 'ok'
627
+ callback(returnmessage)
628
+ } else {
629
+ returnmessage["s"] = 'error'
630
+ errorcallback(returnmessage)
631
+ return
632
+ }
633
+ }
634
+ })
635
+
636
+ } catch (error) {
637
+ logger.error("error converting message", {"error":error}, "conversion")
638
+ }
639
+ }
640
+ hsSocket.onMessage = this.onticks
641
+ }
642
+ else if (onwhat === "error") {
643
+ this.socketonerror = function (message) {
644
+ callback(message)
645
+ }
646
+ hsSocket.onError = this.socketonerror
647
+ }
648
+ else if (onwhat === "close") {
649
+ this.socketonclose = function () {
650
+ callback()
651
+ clearInterval(DataSocket.instance.interval)
652
+ if(!DataSocket.instance.isUserClosed && (reconnectiontries < maxreconnectiontries)){
653
+ DataSocket.instance._autoreconnect()
654
+ }else{
655
+ clearInterval(DataSocket.instance.secondcountertimer)
656
+ }
657
+ }
658
+ hsSocket.onClose = this.socketonclose
659
+ }
660
+ else {
661
+ console.error("invalid parameter:", onwhat)
662
+ logger.error("invalid parameter:", { "input": onwhat }, funcname)
663
+ }
664
+ }
665
+ catch (error) {
666
+ logger.error("error in on function", error, funcname)
667
+ }
668
+ }
669
+
670
+ /**
671
+ * called to connect to the data socket
672
+ */
673
+ connect = function () {
674
+ const funcname = "connect"
675
+ const logger = this.Logger
676
+ try {
677
+ this.interval = setInterval(() => {//start [_recurssivesend] function to get data from queue and send to websocket
678
+ this[_recurssivesend]();
679
+ }, 1);
680
+ var akstkn = this.HSMToken
681
+ var que = queue
682
+ if (this.socketonOpen === undefined) {//default callback function incase not passed by user
683
+ hsSocket.onOpen = function () {
684
+ console.log("connected")
685
+ reconnectiontries = 0
686
+ que.send({ "type": "cn", "sessionid": akstkn, "mode": "P" })
687
+ }
688
+ this.socketonOpen = hsSocket.onOpen
689
+ } else {
690
+ hsSocket.onOpen = this.socketonOpen
691
+ }
692
+
693
+ if (this.onticks === undefined) {//default callback function incase not passed by user
694
+ hsSocket.onMessage = function (message) {
695
+ var Objmessage = JSON.parse(message, reviver)
696
+ Objmessage.forEach(function (element) {
697
+ if (element.stat === undefined) {
698
+ delete element.ts
699
+ fulldata[element.tk][element.name] = Object.assign({}, fulldata[element.tk][element.name], element)
700
+
701
+ var ouptput_to_be_sent = Mapper(fulldata[element.tk][element.name], litemodestatus[currentchannel])
702
+ console.log({ "SocketMessage": ouptput_to_be_sent })
703
+
704
+ } else {
705
+ var returnmessage = [Mapper(JSON.parse(message)[0], litemodestatus[currentchannel])]
706
+ if (returnmessage[0]["s"] === 'Ok') {
707
+ returnmessage[0]["s"] = 'ok'
708
+ console.log({ "SocketMessage": returnmessage })
709
+ } else {
710
+ returnmessage[0]["s"] = 'error'
711
+ console.log({ "SocketMessage": returnmessage })
712
+ return
713
+ }
714
+ }
715
+ })
716
+ }
717
+ } else {
718
+ hsSocket.onMessage = this.onticks
719
+ }
720
+
721
+ if (this.socketonclose === undefined) {//default callback function incase not passed by user
722
+ hsSocket.onClose = function () {
723
+ clearInterval(DataSocket.instance.interval);
724
+ console.log("ws closed")
725
+ if(!DataSocket.instance.isUserClosed && (reconnectiontries < maxreconnectiontries)){
726
+ DataSocket.instance._autoreconnect()
727
+ }else{
728
+ clearInterval(DataSocket.instance.secondcountertimer)
729
+ }
730
+ }
731
+ this.socketonclose = hsSocket.onClose
732
+ } else {
733
+ hsSocket.onClose = this.socketonclose
734
+ }
735
+ if (this.socketonerror === undefined) {//default callback function incase not passed by user
736
+ hsSocket.onError = function (message) {
737
+ console.log("error occoured")
738
+ if (message != undefined) {
739
+ console.log({ "Socketerror": message })
740
+ }
741
+ }
742
+ this.socketonerror = hsSocket.onError
743
+ } else {
744
+ hsSocket.onError = this.socketonerror
745
+ }
746
+ hsSocket.connect(wsURL); //connects to websocket
747
+ }
748
+ catch (error) {
749
+ logger.error(("error in on connect function", error, funcname))
750
+ }
751
+ }
752
+
753
+ /**
754
+ * Subscribe to a symbol.
755
+ * @param {Array} req - array of symbols to subscribe to.
756
+ * @param {Boolean} [depth=false] - true if you want to subscribe for marketdepth data do not pass it true for index as they dont have marketdepth data.
757
+ * @param {Number} [channelnumber=11] - Channel you want to subscribe on(Warning do not pass any value for this if you dont know the significance).
758
+ */
759
+ subscribe = async (req, depth = false, channelnumber = 11) => {
760
+ const funcname = "subscribe"
761
+ const logger = this.Logger
762
+ try {
763
+ var callback = this.socketonerror
764
+ if (channelnumber <= 0 || channelnumber > 30) {
765
+ callback({ "code": -99, "type": "sub", "message": "channel can be in range 1 to 30", "s": "error" })//sends this on error callback
766
+ logger.error("channel passed out of range", { "code": -99, "type": "sub", "message": "channel can be in range 1 to 30", "s": "error" }, funcname)
767
+ return
768
+ }
769
+ var subscribeCountOverAllChannels = countValues(symbolcounter)
770
+ if (req.length + subscribeCountOverAllChannels > 5000) {
771
+ logger.error("symbol limit passed", { "code": -351, "type": "sub", "message": `subscription limit exceeding you have ${5000 - subscribeCountOverAllChannels} ws subscription left across all channels`, "s": "error" }, funcname)
772
+ callback({ "code": -351, "type": "sub", "message": `subscription limit exceeding you have ${5000 - subscribeCountOverAllChannels} ws subscription left across all channels`, "s": "error", "count": 5000 - subscribeCountOverAllChannels })
773
+ return
774
+ }
775
+ var alreadySubscribedCount = symbolcounter["if"][channelnumber].length + symbolcounter["dp"][channelnumber].length + symbolcounter["sf"][channelnumber].length
776
+ if (req.length + alreadySubscribedCount > 5000) {
777
+ logger.error("symbol limit passed", { "code": -351, "type": "sub", "message": `subscription limit exceeding you have ${5000 - alreadySubscribedCount} ws subscription left`, "s": "error" }, funcname)
778
+ callback({ "code": -351, "type": "sub", "message": `subscription limit exceeding you have ${5000 - alreadySubscribedCount} ws subscription left`, "s": "error", "count": 5000 - alreadySubscribedCount })
779
+ return
780
+ }
781
+ var indexdata = []
782
+ var symboldata = []
783
+ const delay = ms => new Promise(resolve => setTimeout(resolve, ms))
784
+ if (hsSocket === undefined) {
785
+ await delay(1000)
786
+ } else if (!(hsSocket.isConnected())) {//waits in case socket is not open till very first subscribe call
787
+ await delay(1000)
788
+ }
789
+ if (hsSocket === undefined) {
790
+ callback({ "code": -99, "type": "sub", "message": "initalize the socket first", "s": "error" })
791
+ logger.error("socket not initalized", { "code": -99, "type": "sub", "message": "initalize the socket first", "s": "error" }, funcname)
792
+ return
793
+ } else if (!(hsSocket.isConnected())) {
794
+ logger.error("socket is disconnected", { "code": -99, "type": "sub", "message": "socket is disconnected", "s": "error" }, funcname)
795
+ callback({ "code": -99, "type": "sub", "message": "socket is disconnected", "s": "error" })
796
+ return
797
+ }
798
+
799
+ var AuthrizationToken = AccessToken
800
+ var splitlist = splitArray(req, 500)
801
+ var bodies = []
802
+ splitlist.forEach(element=>{
803
+ var body = {
804
+ "symbols":element
805
+ }
806
+ bodies.push(body)
807
+ })
808
+
809
+ const url = "https://api-t1.fyers.in/data/symbol-token"
810
+ var symboltokenmap = await getFyToken(url, AuthrizationToken, bodies , logger, callback)
811
+
812
+ for (const [key, value] of Object.entries(symboltokenmap)) {
813
+ if(value==undefined){
814
+ continue;
815
+ }
816
+ var splitkey = key.split('-')
817
+ if (splitkey[splitkey.length - 1] === "INDEX") {
818
+ var instrexg = value.slice(0, 4)//take exchange and segment from fytoken
819
+ var exch = exchmapping[instrexg]//decide exchange name according to HSM based on exchange & segment
820
+ var exchangetoken = mapdata["index_dict"][key]//take symbol name for index required by HSM from our own symbol ticker
821
+ var scripvalue = exch + '|' + exchangetoken
822
+ if (exchangetoken === undefined) {
823
+ callback({ "code": -15, "type": "sub", "message": "Please provide valid symbol", "s": "error", "symbol": key })
824
+ logger.error("map key not found for index", { "symbol": key }, funcname)
825
+ } else {
826
+ if (depth) {
827
+ callback({ "code": -99, "type": "sub", "message": "Index dont have marketdepth", "s": "error" })
828
+ logger.error("map key not found for index", { "code": -99, "type": "sub", "message": "Index dont have marketdepth", "s": "error" }, funcname)
829
+ } else {
830
+ if (fulldata[exchangetoken] === undefined) {
831
+ fulldata[exchangetoken] = {}
832
+ }
833
+ if (fulldata[exchangetoken]['if'] === undefined) {
834
+ fulldata[exchangetoken]['if'] = { 'symbol': key }
835
+ }
836
+ if (fulldata[exchangetoken]['if']['symbol'] === undefined) {
837
+ fulldata[exchangetoken]['if']['symbol'] = key
838
+ }
839
+ indexdata.push(scripvalue)//push data to indexdata array
840
+ symbolcounter["if"][channelnumber] = appendToList(symbolcounter["if"][channelnumber], exchangetoken)//add to symbol counter
841
+ }
842
+ }
843
+ } else {
844
+ var exchangetoken = value.substring(10);//take exchange token from fytoken
845
+ var instrexg = value.slice(0, 4)// taking exchange & segment values from fytoken
846
+ var exch = exchmapping[instrexg]
847
+ var scripvalue = exch + '|' + exchangetoken
848
+ if (depth) {
849
+ var typeis = "dp"
850
+ // make mapping in fulldata
851
+ if (fulldata[exchangetoken] === undefined) {
852
+ fulldata[exchangetoken] = {}
853
+ }
854
+ if (fulldata[exchangetoken][typeis] === undefined) {
855
+ fulldata[exchangetoken][typeis] = { 'symbol': key }
856
+ }
857
+ if (fulldata[exchangetoken][typeis]['symbol'] === undefined) {
858
+ fulldata[exchangetoken][typeis]['symbol'] = key
859
+ }
860
+ } else {
861
+ var typeis = "sf"
862
+ if (fulldata[exchangetoken] === undefined) {
863
+ fulldata[exchangetoken] = {}
864
+ }
865
+ if (fulldata[exchangetoken][typeis] === undefined) {
866
+ fulldata[exchangetoken][typeis] = { 'symbol': key }
867
+ }
868
+ if (fulldata[exchangetoken][typeis]['symbol'] === undefined) {
869
+ fulldata[exchangetoken][typeis]['symbol'] = key
870
+ }
871
+ }
872
+ symboldata.push(scripvalue)//push to symbol data
873
+ //adding to symbol counter to know how many symbols are subscribed on each channel for each type that is index/depth/regular&FNO
874
+ symbolcounter[typeis][channelnumber] = appendToList(symbolcounter[typeis][channelnumber], exchangetoken)
875
+ }
876
+ }
877
+ var requests = []
878
+ //if there is any index to subscribe to
879
+ if (indexdata.length != 0) {
880
+ //split array bigger than length 1500 into array of length 1500
881
+ const splitindexdata = splitArray(indexdata, 1500)
882
+ splitindexdata.forEach(element => {
883
+ var scripstring = ""
884
+ element.forEach(subelement => {
885
+ //making & seperated string of symbols to send on socket
886
+ scripstring = scripstring + subelement + "&"
887
+ });
888
+ scripstring = scripstring.slice(0, -1)
889
+ //push it to the queue to be sent to socket
890
+ requests.push({
891
+ "type": "ifs",
892
+ "scrips": scripstring,
893
+ "channelnum": channelnumber
894
+ })
895
+ });
896
+ }
897
+ //if there is any stock or FNO to subscribe to
898
+ if (symboldata.length != 0) {
899
+ //split array bigger than length 1500 into array of length 1500
900
+ const splitsymboldata = splitArray(symboldata, 1500)
901
+ splitsymboldata.forEach(element => {
902
+ var scripstring = ""
903
+ element.forEach(subelement => {
904
+ //making & seperated string of symbols to send on socket
905
+ scripstring = scripstring + subelement + "&"
906
+ });
907
+ scripstring = scripstring.slice(0, -1)
908
+
909
+ if (depth) {
910
+ var typeval = "dps"
911
+ } else {
912
+ var typeval = "mws"
913
+ }
914
+ requests.push({
915
+ "type": typeval,
916
+ "scrips": scripstring,
917
+ "channelnum": channelnumber
918
+ })
919
+ });
920
+ }
921
+ //once all requests appended to requests array if there is a current channel change we send pause for every other channel and resume for current channel
922
+ if (requests.length != 0) {
923
+ var pauselist = returnstopchannelarray(channelnumber)
924
+ if (channelnumber != currentchannel) {
925
+ requests.push({
926
+ "type": "cp",
927
+ "channelnums": pauselist
928
+ })
929
+ requests.push({
930
+ "type": "cr",
931
+ "channelnums": [channelnumber]
932
+ })
933
+ }
934
+ //sending to queue as a array so one request is sent after another as a group on socket
935
+ queue.send(requests)
936
+ }
937
+ }
938
+ catch (error) {
939
+ logger.error("error in subscribe function", error, funcname)
940
+ }
941
+ }
942
+
943
+ /**
944
+ * Unsubscribe from a symbol(s).
945
+ * @param {Array} req - array of symbols to subscribe to.
946
+ * @param {Boolean} [depth=false] - true if you want to subscribe for marketdepth data do not pass it true for index as they dont have marketdepth data.
947
+ * @param {Number} [channelnumber=11] - Channel you want to subscribe on(Warning do not pass any value for this if you dont know the significance).
948
+ */
949
+ unsubscribe = async (req, depth = false, channelnumber = 11) => {
950
+ const funcname = "unsubscribe"
951
+ const logger = this.Logger
952
+ try {
953
+ var callback = this.socketonerror
954
+ if (channelnumber <= 0 || channelnumber > 30) {
955
+ callback({ "code": -99, "type": "sub", "message": "channel can be in range 1 to 30", "s": "error" })
956
+ logger.error("channel passed out of range", { "code": -99, "type": "sub", "message": "channel can be in range 1 to 30", "s": "error" }, funcname)
957
+ return
958
+ }
959
+ var indexdata = []
960
+ var symboldata = []
961
+ var delobj = []
962
+ if (hsSocket === undefined) {
963
+ callback({ "code": -99, "type": "sub", "message": "initalize the socket first", "s": "error" })
964
+ logger.error("socket not initalized", { "code": -99, "type": "sub", "message": "initalize the socket first", "s": "error" }, funcname)
965
+ return
966
+ }
967
+ else if (!(hsSocket.isConnected())) {
968
+ callback({ "code": -99, "type": "sub", "message": "socket is disconnected", "s": "error" })
969
+ logger.error("socket is disconnected", { "code": -99, "type": "sub", "message": "socket is disconnected", "s": "error" }, funcname)
970
+ return
971
+ }
972
+ var AuthrizationToken = AccessToken
973
+ var splitlist = splitArray(req, 500)
974
+ var bodies = []
975
+
976
+ splitlist.forEach(element=>{
977
+ var body = {
978
+ "symbols":element
979
+ }
980
+ bodies.push(body)
981
+ })
982
+
983
+ const url = "https://api-t1.fyers.in/data/symbol-token"
984
+ var symboltokenmap = await getFyToken(url, AuthrizationToken, bodies , logger, callback)
985
+ for (const [key, value] of Object.entries(symboltokenmap)) {
986
+ if(value==undefined){
987
+ continue;
988
+ }
989
+ var splitkey = key.split('-')
990
+ if (splitkey[splitkey.length - 1] === "INDEX") {
991
+ //getting exchange and segement from fytoken and deciding its values as required by HSM
992
+ var instrexg = value.slice(0, 4)
993
+ var exch = exchmapping[instrexg]
994
+ //getting index name in format as required by HSM
995
+ var exchangetoken = mapdata["index_dict"][key]
996
+ var scripvalue = exch + '|' + exchangetoken
997
+ if (exchangetoken === undefined) {
998
+ callback({ "code": -15, "type": "sub", "message": "Please provide valid symbol", "s": "error", "symbol": key })
999
+ logger.error("map key not found for index", { "symbol": key }, funcname)
1000
+ } else {
1001
+ if (depth) {
1002
+ callback({ "code": -99, "type": "sub", "message": "Index dont have marketdepth", "s": "error" })
1003
+ logger.error("map key not found for index", { "code": -99, "type": "sub", "message": "Index dont have marketdepth", "s": "error" }, funcname)
1004
+ } else {
1005
+ var delval = "if"
1006
+ indexdata.push(scripvalue)
1007
+ delobj.push({ "exchangetoken": exchangetoken, "delval": delval })
1008
+ }
1009
+ }
1010
+ } else {
1011
+ if (depth) {
1012
+ var delval = "dp"
1013
+ } else {
1014
+ var delval = "sf"
1015
+ }
1016
+ //getting exchange token from fytoken
1017
+ var exchangetoken = value.substring(10);
1018
+ var instrexg = value.slice(0, 4)
1019
+ var exch = exchmapping[instrexg]
1020
+ var scripvalue = exch + '|' + exchangetoken
1021
+ symboldata.push(scripvalue)
1022
+ delobj.push({ "exchangetoken": exchangetoken, "delval": delval })
1023
+ }
1024
+ }
1025
+
1026
+ var requests = []
1027
+ if (indexdata.length != 0) {
1028
+ // splitting requested array into sub array of length 1500
1029
+ const splitindexdata = splitArray(indexdata, 1500)
1030
+ splitindexdata.forEach(element => {
1031
+ var scripstring = ""
1032
+ element.forEach(subelement => {
1033
+ //making & seperated string of scrips
1034
+ scripstring = scripstring + subelement + "&"
1035
+ });
1036
+ scripstring = scripstring.slice(0, -1)
1037
+ requests.push({
1038
+ "type": "ifu",
1039
+ "scrips": scripstring,
1040
+ "channelnum": channelnumber
1041
+ })
1042
+ });
1043
+ }
1044
+
1045
+ if (symboldata.length != 0) {
1046
+ const splitsymboldata = splitArray(symboldata, 1500)
1047
+
1048
+ splitsymboldata.forEach(element => {
1049
+ var scripstring = ""
1050
+ element.forEach(subelement => {
1051
+ scripstring = scripstring + subelement + "&"
1052
+ });
1053
+ scripstring = scripstring.slice(0, -1)
1054
+ if (depth) {
1055
+ var typeval = "dpu"
1056
+ } else {
1057
+ var typeval = "mwu"
1058
+ }
1059
+ requests.push({
1060
+ "type": typeval,
1061
+ "scrips": scripstring,
1062
+ "channelnum": channelnumber
1063
+ })
1064
+ });
1065
+ }
1066
+
1067
+ //once all requests appended to requests array if there is a current channel change we send pause for every other channel and resume for current channel
1068
+ if (requests.length != 0) {
1069
+ var pauselist = returnstopchannelarray(channelnumber)
1070
+ if (channelnumber != currentchannel) {
1071
+ //channel pause request
1072
+ requests.push({
1073
+ "type": "cp",
1074
+ "channelnums": pauselist
1075
+ })
1076
+ //channel resume request
1077
+ requests.push({
1078
+ "type": "cr",
1079
+ "channelnums": [channelnumber]
1080
+ })
1081
+ }
1082
+ //sending to queue as a array so one request is sent after another as a group on socket
1083
+ queue.send(requests)
1084
+ }
1085
+
1086
+ //deletes data stored in memory if it is unsubscribed and not subscribed on any other channel
1087
+ if (delobj.length != 0) {
1088
+ delobj.forEach(element => {
1089
+ if (!(fulldata[element.exchangetoken] === undefined) && checkValueInLists(symbolcounter[delval], element.exchangetoken)) {
1090
+ delete fulldata[element.exchangetoken][element.delval]
1091
+ }
1092
+ symbolcounter[delval][channelnumber] = returnstopchannelarray(element.exchangetoken, symbolcounter[delval][channelnumber])
1093
+ })
1094
+ }
1095
+ }
1096
+ catch (error) {
1097
+ logger.error("error in unsubscribe function", error, funcname)
1098
+ }
1099
+ }
1100
+
1101
+ /**
1102
+ * call to close the datasocket.
1103
+ */
1104
+ close = function () {
1105
+ const funcname = "close"
1106
+ const logger = this.Logger
1107
+ try {
1108
+ if (hsSocket === undefined) {
1109
+ console.log("socket already closed")
1110
+ return
1111
+ } else if (!(hsSocket.isConnected())) {
1112
+ console.log("socket already closed")
1113
+ return
1114
+ } else {
1115
+ //stop autoreconnection
1116
+ clearInterval(this.autreconnecttimer)
1117
+ clearInterval(this.interval)
1118
+ clearInterval(this.secondcountertimer)
1119
+
1120
+ this.isUserClosed = true
1121
+
1122
+ hsSocket.close();
1123
+ // clears inmemory socket data stored
1124
+ fulldata = {}
1125
+ //clears queue so incase socket resumed by user queue is cleared
1126
+ queue.clear()
1127
+ logger.debug("socket closed by function", {}, funcname)
1128
+ }
1129
+ }
1130
+ catch (error) {
1131
+ logger.error("error in close function", error, funcname)
1132
+ }
1133
+ }
1134
+
1135
+ /**
1136
+ * call to check if datasocket is connected
1137
+ */
1138
+ isConnected = function () {
1139
+ if (hsSocket === undefined) {
1140
+ return false
1141
+ } else if (!(hsSocket.isConnected())) {
1142
+ return false
1143
+ } else {
1144
+ return true
1145
+ }
1146
+ }
1147
+
1148
+ /**
1149
+ * call to resume a channel pauses all other channel
1150
+ * @param {Number} channelnum - channel number you want to resume.
1151
+ */
1152
+ channelresume = function (channelnum) {
1153
+ const funcname = "channelresume"
1154
+ const logger = this.Logger
1155
+ try {
1156
+ if (channelnum.constructor === Number) {
1157
+ if (channel > 30 || channel < 1) {
1158
+ console.log("channel out of range channel should be between 1 and 30")
1159
+ logger.error("channel out of range channel should be between 1 and 30", null, funcname)
1160
+ return
1161
+ }
1162
+ var pauselist = returnstopchannelarray(channelnum)
1163
+ queue.send([{
1164
+ "type": "cp",
1165
+ "channelnums": pauselist
1166
+ }, {
1167
+ "type": "cr",
1168
+ "channelnums": [channelnum]
1169
+ }])
1170
+ } else {
1171
+ console.log("pass channel as a number")
1172
+ }
1173
+ }
1174
+ catch (error) {
1175
+ logger.error("error in channelresume function", error, funcname)
1176
+ }
1177
+ }
1178
+
1179
+ /**
1180
+ * call to set channel to full mode or lite mode
1181
+ * @param {string} modestring - The value parameter that can be either object.FullMode or object.LiteMode.
1182
+ * @param {Number|Number[]} channel - channel number you want to set mode for as a number or array of numbers.
1183
+ */
1184
+ mode = function (modestring, channel = 11) {
1185
+ const funcname = "mode"
1186
+ const logger = this.Logger
1187
+ try {
1188
+ if (channel.constructor === Array) {
1189
+ channel.forEach(element => {
1190
+ if (element > 30 || element < 1) {
1191
+ console.log("channel out of range channel should be between 1 and 30")
1192
+ logger.error("channel out of range channel should be between 1 and 30", null, funcname)
1193
+ return
1194
+ }
1195
+ });
1196
+ queue.send({
1197
+ "type": modestring,
1198
+ "channelnums": channel
1199
+ })
1200
+ if (modestring === "lit") {
1201
+ channel.forEach(element => {
1202
+ litemodestatus[element] = true
1203
+ });
1204
+ } else {
1205
+ channel.forEach(element => {
1206
+ litemodestatus[element] = false
1207
+ });
1208
+ }
1209
+ } else if (channel.constructor === Number) {
1210
+ if (channel > 30 || channel < 1) {
1211
+ console.log("channel out of range channel should be between 1 and 30")
1212
+ logger.error("channel out of range channel should be between 1 and 30", null, funcname)
1213
+ return
1214
+ }
1215
+ queue.send({
1216
+ "type": modestring,
1217
+ "channelnums": [channel]
1218
+ })
1219
+ if (modestring === "lit") {
1220
+ litemodestatus[channel] = true
1221
+ } else {
1222
+ litemodestatus[channel] = false
1223
+ }
1224
+ } else {
1225
+ console.log("please pass channel as number or array of numbers")
1226
+ logger.error("please pass channel as number or array of numbers", null, funcname)
1227
+ }
1228
+ }
1229
+ catch (error) {
1230
+ logger.error("error in mode function", error, funcname)
1231
+ }
1232
+ }
1233
+
1234
+ /**
1235
+ * call to enable autoreconnect functionality of websocket.
1236
+ */
1237
+ _autoreconnect = function(){
1238
+ const funcname = "autoreconnect"
1239
+ const logger = this.Logger
1240
+ if (this.autoreconnectflag){
1241
+ var waitSeconds = Math.floor((reconnectiontries+5)/5);
1242
+ waitSeconds *= 5;
1243
+
1244
+ try {
1245
+ this.autreconnecttimer = setTimeout(() => {
1246
+ if ((!(hsSocket.isConnected())) && (reconnectiontries < maxreconnectiontries)) {
1247
+ console.log("trying to reconnect ", reconnectiontries + 1)
1248
+ reconnectiontries++;
1249
+ symbolcounter = {
1250
+ "if": { 1: [], 2: [], 3: [], 4: [], 5: [], 6: [], 7: [], 8: [], 9: [], 10: [], 11: [], 12: [], 13: [], 14: [], 15: [], 16: [], 17: [], 18: [], 19: [], 20: [], 21: [], 22: [], 23: [], 24: [], 25: [], 26: [], 27: [], 28: [], 29: [], 30: [] },
1251
+ "sf": { 1: [], 2: [], 3: [], 4: [], 5: [], 6: [], 7: [], 8: [], 9: [], 10: [], 11: [], 12: [], 13: [], 14: [], 15: [], 16: [], 17: [], 18: [], 19: [], 20: [], 21: [], 22: [], 23: [], 24: [], 25: [], 26: [], 27: [], 28: [], 29: [], 30: [] },
1252
+ "dp": { 1: [], 2: [], 3: [], 4: [], 5: [], 6: [], 7: [], 8: [], 9: [], 10: [], 11: [], 12: [], 13: [], 14: [], 15: [], 16: [], 17: [], 18: [], 19: [], 20: [], 21: [], 22: [], 23: [], 24: [], 25: [], 26: [], 27: [], 28: [], 29: [], 30: [] }
1253
+ };
1254
+ this.connect()
1255
+ } else if (reconnectiontries >= maxreconnectiontries) {
1256
+ console.log("max autoconnect tries exceeded")
1257
+ reconnectiontries = 0
1258
+ }
1259
+ }, (waitSeconds)*1000);
1260
+ }
1261
+ catch (error) {
1262
+ logger.error("error in autoreconnect function", error, funcname)
1263
+ }
1264
+ }
1265
+ }
1266
+
1267
+ autoreconnect=function(reConnectTriesCount=5){
1268
+ this.autoreconnectflag=true
1269
+ maxreconnectiontries = (reConnectTriesCount>50) ? 50 : reConnectTriesCount
1270
+ }
1271
+ }
1272
+ return DataSocket
1273
+ })();
1274
+
1275
+
1276
+ module.exports = DataSocket