hl7v2-net 1.0.2 → 1.1.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,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HL7RequestContext = void 0;
4
+ const hl7v2_1 = require("hl7v2");
5
+ const node_events_async_1 = require("node-events-async");
6
+ const uid_1 = require("uid");
7
+ class HL7RequestContext extends node_events_async_1.AsyncEventEmitter {
8
+ constructor(socket, message) {
9
+ super();
10
+ this._finished = false;
11
+ this.socket = socket;
12
+ this.request = message;
13
+ if (!message.header.field(hl7v2_1.MSHSegment.MessageControlID).getValue())
14
+ message.header.field(hl7v2_1.MSHSegment.MessageControlID).setValue((0, uid_1.uid)(8));
15
+ }
16
+ get finished() {
17
+ return this._finished || !this.socket.connected;
18
+ }
19
+ end(message) {
20
+ if (this.finished || !this.socket.connected)
21
+ return;
22
+ if (message)
23
+ this.socket.sendMessage(message);
24
+ this._finished = true;
25
+ this.emit('finish', message);
26
+ }
27
+ }
28
+ exports.HL7RequestContext = HL7RequestContext;
package/cjs/hl7-client.js CHANGED
@@ -4,8 +4,7 @@ exports.Hl7Client = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const node_net_1 = tslib_1.__importDefault(require("node:net"));
6
6
  const node_events_async_1 = require("node-events-async");
7
- const hl7_request_js_1 = require("./hl7-request.js");
8
- const hl7_response_js_1 = require("./hl7-response.js");
7
+ const h_l7_request_context_js_1 = require("./h-l7-request-context.js");
9
8
  const hl7_router_js_1 = require("./hl7-router.js");
10
9
  const hl7_socket_js_1 = require("./hl7-socket.js");
