@nxtedition/lib 15.0.22 → 15.0.24

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.
Files changed (3) hide show
  1. package/app.js +73 -84
  2. package/package.json +2 -1
  3. package/proxy.js +106 -0
package/app.js CHANGED
@@ -1,6 +1,5 @@
1
1
  const os = require('node:os')
2
2
  const net = require('node:net')
3
- const assert = require('node:assert')
4
3
  const stream = require('node:stream')
5
4
  const { Buffer } = require('node:buffer')
6
5
  const { getDockerSecretsSync } = require('./docker-secrets')
@@ -408,7 +407,6 @@ module.exports = function (appConfig, onTerminate) {
408
407
  if (appConfig.status) {
409
408
  const rxjs = require('rxjs')
410
409
  const rx = require('rxjs/operators')
411
- const undici = require('undici')
412
410
  const fp = require('lodash/fp')
413
411
  const hashString = require('./hash')
414
412
 
@@ -489,89 +487,80 @@ module.exports = function (appConfig, onTerminate) {
489
487
  )
490
488
  : rxjs.of({}),
491
489
  ds
492
- ? new rxjs.Observable((o) => {
493
- const client = new undici.Client(`http://${new URL(ds._url || ds.url).host}`, {
494
- keepAliveTimeout: 30e3,
495
- })
496
-
497
- const subscription = rxjs
498
- .timer(0, 10e3)
499
- .pipe(
500
- rx.exhaustMap(async () => {
501
- const messages = []
502
-
503
- if (ds.stats.record.records > 100e3) {
504
- messages.push({
505
- id: 'app:ds_record_records',
506
- level: 40,
507
- code: 'NXT_DEEPSTREAM_RECORDS_RECORDS',
508
- msg: 'ds: ' + ds.stats.record.records + ' records',
509
- })
510
- }
511
-
512
- if (ds.stats.record.pruning > 100e3) {
513
- messages.push({
514
- id: 'app:ds_record_pruning',
515
- level: 40,
516
- code: 'NXT_DEEPSTREAM_RECORDS_PRUNING',
517
- msg: 'ds: ' + ds.stats.record.pruning + ' pruning',
518
- })
519
- }
520
-
521
- if (ds.stats.record.pending > 10e3) {
522
- messages.push({
523
- id: 'app:ds_record_pending',
524
- level: 40,
525
- code: 'NXT_DEEPSTREAM_RECORDS_PENDING',
526
- msg: 'ds: ' + ds.stats.record.pending + ' pending',
527
- })
528
- }
529
-
530
- if (ds.stats.record.updating > 10e3) {
531
- messages.push({
532
- id: 'app:ds_record_updating',
533
- level: 40,
534
- code: 'NXT_DEEPSTREAM_RECORDS_UPDATING',
535
- msg: 'ds: ' + ds.stats.record.updating + ' updating',
536
- })
537
- }
538
-
539
- if (ds.stats.record.patching > 10e3) {
540
- messages.push({
541
- id: 'app:ds_record_patching',
542
- level: 40,
543
- code: 'NXT_DEEPSTREAM_RECORDS_PATCHING',
544
- msg: 'ds: ' + ds.stats.record.patching + ' patching',
545
- })
546
- }
547
-
548
- try {
549
- const { body, statusCode } = await client.request({
550
- method: 'GET',
551
- path: '/healthcheck',
552
- })
553
- await body.dump()
554
- assert(statusCode >= 200 && statusCode < 300)
555
- } catch (err) {
556
- messages.push({
557
- id: 'app:ds_http_connection',
490
+ ? rxjs.fromEvent(ds, 'connectionStateChanged').pipe(
491
+ rxjs.map((connectionState) =>
492
+ connectionState === 'OPEN'
493
+ ? [
494
+ {
495
+ id: 'app:ds_connection_state',
496
+ level: 30,
497
+ msg: 'ds: connected',
498
+ },
499
+ ]
500
+ : [
501
+ {
502
+ id: 'app:ds_connection_state',
558
503
  level: 40,
559
- code: err.code,
560
- msg: 'ds: ' + err.message,
561
- })
562
- }
563
-
564
- return messages
565
- }),
566
- )
567
- .subscribe(o)
568
-
569
- return () => {
570
- client.destroy()
571
- subscription.unsubscribe()
572
- }
573
- }).pipe(rx.startWith([]), rx.distinctUntilChanged(fp.isEqual))
574
- : rxjs.of({}),
504
+ msg: 'ds: connecting',
505
+ },
506
+ ],
507
+ ),
508
+ )
509
+ : rxjs.of([]),
510
+ ds
511
+ ? rxjs.timer(0, 10e3).pipe(
512
+ rx.exhaustMap(async () => {
513
+ const messages = []
514
+
515
+ if (ds.stats.record.records > 100e3) {
516
+ messages.push({
517
+ id: 'app:ds_record_records',
518
+ level: 40,
519
+ code: 'NXT_DEEPSTREAM_RECORDS_RECORDS',
520
+ msg: 'ds: ' + ds.stats.record.records + ' records',
521
+ })
522
+ }
523
+
524
+ if (ds.stats.record.pruning > 100e3) {
525
+ messages.push({
526
+ id: 'app:ds_record_pruning',
527
+ level: 40,
528
+ code: 'NXT_DEEPSTREAM_RECORDS_PRUNING',
529
+ msg: 'ds: ' + ds.stats.record.pruning + ' pruning',
530
+ })
531
+ }
532
+
533
+ if (ds.stats.record.pending > 10e3) {
534
+ messages.push({
535
+ id: 'app:ds_record_pending',
536
+ level: 40,
537
+ code: 'NXT_DEEPSTREAM_RECORDS_PENDING',
538
+ msg: 'ds: ' + ds.stats.record.pending + ' pending',
539
+ })
540
+ }
541
+
542
+ if (ds.stats.record.updating > 10e3) {
543
+ messages.push({
544
+ id: 'app:ds_record_updating',
545
+ level: 40,
546
+ code: 'NXT_DEEPSTREAM_RECORDS_UPDATING',
547
+ msg: 'ds: ' + ds.stats.record.updating + ' updating',
548
+ })
549
+ }
550
+
551
+ if (ds.stats.record.patching > 10e3) {
552
+ messages.push({
553
+ id: 'app:ds_record_patching',
554
+ level: 40,
555
+ code: 'NXT_DEEPSTREAM_RECORDS_PATCHING',
556
+ msg: 'ds: ' + ds.stats.record.patching + ' patching',
557
+ })
558
+ }
559
+
560
+ return messages
561
+ }),
562
+ )
563
+ : rxjs.of([]),
575
564
  rxjs.timer(0, 10e3),
576
565
  ].filter(Boolean),
577
566
  )
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxtedition/lib",
3
- "version": "15.0.22",
3
+ "version": "15.0.24",
4
4
  "license": "MIT",
