Skip to content

Commit 08fa451

Browse files
committed
Eliminate circular dependency
1 parent bb84ded commit 08fa451

File tree

4 files changed

+105
-96
lines changed

4 files changed

+105
-96
lines changed

backend/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ async function appStart () {
99
const apiValidator = require('./lib/validator/api');
1010
const internalCertificate = require('./internal/certificate');
1111
const internalIpRanges = require('./internal/ip_ranges');
12-
const ddnsResolver = require('./lib/ddns_resolver');
12+
const ddnsUpdater = require('./lib/ddns_resolver/ddns_updater');
1313

1414
return migrate.latest()
1515
.then(setup)
@@ -21,7 +21,7 @@ async function appStart () {
2121

2222
internalCertificate.initTimer();
2323
internalIpRanges.initTimer();
24-
ddnsResolver.initTimer();
24+
ddnsUpdater.initTimer();
2525

2626
const server = app.listen(3000, () => {
2727
logger.info('Backend PID ' + process.pid + ' listening on port 3000 ...');

backend/internal/nginx.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const logger = require('../logger').nginx;
44
const config = require('../lib/config');
55
const utils = require('../lib/utils');
66
const error = require('../lib/error');
7-
const ddnsResolver = require('../lib/ddns_resolver');
7+
const ddnsResolver = require('../lib/ddns_resolver/ddns_resolver');
88

99
const internalNginx = {
1010

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
const error = require('../error');
2+
const logger = require('../../logger').ddns;
3+
const utils = require('../utils');
4+
5+
const ddnsResolver = {
6+
/**
7+
* Checks whether the address requires resolution (i.e. starts with ddns:)
8+
* @param {String} address
9+
* @returns {boolean}
10+
*/
11+
requiresResolution: (address) => {
12+
if (typeof address !== 'undefined' && address && address.toLowerCase().startsWith('ddns:')) {
13+
return true;
14+
}
15+
return false;
16+
},
17+
18+
/**
19+
* Resolves the given address to its IP
20+
* @param {String} address
21+
* @param {boolean} forceUpdate: whether to force resolution instead of using the cached value
22+
*/
23+
resolveAddress: (address, forceUpdate=false) => {
24+
if (!forceUpdate && ddnsResolver._cache.has(address)) {
25+
// Check if it is still valid
26+
const value = ddnsResolver._cache.get(address);
27+
const ip = value[0];
28+
const lastUpdated = value[1];
29+
const nowSeconds = Date.now();
30+
const delta = nowSeconds - lastUpdated;
31+
if (delta < ddnsResolver._updateIntervalMs) {
32+
return Promise.resolve(ip);
33+
}
34+
}
35+
ddnsResolver._cache.delete(address);
36+
// Reach here only if cache value doesn't exist or needs to be updated
37+
let host = address.toLowerCase();
38+
if (host.startsWith('ddns:')) {
39+
host = host.substring(5);
40+
}
41+
return ddnsResolver._queryHost(host)
42+
.then((resolvedIP) => {
43+
ddnsResolver._cache.set(address, [resolvedIP, Date.now()]);
44+
return resolvedIP;
45+
})
46+
.catch((/*error*/) => {
47+
// return input address in case of failure
48+
return address;
49+
});
50+
},
51+
52+
53+
/** Private **/
54+
// Properties
55+
/**
56+
* cache mapping host to (ip address, last updated time)
57+
*/
58+
_cache: new Map(),
59+
60+
// Methods
61+
/**
62+
*
63+
* @param {String} host
64+
* @returns {Promise}
65+
*/
66+
_queryHost: (host) => {
67+
logger.info('Looking up IP for ', host);
68+
return utils.execSafe('getent', ['hosts', host])
69+
.then((result) => {
70+
if (result.length < 8) {
71+
logger.error('IP lookup returned invalid output: ', result);
72+
throw error.ValidationError('Invalid output from getent hosts');
73+
}
74+
const out = result.split(/\s+/);
75+
logger.info(`Resolved ${host} to ${out[0]}`);
76+
return out[0];
77+
},
78+
(error) => {
79+
logger.error('Error looking up IP for ' + host + ': ', error);
80+
throw error;
81+
});
82+
},
83+
};
84+
85+
module.exports = ddnsResolver;
Lines changed: 17 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,31 @@
1-
const error = require('./error');
2-
const logger = require('../logger').ddns;
3-
const internalAccessList = require('../internal/access-list');
4-
const utils = require('./utils');
1+
const internalNginx = require('../../internal/nginx');
2+
const logger = require('../../logger').ddns;
3+
const internalAccessList = require('../../internal/access-list');
4+
const ddnsResolver = require('./ddns_resolver');
55

6-
const ddnsResolver = {
6+
const ddnsUpdater = {
77
/**
88
* Starts a timer to periodically check for ddns updates
99
*/
1010
initTimer: () => {
11-
ddnsResolver._initialize();
12-
ddnsResolver._interval = setInterval(ddnsResolver._checkForDDNSUpdates, ddnsResolver._updateIntervalMs);
13-
logger.info(`DDNS Update Timer initialized (interval: ${Math.floor(ddnsResolver._updateIntervalMs / 1000)}s)`);
11+
ddnsUpdater._initialize();
12+
ddnsUpdater._interval = setInterval(ddnsUpdater._checkForDDNSUpdates, ddnsUpdater._updateIntervalMs);
13+
logger.info(`DDNS Update Timer initialized (interval: ${Math.floor(ddnsUpdater._updateIntervalMs / 1000)}s)`);
1414
// Trigger a run so that initial cache is populated and hosts can be updated - delay by 10s to give server time to boot up
15-
setTimeout(ddnsResolver._checkForDDNSUpdates, 10 * 1000);
15+
setTimeout(ddnsUpdater._checkForDDNSUpdates, 10 * 1000);
1616
},
1717

18-
/**
19-
* Checks whether the address requires resolution (i.e. starts with ddns:)
20-
* @param {String} address
21-
* @returns {boolean}
22-
*/
23-
requiresResolution: (address) => {
24-
if (typeof address !== 'undefined' && address && address.toLowerCase().startsWith('ddns:')) {
25-
return true;
26-
}
27-
return false;
28-
},
29-
30-
/**
31-
* Resolves the given address to its IP
32-
* @param {String} address
33-
* @param {boolean} forceUpdate: whether to force resolution instead of using the cached value
34-
*/
35-
resolveAddress: (address, forceUpdate=false) => {
36-
if (!forceUpdate && ddnsResolver._cache.has(address)) {
37-
// Check if it is still valid
38-
const value = ddnsResolver._cache.get(address);
39-
const ip = value[0];
40-
const lastUpdated = value[1];
41-
const nowSeconds = Date.now();
42-
const delta = nowSeconds - lastUpdated;
43-
if (delta < ddnsResolver._updateIntervalMs) {
44-
return Promise.resolve(ip);
45-
}
46-
}
47-
ddnsResolver._cache.delete(address);
48-
// Reach here only if cache value doesn't exist or needs to be updated
49-
let host = address.toLowerCase();
50-
if (host.startsWith('ddns:')) {
51-
host = host.substring(5);
52-
}
53-
return ddnsResolver._queryHost(host)
54-
.then((resolvedIP) => {
55-
ddnsResolver._cache.set(address, [resolvedIP, Date.now()]);
56-
return resolvedIP;
57-
})
58-
.catch((/*error*/) => {
59-
// return input address in case of failure
60-
return address;
61-
});
62-
},
63-
64-
6518
/** Private **/
6619
// Properties
6720
_initialized: false,
6821
_updateIntervalMs: 60 * 60 * 1000, // 1 hr default (overriden with $DDNS_UPDATE_INTERVAL env var)
69-
/**
70-
* cache mapping host to (ip address, last updated time)
71-
*/
72-
_cache: new Map(),
7322
_interval: null, // reference to created interval id
7423
_processingDDNSUpdate: false,
7524

7625
// Methods
7726

7827
_initialize: () => {
79-
if (ddnsResolver._initialized) {
28+
if (ddnsUpdater._initialized) {
8029
return;
8130
}
8231
// Init the resolver
@@ -85,51 +34,26 @@ const ddnsResolver = {
8534
const interval = Number(process.env.DDNS_UPDATE_INTERVAL.toLowerCase());
8635
if (!isNaN(interval)) {
8736
// Interval value from env is in seconds. Set min to 60s.
88-
ddnsResolver._updateIntervalMs = Math.max(interval * 1000, 60 * 1000);
37+
ddnsUpdater._updateIntervalMs = Math.max(interval * 1000, 60 * 1000);
8938
} else {
9039
logger.warn(`[DDNS] invalid value for update interval: '${process.env.DDNS_UPDATE_INTERVAL}'`);
9140
}
9241
}
93-
ddnsResolver._initialized = true;
94-
},
95-
96-
/**
97-
*
98-
* @param {String} host
99-
* @returns {Promise}
100-
*/
101-
_queryHost: (host) => {
102-
logger.info('Looking up IP for ', host);
103-
return utils.execSafe('getent', ['hosts', host])
104-
.then((result) => {
105-
if (result.length < 8) {
106-
logger.error('IP lookup returned invalid output: ', result);
107-
throw error.ValidationError('Invalid output from getent hosts');
108-
}
109-
const out = result.split(/\s+/);
110-
logger.info(`Resolved ${host} to ${out[0]}`);
111-
return out[0];
112-
},
113-
(error) => {
114-
logger.error('Error looking up IP for ' + host + ': ', error);
115-
throw error;
116-
});
42+
ddnsUpdater._initialized = true;
11743
},
11844

11945
/**
12046
* Triggered by a timer, will check for and update ddns hosts in access list clients
12147
*/
12248
_checkForDDNSUpdates: () => {
123-
const internalNginx = require('../internal/nginx'); // Prevent circular import
124-
12549
logger.info('Checking for DDNS updates...');
126-
if (!ddnsResolver._processingDDNSUpdate) {
127-
ddnsResolver._processingDDNSUpdate = true;
50+
if (!ddnsUpdater._processingDDNSUpdate) {
51+
ddnsUpdater._processingDDNSUpdate = true;
12852

12953
const updatedAddresses = new Map();
13054

13155
// Get all ddns hostnames in use
132-
return ddnsResolver._getAccessLists()
56+
return ddnsUpdater._getAccessLists()
13357
.then((rows) => {
13458
// Build map of used addresses that require resolution
13559
const usedAddresses = new Map();
@@ -202,7 +126,7 @@ const ddnsResolver = {
202126
})
203127
.then(() => {
204128
logger.info('Finished checking for DDNS updates');
205-
ddnsResolver._processingDDNSUpdate = false;
129+
ddnsUpdater._processingDDNSUpdate = false;
206130
});
207131
} else {
208132
logger.info('Skipping since previous DDNS update check is in progress');
@@ -236,4 +160,4 @@ const ddnsResolver = {
236160
}
237161
};
238162

239-
module.exports = ddnsResolver;
163+
module.exports = ddnsUpdater;

0 commit comments

Comments
 (0)