11
10
  class Hl7Client extends node_events_async_1.AsyncEventEmitter {
@@ -101,11 +100,10 @@ class Hl7Client extends node_events_async_1.AsyncEventEmitter {
101
100
  this._router.use(handler, priority);
102
101
  }
103
102
  _onMessage(message) {
104
- const req = new hl7_request_js_1.HL7Request(this._socket, message);
105
- const res = new hl7_response_js_1.HL7Response(req);
106
- this._router.handle(undefined, req, res, error => {
107
- if (error)
108
- this.emit('error', error);
103
+ const context = new h_l7_request_context_js_1.HL7RequestContext(this._socket, message);
104
+ this._router.handle(context, () => {
105
+ if (context.error)
106
+ this.emit('error', context.error);
109
107
  });
110
108
  }
111
109
  }
package/cjs/hl7-router.js CHANGED
@@ -1,104 +1,95 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.HL7Router = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const node_process_1 = tslib_1.__importDefault(require("node:process"));
6
+ const hl7v2_dictionary_1 = require("hl7v2-dictionary");
7
+ const hl7_exchange_error_js_1 = require("./helpers/hl7-exchange-error.js");
4
8
  class HL7Router {
5
9
  constructor() {
6
- this._allHandlers = {};
10
+ this._handlerStack = new Map();
11
+ this._needPrepare = true;
7
12
  this._handlers = [];
8
- this._errorHandlers = [];
9
13
  }
10
14
  use(handler, priority = 0) {
11
- let list = this._allHandlers[priority];
15
+ let list = this._handlerStack[priority];
12
16
  if (!list) {
13
17
  list = [];
14
- this._allHandlers[priority] = list;
15
- }
16
- if (typeof handler === 'function')
17
- list.push(handler);
18
- else {
19
- // noinspection SuspiciousTypeOfGuard
20
- if (handler instanceof HL7Router) {
21
- list.push((req, res, next) => {
22
- handler.handle(undefined, req, res, error => {
23
- if (!res.finished)
24
- next(error);
25
- });
26
- });
27
- list.push((err, req, res, next) => {
28
- handler.handle(err, req, res, error => {
29
- if (!res.finished)
30
- next(error);
31
- });
32
- });
33
- } /* c8 ignore else */
34
- else {
35
- throw new TypeError('Router handler must be a function or HL7Router');
36
- }
18
+ this._handlerStack.set(priority, list);
37
19
  }
20
+ list.push(handler);
38
21
  this._needPrepare = true;
39
22
  }
40
- handle(error, req, res, callback) {
41
- this._prepareStack();
42
- let errIdx = -1;
23
+ handle(context, callback) {
24
+ this._prepareStack(true);
43
25
  let handlerIdx = -1;
44
- let lastErr;
45
26
  let callbackCalled = false;
46
- const doCallback = (err) => {
27
+ const doCallback = () => {
47
28
  if (callbackCalled)
48
29
  return;
49
30
  callbackCalled = true;
50
- res.removeListener('finish', onFinish);
51
- callback(err);
31
+ context.removeListener('finish', onFinish);
32
+ callback();
52
33
  };
53
34
  const onFinish = () => doCallback();
54
- res.once('finish', onFinish);
35
+ context.once('finish', onFinish);
55
36
  const next = (err) => {
56
- lastErr = err || lastErr;
57
- if (res.finished) {
58
- doCallback();
37
+ if (context.finished)
59
38
  return;
60
- }
39
+ context.error = context.error || err;
61
40
  try {
62
- if (err) {
63
- errIdx++;
64
- const handler = this._errorHandlers[errIdx];
65
- if (!handler) {
66
- doCallback(lastErr);
67
- return;
68
- }
69
- handler(err, req, res, next);
70
- return;
71
- }
72
- else {
73
- handlerIdx++;
74
- const handler = this._handlers[handlerIdx];
75
- if (!handler) {
76
- doCallback(lastErr);
77
- return;
78
- }
79
- handler(req, res, next);
41
+ handlerIdx++;
42
+ const handler = this._handlers[handlerIdx];
43
+ if (handler) {
44
+ handler(context, next);
80
45
  return;
81
46
  }
47
+ doCallback();
82
48
  }
83
49
  catch (e) {
84
50
  next(e);
85
51
  }
86
52
  };
87
- next(error);
53
+ next();
88
54
  }
89
- _prepareStack() {
55
+ _prepareStack(final) {
90
56
  if (!this._needPrepare)
91
57
  return;
92
- delete this._needPrepare;
93
- this._errorHandlers = [];
58
+ this._needPrepare = false;
94
59
  this._handlers = [];
95
- Object.keys(this._allHandlers).forEach(p => {
96
- const h = this._allHandlers[p];
97
- if (h.length === 4)
98
- this._errorHandlers.push(...h);
99
- else
100
- this._handlers.push(...h);
60
+ Array.from(this._handlerStack.keys())
61
+ .sort()
62
+ .forEach(p => {
63
+ const list = this._handlerStack.get(p);
64
+ for (const h of list) {
65
+ if (h instanceof HL7Router) {
66
+ h._prepareStack(false);
67
+ this._handlers.push(...h._handlers);
68
+ }
69
+ else
70
+ this._handlers.push(h);
71
+ }
101
72
  });
73
+ if (final) {
74
+ const finalHandler = (ctx) => {
75
+ if (ctx.finished)
76
+ return;
77
+ const error = ctx.error ||
78
+ new hl7_exchange_error_js_1.HL7ExchangeError('There is not handler to process this message', {
79
+ request: ctx.request,
80
+ });
81
+ const ack = ctx.request.createAck('AE', error);
82
+ if ((node_process_1.default?.env.NODE_ENV || '').startsWith('dev')) {
83
+ const errSeg = ack.getSegment('ERR');
84
+ if (errSeg)
85
+ errSeg
86
+ .field(hl7v2_dictionary_1.ERRSegment.DiagnosticInformation)
87
+ .setValue(error.stack);
88
+ }
89
+ ctx.end(ack);
90
+ };
91
+ this._handlers.push(finalHandler);
92
+ }
102
93
  }
103
94
  }
104
95
  exports.HL7Router = HL7Router;
package/cjs/hl7-server.js CHANGED
@@ -3,13 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.HL7Server = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const node_net_1 = tslib_1.__importDefault(require("node:net"));
6
- const process = tslib_1.__importStar(require("node:process"));
7
6
  const node_tls_1 = tslib_1.__importDefault(require("node:tls"));
8
- const hl7v2_1 = require("hl7v2");
9
7
  const node_events_async_1 = require("node-events-async");
8
+ const h_l7_request_context_js_1 = require("./h-l7-request-context.js");
10
9
  const hl7_exchange_error_js_1 = require("./helpers/hl7-exchange-error.js");
11
- const hl7_request_js_1 = require("./hl7-request.js");
12
- const hl7_response_js_1 = require("./hl7-response.js");
13
10
  const hl7_router_js_1 = require("./hl7-router.js");
14
11
  const hl7_socket_js_1 = require("./hl7-socket.js");
15
12
  class HL7Server extends node_events_async_1.AsyncEventEmitter {
@@ -190,46 +187,27 @@ class HL7Server extends node_events_async_1.AsyncEventEmitter {
190
187
  this._sockets.delete(socket);
191
188
  this.emit('disconnect', socket);
192
189
  });
190
+ socket.on('error', error => this.emit('error', error, socket));
193
191
  this.emit('connection', socket);
194
192
  }
195
193
  _onMessage(socket, message) {
196
- const req = new hl7_request_js_1.HL7Request(socket, message);
197
- const res = new hl7_response_js_1.HL7Response(req);
198
194
  const waitPromise = new Promise(resolve => {
195
+ const context = new h_l7_request_context_js_1.HL7RequestContext(socket, message);
199
196
  const timeoutTimer = setTimeout(() => {
200
197
  try {
201
198
  const error = new hl7_exchange_error_js_1.HL7ExchangeError('Response timeout');
202
- const ack = req.message.createAck('AE', error);
203
- res.send(ack);
199
+ const ack = context.request.createAck('AE', error);
200
+ context.end(ack);
204
201
  }
205
202
  finally {
206
203
  resolve();
207
204
  }
208
205
  }, this.responseTimeout || 30000).unref();
209
- this._router.handle(undefined, req, res, error => {
206
+ this._router.handle(context, () => {
210
207
  clearTimeout(timeoutTimer);
211
- try {
212
- if (!res.finished) {
213
- error =
214
- error ||
215
- new hl7_exchange_error_js_1.HL7ExchangeError('No middleware handled the request', {
216
- request: req.message,
217
- });
218
- const ack = req.message.createAck('AE', error);
219
- if ((process?.env.NODE_ENV || '').startsWith('dev')) {
220
- const errSeg = ack.getSegment('ERR');
221
- if (errSeg)
222
- errSeg.field(hl7v2_1.ERRSegment.DiagnosticInformation).value =
223
- error.stack;
224
- }
225
- res.send(ack);
226
- }
227
- if (error)
228
- this.emit('error', error, socket);
229
- }
230
- finally {
231
- resolve();
232
- }
208
+ if (context.error)
209
+ this.emit('error', context.error, socket);
210
+ resolve();
233
211
  });
234
212
  });
235
213
  this._runningHandlers.add(waitPromise);
package/cjs/hl7-socket.js CHANGED
@@ -6,10 +6,10 @@ const hl7v2_1 = require("hl7v2");
6
6
  const iconv_lite_1 = tslib_1.__importDefault(require("iconv-lite"));
7
7
  const node_events_async_1 = require("node-events-async");
8
8
  const frame_stream_js_1 = require("./helpers/frame-stream.js");
9
- const hl7_exchange_error_js_1 = require("./helpers/hl7-exchange-error.js");
10
9
  class HL7Socket extends node_events_async_1.AsyncEventEmitter {
11
10
  constructor(socket, options) {
12
11
  super();
12
+ this._messageHooks = new Set();
13
13
  this._waitPromises = new Set();
14
14
  this.socket = socket;
15
15
  this._options = options;
@@ -74,10 +74,12 @@ class HL7Socket extends node_events_async_1.AsyncEventEmitter {
74
74
  sendMessage(message) {
75
75
  if (!this.connected)
76
76
  throw new Error('Socket is not connected');
77
- let encoding = message.header.field(hl7v2_1.MSHSegment.CharacterSet).value;
77
+ if (!this.socket.writable)
78
+ throw new Error('Socket is not writable');
79
+ let encoding = message.header.field(hl7v2_1.MSHSegment.CharacterSet).getValue();
78
80
  if (!encoding) {
79
81
  encoding = 'UTF-8';
80
- message.header.field(hl7v2_1.MSHSegment.CharacterSet).value = encoding;
82
+ message.header.field(hl7v2_1.MSHSegment.CharacterSet).setValue(encoding);
81
83
  }
82
84
  const str = message.toHL7String();
83
85
  const buf = iconv_lite_1.default.encode(str, encoding);
@@ -90,26 +92,17 @@ class HL7Socket extends node_events_async_1.AsyncEventEmitter {
90
92
  const responseTimeout = this.responseTimeout;
91
93
  const waitPromise = new Promise((resolve, reject) => {
92
94
  let responseTimer;
93
- const onMessage = (resp) => {
94
- const msgType2 = resp.header.field(hl7v2_1.MSHSegment.MessageType).value;
95
+ const messageHook = (resp) => {
96
+ const msgType2 = resp.header.field(hl7v2_1.MSHSegment.MessageType).getValue();
95
97
  if (msgType2 !== 'ACK')
96
- return;
98
+ return false;
97
99
  const msa = resp.getSegment('MSA');
98
- if (!msa) {
99
- const err = new hl7_exchange_error_js_1.HL7ExchangeError(`Invalid message returned from server. MSA segment not found.`, {
100
- response: message,
101
- request: resp,
102
- segmentType: 'MSA',
103
- hl7ErrorCode: 100,
104
- });
105
- onError(err);
106
- return;
107
- }
108
- const controlId2 = msa.field(hl7v2_1.MSASegment.MessageControlID).value;
100
+ const controlId2 = msa?.field(hl7v2_1.MSASegment.MessageControlID).getValue();
109
101
  if (controlId2 !== controlId)
110
- return;
102
+ return false;
111
103
  cleanup();
112
104
  resolve(resp);
105
+ return true;
113
106
  };
114
107
  const onError = (error) => {
115
108
  cleanup();
@@ -117,12 +110,15 @@ class HL7Socket extends node_events_async_1.AsyncEventEmitter {
117
110
  };
118
111
  const cleanup = () => {
119
112
  clearTimeout(responseTimer);
120
- this.removeListener('message', onMessage);
113
+ this._messageHooks.delete(messageHook);
121
114
  this.socket.removeListener('error', onError);
122
115
  };
123
- const controlId = message.header.field(hl7v2_1.MSHSegment.MessageControlID).value;
116
+ const controlId = message.header
117
+ .field(hl7v2_1.MSHSegment.MessageControlID)
118
+ .getValue();
124
119
  this.socket.once('error', reject);
125
- this.on('message', onMessage);
120
+ this._messageHooks.add(messageHook);
121
+ // this.on('message', messageHook);
126
122
  if (responseTimeout) {
127
123
  responseTimer = setTimeout(() => {
128
124
  onError(new Error('Response timeout'));
@@ -144,6 +140,10 @@ class HL7Socket extends node_events_async_1.AsyncEventEmitter {
144
140
  try {
145
141
  const message = new hl7v2_1.HL7Message();
146
142
  message.parse(data);
143
+ for (const hook of this._messageHooks) {
144
+ if (hook(message))
145
+ break;
146
+ }
147
147
  this.emit('message', message);
148
148
  }
149
149
  catch (err) {
package/cjs/index.js CHANGED
@@ -1,10 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("./h-l7-request-context.js"), exports);
4
5
  tslib_1.__exportStar(require("./helpers/hl7-exchange-error.js"), exports);
5
6
  tslib_1.__exportStar(require("./hl7-client.js"), exports);
6
- tslib_1.__exportStar(require("./hl7-request.js"), exports);
7
- tslib_1.__exportStar(require("./hl7-response.js"), exports);
8
7
  tslib_1.__exportStar(require("./hl7-router.js"), exports);
9
8
  tslib_1.__exportStar(require("./hl7-server.js"), exports);
10
9
  tslib_1.__exportStar(require("./hl7-socket.js"), exports);
@@ -0,0 +1,24 @@
1
+ import { MSHSegment } from 'hl7v2';
2
+ import { AsyncEventEmitter } from 'node-events-async';
3
+ import { uid } from 'uid';
4
+ export class HL7RequestContext extends AsyncEventEmitter {
5
+ constructor(socket, message) {
6
+ super();
7
+ this._finished = false;
8
+ this.socket = socket;
9
+ this.request = message;
10
+ if (!message.header.field(MSHSegment.MessageControlID).getValue())
11
+ message.header.field(MSHSegment.MessageControlID).setValue(uid(8));
12
+ }
13
+ get finished() {
14
+ return this._finished || !this.socket.connected;
15
+ }
16
+ end(message) {
17
+ if (this.finished || !this.socket.connected)
18
+ return;
19
+ if (message)
20
+ this.socket.sendMessage(message);
21
+ this._finished = true;
22
+ this.emit('finish', message);
23
+ }
24
+ }
package/esm/hl7-client.js CHANGED
@@ -1,7 +1,6 @@
1
1
  import net from 'node:net';
2
2
  import { AsyncEventEmitter } from 'node-events-async';
3
- import { HL7Request } from './hl7-request.js';
4
- import { HL7Response } from './hl7-response.js';
3
+ import { HL7RequestContext } from './h-l7-request-context.js';
5
4
  import { HL7Router } from './hl7-router.js';
6
5
  import { HL7Socket } from './hl7-socket.js';
7
6
  export class Hl7Client extends AsyncEventEmitter {
@@ -97,11 +96,10 @@ export class Hl7Client extends AsyncEventEmitter {
97
96
  this._router.use(handler, priority);
98
97
  }
99
98
  _onMessage(message) {
100
- const req = new HL7Request(this._socket, message);
101
- const res = new HL7Response(req);
102
- this._router.handle(undefined, req, res, error => {
103
- if (error)
104
- this.emit('error', error);
99
+ const context = new HL7RequestContext(this._socket, message);
100
+ this._router.handle(context, () => {
101
+ if (context.error)
102
+ this.emit('error', context.error);
105
103
  });
106
104
  }
107
105
  }
package/esm/hl7-router.js CHANGED
@@ -1,100 +1,90 @@
1
+ import process from 'node:process';
2
+ import { ERRSegment } from 'hl7v2-dictionary';
3
+ import { HL7ExchangeError } from './helpers/hl7-exchange-error.js';
1
4
  export class HL7Router {
2
5
  constructor() {
3
- this._allHandlers = {};
6
+ this._handlerStack = new Map();
7
+ this._needPrepare = true;
4
8
  this._handlers = [];
5
- this._errorHandlers = [];
6
9
  }
7
10
  use(handler, priority = 0) {
8
- let list = this._allHandlers[priority];
11
+ let list = this._handlerStack[priority];
9
12
  if (!list) {
10
13
  list = [];
11
- this._allHandlers[priority] = list;
12
- }
13
- if (typeof handler === 'function')
14
- list.push(handler);
15
- else {
16
- // noinspection SuspiciousTypeOfGuard
17
- if (handler instanceof HL7Router) {
18
- list.push((req, res, next) => {
19
- handler.handle(undefined, req, res, error => {
20
- if (!res.finished)
21
- next(error);
22
- });
23
- });
24
- list.push((err, req, res, next) => {
25
- handler.handle(err, req, res, error => {
26
- if (!res.finished)
27
- next(error);
28
- });
29
- });
30
- } /* c8 ignore else */
31
- else {
32
- throw new TypeError('Router handler must be a function or HL7Router');
33
- }
14
+ this._handlerStack.set(priority, list);
34
15
  }
16
+ list.push(handler);
35
17
  this._needPrepare = true;
36
18
  }
37
- handle(error, req, res, callback) {
38
- this._prepareStack();
39
- let errIdx = -1;
19
+ handle(context, callback) {
20
+ this._prepareStack(true);
40
21
  let handlerIdx = -1;
41
- let lastErr;
42
22
  let callbackCalled = false;
43
- const doCallback = (err) => {
23
+ const doCallback = () => {
44
24
  if (callbackCalled)
45
25
  return;
46
26
  callbackCalled = true;
47
- res.removeListener('finish', onFinish);
48
- callback(err);
27
+ context.removeListener('finish', onFinish);
28
+ callback();
49
29
  };
50
30
  const onFinish = () => doCallback();
51
- res.once('finish', onFinish);
31
+ context.once('finish', onFinish);
52
32
  const next = (err) => {
53
- lastErr = err || lastErr;
54
- if (res.finished) {
55
- doCallback();
33
+ if (context.finished)
56
34
  return;
57
- }
35
+ context.error = context.error || err;
58
36
  try {
59
- if (err) {
60
- errIdx++;
61
- const handler = this._errorHandlers[errIdx];
62
- if (!handler) {
63
- doCallback(lastErr);
64
- return;
65
- }
66
- handler(err, req, res, next);
67
- return;
68
- }
69
- else {
70
- handlerIdx++;
71
- const handler = this._handlers[handlerIdx];
72
- if (!handler) {
73
- doCallback(lastErr);
74
- return;
75
- }
76
- handler(req, res, next);
37
+ handlerIdx++;
38
+ const handler = this._handlers[handlerIdx];
39
+ if (handler) {
40
+ handler(context, next);
77
41
  return;
78
42
  }
43
+ doCallback();
79
44
  }
80
45
  catch (e) {
81
46
  next(e);
82
47
  }
83
48
  };
84
- next(error);
49
+ next();
85
50
  }
86
- _prepareStack() {
51
+ _prepareStack(final) {
87
52
  if (!this._needPrepare)
88
53
  return;
89
- delete this._needPrepare;
90
- this._errorHandlers = [];
54
+ this._needPrepare = false;
91
55
  this._handlers = [];
92
- Object.keys(this._allHandlers).forEach(p => {
93
- const h = this._allHandlers[p];
94
- if (h.length === 4)
95
- this._errorHandlers.push(...h);
96
- else
97
- this._handlers.push(...h);
56
+ Array.from(this._handlerStack.keys())
57
+ .sort()
58
+ .forEach(p => {
59
+ const list = this._handlerStack.get(p);
60
+ for (const h of list) {
61
+ if (h instanceof HL7Router) {
62
+ h._prepareStack(false);
63
+ this._handlers.push(...h._handlers);
64
+ }
65
+ else
66
+ this._handlers.push(h);
67
+ }
98
68
  });
69
+ if (final) {
70
+ const finalHandler = (ctx) => {
71
+ if (ctx.finished)
72
+ return;
73
+ const error = ctx.error ||
74
+ new HL7ExchangeError('There is not handler to process this message', {
75
+ request: ctx.request,
76
+ });
77
+ const ack = ctx.request.createAck('AE', error);
78
+ if ((process?.env.NODE_ENV || '').startsWith('dev')) {
79
+ const errSeg = ack.getSegment('ERR');
80
+ if (errSeg)
81
+ errSeg
82
+ .field(ERRSegment.DiagnosticInformation)
83
+ .setValue(error.stack);
84
+ }
85
+ ctx.end(ack);
86
+ };
87
+ this._handlers.push(finalHandler);
88
+ }
99
89
  }
100
90
  }
package/esm/hl7-server.js CHANGED
@@ -1,11 +1,8 @@
1
1
  import net from 'node:net';
2
- import * as process from 'node:process';
3
2
  import tls from 'node:tls';
4
- import { ERRSegment } from 'hl7v2';
5
3
  import { AsyncEventEmitter } from 'node-events-async';
4
+ import { HL7RequestContext } from './h-l7-request-context.js';
6
5
  import { HL7ExchangeError } from './helpers/hl7-exchange-error.js';
7
- import { HL7Request } from './hl7-request.js';
8
- import { HL7Response } from './hl7-response.js';
9
6
  import { HL7Router } from './hl7-router.js';
10
7
  import { HL7Socket } from './hl7-socket.js';
11
8
  export class HL7Server extends AsyncEventEmitter {
@@ -186,46 +183,27 @@ export class HL7Server extends AsyncEventEmitter {
186
183
  this._sockets.delete(socket);
187
184
  this.emit('disconnect', socket);
188
185
  });
186
+ socket.on('error', error => this.emit('error', error, socket));
189
187
  this.emit('connection', socket);
190
188
  }
191
189
  _onMessage(socket, message) {
192
- const req = new HL7Request(socket, message);
193
- const res = new HL7Response(req);
194
190
  const waitPromise = new Promise(resolve => {
191
+ const context = new HL7RequestContext(socket, message);
195
192
  const timeoutTimer = setTimeout(() => {
196
193
  try {
197
194
  const error = new HL7ExchangeError('Response timeout');
198
- const ack = req.message.createAck('AE', error);
199
- res.send(ack);
195
+ const ack = context.request.createAck('AE', error);
196
+ context.end(ack);
200
197
  }
201
198
  finally {
202
199
  resolve();
203
200
  }
204
201
  }, this.responseTimeout || 30000).unref();
205
- this._router.handle(undefined, req, res, error => {
202
+ this._router.handle(context, () => {
206
203
  clearTimeout(timeoutTimer);
207
- try {
208
- if (!res.finished) {
209
- error =
210
- error ||
211
- new HL7ExchangeError('No middleware handled the request', {
212
- request: req.message,
213
- });
214
- const ack = req.message.createAck('AE', error);
215
- if ((process?.env.NODE_ENV || '').startsWith('dev')) {
216
- const errSeg = ack.getSegment('ERR');
217
- if (errSeg)
218
- errSeg.field(ERRSegment.DiagnosticInformation).value =
219
- error.stack;
220
- }
221
- res.send(ack);
222
- }
223
- if (error)
224
- this.emit('error', error, socket);
225
- }
226
- finally {
227
- resolve();
228
- }
204
+ if (context.error)
205
+ this.emit('error', context.error, socket);
206
+ resolve();
229
207
  });
230
208
  });
231
209
  this._runningHandlers.add(waitPromise);
package/esm/hl7-socket.js CHANGED
@@ -2,10 +2,10 @@ import { CR, FS, HL7Message, MSASegment, MSHSegment, VT } from 'hl7v2';
2
2
  import iconv from 'iconv-lite';
3
3
  import { AsyncEventEmitter } from 'node-events-async';
4
4
  import { FrameStream } from './helpers/frame-stream.js';
5
- import { HL7ExchangeError } from './helpers/hl7-exchange-error.js';
6
5
  export class HL7Socket extends AsyncEventEmitter {
7
6
  constructor(socket, options) {
8
7
  super();
8
+ this._messageHooks = new Set();
9
9
  this._waitPromises = new Set();
10
10
  this.socket = socket;
11
11
  this._options = options;
@@ -70,10 +70,12 @@ export class HL7Socket extends AsyncEventEmitter {
70
70
  sendMessage(message) {
71
71
  if (!this.connected)
72
72
  throw new Error('Socket is not connected');
73
- let encoding = message.header.field(MSHSegment.CharacterSet).value;
73
+ if (!this.socket.writable)
74
+ throw new Error('Socket is not writable');
75
+ let encoding = message.header.field(MSHSegment.CharacterSet).getValue();
74
76
  if (!encoding) {
75
77
  encoding = 'UTF-8';
76
- message.header.field(MSHSegment.CharacterSet).value = encoding;
78
+ message.header.field(MSHSegment.CharacterSet).setValue(encoding);
77
79
  }
78
80
  const str = message.toHL7String();
79
81
  const buf = iconv.encode(str, encoding);
@@ -86,26 +88,17 @@ export class HL7Socket extends AsyncEventEmitter {
86
88
  const responseTimeout = this.responseTimeout;
87
89
  const waitPromise = new Promise((resolve, reject) => {
88
90
  let responseTimer;
89
- const onMessage = (resp) => {
90
- const msgType2 = resp.header.field(MSHSegment.MessageType).value;
91
+ const messageHook = (resp) => {
92
+ const msgType2 = resp.header.field(MSHSegment.MessageType).getValue();
91
93
  if (msgType2 !== 'ACK')
92
- return;
94
+ return false;
93
95
  const msa = resp.getSegment('MSA');
94
- if (!msa) {
95
- const err = new HL7ExchangeError(`Invalid message returned from server. MSA segment not found.`, {
96
- response: message,
97
- request: resp,
98
- segmentType: 'MSA',
99
- hl7ErrorCode: 100,
100
- });
101
- onError(err);
102
- return;
103
- }
104
- const controlId2 = msa.field(MSASegment.MessageControlID).value;
96
+ const controlId2 = msa?.field(MSASegment.MessageControlID).getValue();
105
97
  if (controlId2 !== controlId)
106
- return;
98
+ return false;
107
99
  cleanup();
108
100
  resolve(resp);
101
+ return true;
109
102
  };
110
103
  const onError = (error) => {
111
104
  cleanup();
@@ -113,12 +106,15 @@ export class HL7Socket extends AsyncEventEmitter {
113
106
  };
114
107
  const cleanup = () => {
115
108
  clearTimeout(responseTimer);
116
- this.removeListener('message', onMessage);
109
+ this._messageHooks.delete(messageHook);
117
110
  this.socket.removeListener('error', onError);
118
111
  };
119
- const controlId = message.header.field(MSHSegment.MessageControlID).value;
112
+ const controlId = message.header
113
+ .field(MSHSegment.MessageControlID)
114
+ .getValue();
120
115
  this.socket.once('error', reject);
121
- this.on('message', onMessage);
116
+ this._messageHooks.add(messageHook);
117
+ // this.on('message', messageHook);
122
118
  if (responseTimeout) {
123
119
  responseTimer = setTimeout(() => {
124
120
  onError(new Error('Response timeout'));
@@ -140,6 +136,10 @@ export class HL7Socket extends AsyncEventEmitter {
140
136
  try {
141
137
  const message = new HL7Message();
142
138
  message.parse(data);
139
+ for (const hook of this._messageHooks) {
140
+ if (hook(message))
141
+ break;
142
+ }
143
143
  this.emit('message', message);
144
144
  }
145
145
  catch (err) {
package/esm/index.js CHANGED
@@ -1,7 +1,6 @@
1
+ export * from './h-l7-request-context.js';
1
2
  export * from './helpers/hl7-exchange-error.js';
2
3
  export * from './hl7-client.js';
3
- export * from './hl7-request.js';
4
- export * from './hl7-response.js';
5
4
  export * from './hl7-router.js';
6
5
  export * from './hl7-server.js';
7
6
  export * from './hl7-socket.js';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "hl7v2-net",
3
3
  "description": "HL7 v2 server/client for NodeJS",
4
- "version": "1.0.2",
4
+ "version": "1.1.0",
5
5
  "author": "Panates",
6
6
  "license": "MIT",
7
7
  "dependencies": {
@@ -15,7 +15,8 @@
15
15
  "uid": "^2.0.2"
16
16
  },
17
17
  "peerDependencies": {
18
- "hl7v2": "^1.0.2"
18
+ "hl7v2": "^1.1.0",
19
+ "hl7v2-dictionary": "^1.1.0"
19
20
  },
20
21
  "type": "module",
21
22
  "exports": {
@@ -0,0 +1,12 @@
1
+ import { HL7Message } from 'hl7v2';
2
+ import { AsyncEventEmitter } from 'node-events-async';
3
+ import { HL7Socket } from './hl7-socket.js';
4
+ export declare class HL7RequestContext extends AsyncEventEmitter {
5
+ protected _finished: boolean;
6
+ readonly socket: HL7Socket;
7
+ readonly request: HL7Message;
8
+ error?: Error;
9
+ constructor(socket: HL7Socket, message: HL7Message);
10
+ get finished(): boolean;
11
+ end(message?: HL7Message): void;
12
+ }
@@ -5,7 +5,7 @@ import { AsyncEventEmitter } from 'node-events-async';
5
5
  import { StrictOmit } from 'ts-gems';
6
6
  import { HL7Router } from './hl7-router.js';
7
7
  import { HL7Socket } from './hl7-socket.js';
8
- import { HL7ErrorMiddleware, HL7Middleware } from './types.js';
8
+ import { HL7Middleware } from './types.js';
9
9
  export declare class Hl7Client extends AsyncEventEmitter {
10
10
  protected _router: HL7Router;
11
11
  protected _socket?: HL7Socket;
@@ -24,7 +24,7 @@ export declare class Hl7Client extends AsyncEventEmitter {
24
24
  sendMessage(message: HL7Message): Promise<void>;
25
25
  sendMessageWaitAck(request: HL7Message): Promise<HL7Message>;
26
26
  setKeepAlive(enable?: boolean, initialDelay?: number): void;
27
- use(handler: HL7Middleware | HL7ErrorMiddleware, priority?: number): void;
27
+ use(handler: HL7Middleware, priority?: number): void;
28
28
  protected _onMessage(message: HL7Message): void;
29
29
  }
30
30
  export declare namespace Hl7Client {
@@ -1,12 +1,10 @@
1
- import type { HL7Request } from './hl7-request.js';
2
- import { HL7Response } from './hl7-response.js';
3
- import { HL7ErrorMiddleware, HL7Middleware } from './types.js';
1
+ import type { HL7RequestContext } from './h-l7-request-context.js';
2
+ import { HL7Middleware } from './types.js';
4
3
  export declare class HL7Router {
5
- protected _allHandlers: Record<number, (HL7Middleware | HL7ErrorMiddleware)[]>;
6
- protected _needPrepare?: boolean;
4
+ protected _handlerStack: Map<number, (HL7Router | HL7Middleware)[]>;
5
+ protected _needPrepare: boolean;
7
6
  protected _handlers: HL7Middleware[];
8
- protected _errorHandlers: HL7ErrorMiddleware[];
9
- use(handler: HL7Middleware | HL7ErrorMiddleware | HL7Router, priority?: number): void;
10
- handle(error: Error | undefined, req: HL7Request, res: HL7Response, callback: (err?: Error) => void): void;
11
- protected _prepareStack(): void;
7
+ use(handler: HL7Middleware | HL7Router, priority?: number): void;
8
+ handle(context: HL7RequestContext, callback: () => void): void;
9
+ protected _prepareStack(final?: boolean): void;
12
10
  }
@@ -5,7 +5,7 @@ import { AddressInfo, ListenOptions, Socket } from 'net';
5
5
  import { AsyncEventEmitter } from 'node-events-async';
6
6
  import { HL7Router } from './hl7-router.js';
7
7
  import { HL7Socket } from './hl7-socket.js';
8
- import { HL7ErrorMiddleware, HL7Middleware } from './types.js';
8
+ import { HL7Middleware } from './types.js';
9
9
  export declare class HL7Server extends AsyncEventEmitter<HL7Server.Events> {
10
10
  protected _server: net.Server | tls.Server;
11
11
  protected _sockets: Set<HL7Socket>;
@@ -76,7 +76,7 @@ export declare class HL7Server extends AsyncEventEmitter<HL7Server.Events> {
76
76
  * connections.
77
77
  */
78
78
  close(waitRunningHandlers?: number): Promise<void>;
79
- use(handler: HL7Middleware | HL7ErrorMiddleware, priority?: number): void;
79
+ use(handler: HL7Middleware, priority?: number): void;
80
80
  /**
81
81
  * Asynchronously get the number of concurrent connections on the server. Works
82
82
  * when sockets were sent to forks.
@@ -5,6 +5,7 @@ import { AsyncEventEmitter } from 'node-events-async';
5
5
  import { FrameStream } from './helpers/frame-stream.js';
6
6
  export declare class HL7Socket extends AsyncEventEmitter {
7
7
  readonly socket: Socket;
8
+ protected _messageHooks: Set<(resp: HL7Message) => boolean>;
8
9
  protected _frameStream: FrameStream;
9
10
  protected _waitPromises: Set<Promise<any>>;
10
11
  protected _options: HL7Socket.Options;
package/types/index.d.cts CHANGED
@@ -1,7 +1,6 @@
1
+ export * from './h-l7-request-context.js';
1
2
  export * from './helpers/hl7-exchange-error.js';
2
3
  export * from './hl7-client.js';
3
- export * from './hl7-request.js';
4
- export * from './hl7-response.js';
5
4
  export * from './hl7-router.js';
6
5
  export * from './hl7-server.js';
7
6
  export * from './hl7-socket.js';
package/types/index.d.ts CHANGED
@@ -1,7 +1,6 @@
1
+ export * from './h-l7-request-context.js';
1
2
  export * from './helpers/hl7-exchange-error.js';
2
3
  export * from './hl7-client.js';
3
- export * from './hl7-request.js';
4
- export * from './hl7-response.js';
5
4
  export * from './hl7-router.js';
6
5
  export * from './hl7-server.js';
7
6
  export * from './hl7-socket.js';
package/types/types.d.ts CHANGED
@@ -1,5 +1,3 @@
1
- import type { HL7Request } from './hl7-request.js';
2
- import type { HL7Response } from './hl7-response.js';
1
+ import type { HL7RequestContext } from './h-l7-request-context.js';
3
2
  export type NextFunction = (error?: Error) => void;
4
- export type HL7Middleware = (req: HL7Request, res: HL7Response, next: NextFunction) => void;
5
- export type HL7ErrorMiddleware = (error: Error, req: HL7Request, res: HL7Response, next: NextFunction) => void;
3
+ export type HL7Middleware = (context: HL7RequestContext, next: NextFunction) => void;
@@ -1,10 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.HL7Request = void 0;
4
- class HL7Request {
5
- constructor(socket, message) {
6
- this.socket = socket;
7
- this.message = message;
8
- }
9
- }
10
- exports.HL7Request = HL7Request;
@@ -1,28 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.HL7Response = void 0;
4
- const node_events_async_1 = require("node-events-async");
5
- class HL7Response extends node_events_async_1.AsyncEventEmitter {
6
- constructor(req) {
7
- super();
8
- this._finished = false;
9
- this._req = req;
10
- }
11
- get socket() {
12
- return this._req.socket;
13
- }
14
- get request() {
15
- return this._req;
16
- }
17
- get finished() {
18
- return this._finished || !this.socket.connected;
19
- }
20
- send(message) {
21
- if (this.finished || !this.socket.connected)
22
- return;
23
- this.socket.sendMessage(message);
24
- this._finished = true;
25
- this.emit('finish', message);
26
- }
27
- }
28
- exports.HL7Response = HL7Response;
@@ -1,6 +0,0 @@
1
- export class HL7Request {
2
- constructor(socket, message) {
3
- this.socket = socket;
4
- this.message = message;
5
- }
6
- }
@@ -1,24 +0,0 @@
1
- import { AsyncEventEmitter } from 'node-events-async';
2
- export class HL7Response extends AsyncEventEmitter {
3
- constructor(req) {
4
- super();
5
- this._finished = false;
6
- this._req = req;
7
- }
8
- get socket() {
9
- return this._req.socket;
10
- }
11
- get request() {
12
- return this._req;
13
- }
14
- get finished() {
15
- return this._finished || !this.socket.connected;
16
- }
17
- send(message) {
18
- if (this.finished || !this.socket.connected)
19
- return;
20
- this.socket.sendMessage(message);
21
- this._finished = true;
22
- this.emit('finish', message);
23
- }
24
- }
@@ -1,7 +0,0 @@
1
- import { HL7Message } from 'hl7v2';
2
- import { HL7Socket } from './hl7-socket.js';
3
- export declare class HL7Request {
4
- readonly socket: HL7Socket;
5
- readonly message: HL7Message;
6
- constructor(socket: HL7Socket, message: HL7Message);
7
- }
@@ -1,13 +0,0 @@
1
- import { HL7Message } from 'hl7v2';
2
- import { AsyncEventEmitter } from 'node-events-async';
3
- import { HL7Request } from './hl7-request.js';
4
- import { HL7Socket } from './hl7-socket.js';
5
- export declare class HL7Response extends AsyncEventEmitter {
6
- protected _req: HL7Request;
7
- protected _finished: boolean;
8
- constructor(req: HL7Request);
9
- get socket(): HL7Socket;
10
- get request(): HL7Request;
11
- get finished(): boolean;
12
- send(message: HL7Message): void;
13
- }