openhim-core
Version:
The OpenHIM core application that provides logging and routing of http requests
295 lines (270 loc) • 9.32 kB
JavaScript
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