postmailer
Version:
HTTP POST -> SMTP proxy, as Express middleware
120 lines (111 loc) • 3.48 kB
JavaScript
var EventPlus = require('eventplus');
var UriTemplate = require('uri-templates');
function nameFromUrl(url) {
return (url + "").replace(/.*?\:\/\//, '');
}
function Transform(obj, options) {
var receiveTemplates = [].concat(obj.receive || obj.url || []).map(function (spec) {
if (typeof spec === 'string') return UriTemplate(spec);
return spec;
});
var sendTemplates = [].concat(obj.send || obj.url || []).map(function (spec) {
if (typeof spec === 'string') return UriTemplate(spec);
return spec;
});
var canonicalTemplates = [].concat(obj.canonical || obj.url || obj.receive || []).map(function (spec) {
if (typeof spec === 'string') return UriTemplate(spec);
return spec;
});
var allTemplates = receiveTemplates.concat(sendTemplates).concat(canonicalTemplates);
var name = obj.name;
var defaultParams = options.defaultParams || {};
function firstMatch(matchTemplates, replacementTemplates, urls) {
urls = [].concat(urls);
for (var i = 0; i < matchTemplates.length; i++) {
for (var j = 0; j < urls.length; j++) {
// TODO: normalise to mailto: addresses
var url = urls[j];
var params = matchTemplates[i].fromUri(url);
if (params) {
var urls = [];
replacementTemplates.forEach(function (template) {
var url = template.fill(params);
if (options.strict) {
// Check round-trip consistency of params
var roundTripParams = template.fromUri(url);
for (var key in roundTripParams) {
if (roundTripParams[key] != (params[key] || defaultParams[key])) {
return;
}
}
for (var key in params) {
if (params[key] != (roundTripParams[key] || defaultParams[key])) {
return;
}
}
}
urls.push(url);
});
var match = {
matchedUrl: url,
urls: urls,
params: params
};
if (typeof name === 'function') {
match.name = name(params, match);
} else {
match.name = name || nameFromUrl(match.urls[0]);
}
return match;
}
}
}
return null;
}
this.match = function (urls) {
return firstMatch(receiveTemplates, sendTemplates, urls);
};
this.canonical = function (url) {
var match = firstMatch(allTemplates, canonicalTemplates, url);
return match ? match.urls : [];
}
}
Transform.prototype = {};
function Hub(options) {
if (!(this instanceof Hub)) return new Hub(options);
EventPlus.call(this);
var transforms = [].concat(options.mapping || []).map(function (transformSpec) {
return new Transform(transformSpec, options);
});
this.match = function (urls) {
for (var i = 0; i < transforms.length; i++) {
var match = transforms[i].match(urls);
if (match) return match;
}
return null;
};
this.canonical = function (url) {
var result = [];
for (var i = 0; i < transforms.length; i++) {
result = result.concat(transforms[i].canonical(urls));
}
// Last option is original URL
result.push(url);
return result;
};
// Mail and chat events must be handled
this.on('mail', function (mail) {
var error = new Error('Unhandled mail message for ' + mail.target.name);
error.mail = mail;
error.urls = mail.target.urls;
this.emit('error', error);
});
this.on('chat', function (chat) {
var error = new Error('Unhandled chat message for ' + chat.target.name);
error.chat = chat;
error.urls = chat.target.urls;
this.emit('error', error);
});
}
Hub.prototype = Object.create(EventPlus.prototype);
module.exports = Hub;