diff --git a/lib/ddns/index.js b/lib/ddns/index.js index 0de208f..4939d68 100644 --- a/lib/ddns/index.js +++ b/lib/ddns/index.js @@ -40,31 +40,28 @@ module.exports.create = function (deps, conf) { return deps.PromiseA.all(promises.filter(Boolean)); } + async function getSession(id) { + var session = await deps.storage.tokens.get(id); + if (!session) { + throw new Error('no user token with ID "'+id+'"'); + } + return session; + } + var tunnelActive = false; async function connectTunnel() { - var sessionCache = {}; - var sessionOverride; + var tunnelSession; if (conf.ddns.tunnel) { - sessionOverride = await deps.storage.tokens.get(conf.ddns.tunnel.tokenId); - } - async function getSession(id) { - if (sessionOverride) { - return sessionOverride; - } - if (!sessionCache.hasOwnProperty(id)) { - sessionCache[id] = await deps.storage.tokens.get(conf.ddns.tunnel.tokenId); - } - if (!sessionCache[id]) { - throw new Error('no user token with ID "'+id+'"'); - } - return sessionCache[id]; + // In the case of a non-existant token, I'm not sure if we want to throw here and prevent + // any tunnel connections, or if we want to ignore it and fall back to the DNS tokens + tunnelSession = await deps.storage.tokens.get(conf.ddns.tunnel.tokenId); } await iterateAllModules(function startTunnel(mod, domainsList) { if (mod.type !== 'dns@oauth3.org') { return null; } - return getSession(mod.token_id).then(function (session) { - return deps.tunnelClients.start(session, domainsList); + return getSession(mod.token_id).then(function (dnsSession) { + return deps.tunnelClients.start(tunnelSession || dnsSession, domainsList); }).catch(function (err) { console.log('error starting tunnel for', domainsList.join(', ')); console.log(err); @@ -131,17 +128,6 @@ module.exports.create = function (deps, conf) { } publicAddress = addr; - var sessionCache = {}; - async function getSession(id) { - if (!sessionCache.hasOwnProperty(id)) { - sessionCache[id] = await deps.storage.tokens.get(conf.ddns.tunnel.tokenId); - } - if (!sessionCache[id]) { - throw new Error('no user token with ID "'+id+'"'); - } - return sessionCache[id]; - } - await iterateAllModules(function setModuleDNS(mod, domainsList) { if (mod.type !== 'dns@oauth3.org' || mod.disabled) { return null; } diff --git a/lib/storage.js b/lib/storage.js index 271fed7..5c2928f 100644 --- a/lib/storage.js +++ b/lib/storage.js @@ -97,7 +97,8 @@ module.exports.create = function (deps, conf) { var userTokens = { _filename: 'user-tokens.json' - , _convertToken(id, token) { + , _cache: {} + , _convertToken: function convertToken(id, token) { // convert the token into something that looks more like what OAuth3 uses internally // as sessions so we can use it with OAuth3. We don't use OAuth3's internal session // storage because it effectively only supports storing tokens based on provider URI. @@ -118,16 +119,31 @@ module.exports.create = function (deps, conf) { } , all: function allUserTokens() { var self = this; + if (self._cacheComplete) { + return deps.PromiseA.resolve(Object.values(self._cache)); + } + return read(self._filename).then(function (tokens) { + // We will read every single token into our cache, so it will be complete once we finish + // creating the result (it's set out of order so we can directly return the result). + self._cacheComplete = true; + return Object.keys(tokens).map(function (id) { - return self._convertToken(id, tokens[id]); + self._cache[id] = self._convertToken(id, tokens[id]); + return self._cache[id]; }); }); } , get: function getUserToken(id) { var self = this; + if (self._cache.hasOwnProperty(id) || self._cacheComplete) { + return deps.PromiseA.resolve(self._cache[id] || null); + } + return read(self._filename).then(function (tokens) { return self._convertToken(id, tokens[id]); + }).then(function (session) { + self._cache[id] = session; }); } , save: function saveUserToken(newToken) { @@ -155,6 +171,9 @@ module.exports.create = function (deps, conf) { var id = idHash.digest('hex'); tokens[id] = rawToken; return write(self._filename, tokens).then(function () { + // Delete the current cache so that if this is an update it will refresh + // the cache once we read the ID. + delete self._cache[id]; return self.get(id); }); }); @@ -168,6 +187,7 @@ module.exports.create = function (deps, conf) { } return write(self._filename, tokens).then(function () { + delete self._cache[id]; return true; }); });