2026-03-26 16:52:54 +07:00
|
|
|
const queue = require('../queue/sqliteQueue');
|
|
|
|
|
const logger = require('../utils/logger');
|
|
|
|
|
const { normalize } = require('../normalizers');
|
|
|
|
|
const { dedupeKey } = require('../utils/hash');
|
|
|
|
|
const instrumentService = require('../instrumentConfig/service');
|
|
|
|
|
|
|
|
|
|
const parserMap = {
|
|
|
|
|
'http-json': require('../parsers/httpParser'),
|
|
|
|
|
'hl7-tcp': require('../parsers/hl7Parser'),
|
2026-04-06 16:50:17 +07:00
|
|
|
'astm-serial': require('../parsers/astmParser'),
|
|
|
|
|
hl7: require('../parsers/hl7Parser'),
|
|
|
|
|
astm: require('../parsers/astmParser'),
|
|
|
|
|
http: require('../parsers/httpParser')
|
2026-03-26 16:52:54 +07:00
|
|
|
};
|
|
|
|
|
|
2026-04-06 16:50:17 +07:00
|
|
|
function resolveParser(connector, instrumentEntry) {
|
|
|
|
|
const parserName = instrumentEntry?.translator?.parser || connector;
|
|
|
|
|
const parser = parserMap[parserName];
|
|
|
|
|
if (!parser) {
|
|
|
|
|
throw new Error(`no parser registered for ${parserName}`);
|
|
|
|
|
}
|
|
|
|
|
return parser;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function processMessage(connector, rawPayload, context = {}) {
|
2026-03-26 16:52:54 +07:00
|
|
|
const rawRecord = await queue.insertRaw(connector, rawPayload);
|
|
|
|
|
const rawId = rawRecord?.lastID;
|
|
|
|
|
try {
|
2026-04-06 16:50:17 +07:00
|
|
|
const matcher = instrumentService.resolveForMessage(connector, context);
|
|
|
|
|
if (matcher.status === 'no_match') {
|
|
|
|
|
logger.warn({ connector, context }, 'no matching instrument config, dropping payload');
|
|
|
|
|
await queue.markRawParsed(rawId, 'dropped', 'no matching instrument config');
|
2026-03-26 16:52:54 +07:00
|
|
|
return { dropped: true };
|
|
|
|
|
}
|
2026-04-06 16:50:17 +07:00
|
|
|
if (matcher.status === 'ambiguous') {
|
|
|
|
|
logger.warn({ connector, context, matches: matcher.matches }, 'ambiguous instrument match, dropping payload');
|
|
|
|
|
await queue.markRawParsed(rawId, 'dropped', 'ambiguous instrument match');
|
2026-03-26 16:52:54 +07:00
|
|
|
return { dropped: true };
|
|
|
|
|
}
|
2026-04-06 16:50:17 +07:00
|
|
|
|
|
|
|
|
const instrumentEntry = matcher.entry;
|
|
|
|
|
const parser = resolveParser(connector, instrumentEntry);
|
|
|
|
|
const parsed = await parser.parse(rawPayload);
|
|
|
|
|
const translated = instrumentService.applyTranslator(instrumentEntry, parsed, connector);
|
|
|
|
|
const canonical = normalize(translated);
|
2026-03-26 16:52:54 +07:00
|
|
|
const dedupe = dedupeKey(canonical);
|
|
|
|
|
const inserted = await queue.insertOutbox(canonical, dedupe);
|
|
|
|
|
await queue.markRawParsed(rawId, 'processed');
|
|
|
|
|
if (inserted && inserted.duplicate) {
|
|
|
|
|
logger.info({ dedupe, connector }, 'duplicate payload detected');
|
|
|
|
|
}
|
|
|
|
|
return { canonical, inserted, dedupe };
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error({ err: error.message, connector }, 'message processing failed');
|
|
|
|
|
if (rawId) {
|
|
|
|
|
await queue.markRawParsed(rawId, 'failed', error.message);
|
|
|
|
|
}
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module.exports = { processMessage };
|