lots and lots of failover
This commit is contained in:
parent
9bb093fd4f
commit
5b1191f1be
141
lib/index.js
141
lib/index.js
|
@ -10,44 +10,131 @@ module.exports.create = function (args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var servers = loopback.create(args);
|
var servers = loopback.create(args);
|
||||||
var promises = [];
|
//var promises = [];
|
||||||
|
|
||||||
if (args.debug) {
|
if (args.debug) {
|
||||||
console.log('[HP] create servers');
|
console.log('[HP] create servers');
|
||||||
console.log(servers);
|
console.log(servers);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (-1 !== args.protocols.indexOf('none')) {
|
function getExternalIps() {
|
||||||
promises.push(PromiseA.any(args.ipifyUrls.map(function (ipifyUrl) {
|
return PromiseA.any(args.ipifyUrls.map(function (ipifyUrl) {
|
||||||
var getIp = require('./external-ip');
|
var getIp = require('./external-ip');
|
||||||
|
|
||||||
return getIp({ hostname: ipifyUrl, debug: args.debug });
|
return getIp({ hostname: ipifyUrl, debug: args.debug });
|
||||||
})).then(function (ips) {
|
|
||||||
// TODO how (if at all) should ip.address === ip.localAddress be treated differently?
|
|
||||||
// TODO check local firewall?
|
|
||||||
// TODO would it ever make sense for a public ip to respond to upnp?
|
|
||||||
var requestAsync = require('./request');
|
|
||||||
|
|
||||||
return PromiseA.all(ips.map(function (ip) {
|
|
||||||
return requestAsync({
|
|
||||||
secure: false
|
|
||||||
, hostname: ip.address
|
|
||||||
, path: '/api/com.daplie.loopback'
|
|
||||||
, servername: 'daplie.invalid'
|
|
||||||
, localAddress: ip.localAddress
|
|
||||||
, port: 65080
|
|
||||||
, headers: {
|
|
||||||
Host: 'daplie.invalid'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
return PromiseA.all(promises).then(function (results) {
|
function testOpenPort(ip, portInfo) {
|
||||||
if (args.debug) {
|
var requestAsync = require('./request');
|
||||||
console.log('[HP] all done');
|
|
||||||
console.log(results);
|
return requestAsync({
|
||||||
}
|
secure: portInfo.secure
|
||||||
|
, rejectUnauthorized: false
|
||||||
|
, hostname: ip.address
|
||||||
|
// '/.well-known/com.daplie.loopback/'
|
||||||
|
, path: args.loopbackPrefix + args.key
|
||||||
|
// 'loopback.daplie.invalid'
|
||||||
|
, servername: args.loopbackHostname
|
||||||
|
, localAddress: ip.localAddress
|
||||||
|
, port: portInfo.external || portInfo.internal
|
||||||
|
, headers: {
|
||||||
|
// 'loopback.daplie.invalid'
|
||||||
|
Host: args.loopbackHostname
|
||||||
|
}
|
||||||
|
}).then(function (val) {
|
||||||
|
if (val !== args.value) {
|
||||||
|
return PromiseA.reject(new Error("invalid loopback token value"));
|
||||||
|
}
|
||||||
|
|
||||||
|
ip.validated = true;
|
||||||
|
|
||||||
|
ip.ports.push(portInfo);
|
||||||
|
portInfo.ips.push(ip);
|
||||||
|
|
||||||
|
return portInfo;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function testPort(opts) {
|
||||||
|
// TODO should ip.address === ip.localAddress be treated differently?
|
||||||
|
// TODO check local firewall?
|
||||||
|
// TODO would it ever make sense for a public ip to respond to upnp?
|
||||||
|
|
||||||
|
// TODO should we pass any or require all?
|
||||||
|
opts.portInfo.ips = [];
|
||||||
|
|
||||||
|
return PromiseA.any(opts.ips.map(function (ip) {
|
||||||
|
ip.ports = [];
|
||||||
|
|
||||||
|
if (!opts.pretest) {
|
||||||
|
//console.log('[HP pretest]', opts.pretest);
|
||||||
|
return ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
return testOpenPort(ip, opts.portInfo);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
return getExternalIps().then(function (ips) {
|
||||||
|
var pretest = (-1 !== args.protocols.indexOf('none'));
|
||||||
|
var portInfos = args.plainPorts.concat(args.tlsPorts.map(function (info) {
|
||||||
|
info.secure = true;
|
||||||
|
return info;
|
||||||
|
}));
|
||||||
|
|
||||||
|
return PromiseA.all(portInfos.map(function (info) {
|
||||||
|
// TODO clone-merge args
|
||||||
|
return testPort({
|
||||||
|
portInfo: info
|
||||||
|
, ips: ips
|
||||||
|
, pretest: pretest
|
||||||
|
});
|
||||||
|
})).then(function (portInfos) {
|
||||||
|
if (args.debug) {
|
||||||
|
console.log('[HP] all done on the first try');
|
||||||
|
console.log(portInfos);
|
||||||
|
}
|
||||||
|
return portInfos;
|
||||||
|
}, function () {
|
||||||
|
// at least one port could not be mapped
|
||||||
|
var mappers = [];
|
||||||
|
|
||||||
|
if (-1 !== args.protocols.indexOf('upnp')
|
||||||
|
|| -1 !== args.protocols.indexOf('ssdp')
|
||||||
|
) {
|
||||||
|
mappers.push(require('./upnp'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-1 !== args.protocols.indexOf('pmp')
|
||||||
|
|| -1 !== args.protocols.indexOf('nat-pmp')
|
||||||
|
) {
|
||||||
|
mappers.push(require('./pmp'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return PromiseA.all(portInfos.map(function (portInfo) {
|
||||||
|
return PromiseA.any(mappers.map(function (fn) {
|
||||||
|
var p = fn(args, ips, portInfo);
|
||||||
|
|
||||||
|
if (portInfos.ips.length) {
|
||||||
|
return portInfos;
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}));
|
||||||
|
})).then(function () {
|
||||||
|
if (args.debug) {
|
||||||
|
console.log("[HP] all ports successfully mapped");
|
||||||
|
console.log(portInfos);
|
||||||
|
}
|
||||||
|
|
||||||
|
return portInfos;
|
||||||
|
});
|
||||||
|
}).then(function () {
|
||||||
|
return portInfos;
|
||||||
|
}, function () {
|
||||||
|
console.warn('[HP] RVPN not implemented');
|
||||||
|
return portInfos;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -56,5 +56,8 @@ module.exports.create = function (opts) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
results.key = opts.key;
|
||||||
|
results.value = opts.value;
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,14 +6,20 @@ function middleware(opts) {
|
||||||
var key = opts.key;
|
var key = opts.key;
|
||||||
var val = opts.value;
|
var val = opts.value;
|
||||||
var vhost = opts.vhost;
|
var vhost = opts.vhost;
|
||||||
var pathnamePrefix = opts.prefix || '/.well-known/com.daplie.loopback/';
|
var pathnamePrefix = opts.loopbackPrefix;
|
||||||
var defaultHostname = 'loopback.daplie.invalid';
|
var defaultHostname = opts.loopbackHostname;
|
||||||
|
|
||||||
|
if (!defaultHostname) {
|
||||||
|
defaultHostname = opts.loopbackHostname = 'loopback.daplie.invalid';
|
||||||
|
}
|
||||||
|
if (!pathnamePrefix) {
|
||||||
|
pathnamePrefix = opts.loopbackPrefix = '/.well-known/com.daplie.loopback/';
|
||||||
|
}
|
||||||
if (!key) {
|
if (!key) {
|
||||||
opts.key = require('crypto').randomBytes(8).toString('hex');
|
key = opts.key = require('crypto').randomBytes(8).toString('hex');
|
||||||
}
|
}
|
||||||
if (!val) {
|
if (!val) {
|
||||||
opts.value = require('crypto').randomBytes(16).toString('hex');
|
val = opts.value = require('crypto').randomBytes(16).toString('hex');
|
||||||
}
|
}
|
||||||
if (!vhost && vhost !== false) {
|
if (!vhost && vhost !== false) {
|
||||||
vhost = defaultHostname;
|
vhost = defaultHostname;
|
||||||
|
|
Loading…
Reference in New Issue