5
5
  "author": "Robert Nagy <robert.nagy@boffins.se>",
6
6
  "files": [
@@ -20,6 +20,7 @@
20
20
  "deepstream.js",
21
21
  "logger.js",
22
22
  "mime.js",
23
+ "proxy.js",
23
24
  "trace.js",
24
25
  "weakCache.js",
25
26
  "couch.js",
package/proxy.js ADDED
@@ -0,0 +1,106 @@
1
+ const createError = require('http-errors')
2
+ const net = require('net')
3
+
4
+ // This expression matches hop-by-hop headers.
5
+ // These headers are meaningful only for a single transport-level connection,
6
+ // and must not be retransmitted by proxies or cached.
7
+ const HOP_EXPR =
8
+ /^(te|host|upgrade|trailers|connection|keep-alive|http2-settings|transfer-encoding|proxy-connection|proxy-authenticate|proxy-authorization)$/i
9
+
10
+ // Removes hop-by-hop and pseudo headers.
11
+ // Updates via and forwarded headers.
12
+ // Only hop-by-hop headers may be set using the Connection general header.
13
+ module.exports.reduceHeaders = function reduceHeaders(
14
+ { id, headers, proxyName, httpVersion, socket },
15
+ fn,
16
+ acc,
17
+ ) {
18
+ let via
19
+ let forwarded
20
+ let host
21
+ let authority
22
+ let connection
23
+
24
+ const entries = Object.entries(headers)
25
+
26
+ for (const [key, val] of entries) {
27
+ const len = key.length
28
+ if (len === 3 && !via && key.toLowerCase() === 'via') {
29
+ via = val
30
+ } else if (len === 4 && !host && key.toLowerCase() === 'host') {
31
+ host = val
32
+ } else if (len === 9 && !forwarded && key.toLowerCase() === 'forwarded') {
33
+ forwarded = val
34
+ } else if (len === 10 && !connection && key.toLowerCase() === 'connection') {
35
+ connection = val
36
+ } else if (len === 10 && !authority && key.toLowerCase() === ':authority') {
37
+ authority = val
38
+ }
39
+ }
40
+
41
+ let remove
42
+ if (connection && !HOP_EXPR.test(connection)) {
43
+ remove = connection.split(/,\s*/)
44
+ }
45
+
46
+ for (const [key, val] of entries) {
47
+ if (key.charAt(0) !== ':' && !remove?.includes(key) && !HOP_EXPR.test(key)) {
48
+ acc = fn(acc, key, val)
49
+ }
50
+ }
51
+
52
+ if (socket) {
53
+ const forwardedHost = authority || host
54
+ acc = fn(
55
+ acc,
56
+ 'forwarded',
57
+ (forwarded ? forwarded + ', ' : '') +
58
+ [
59
+ socket.localAddress && `by=${printIp(socket.localAddress, socket.localPort)}`,
60
+ socket.remoteAddress && `for=${printIp(socket.remoteAddress, socket.remotePort)}`,
61
+ `proto=${socket.encrypted ? 'https' : 'http'}`,
62
+ forwardedHost && `host="${forwardedHost}"`,
63
+ ].join(';'),
64
+ )
65
+ } else if (forwarded) {
66
+ // The forwarded header should not be included in response.
67
+ throw new createError.BadGateway()
68
+ }
69
+
70
+ if (proxyName) {
71
+ if (via) {
72
+ if (via.split(',').some((name) => name.endsWith(proxyName))) {
73
+ throw new createError.LoopDetected()
74
+ }
75
+ via += ', '
76
+ } else {
77
+ via = ''
78
+ }
79
+ via += `${httpVersion} ${proxyName}`
80
+ }
81
+
82
+ if (via) {
83
+ acc = fn(acc, 'via', via)
84
+ }
85
+
86
+ if (id) {
87
+ acc = fn(acc, 'request-id', id)
88
+ }
89
+
90
+ return acc
91
+ }
92
+
93
+ function printIp(address, port) {
94
+ const isIPv6 = net.isIPv6(address)
95
+ let str = `${address}`
96
+ if (isIPv6) {
97
+ str = `[${str}]`
98
+ }
99
+ if (port) {
100
+ str = `${str}:${port}`
101
+ }
102
+ if (isIPv6 || port) {
103
+ str = `"${str}"`
104
+ }
105
+ return str
106
+ }