mind-client-js 0.20.0

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,789 @@
1
+ /*###############################################################
2
+ # #
3
+ # Copyright (c) 2025-2026 DnaSoft BV and/or its subsidiaries. #
4
+ # All rights reserved. #
5
+ # #
6
+ # This source code contains the intellectual property #
7
+ # of its copyright holder(s), and is made available #
8
+ # under a license. If you do not know the terms of #
9
+ # the license, please stop and do not read further. #
10
+ # #
11
+ ###############################################################*/
12
+ const errors = require("./errors")
13
+ const {size} = require("lodash")
14
+ const utils = require("./utils")
15
+
16
+ const noMoreHitsTimeout = 30
17
+
18
+ module.exports = {
19
+ create: async function (that, classModule, host, port, username, password, options) {
20
+ return new Promise(async (resolve, reject) => {
21
+ // regular sessions
22
+ for (let ix = 0; ix < that.size; ix++) {
23
+ const session = new classModule.exports.session
24
+
25
+ try {
26
+ await session.connect(host, port, username, password, options)
27
+
28
+ that.sessions.push({
29
+ session: session,
30
+ inUse: false,
31
+ isExtension: false
32
+ })
33
+
34
+ session.on('disconnect', function () {
35
+ for (let ix in that.sessions) {
36
+ if (that.sessions[ix].session.session.GUID === this.session.GUID) {
37
+ that.sessions.splice(ix, 1)
38
+ }
39
+ }
40
+
41
+ that.stats.remoteDisconnects++
42
+ that.size--
43
+ })
44
+
45
+ } catch (err) {
46
+ reject(err)
47
+
48
+ return
49
+ }
50
+ }
51
+
52
+ // devOps session
53
+ that.devOps.session = new classModule.exports.session
54
+
55
+ try {
56
+ await that.devOps.session.connect(host, port, username, password, options)
57
+ that.devOps.sessionInUse = true
58
+
59
+ Object.assign(that.devOps.session, {
60
+ done: function () {
61
+ that.devOps.sessionInUse = false
62
+ }
63
+ })
64
+
65
+ // initialize the pids and register the unique guid for this pool
66
+ that.guid = await that.devOps.session._staticPool._register(that)
67
+
68
+ // and make it read only
69
+ Object.defineProperties(that, {
70
+ guid: {
71
+ writable: false,
72
+ },
73
+ })
74
+
75
+ // flag the devOps session as not in use
76
+ that.devOps.sessionInUse = false
77
+
78
+ } catch (err) {
79
+ reject(err)
80
+
81
+ return
82
+ }
83
+
84
+ that.host = host
85
+ that.port = port
86
+ that.username = username
87
+ that.password = password
88
+ that.options = options
89
+
90
+ that.devOps.sessionInUse = false
91
+
92
+ resolve()
93
+ })
94
+ },
95
+
96
+ changeSize: function (that, classModule, newSize) {
97
+ return new Promise(async (resolve, reject) => {
98
+ if (that.sessions.length === 0) {
99
+ reject(new Error(errors.POOL_NOT_INITIALIZED + 'pool not initialized'))
100
+
101
+ return
102
+ }
103
+
104
+ if (typeof newSize !== 'number') {
105
+ reject(new Error(errors.PARAM_NOT_NUMBER + 'newSize must be a number'))
106
+
107
+ return
108
+ }
109
+
110
+ if (newSize < 2) {
111
+ reject(new Error(errors.POOL_SIZE_NOT_MIN_TWO + 'newSize must be greater than 1'))
112
+
113
+ return
114
+ }
115
+
116
+ if (newSize === that.size) {
117
+ reject(new Error(errors.POOL_NEWSIZE_SAME_AS_SIZE + 'the new size must be different than the current size'))
118
+
119
+ return
120
+ }
121
+
122
+ if (newSize > that.size) {
123
+ // we can extend the size, let's connect the new sessions
124
+ for (let ix = 0; ix < newSize - that.size; ix++) {
125
+ const session = new classModule.exports.session
126
+
127
+ try {
128
+ await session.connect(that.host, that.port, that.username, that.password, that.options)
129
+ that.sessions.push({
130
+ session: session,
131
+ inUse: false,
132
+ isExtension: false
133
+ })
134
+
135
+ session.on('disconnect', function () {
136
+ for (let ix in that.sessions) {
137
+ if (that.sessions[ix].session.session.GUID === this.session.GUID) {
138
+ that.sessions.splice(ix, 1)
139
+ }
140
+ }
141
+
142
+ that.stats.remoteDisconnects++
143
+ that.size--
144
+ })
145
+
146
+ } catch (err) {
147
+ reject(err)
148
+
149
+ return
150
+ }
151
+
152
+ }
153
+
154
+ // update size
155
+ that.size = newSize
156
+
157
+ resolve()
158
+
159
+ } else {
160
+ // we need to shrink
161
+ // we start allocating the sessions to be removed, then disconnect them and change the size
162
+ const freeSlots = that.sessions.filter(session => session.inUse === false)
163
+
164
+ // verify that there are enough sessions to be removed
165
+ if (newSize > freeSlots.length) {
166
+ reject(new Error(errors.POOL_TOO_MANY_SESSIONS_IN_USE + 'Can not shrink due to sessions in use'))
167
+
168
+ return
169
+ }
170
+
171
+ // lock up the free sessions to ensure nobody gets them while disconnecting
172
+ freeSlots.forEach(session => {
173
+ session.session.inUse = true
174
+ })
175
+
176
+ // disconnect them and remove them from the sessions array
177
+ let deleteCount = 0
178
+ let ix = that.sessions.length
179
+
180
+ while (ix--) {
181
+ if (that.sessions.sessionInUse === true) continue
182
+ if (deleteCount === that.size - newSize) break
183
+
184
+ deleteCount++
185
+
186
+ freeSlots[ix].session.disconnect()
187
+
188
+ that.sessions.splice(ix, 1)
189
+ }
190
+
191
+ // update size
192
+ that.size = newSize
193
+
194
+ resolve()
195
+ }
196
+ })
197
+ },
198
+
199
+ changeExtension: function (that, newSize) {
200
+ return new Promise(async (resolve, reject) => {
201
+ if (that.sessions.length === 0) {
202
+ reject(new Error(errors.POOL_NOT_INITIALIZED + 'pool not initialized'))
203
+
204
+ return
205
+ }
206
+
207
+ if (typeof newSize !== 'number') {
208
+ reject(new Error(errors.PARAM_NOT_NUMBER + 'newSize must be a number'))
209
+
210
+ return
211
+ }
212
+
213
+ if (newSize < 0) {
214
+ reject(new Error(errors.PARAM_NOT_ZERO_OR_GREATER + 'newSize must be equal or greater than 0'))
215
+
216
+ return
217
+ }
218
+
219
+ if (newSize === that.extension) {
220
+ reject(new Error(errors.POOL_NEWSIZE_SAME_AS_SIZE + 'the new size must be different than the current size'))
221
+
222
+ return
223
+ }
224
+
225
+ that.extension = newSize
226
+
227
+ resolve()
228
+
229
+ })
230
+ },
231
+
232
+ destroy: function (that) {
233
+ if (that.sessions.length === 0) {
234
+ throw new Error(errors.POOL_NOT_INITIALIZED + 'pool not initialized')
235
+ }
236
+
237
+ that.sessions.forEach(async session => session.session.disconnect())
238
+
239
+ that.devOps.session.disconnect()
240
+
241
+ that.sessions = []
242
+ },
243
+
244
+ rundown: async function (that) {
245
+ if (that.sessions.length === 0) {
246
+ throw new Error(errors.POOL_NOT_INITIALIZED + 'pool not initialized')
247
+ }
248
+
249
+ let session
250
+
251
+ try {
252
+ session = await that.devOps._getDevOpsSession()
253
+ await session._staticPool._rundown()
254
+
255
+ session.disconnect()
256
+
257
+ that.sessions = []
258
+
259
+ } catch (err) {
260
+ try {
261
+ session.done()
262
+ } catch (err) {
263
+ }
264
+
265
+ throw new Error(err.message)
266
+ }
267
+ },
268
+
269
+ getSession: async function (that, classModule, timeout) {
270
+ return new Promise(async (resolve, reject) => {
271
+ if (that.sessions.length === 0) {
272
+ reject(new Error(errors.POOL_NOT_INITIALIZED + 'pool not initialized'))
273
+
274
+ return
275
+ }
276
+
277
+ const freeSlotIx = that.sessions.findIndex(session => session.inUse === false && session.isExtension === false)
278
+ let hInterval = null
279
+
280
+ // can we get a normal session?
281
+ if (freeSlotIx > -1) {
282
+ that.sessions[freeSlotIx].inUse = true
283
+
284
+ Object.assign(that.sessions[freeSlotIx].session, {
285
+ that: that,
286
+ ix: freeSlotIx,
287
+ done: function () {
288
+ that.stats.sessionsDone++
289
+
290
+ that.sessions[this.ix].inUse = false
291
+ }
292
+ })
293
+
294
+ that.stats.sessionsCreatedOk++
295
+
296
+ const sessionsInUse = that.sessions.filter(session => session.inUse === true && session.isExtension === false)
297
+ if (sessionsInUse.length > that.stats.sessionsPeak) that.stats.sessionsPeak = sessionsInUse.length
298
+
299
+ that.hidePropsInObject(that.sessions[freeSlotIx])
300
+
301
+ resolve(that.sessions[freeSlotIx].session)
302
+
303
+ return
304
+ }
305
+
306
+ // can we extend?
307
+ if (that.extension > 0 && (that.extension - that.extensionInUse) > 0) {
308
+ const session = new classModule.exports.session
309
+
310
+ try {
311
+ await session.connect(that.host, that.port, that.username, that.password, that.options)
312
+
313
+ } catch (err) {
314
+ that.stats.extendsCreatedInError++
315
+
316
+ reject(err)
317
+
318
+ return
319
+ }
320
+
321
+ const newSession = {
322
+ session: session,
323
+ guid: session.session.GUID,
324
+ inUse: true,
325
+ isExtension: true
326
+ }
327
+
328
+ that.sessions.push(newSession)
329
+
330
+ that.stats.extendsCreatedOk++
331
+
332
+ const sessionsInUse = that.sessions.filter(session => session.inUse === true && session.isExtension === true)
333
+ if (sessionsInUse.length > that.stats.extendsPeak) that.stats.extendsPeak = sessionsInUse.length
334
+
335
+ Object.assign(newSession.session, {
336
+ that: that,
337
+ newSession: newSession,
338
+ done: function () {
339
+ const ix = that.sessions.findIndex(session => {
340
+ return session.session.session.GUID === this.newSession.session.session.GUID
341
+ })
342
+ that.sessions[ix].session.disconnect()
343
+
344
+ that.sessions.splice(ix, 1)
345
+
346
+ that.extensionInUse--
347
+
348
+ that.stats.extendsDone++
349
+
350
+ that.stats.extendsRemoved++
351
+ }
352
+ })
353
+
354
+ session.on('disconnect', function () {
355
+ this.that.sessions.splice(this.ix, 1)
356
+ that.stats.remoteDisconnects++
357
+ that.extensionInUse--
358
+ that.stats.extendsRemoved++
359
+ })
360
+
361
+ that.hidePropsInObject(newSession)
362
+
363
+ that.extensionInUse++
364
+
365
+ resolve(newSession.session)
366
+
367
+ return
368
+ }
369
+
370
+ that.stats.noMoreSlotsHits++
371
+ that.emit('noMoreSlotsHits')
372
+
373
+ that.timerTick -= false
374
+
375
+ // do we have a timeout?
376
+ let hTimeout = 0
377
+ if (timeout > 0) {
378
+ // setup main timer
379
+ hTimeout = setTimeout(async () => {
380
+ that.stats.timeoutExpired++
381
+ that.emit('timeoutExpired')
382
+
383
+ reject(new Error(errors.TIMEOUT_OCCURRED + 'timeout expired while trying to get a session'))
384
+
385
+ }, timeout)
386
+
387
+ }
388
+
389
+ hInterval = setInterval(async () => {
390
+ // is there a slot available?
391
+ if (that.timerTick === true) {
392
+ clearInterval(hInterval)
393
+ hInterval = null
394
+
395
+ return
396
+ }
397
+
398
+ const freeSlotIx = that.sessions.findIndex(session => session.inUse === false && session.isExtension === false)
399
+ //const freeSlots = that.sessions.filter(session => session.inUse === false)
400
+
401
+ if (freeSlotIx > -1) {
402
+ that.timerTick = true
403
+
404
+ clearTimeout(hTimeout)
405
+ clearInterval(hInterval)
406
+ hInterval = null
407
+
408
+ Object.assign(that.sessions[freeSlotIx].session, {
409
+ that: that,
410
+ ix: freeSlotIx,
411
+ done: function () {
412
+
413
+ that.stats.sessionsDone++
414
+
415
+ that.sessions[this.ix].inUse = false
416
+ }
417
+ })
418
+
419
+ that.hidePropsInObject(that.sessions[freeSlotIx])
420
+
421
+ that.sessions[freeSlotIx].inUse = true
422
+
423
+ that.stats.sessionsCreatedOk++
424
+ that.stats.noMoreSlotsHitsResolved++
425
+ that.emit('noMoreSlotsHitsResolved')
426
+
427
+ const sessionsInUse = that.sessions.filter(session => session.inUse === true && session.isExtension === false)
428
+ if (sessionsInUse.length > that.stats.sessionsPeak) that.stats.sessionsPeak = sessionsInUse.length
429
+
430
+ resolve(that.sessions[freeSlotIx].session)
431
+
432
+ return
433
+ }
434
+
435
+ // can we extend?
436
+ if (that.extension > 0 && (that.extension - that.extensionInUse) > 0) {
437
+ that.timerTick = true
438
+
439
+ clearTimeout(hTimeout)
440
+ clearInterval(hInterval)
441
+ hInterval = null
442
+
443
+ const session = new classModule.exports.session
444
+
445
+ try {
446
+ await session.connect(that.host, that.port, that.username, that.password, that.options)
447
+
448
+ } catch (err) {
449
+ that.stats.extendsCreatedInError++
450
+
451
+ reject(err)
452
+
453
+ return
454
+ }
455
+
456
+ const newSession = {
457
+ session: session,
458
+ guid: session.session.GUID,
459
+ inUse: true,
460
+ isExtension: true
461
+ }
462
+
463
+ that.sessions.push(newSession)
464
+
465
+ that.stats.extendsCreatedOk++
466
+ that.stats.noMoreSlotsHitsResolved++
467
+ that.eimt('noMoreSlotsHitsResolved')
468
+
469
+ const sessionsInUse = that.sessions.filter(session => session.inUse === true && session.isExtension === true)
470
+ if (sessionsInUse.length > that.stats.extendsPeak) that.stats.extendsPeak = sessionsInUse.length
471
+
472
+ Object.assign(newSession.session, {
473
+ that: that,
474
+ newSession: newSession,
475
+ done: function () {
476
+ const ix = that.sessions.findIndex(session => {
477
+ return session.session.session.GUID === this.newSession.session.session.GUID
478
+ })
479
+ that.sessions[ix].session.disconnect()
480
+
481
+ that.sessions.splice(ix, 1)
482
+
483
+ that.extensionInUse--
484
+
485
+ that.stats.extendsDone++
486
+
487
+ that.stats.extendsRemoved++
488
+ }
489
+ })
490
+
491
+ session.on('disconnect', function () {
492
+ this.that.sessions.splice(this.ix, 1)
493
+ that.stats.remoteDisconnects++
494
+ that.emit('remoteDisconnects')
495
+ that.extensionInUse--
496
+ that.stats.extendsRemoved++
497
+ })
498
+
499
+ that.hidePropsInObject(newSession)
500
+
501
+ that.extensionInUse++
502
+
503
+ resolve(newSession.session)
504
+ }
505
+ }, noMoreHitsTimeout)
506
+ })
507
+ },
508
+
509
+ getStatus: function (that, formatNumbers) {
510
+ const sessionsInUse = that.sessions.filter(session => session.inUse === true && session.isExtension === false)
511
+ const sessionsExtended = that.sessions.filter(session => session.isExtension === true && session.inUse === true)
512
+ const sessionsTotal = that.sessions.length
513
+ const extensions = that.extension
514
+ const size = that.size
515
+
516
+ return {
517
+ GUID: that.guid,
518
+ host: that.host,
519
+ port: that.port,
520
+ username: that.username,
521
+ options: that.options,
522
+ initialized: that.guid !== '',
523
+ size: size,
524
+ extensions: extensions,
525
+ sessionsTotal: sessionsTotal,
526
+ sessionsExtendedInUse: sessionsExtended.length,
527
+ sessionsInUse: sessionsInUse.length,
528
+ stats: formatNumbers === false
529
+ ? that.stats
530
+ : {
531
+ sessionsCreatedOk: utils.formatNumber(that.stats.sessionsCreatedOk),
532
+ sessionsCreatedInError: utils.formatNumber(that.stats.sessionsCreatedInError),
533
+ sessionsPeak: utils.formatNumber(that.stats.sessionsPeak),
534
+ sessionsDone: utils.formatNumber(that.stats.sessionsDone),
535
+ extendsCreatedOk: utils.formatNumber(that.stats.extendsCreatedOk),
536
+ extendsCreatedInError: utils.formatNumber(that.stats.extendsCreatedInError),
537
+ extendsRemoved: utils.formatNumber(that.stats.extendsRemoved),
538
+ extendsPeak: utils.formatNumber(that.stats.extendsPeak),
539
+ extendsDone: utils.formatNumber(that.stats.extendsDone),
540
+ noMoreSlotsHits: utils.formatNumber(that.stats.noMoreSlotsHits),
541
+ noMoreSlotsHitsResolved: utils.formatNumber(that.stats.noMoreSlotsHitsResolved),
542
+ timeoutExpired: utils.formatNumber(that.stats.timeoutExpired),
543
+ remoteDisconnects: utils.formatNumber(that.stats.remoteDisconnects),
544
+ }
545
+ }
546
+ },
547
+
548
+ resetStatus: function (that) {
549
+ that.stats.sessionsCreatedOk = 0
550
+ that.stats.sessionsCreatedInError = 0
551
+ that.stats.sessionsPeak = 0
552
+ that.stats.sessionsDone = 0
553
+
554
+ that.stats.extendsCreatedOk = 0
555
+ that.stats.extendsCreatedInError = 0
556
+ that.stats.extendsRemoved = 0
557
+ that.stats.extendsPeak = 0
558
+ that.stats.extendsDone = 0
559
+
560
+ that.stats.noMoreSlotsHits = 0
561
+ that.stats.noMoreSlotsHitsResolved = 0
562
+ that.stats.timeoutExpired = 0
563
+ that.stats.remoteDisconnects = 0
564
+ },
565
+
566
+ devOps: {
567
+ _getDevOpsSession: async function (that, timeout = 0) {
568
+ if (Object.keys(that.session).length === 0 || (that.session.loggedIn && that.session.loggedIn === false)) {
569
+ throw new Error(errors.POOL_NOT_INITIALIZED + 'pool not initialized')
570
+ }
571
+
572
+ if (that.sessionInUse === true) {
573
+ throw new Error(errors.POOL_DEVOPS_SESSION_IN_USE + 'devOps session inUse')
574
+ }
575
+
576
+ that.sessionInUse = true
577
+
578
+ return that.session
579
+ },
580
+
581
+ getServerStats: async function (that) {
582
+ if (Object.keys(that.session).length === 0 || (that.session.loggedIn && that.session.loggedIn === false)) {
583
+ throw new Error(errors.POOL_NOT_INITIALIZED + 'pool not initialized')
584
+ }
585
+
586
+ let session
587
+ try {
588
+ session = await that._getDevOpsSession()
589
+ const res = await session._staticPool._getPoolStats()
590
+
591
+ session.done()
592
+
593
+ return res
594
+
595
+ } catch (err) {
596
+ try {
597
+ session.done()
598
+ } catch (err) {
599
+ }
600
+
601
+ throw new Error(err.message)
602
+ }
603
+ },
604
+
605
+ setLogLevel: async function (that, logLevel) {
606
+ return new Promise(async (resolve, reject) => {
607
+ let session
608
+
609
+ try {
610
+ session = await that._getDevOpsSession()
611
+ await session._staticPool._changeServerSetting('logLevel', logLevel)
612
+
613
+ session.done()
614
+
615
+ resolve()
616
+
617
+ } catch (err) {
618
+ try {
619
+ session.done()
620
+ } catch (err) {
621
+ }
622
+
623
+ reject(err)
624
+ }
625
+ })
626
+ },
627
+
628
+ setDumpResponse: async function (that, value) {
629
+ return new Promise(async (resolve, reject) => {
630
+ let session
631
+
632
+ try {
633
+ session = await that._getDevOpsSession()
634
+ await session._staticPool._changeServerSetting('dumpResponse', value)
635
+
636
+ session.done()
637
+
638
+ resolve()
639
+
640
+ } catch (err) {
641
+ try {
642
+ session.done()
643
+ } catch (err) {
644
+ }
645
+
646
+ reject(err)
647
+ }
648
+ })
649
+ },
650
+
651
+ setDumpRequest: async function (that, value) {
652
+ return new Promise(async (resolve, reject) => {
653
+ let session
654
+
655
+ try {
656
+ session = await that._getDevOpsSession()
657
+ await session._staticPool._changeServerSetting('dumpRequest', value)
658
+
659
+ session.done()
660
+
661
+ resolve()
662
+
663
+ } catch (err) {
664
+ try {
665
+ session.done()
666
+ } catch (err) {
667
+ }
668
+
669
+ reject(err)
670
+ }
671
+ })
672
+ },
673
+
674
+ setStats: async function (that, value) {
675
+ return new Promise(async (resolve, reject) => {
676
+ let session
677
+
678
+ try {
679
+ session = await that._getDevOpsSession()
680
+ await session._staticPool._changeServerSetting('stats', value)
681
+
682
+ session.done()
683
+
684
+ resolve()
685
+
686
+ } catch (err) {
687
+ try {
688
+ session.done()
689
+ } catch (err) {
690
+ }
691
+
692
+ reject(err)
693
+ }
694
+ })
695
+ },
696
+
697
+ setErrorDump: async function (that, value) {
698
+ return new Promise(async (resolve, reject) => {
699
+ let session
700
+
701
+ try {
702
+ session = await that._getDevOpsSession()
703
+ await session._staticPool._changeServerSetting('errorDump', value)
704
+
705
+ session.done()
706
+
707
+ resolve()
708
+
709
+ } catch (err) {
710
+ try {
711
+ session.done()
712
+ } catch (err) {
713
+ }
714
+
715
+ reject(err)
716
+ }
717
+ })
718
+ },
719
+
720
+ setIdleTimeout: async function (that, timeout) {
721
+ return new Promise(async (resolve, reject) => {
722
+ let session
723
+
724
+ try {
725
+ session = await that._getDevOpsSession()
726
+ await session._staticPool._changeServerSetting('idleTimeout', timeout)
727
+
728
+ session.done()
729
+
730
+ resolve()
731
+
732
+ } catch (err) {
733
+ try {
734
+ session.done()
735
+ } catch (err) {
736
+ }
737
+
738
+ reject(err)
739
+ }
740
+ })
741
+ },
742
+
743
+ resetSettings: async function (that) {
744
+ return new Promise(async (resolve, reject) => {
745
+ let session
746
+
747
+ try {
748
+ session = await that._getDevOpsSession()
749
+ await session._staticPool._changeServerSetting('RESET_SETTINGS', 0)
750
+
751
+ session.done()
752
+
753
+ resolve()
754
+
755
+ } catch (err) {
756
+ try {
757
+ session.done()
758
+ } catch (err) {
759
+ }
760
+
761
+ reject(err)
762
+ }
763
+ })
764
+ },
765
+
766
+ resetServerStats: async function (that) {
767
+ return new Promise(async (resolve, reject) => {
768
+ let session
769
+
770
+ try {
771
+ session = await that._getDevOpsSession()
772
+ await session._staticPool._changeServerSetting('RESET_SERVER_STATS', 0)
773
+
774
+ session.done()
775
+
776
+ resolve()
777
+
778
+ } catch (err) {
779
+ try {
780
+ session.done()
781
+ } catch (err) {
782
+ }
783
+
784
+ reject(err)
785
+ }
786
+ })
787
+ }
788
+ }
789
+ }