From 20f33c37943677bb2d21a386fbdf3fec63fe1d86 Mon Sep 17 00:00:00 2001 From: Bugs5382 Date: Sat, 17 Aug 2024 08:06:38 -0400 Subject: [PATCH 1/2] feat(#100): added AE support * updated documentation * added unit tests for AA, AR, and AE * updated inbound to use messageParsed vs. message for code consistency --- __tests__/hl7.end2end.test.ts | 102 ++++++++++++++++++++++++++++- src/server/inbound.ts | 5 +- src/server/modules/sendResponse.ts | 31 +++++++-- src/server/server.ts | 5 +- 4 files changed, 130 insertions(+), 13 deletions(-) diff --git a/__tests__/hl7.end2end.test.ts b/__tests__/hl7.end2end.test.ts index c243e89..5137c27 100644 --- a/__tests__/hl7.end2end.test.ts +++ b/__tests__/hl7.end2end.test.ts @@ -10,7 +10,7 @@ describe('node hl7 end to end - client', () => { describe('server/client sanity checks', () => { - test('...simple connect', async () => { + test('...simple connect .. send AA', async () => { let dfd = createDeferred() @@ -58,6 +58,102 @@ describe('node hl7 end to end - client', () => { }) + test('...simple connect .. send AR', async () => { + + let dfd = createDeferred() + + const server = new Server({bindAddress: '0.0.0.0'}) + const listener = server.createInbound({port: 3000}, async (req, res) => { + const messageReq = req.getMessage() + expect(messageReq.get('MSH.12').toString()).toBe('2.7') + await res.sendResponse('AR') + const messageRes = res.getAckMessage() + expect(messageRes?.get('MSA.1').toString()).toBe('AR') + }) + + await expectEvent(listener, 'listen') + + const client = new Client({ host: '0.0.0.0' }) + + const outbound = client.createConnection({ port: 3000 }, async (res) => { + const messageRes = res.getMessage() + expect(messageRes.get('MSA.1').toString()).toBe('AR') + dfd.resolve() + }) + + await expectEvent(outbound, 'connect') + + let message = new Message({ + messageHeader: { + msh_9_1: 'ADT', + msh_9_2: 'A01', + msh_10: 'CONTROL_ID', + msh_11_1: 'D' + } + }) + + await outbound.sendMessage(message) + + await dfd.promise + + expect(client.totalSent()).toEqual(1) + expect(client.totalAck()).toEqual(1) + + await outbound.close() + await listener.close() + + client.closeAll() + + }) + + test('...simple connect .. send AE', async () => { + + let dfd = createDeferred() + + const server = new Server({bindAddress: '0.0.0.0'}) + const listener = server.createInbound({port: 3000}, async (req, res) => { + const messageReq = req.getMessage() + expect(messageReq.get('MSH.12').toString()).toBe('2.7') + await res.sendResponse('AE') + const messageRes = res.getAckMessage() + expect(messageRes?.get('MSA.1').toString()).toBe('AE') + }) + + await expectEvent(listener, 'listen') + + const client = new Client({ host: '0.0.0.0' }) + + const outbound = client.createConnection({ port: 3000 }, async (res) => { + const messageRes = res.getMessage() + expect(messageRes.get('MSA.1').toString()).toBe('AE') + dfd.resolve() + }) + + await expectEvent(outbound, 'connect') + + let message = new Message({ + messageHeader: { + msh_9_1: 'ADT', + msh_9_2: 'A01', + msh_10: 'CONTROL_ID', + msh_11_1: 'D' + } + }) + + await outbound.sendMessage(message) + + await dfd.promise + + expect(client.totalSent()).toEqual(1) + expect(client.totalAck()).toEqual(1) + + await outbound.close() + await listener.close() + + client.closeAll() + + }) + test('...simple connect ... MSH 9.3 override', async () => { let dfd = createDeferred() @@ -153,9 +249,11 @@ describe('node hl7 end to end - client', () => { client.closeAll() }) + }) describe('server/client failure checks', () => { + test('...host does not exist, error out', async () => { const client = new Client({ host: '0.0.0.0' }) @@ -289,6 +387,7 @@ describe('node hl7 end to end - client', () => { }) describe("server/client large data checks", () => { + test("...large encapsulated data", async () => { let dfd = createDeferred(); @@ -353,5 +452,6 @@ describe('node hl7 end to end - client', () => { client.closeAll(); }); + }); }); diff --git a/src/server/inbound.ts b/src/server/inbound.ts index 071eb14..d03bc1f 100644 --- a/src/server/inbound.ts +++ b/src/server/inbound.ts @@ -10,7 +10,7 @@ import { Server } from './server.js' /** * Inbound Handler - * @description The handler that will handle the user parsing a received message by the client to the server. + * @remarks The handler that will handle the user parsing a received message by the client to the server. * @since 1.0.0 * @example * In this example, we are processing the results in an async handler. @@ -47,7 +47,6 @@ export interface Inbound extends EventEmitter { /** * Inbound Listener Class * @since 1.0.0 - * @extends EventEmitter */ export class Inbound extends EventEmitter implements Inbound { /** @internal */ @@ -202,7 +201,7 @@ export class Inbound extends EventEmitter implements Inbound { // create the inbound request const req = new InboundRequest(messageParsed, { type: 'file' }) // create the send response function - const res = new SendResponse(socket, message, this._opt.overrideMSH) + const res = new SendResponse(socket, messageParsed, this._opt.overrideMSH) // on a response sent, tell the inbound listener void this._handler(req, res) }) diff --git a/src/server/modules/sendResponse.ts b/src/server/modules/sendResponse.ts index 47f7b9f..fba9a4d 100644 --- a/src/server/modules/sendResponse.ts +++ b/src/server/modules/sendResponse.ts @@ -43,17 +43,36 @@ export class SendResponse extends EventEmitter { * If you are to confirm to the end user (client) that the message they sent was good and processed successfully. * you would send an "AA" style message (Application Accept). * Otherwise, send an "AR" (Application Reject) to tell the client the data was - * no accept.ed/processed. - * ``` + * not accepted/processed or send an "AE" + * (Application Error) to tell the client your overall application had an error. + * ```ts * const server = new Server({bindAddress: '0.0.0.0'}) * const IB_ADT = server.createInbound({port: LISTEN_PORT}, async (req, res) => { * const messageReq = req.getMessage() * await res.sendResponse("AA") * }) - * ``` - * "AE" (Application Error) will be sent if there is a problem creating either an "AA" or "AR" message from the orginial message sent. + * + * ot + * + * const server = new Server({bindAddress: '0.0.0.0'}) + * const IB_ADT = server.createInbound({port: LISTEN_PORT}, async (req, res) => { + * const messageReq = req.getMessage() + * await res.sendResponse("AR") + * }) + * + * or + * + * const server = new Server({bindAddress: '0.0.0.0'}) + * const IB_ADT = server.createInbound({port: LISTEN_PORT}, async (req, res) => { + * const messageReq = req.getMessage() + * await res.sendResponse("AE") + * }) + *``` + * + * "AE" (Application Error) will be automatically sent if there is a problem creating either an "AA" or "AR" + * message from the original message sent because the original message structure sent wrong in the first place. */ - async sendResponse (type: 'AA' | 'AR'): Promise { + async sendResponse (type: 'AA' | 'AR' | 'AE'): Promise { try { this._ack = this._createAckMessage(type, this._message) this._socket.write(Buffer.from(`${PROTOCOL_MLLP_HEADER}${this._ack.toString()}${PROTOCOL_MLLP_FOOTER}`)) @@ -69,7 +88,7 @@ export class SendResponse extends EventEmitter { /** * Get the Ack Message * @since 2.2.0 - * @description Get the acknowledged message that was sent to the client. + * @remarks Get the acknowledged message that was sent to the client. * This could return undefined if accessed prior to sending the response */ getAckMessage (): Message | undefined { diff --git a/src/server/server.ts b/src/server/server.ts index 96b6181..564a149 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -4,10 +4,9 @@ import { ServerOptions, normalizeServerOptions, ListenerOptions } from '../utils /** * Server Class - * @description Start Server listening on a network address. + * @remarks Start Server listening on a network address. * {@link ServerOptions} Link to the options that can be passed into props. * @since 1.0.0 - * @extends EventEmitter */ export class Server extends EventEmitter { /** @internal */ @@ -43,7 +42,7 @@ export class Server extends EventEmitter { } /** This creates an instance of a HL7 server. - * @description You would specify your port and what it will do when it gets a message. + * @remarks You would specify your port and what it will do when it gets a message. * @since 1.0.0 * @example *``` From 24146748430d0b5053efda71addfc19a0db65b37 Mon Sep 17 00:00:00 2001 From: Bugs5382 Date: Sat, 17 Aug 2024 14:02:39 -0400 Subject: [PATCH 2/2] docs(#100): fix type [skip ci] --- src/server/modules/sendResponse.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/modules/sendResponse.ts b/src/server/modules/sendResponse.ts index fba9a4d..b8ca1ba 100644 --- a/src/server/modules/sendResponse.ts +++ b/src/server/modules/sendResponse.ts @@ -52,7 +52,7 @@ export class SendResponse extends EventEmitter { * await res.sendResponse("AA") * }) * - * ot + * or * * const server = new Server({bindAddress: '0.0.0.0'}) * const IB_ADT = server.createInbound({port: LISTEN_PORT}, async (req, res) => {