Skip to content

Commit

Permalink
feat: basic client sends
Browse files Browse the repository at this point in the history
- sending messages works, no data interpretation or checking for the correct ACK flags
- refactored the option files into two files // was getting to big // updated files
- updated unit tests

#15

[ci skip]
  • Loading branch information
Bugs5382 committed Dec 13, 2023
1 parent 999223b commit 2fc1c83
Show file tree
Hide file tree
Showing 9 changed files with 288 additions and 168 deletions.
101 changes: 98 additions & 3 deletions __tests__/hl7.client.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import portfinder from 'portfinder'
import {Server} from "../../node-hl7-server/src";
import { Client } from '../src'
import {Server, Listener as ServerListener} from "../../node-hl7-server/src";
import {Client, Listener, Message} from '../src'
import {expectEvent} from "./__utils__/utils";

describe('node hl7 client', () => {
Expand Down Expand Up @@ -196,7 +196,102 @@ describe('node hl7 client', () => {

describe('end to end testing', () => {

test.todo('...send HL7 and get response back')
let waitAck: number = 0

let server: Server
let listener: ServerListener

let client: Client
let outGoing: Listener

beforeEach(async () => {

const LISTEN_PORT = await portfinder.getPortPromise({
port: 3000,
stopPort: 65353
})

server = new Server({bindAddress: 'localhost'})
listener = server.createListener({port: LISTEN_PORT}, async () => {})

client = new Client({hostname: 'localhost'})
outGoing = client.connectToListener({port: LISTEN_PORT, waitAck: waitAck !== 2}, async () => {})

})

afterEach(async () => {
await outGoing.close()
await listener.close()

waitAck = waitAck + 1;
})

test('...send simple message, just to make sure it sends, no data checks', async () => {

let message = new Message({
messageHeader: {
msh_9: {
msh_9_1: "ADT",
msh_9_2: "A01"
},
msh_10: 'CONTROL_ID'
}
})

await outGoing.sendMessage(message)

})

test('...send simple message twice, fails because no ACK of the first', async () => {

try {
let message = new Message({
messageHeader: {
msh_9: {
msh_9_1: "ADT",
msh_9_2: "A01"
},
msh_10: 'CONTROL_ID'
}
})

await outGoing.sendMessage(message)
await outGoing.sendMessage(message)

} catch (err: any) {
expect(err.message).toBe(`Can't send message while we are waiting for a response.`)
}

})

// Note: For this test to pass, you must run it from the describe block!
test('...send simple message twice, no ACK needed', async () => {

let message = new Message({
messageHeader: {
msh_9: {
msh_9_1: "ADT",
msh_9_2: "A01"
},
msh_10: 'CONTROL_ID'
}
})

await outGoing.sendMessage(message)

message = new Message({
messageHeader: {
msh_9: {
msh_9_1: "ADT",
msh_9_2: "A01"
},
msh_10: 'CONTROL_ID'
}
})

await outGoing.sendMessage(message)

})

})

Expand Down
5 changes: 1 addition & 4 deletions src/builder/batch.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import * as Util from '../utils'
import { HL7FatalError, HL7ParserError } from '../utils/exception.js'
import {
ClientBuilderBatchOptions,
normalizedClientBatchBuilderOptions
} from '../utils/normalize.js'
import { ClientBuilderBatchOptions, normalizedClientBatchBuilderOptions } from '../utils/normalizedBuilder.js'
import { Node } from './interface/node.js'
import { Message } from './message.js'
import { RootBase } from './modules/rootBase.js'
Expand Down
2 changes: 1 addition & 1 deletion src/builder/message.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { HL7FatalError } from '../utils/exception.js'
import { ClientBuilderMessageOptions, normalizedClientMessageBuilderOptions } from '../utils/normalizedBuilder.js'
import { RootBase } from './modules/rootBase.js'
import { Segment } from './modules/segment.js'
import { SegmentList } from './modules/segmentList.js'
import * as Util from '../utils'
import { ClientBuilderMessageOptions, normalizedClientMessageBuilderOptions } from '../utils/normalize.js'
import { Node } from './interface/node.js'

/**
Expand Down
3 changes: 2 additions & 1 deletion src/builder/modules/rootBase.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { HL7FatalError } from '../../utils/exception.js'
import { ClientBuilderOptions } from '../../utils/normalize.js'

import { ClientBuilderOptions } from '../../utils/normalizedBuilder'
import { Delimiters } from '../decorators/delimiters.js'
import { NodeBase } from './nodeBase.js'
import * as Util from '../../utils'
Expand Down
2 changes: 1 addition & 1 deletion src/client/client.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import EventEmitter from 'events'
import { Listener } from './listener.js'
import { normalizeClientOptions, ClientListenerOptions, ClientOptions } from '../utils/normalize.js'
import { normalizeClientOptions, ClientListenerOptions, ClientOptions } from '../utils/normalizeClient.js'

/**
* Client Class
Expand Down
64 changes: 43 additions & 21 deletions src/client/listener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@ import EventEmitter from 'events'
import { Socket } from 'net'
import * as net from 'net'
import * as tls from 'tls'
import {Batch} from "../builder/batch.js";
import {Message} from "../builder/message.js";
import {CR, FS, VT} from "../utils/constants.js";
import {HL7FatalError} from "../utils/exception";
import { Batch } from '../builder/batch.js'
import { Message } from '../builder/message.js'
import { CR, FS, VT } from '../utils/constants.js'
import { HL7FatalError } from '../utils/exception'
import { Client } from './client.js'
import { ClientListenerOptions, normalizeClientListenerOptions } from '../utils/normalize.js'
import { ClientListenerOptions, normalizeClientListenerOptions } from '../utils/normalizeClient.js'

/** Listener Class
* @since 1.0.0 */
export class Listener extends EventEmitter {
/** @internal */
_awaitingResponse: boolean
/** @internal */
_handler?: any | undefined
/** @internal */
Expand All @@ -28,6 +30,7 @@ export class Listener extends EventEmitter {
constructor (client: Client, props: ClientListenerOptions, handler?: any) {
super()
this._main = client
this._awaitingResponse = false

// process listener options
this._opt = normalizeClientListenerOptions(props)
Expand All @@ -43,41 +46,61 @@ export class Listener extends EventEmitter {
* @since 1.0.0
*/
async sendMessage (message: Message | Batch): Promise<void> {
this._server?.write(`${VT}${message.toString()}${FS}${CR}`)
}
// if we are waiting for an ack before we can send something else, and we are in that process.
if (this._opt.waitAck && this._awaitingResponse) {
throw new HL7FatalError(500, 'Can\'t send message while we are waiting for a response.')
}

if (typeof this._socket !== 'undefined' && this._socket.destroyed) {
// if we have auto connection and retry, this might take a while to fire.
throw new HL7FatalError(500, 'The socket/connect has already been destroyed. Please reconnect.')
}

if (typeof this._socket === 'undefined') {
throw new HL7FatalError(500, 'There is no valid connection.')
}

// ok, if our options are to wait for an acknowledgement, set the var to "true"
if (this._opt.waitAck) {
this._awaitingResponse = true
}

const toSendData = message.toString()

this._server?.write(`${VT}${toSendData}${FS}${CR}`)
}

/** @internal */
private _connect (): Socket | tls.TLSSocket {
let server: Socket | tls.TLSSocket

if (this._main._opt.tls != null) {
server = tls.connect({port: this._opt.port})
server = tls.connect({ port: this._opt.port })
} else {
server = net.createConnection({host: this._main._opt.hostname, port: this._opt.port}, () => {
this._lastUsed = new Date();
server.setNoDelay(true);
server = net.createConnection({ host: this._main._opt.hostname, port: this._opt.port }, () => {
this._lastUsed = new Date()
server.setNoDelay(true)
this._socket = server
this.emit('connect', server);
this.emit('connect', server)
})
}

server.on('close', () => {
this.emit('close');
});
this.emit('close')
})

server.on('data', data => {
this.emit('data', data)
});
})

server.on('error', err => {
this.emit('error', err);
this.emit('error', err)
throw new HL7FatalError(500, 'Unable to connect to remote host.')
});
})

server.on('end', () => {
this.emit('end');
});
this.emit('end')
})

server.unref()

Expand All @@ -90,9 +113,8 @@ export class Listener extends EventEmitter {
if (typeof this._socket !== 'undefined') {
this._socket.end()
this._socket.destroy()
this.emit('client.close');
this.emit('client.close')
}
return true
}

}
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ export type { HL7_2_7_MSH } from './specification/2.7.js'
/** HL7 Class **/
export { HL7_SPEC, HL7_SPEC_BASE, HL7_2_7 }

export type { ClientOptions, ClientListenerOptions, ClientBuilderOptions, ClientBuilderBatchOptions, ClientBuilderFileOptions, ParserProcessRawData } from './utils/normalize.js'
export type { ClientOptions, ClientListenerOptions, ParserProcessRawData } from './utils/normalizeClient.js'
export type { ClientBuilderFileOptions, ClientBuilderBatchOptions, ClientBuilderOptions } from './utils/normalizedBuilder.js'
export type { HL7Error, HL7FatalError, HL7ParserError } from './utils/exception.js'
Loading

0 comments on commit 2fc1c83

Please sign in to comment.