hl7v2_mllp

Pub Version Build Status License: BSD-3-Clause

MLLP transport for HL7v2 messages in Dart.

TCP client and server implementing the Minimum Lower Layer Protocol (MLLP) for HL7v2 message exchange. Supports TLS/mTLS and automatic reconnection with exponential backoff.

Companion to hl7v2 — the core parsing and generation package.

Quick Start

# pubspec.yaml
dependencies:
  hl7v2_parser: ^0.1.0
  hl7v2_mllp: ^0.1.0

Client

Connect to an HL7v2 listener (e.g., Mirth Connect, HAPI server, hospital LIS):

import 'package:hl7v2_parser/hl7v2_parser.dart';
import 'package:hl7v2_mllp/hl7v2_mllp.dart';

final client = MllpClient(host: '192.168.1.100', port: 2575);
await client.connect();

// Build and send a message
final order = MessageBuilder()
    .msh((b) => b
        .sendingApplication('APP')
        .sendingFacility('HOSP')
        .receivingApplication('LIS')
        .receivingFacility('LAB')
        .messageType('ORM', 'O01')
        .version('2.5'))
    .addSegment('PID', (b) => b
        .field(3, '12345^^^HOSP^MR')
        .field(5, 'DOE^JOHN'))
    .build();

final response = await client.send(order.encode());
final ack = Message.parse(response);
print(ack.get('MSA-1')); // AA

await client.close();

Server

Listen for incoming HL7v2 messages:

final server = MllpServer(port: 2575);
await server.start();
print('Listening on port ${server.boundPort}');

await for (final envelope in server.messages) {
  final message = Message.parse(envelope.payload);
  print('Received: ${message.messageType}^${message.triggerEvent}');

  // Send ACK back
  final ack = message.generateAck(code: AckCode.aa);
  await envelope.respond(ack.encode());
}

TLS

Both client and server support TLS and mutual TLS (mTLS):

// Client with TLS
final tlsConfig = MllpTlsConfig.fromPem(
  certChainPath: 'certs/client.pem',
  privateKeyPath: 'certs/client.key',
);

final client = MllpClient(
    host: 'hl7.hospital.org',
    port: 2576,
    tlsConfig: tlsConfig,
);

// Server with TLS + client certificate verification (mTLS)
final serverTls = MllpTlsConfig.fromPem(
    certChainPath: 'certs/server.pem',
    privateKeyPath: 'certs/server.key',
    requestClientCertificate: true,
);

final server = MllpServer(port: 2576, tlsConfig: serverTls);

Reconnection

Client automatically reconnects on connection loss:

final client = MllpClient(
    host: '192.168.1.100',
    port: 2575,
    reconnectConfig: ReconnectConfig(
        initialDelay: Duration(seconds: 1),
        maxDelay: Duration(seconds: 30),
        maxAttempts: 10,
    ),
);

// Monitor reconnection events
client.reconnectEvents.listen((event) {
  switch (event.type) {
    case ReconnectEventType.connectionLost:
      print('Connection lost: ${event.error}');
    case ReconnectEventType.reconnecting:
      print('Reconnecting (attempt ${event.attempt})...');
    case ReconnectEventType.reconnected:
      print('Reconnected!');
    case ReconnectEventType.gaveUp:
      print('Gave up after ${event.attempt} attempts');
  }
});

MLLP Codec

Low-level MLLP framing as Dart StreamTransformers — use these if you need custom transport logic:

// Encode: String → MLLP frame bytes
final encoder = MllpFrameEncoder();

// Decode: byte stream → String messages
final decoder = MllpFrameDecoder();

// Use with raw sockets
socket
    .cast<List<int>>()
    .transform(decoder)
    .listen((message) => print('Got: $message'));

Platform Support

This package requires dart:io for TCP sockets and is not available on web. For parsing without transport, use hl7v2 which works on all platforms.

Platform Supported
Dart VM (server) Yes
Flutter (Android/iOS) Yes
Flutter Web No
Dart CLI Yes

License

BSD-3-Clause. See LICENSE.

Libraries

hl7v2_mllp
MLLP transport for HL7v2 messages.