UNPKG

openhim-core

Version:

The OpenHIM core application that provides logging and routing of http requests

295 lines (270 loc) 9.32 kB
var AutoRetry, MAX_BODIES_SIZE, Q, SDC, _, application, autoRetryUtils, config, copyMapWithEscapedReservedCharacters, domain, enforceMaxBodiesSize, logger, os, sdc, setFinalStatus, stats, statsdServer, transactionStatus, transactions; transactions = require("../model/transactions"); logger = require("winston"); Q = require("q"); _ = require('lodash'); AutoRetry = require('../model/autoRetry').AutoRetry; autoRetryUtils = require('../autoRetry'); config = require('../config/config'); statsdServer = config.get('statsd'); application = config.get('application'); SDC = require('statsd-client'); stats = require('../stats'); os = require('os'); domain = (os.hostname()) + "." + application.name + ".appMetrics"; sdc = new SDC(statsdServer); exports.MAX_BODIES_SIZE = MAX_BODIES_SIZE = 15 * 1024 * 1024; exports.transactionStatus = transactionStatus = { PROCESSING: 'Processing', SUCCESSFUL: 'Successful', COMPLETED: 'Completed', COMPLETED_W_ERR: 'Completed with error(s)', FAILED: 'Failed' }; copyMapWithEscapedReservedCharacters = function(map) { var escapedMap, k, v; escapedMap = {}; for (k in map) { v = map[k]; if (k.indexOf('.') > -1 || k.indexOf('$') > -1) { k = k.replace('.', '\uff0e').replace('$', '\uff04'); } escapedMap[k] = v; } return escapedMap; }; enforceMaxBodiesSize = function(ctx, tx) { var enforced, len; enforced = false; if (ctx.totalBodyLength == null) { ctx.totalBodyLength = 0; } len = Buffer.byteLength(tx.body); if (ctx.totalBodyLength + len > MAX_BODIES_SIZE) { len = Math.max(0, MAX_BODIES_SIZE - ctx.totalBodyLength); tx.body = tx.body.slice(0, len); enforced = true; logger.warn('Truncated body for storage as it exceeds limits'); } ctx.totalBodyLength += len; return enforced; }; exports.storeTransaction = function(ctx, done) { var headers, ref, ref1, ref2, tx; logger.info('Storing request metadata for inbound transaction'); ctx.requestTimestamp = new Date(); headers = copyMapWithEscapedReservedCharacters(ctx.header); tx = new transactions.Transaction({ status: transactionStatus.PROCESSING, clientID: (ref = ctx.authenticated) != null ? ref._id : void 0, channelID: ctx.authorisedChannel._id, clientIP: ctx.ip, request: { host: (ref1 = ctx.host) != null ? ref1.split(':')[0] : void 0, port: (ref2 = ctx.host) != null ? ref2.split(':')[1] : void 0, path: ctx.path, headers: headers, querystring: ctx.querystring, body: ctx.body, method: ctx.method, timestamp: ctx.requestTimestamp } }); if (ctx.parentID && ctx.taskID) { tx.parentID = ctx.parentID; tx.taskID = ctx.taskID; } if (ctx.currentAttempt) { tx.autoRetryAttempt = ctx.currentAttempt; } if (ctx.authorisedChannel.requestBody === false || tx.request.body === '') { tx.request.body = ''; if (ctx.method === 'POST' || ctx.method === 'PUT' || ctx.method === 'PATCH') { tx.canRerun = false; } } if (enforceMaxBodiesSize(ctx, tx.request)) { tx.canRerun = false; } return tx.save(function(err, tx) { if (err) { logger.error('Could not save transaction metadata: ' + err); return done(err); } else { ctx.transactionId = tx._id; ctx.header['X-OpenHIM-TransactionID'] = tx._id.toString(); return done(null, tx); } }); }; exports.storeResponse = function(ctx, done) { var headers, i, len1, orch, ref, ref1, ref2, ref3, res, update; headers = copyMapWithEscapedReservedCharacters(ctx.response.header); res = { status: ctx.response.status, headers: headers, body: !ctx.response.body ? "" : ctx.response.body.toString(), timestamp: ctx.response.timestamp }; if (ctx.authorisedChannel.responseBody === false) { res.body = ''; } update = { response: res, error: ctx.error }; enforceMaxBodiesSize(ctx, update.response); if (((ref = ctx.mediatorResponse) != null ? ref.status : void 0) != null) { update.status = ctx.mediatorResponse.status; } if (ctx.mediatorResponse) { if (ctx.mediatorResponse.orchestrations) { update.orchestrations = ctx.mediatorResponse.orchestrations; ref1 = update.orchestrations; for (i = 0, len1 = ref1.length; i < len1; i++) { orch = ref1[i]; if (((ref2 = orch.request) != null ? ref2.body : void 0) != null) { enforceMaxBodiesSize(ctx, orch.request); } if (((ref3 = orch.response) != null ? ref3.body : void 0) != null) { enforceMaxBodiesSize(ctx, orch.response); } } } if (ctx.mediatorResponse.properties) { update.properties = ctx.mediatorResponse.properties; } } return transactions.Transaction.findOneAndUpdate({ _id: ctx.transactionId }, update, { runValidators: true }, function(err, tx) { if (err) { logger.error('Could not save response metadata for transaction: ' + ctx.transactionId + '. ' + err); return done(err); } if (tx === void 0 || tx === null) { logger.error('Could not find transaction: ' + ctx.transactionId); return done(err); } logger.info("stored primary response for " + tx._id); return done(); }); }; exports.storeNonPrimaryResponse = function(ctx, route, done) { var ref, ref1; if (ctx.authorisedChannel.responseBody === false) { route.response.body = ''; } if (ctx.transactionId != null) { if (((ref = route.request) != null ? ref.body : void 0) != null) { enforceMaxBodiesSize(ctx, route.request); } if (((ref1 = route.response) != null ? ref1.body : void 0) != null) { enforceMaxBodiesSize(ctx, route.response); } return transactions.Transaction.findByIdAndUpdate(ctx.transactionId, { $push: { "routes": route } }, function(err, tx) { if (err) { logger.error(err); } return done(tx); }); } else { return logger.error("the request has no transactionId"); } }; exports.setFinalStatus = setFinalStatus = function(ctx, callback) { var ref, ref1, transactionId; transactionId = ''; if ((ref = ctx.request) != null ? (ref1 = ref.header) != null ? ref1["X-OpenHIM-TransactionID"] : void 0 : void 0) { transactionId = ctx.request.header["X-OpenHIM-TransactionID"]; } else { transactionId = ctx.transactionId.toString(); } return transactions.Transaction.findById(transactionId, function(err, tx) { var i, len1, ref2, ref3, ref4, ref5, ref6, ref7, ref8, route, routeFailures, routeSuccess, update; update = {}; if (((ref2 = ctx.mediatorResponse) != null ? ref2.status : void 0) != null) { logger.info("The transaction status has been set to " + ctx.mediatorResponse.status + " by the mediator"); } else { routeFailures = false; routeSuccess = true; if (ctx.routes) { ref3 = ctx.routes; for (i = 0, len1 = ref3.length; i < len1; i++) { route = ref3[i]; if ((500 <= (ref4 = route.response.status) && ref4 <= 599)) { routeFailures = true; } if (!((200 <= (ref5 = route.response.status) && ref5 <= 299))) { routeSuccess = false; } } } if ((500 <= (ref6 = ctx.response.status) && ref6 <= 599)) { tx.status = transactionStatus.FAILED; } else { if (routeFailures) { tx.status = transactionStatus.COMPLETED_W_ERR; } if (((200 <= (ref7 = ctx.response.status) && ref7 <= 299)) && routeSuccess) { tx.status = transactionStatus.SUCCESSFUL; } if (((400 <= (ref8 = ctx.response.status) && ref8 <= 499)) && routeSuccess) { tx.status = transactionStatus.COMPLETED; } } if (tx.status === 'Processing') { tx.status = transactionStatus.COMPLETED; } ctx.transactionStatus = tx.status; logger.info("Final status for transaction " + tx._id + " : " + tx.status); update.status = tx.status; } if (ctx.autoRetry != null) { if (!autoRetryUtils.reachedMaxAttempts(tx, ctx.authorisedChannel)) { update.autoRetry = ctx.autoRetry; } else { update.autoRetry = false; } } if (_.isEmpty(update)) { return callback(tx); } return transactions.Transaction.findByIdAndUpdate(transactionId, update, {}, function(err, tx) { callback(tx); if (update.autoRetry) { autoRetryUtils.queueForRetry(tx); } if (config.statsd.enabled) { stats.incrementTransactionCount(ctx, function() {}); return stats.measureTransactionDuration(ctx, function() {}); } }); }); }; exports.koaMiddleware = function*(next) { var saveTransaction, startTime; if (statsdServer.enabled) { startTime = new Date(); } saveTransaction = Q.denodeify(exports.storeTransaction); (yield saveTransaction(this)); if (statsdServer.enabled) { sdc.timing(domain + ".messageStoreMiddleware.storeTransaction", startTime); } (yield next); if (statsdServer.enabled) { startTime = new Date(); } exports.storeResponse(this, function() {}); if (statsdServer.enabled) { return sdc.timing(domain + ".messageStoreMiddleware.storeResponse", startTime); } }; //# sourceMappingURL=messageStore.js.map