/
ResolveTask.js
100 lines (80 loc) · 2.4 KB
/
ResolveTask.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
'use strict';
/**
* @typedef {Object} Address
* @property {string} address - IPv4 or IPv6 address
* @property {number} ttl - IP DNS TTL
* @property {number} family - IP family
* @property {number} expiredTime - DNS TTL expiration timestamp
*/
const assert = require('assert');
const dns = require('dns');
const { EventEmitter } = require('events');
const _ = require('lodash');
class ResolveTask extends EventEmitter {
/**
* @returns {number}
*/
static get IPv4() {
return 4;
}
/**
* @returns {number}
*/
static get IPv6() {
return 6;
}
/**
* @param {string} hostname
* @param {number} ipVersion
*/
constructor(hostname, ipVersion) {
super();
assert(
_.isString(hostname) && hostname.length > 0,
`hostname must be not empty string, '${hostname}' has been provided.`
);
assert(
ipVersion === ResolveTask.IPv4 || ipVersion === ResolveTask.IPv6,
`ipVersion must be 4 or 6. '${ipVersion}' has been provided.`
);
this._callbacks = [];
this._hostname = hostname;
this._ipVersion = ipVersion;
this._resolver =
ipVersion === ResolveTask.IPv4 ? dns.resolve4 : dns.resolve6;
this._resolved = this._resolved.bind(this);
}
/**
* @param {Function} callback
*/
addResolvedCallback(callback) {
this._callbacks.push(callback);
}
run() {
this._resolver(this._hostname, { ttl: true }, this._resolved);
}
/**
* @param {Error} error
* @param {Address[]} addresses
* @emits ResolveTask#addresses array of addresses
* @emits ResolveTask#done notification about completion
* @private
*/
_resolved(error, addresses) {
assert(this._callbacks.length > 0, 'callbacks array cannot be empty.');
if (!error) {
assert(Array.isArray(addresses), 'addresses must be an array.');
addresses.forEach(address => {
address.family = this._ipVersion;
address.expiredTime = Date.now() + address.ttl * 1000;
});
this.emit('addresses', addresses);
}
this._callbacks.forEach(callback => {
setImmediate(() => callback(error, addresses));
});
this._callbacks = [];
this.emit('done');
}
}
module.exports = ResolveTask;