@eggjs/tegg-dns-cache 3.68.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017-present Alibaba Group Holding Limited and other contributors.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,144 @@
1
+ # @eggjs/tegg-dns-cache
2
+
3
+ DNS cache plugin for tegg framework. This plugin provides DNS caching capabilities to improve performance and reduce DNS lookup time.
4
+
5
+ ## Features
6
+
7
+ - 🚀 DNS lookup caching with LRU algorithm
8
+ - ⚖️ Round-robin address rotation for load balancing
9
+ - 🔄 Support both `dns.lookup` and `dns.resolve` modes
10
+ - ⏱️ Configurable cache TTL
11
+ - 🔌 Automatic integration with egg httpclient
12
+ - 🎯 Custom DNS nameservers support
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install @eggjs/tegg-dns-cache --save
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ ### Enable Plugin
23
+
24
+ ```js
25
+ // config/plugin.js
26
+ exports.dnsCache = {
27
+ enable: true,
28
+ package: '@eggjs/tegg-dns-cache',
29
+ };
30
+ ```
31
+
32
+ ### Configuration
33
+
34
+ ```js
35
+ // config/config.default.js
36
+ exports.dnsCache = {
37
+ // DNS resolution mode: 'lookup' or 'resolve' (default: 'resolve')
38
+ // - lookup: Use dns.lookup, respects /etc/hosts, but no TTL support
39
+ // - resolve: Use dns.resolve, queries DNS directly, TTL supported
40
+ mode: 'resolve',
41
+
42
+ // Custom DNS nameservers (only for 'resolve' mode)
43
+ dnsServers: ['8.8.8.8', '1.1.1.1'],
44
+
45
+ // Maximum cache entries (default: 1000)
46
+ maxCacheLength: 1000,
47
+
48
+ // Cache lookup interval in ms (only for 'lookup' mode, default: 10000)
49
+ lookupInterval: 10000,
50
+
51
+ // Enable address rotation for multiple IPs (default: true)
52
+ addressRotation: true,
53
+ };
54
+ ```
55
+
56
+ ## DNS Resolution Modes
57
+
58
+ ### Resolve Mode (Recommended)
59
+
60
+ Uses `dns.resolve4()` to query DNS servers directly. Supports TTL from DNS records.
61
+
62
+ **Advantages:**
63
+ - Respects DNS TTL from authoritative servers
64
+ - More control over DNS resolution
65
+ - Can specify custom nameservers
66
+
67
+ **Note:** Does not respect `/etc/hosts` file.
68
+
69
+ ```js
70
+ exports.dnsCache = {
71
+ mode: 'resolve',
72
+ dnsServers: ['8.8.8.8', '1.1.1.1'], // Optional custom DNS servers
73
+ };
74
+ ```
75
+
76
+ ### Lookup Mode
77
+
78
+ Uses `dns.lookup()` which respects system DNS configuration and `/etc/hosts`.
79
+
80
+ **Advantages:**
81
+ - Respects `/etc/hosts` entries
82
+ - Uses system DNS configuration
83
+
84
+ **Disadvantages:**
85
+ - Fixed cache interval (no real TTL)
86
+ - Less control over resolution
87
+
88
+ ```js
89
+ exports.dnsCache = {
90
+ mode: 'lookup',
91
+ lookupInterval: 10000, // Cache refresh interval in ms
92
+ };
93
+ ```
94
+
95
+ ## API
96
+
97
+ ### Access DNS Resolver
98
+
99
+ ```js
100
+ // In controller or service
101
+ const resolver = this.app.dnsResolver;
102
+
103
+ // Get cached DNS record
104
+ const record = resolver.getCacheRecord('example.com');
105
+ console.log(record); // { ip: '93.184.216.34', family: 4, ttl: 60000, ... }
106
+
107
+ // Clear DNS cache
108
+ resolver.resetCache();
109
+
110
+ // Get the underlying LRU cache
111
+ const cache = resolver.getDnsCache();
112
+ ```
113
+
114
+ ## Address Rotation
115
+
116
+ When a hostname resolves to multiple IP addresses, the plugin can automatically rotate through them for load balancing:
117
+
118
+ ```js
119
+ exports.dnsCache = {
120
+ addressRotation: true, // Enable round-robin rotation
121
+ };
122
+ ```
123
+
124
+ Each request to the same hostname will use the next IP address in rotation.
125
+
126
+ ## Integration with HttpClient
127
+
128
+ The plugin automatically integrates with egg's built-in httpclient. All HTTP requests will benefit from DNS caching:
129
+
130
+ ```js
131
+ // This request will use cached DNS
132
+ await this.app.httpclient.request('https://example.com/api');
133
+ ```
134
+
135
+ ## Performance Benefits
136
+
137
+ - **Reduced DNS lookup time**: Cached DNS results eliminate network round trips
138
+ - **Lower DNS server load**: Fewer queries to DNS servers
139
+ - **Improved request throughput**: Faster connection establishment
140
+ - **Load distribution**: Address rotation spreads load across multiple IPs
141
+
142
+ ## License
143
+
144
+ MIT
package/app.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ import { Application } from 'egg';
2
+ export default class DnsCacheAppHook {
3
+ private readonly app;
4
+ private dnsResolver;
5
+ constructor(app: Application);
6
+ configWillLoad(): void;
7
+ configDidLoad(): void;
8
+ didLoad(): Promise<void>;
9
+ beforeClose(): void;
10
+ }
package/app.js ADDED
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const DnsResolver_1 = require("./lib/DnsResolver");
4
+ class DnsCacheAppHook {
5
+ constructor(app) {
6
+ this.app = app;
7
+ }
8
+ configWillLoad() {
9
+ if (!this.app.config.dnsCache) {
10
+ this.app.logger.warn('[tegg-dns-cache-plugin] DNS cache is disabled, please setup dnsCache config.');
11
+ }
12
+ const config = this.app.config.dnsCache || {};
13
+ // Create DNS resolver instance
14
+ const useDNSResolver = config.mode !== 'lookup';
15
+ this.dnsResolver = new DnsResolver_1.DnsResolver({
16
+ useResolver: useDNSResolver,
17
+ servers: config.dnsServers,
18
+ max: config.maxCacheLength || 1000,
19
+ dnsCacheLookupInterval: config.lookupInterval || 10000,
20
+ addressRotation: config.addressRotation !== false,
21
+ }, { logger: this.app.logger });
22
+ const lookupFunction = this.dnsResolver.getLookupFunction();
23
+ this.app.config.httpclient = this.app.config.httpclient || {};
24
+ this.app.config.httpclient.lookup = lookupFunction;
25
+ }
26
+ configDidLoad() {
27
+ // Add dnsResolver to app
28
+ this.app.dnsResolver = this.dnsResolver;
29
+ }
30
+ async didLoad() {
31
+ await this.app.moduleHandler.ready();
32
+ }
33
+ beforeClose() {
34
+ // Cleanup DNS cache resources
35
+ this.dnsResolver.resetCache();
36
+ }
37
+ }
38
+ exports.default = DnsCacheAppHook;
39
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBwLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiYXBwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQ0EsbURBQWdEO0FBRWhELE1BQXFCLGVBQWU7SUFJbEMsWUFBWSxHQUFnQjtRQUMxQixJQUFJLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQztJQUNqQixDQUFDO0lBRUQsY0FBYztRQUNaLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUM5QixJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQ2xCLDhFQUE4RSxDQUMvRSxDQUFDO1FBQ0osQ0FBQztRQUNELE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLFFBQVEsSUFBSSxFQUFFLENBQUM7UUFFOUMsK0JBQStCO1FBQy9CLE1BQU0sY0FBYyxHQUFHLE1BQU0sQ0FBQyxJQUFJLEtBQUssUUFBUSxDQUFDO1FBQ2hELElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSx5QkFBVyxDQUNoQztZQUNFLFdBQVcsRUFBRSxjQUFjO1lBQzNCLE9BQU8sRUFBRSxNQUFNLENBQUMsVUFBVTtZQUMxQixHQUFHLEVBQUUsTUFBTSxDQUFDLGNBQWMsSUFBSSxJQUFJO1lBQ2xDLHNCQUFzQixFQUFFLE1BQU0sQ0FBQyxjQUFjLElBQUksS0FBSztZQUN0RCxlQUFlLEVBQUUsTUFBTSxDQUFDLGVBQWUsS0FBSyxLQUFLO1NBQ2xELEVBQ0QsRUFBRSxNQUFNLEVBQUUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsQ0FDNUIsQ0FBQztRQUNGLE1BQU0sY0FBYyxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztRQUM1RCxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsVUFBVSxJQUFJLEVBQUUsQ0FBQztRQUM5RCxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsTUFBTSxHQUFHLGNBQWMsQ0FBQztJQUNyRCxDQUFDO0lBRUQsYUFBYTtRQUNYLHlCQUF5QjtRQUN6QixJQUFJLENBQUMsR0FBRyxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDO0lBQzFDLENBQUM7SUFFRCxLQUFLLENBQUMsT0FBTztRQUNYLE1BQU0sSUFBSSxDQUFDLEdBQUcsQ0FBQyxhQUFhLENBQUMsS0FBSyxFQUFFLENBQUM7SUFDdkMsQ0FBQztJQUVELFdBQVc7UUFDVCw4QkFBOEI7UUFDOUIsSUFBSSxDQUFDLFdBQVcsQ0FBQyxVQUFVLEVBQUUsQ0FBQztJQUNoQyxDQUFDO0NBQ0Y7QUE5Q0Qsa0NBOENDIn0=
@@ -0,0 +1,26 @@
1
+ /**
2
+ * DNS Cache Configuration
3
+ *
4
+ * The DNS cache plugin provides DNS caching and resolution capabilities to improve performance
5
+ * by caching DNS lookups and supports both dns.lookup and dns.resolve modes with address rotation.
6
+ *
7
+ * @property {'lookup' | 'resolve'} mode - Use dns.lookup or dns.resolve, default is 'resolve'.
8
+ * - lookup: Use dns.lookup mode (old behavior), respects system DNS configuration and /etc/hosts, but does not support ttl.
9
+ * - resolve: Use dns.resolve mode (new feature), queries DNS servers directly, ttl supported.
10
+ * Note: When using resolve mode, /etc/hosts is not respected. You may need to implement custom logic
11
+ * if you want to include /etc/hosts resolution.
12
+ * @property {Number} maxCacheLength - Maximum number of DNS cache entries, default is 1000.
13
+ * Uses LRU (Least Recently Used) algorithm to evict old entries when cache is full.
14
+ * @property {Number} lookupInterval - Only works when mode is 'lookup'. DNS cache lookup interval in milliseconds, default is 10000 (10 seconds).
15
+ * @property {Boolean} addressRotation - Enable round-robin address rotation when multiple IP addresses
16
+ * are returned for a hostname, default is true. Helps distribute load across multiple servers.
17
+ * @property {Array<String>} dnsServers - Custom DNS nameservers for dns.resolve mode, e.g. ['8.8.8.8', '1.1.1.1'].
18
+ * Only effective when mode is 'resolve'. If not set, uses system default DNS servers.
19
+ */
20
+ export declare const dnsCache: {
21
+ mode: "lookup" | "resolve";
22
+ maxCacheLength: number;
23
+ lookupInterval: number;
24
+ addressRotation: boolean;
25
+ dnsServers: string[] | undefined;
26
+ };
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ /**
3
+ * DNS Cache Configuration
4
+ *
5
+ * The DNS cache plugin provides DNS caching and resolution capabilities to improve performance
6
+ * by caching DNS lookups and supports both dns.lookup and dns.resolve modes with address rotation.
7
+ *
8
+ * @property {'lookup' | 'resolve'} mode - Use dns.lookup or dns.resolve, default is 'resolve'.
9
+ * - lookup: Use dns.lookup mode (old behavior), respects system DNS configuration and /etc/hosts, but does not support ttl.
10
+ * - resolve: Use dns.resolve mode (new feature), queries DNS servers directly, ttl supported.
11
+ * Note: When using resolve mode, /etc/hosts is not respected. You may need to implement custom logic
12
+ * if you want to include /etc/hosts resolution.
13
+ * @property {Number} maxCacheLength - Maximum number of DNS cache entries, default is 1000.
14
+ * Uses LRU (Least Recently Used) algorithm to evict old entries when cache is full.
15
+ * @property {Number} lookupInterval - Only works when mode is 'lookup'. DNS cache lookup interval in milliseconds, default is 10000 (10 seconds).
16
+ * @property {Boolean} addressRotation - Enable round-robin address rotation when multiple IP addresses
17
+ * are returned for a hostname, default is true. Helps distribute load across multiple servers.
18
+ * @property {Array<String>} dnsServers - Custom DNS nameservers for dns.resolve mode, e.g. ['8.8.8.8', '1.1.1.1'].
19
+ * Only effective when mode is 'resolve'. If not set, uses system default DNS servers.
20
+ */
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.dnsCache = void 0;
23
+ exports.dnsCache = {
24
+ mode: 'resolve',
25
+ maxCacheLength: 1000,
26
+ lookupInterval: 10000,
27
+ addressRotation: true,
28
+ dnsServers: undefined,
29
+ };
30
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmRlZmF1bHQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJjb25maWcuZGVmYXVsdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWtCRzs7O0FBRVUsUUFBQSxRQUFRLEdBQUc7SUFDdEIsSUFBSSxFQUFFLFNBQWlDO0lBQ3ZDLGNBQWMsRUFBRSxJQUFJO0lBQ3BCLGNBQWMsRUFBRSxLQUFLO0lBQ3JCLGVBQWUsRUFBRSxJQUFJO0lBQ3JCLFVBQVUsRUFBRSxTQUFpQztDQUM5QyxDQUFDIn0=
@@ -0,0 +1,97 @@
1
+ import * as dns from 'node:dns';
2
+ import { LRU } from 'ylru';
3
+ import { EggLogger } from 'egg';
4
+ import { LookupAddress } from 'node:dns';
5
+ export interface DnsResolverOptions {
6
+ useResolver?: boolean;
7
+ max?: number;
8
+ dnsCacheLookupInterval?: number;
9
+ servers?: string[];
10
+ addressRotation?: boolean;
11
+ }
12
+ export interface DnsCacheRecord {
13
+ ip: string;
14
+ family: number;
15
+ ttl: number;
16
+ timestamp: number;
17
+ index: number;
18
+ }
19
+ export declare class DnsResolver {
20
+ private _maxCacheSize;
21
+ private _dnsCache;
22
+ private useResolver;
23
+ private dnsCacheLookupInterval;
24
+ private enableAddressRotation;
25
+ private resolver?;
26
+ private _resolve4?;
27
+ private _lookup?;
28
+ logger: EggLogger;
29
+ /**
30
+ * Create a DNS cache resolver instance
31
+ * @param options - Configuration options
32
+ * @param options.useResolver - enable dns.resolver, otherwise use dns.lookup by default
33
+ * @param options.max - Maximum cache size, default is 1000
34
+ * @param options.dnsCacheLookupInterval - DNS cache lookup interval in milliseconds, effective when useResolver == false, default is 10000
35
+ * @param options.servers - Custom DNS nameservers, effective when useResolver == true, e.g. ['8.8.8.8', '1.1.1.1']
36
+ * @param options.addressRotation - Enable address rotation for both lookup and resolve modes, default is true
37
+ */
38
+ constructor(options: DnsResolverOptions | undefined, args: {
39
+ logger: EggLogger;
40
+ });
41
+ get maxCacheSize(): number;
42
+ private _debugLog;
43
+ resetCacheSize(size: number): void;
44
+ /**
45
+ * Initialize DNS resolver with custom nameservers if provided
46
+ * @param defaultServers - Custom DNS nameservers
47
+ * @private
48
+ */
49
+ private _initializeResolver;
50
+ /**
51
+ * Get the lookup function compatible with dns.lookup signature
52
+ */
53
+ getLookupFunction(): typeof dns.lookup;
54
+ /**
55
+ * This method may throw error if there is dns query in progress!
56
+ * @throws Error
57
+ * @param {string[]} servers eg. ['8.8.8.8']
58
+ */
59
+ setServers(servers: string[]): void;
60
+ getDnsCache(): LRU;
61
+ /**
62
+ * Callback with record, handling rotation
63
+ * @param record - DNS record with rotation state
64
+ * @param options - Lookup options
65
+ * @param callback - Callback function
66
+ * @private
67
+ */
68
+ private _callbackWithRecord;
69
+ lookup(hostname: string): Promise<LookupAddress[]>;
70
+ resolve4(hostname: string): Promise<dns.RecordWithTtl[]>;
71
+ /**
72
+ * Update DNS cache with fresh resolution
73
+ * Supports both dns.lookup and dns.resolve modes
74
+ * @param hostname - The hostname to resolve
75
+ * @private
76
+ */
77
+ private _updateDNS;
78
+ /**
79
+ * Debug DNS errors
80
+ * @param err - Error object
81
+ * @param mode - 'lookup' or 'resolve'
82
+ * @private
83
+ */
84
+ private _errorDNS;
85
+ /**
86
+ * Clear the DNS cache
87
+ * @param recreate - Whether to recreate the cache instance, default is false.
88
+ * If true, creates a new LRU instance even if cache already exists.
89
+ */
90
+ resetCache(recreate?: boolean): void;
91
+ /**
92
+ * Get a specific hostname's single record from cache
93
+ * @param hostname - Hostname to query
94
+ * @return {DnsCacheRecord | null} cache record
95
+ */
96
+ getCacheRecord(hostname: string): DnsCacheRecord | null;
97
+ }
@@ -0,0 +1,346 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.DnsResolver = void 0;
37
+ const util = __importStar(require("node:util"));
38
+ const dns = __importStar(require("node:dns"));
39
+ const ylru_1 = require("ylru");
40
+ const IP_REGEX = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
41
+ class DnsResolver {
42
+ /**
43
+ * Create a DNS cache resolver instance
44
+ * @param options - Configuration options
45
+ * @param options.useResolver - enable dns.resolver, otherwise use dns.lookup by default
46
+ * @param options.max - Maximum cache size, default is 1000
47
+ * @param options.dnsCacheLookupInterval - DNS cache lookup interval in milliseconds, effective when useResolver == false, default is 10000
48
+ * @param options.servers - Custom DNS nameservers, effective when useResolver == true, e.g. ['8.8.8.8', '1.1.1.1']
49
+ * @param options.addressRotation - Enable address rotation for both lookup and resolve modes, default is true
50
+ */
51
+ constructor(options = {}, args) {
52
+ this._maxCacheSize = options.max || 1000;
53
+ this._dnsCache = new ylru_1.LRU(this._maxCacheSize);
54
+ this.logger = args.logger;
55
+ // Set useResolver before using it
56
+ this.useResolver = options.useResolver === true;
57
+ this.dnsCacheLookupInterval = options.dnsCacheLookupInterval || 10000;
58
+ // Address rotation is enabled by default
59
+ this.enableAddressRotation = options.addressRotation !== false;
60
+ if (this.useResolver) {
61
+ this._initializeResolver(options.servers);
62
+ }
63
+ else {
64
+ // Use dns.lookup mode (old behavior)
65
+ this._lookup = util.promisify(dns.lookup);
66
+ }
67
+ this.resetCache = this.resetCache.bind(this);
68
+ this.logger.debug(`[dns-cache] DNS Resolver initialized in ${this.useResolver ? 'resolve' : 'lookup'} mode, maxCacheSize: ${this._maxCacheSize}, addressRotation: ${this.enableAddressRotation}`);
69
+ }
70
+ get maxCacheSize() {
71
+ return this._maxCacheSize;
72
+ }
73
+ _debugLog(msg, ...args) {
74
+ this.logger.debug.apply(this.logger, [msg, ...args]);
75
+ }
76
+ resetCacheSize(size) {
77
+ this._maxCacheSize = size;
78
+ this.resetCache(true);
79
+ }
80
+ /**
81
+ * Initialize DNS resolver with custom nameservers if provided
82
+ * @param defaultServers - Custom DNS nameservers
83
+ * @private
84
+ */
85
+ _initializeResolver(defaultServers) {
86
+ this.resolver = new dns.Resolver({
87
+ timeout: 3000,
88
+ tries: 2,
89
+ });
90
+ const hasDefaultServers = defaultServers &&
91
+ Array.isArray(defaultServers) &&
92
+ defaultServers.length > 0;
93
+ if (hasDefaultServers) {
94
+ this.resolver.setServers(defaultServers);
95
+ this._debugLog(`[dns-cache] Custom DNS servers configured: ${defaultServers.join(', ')}`);
96
+ }
97
+ this._resolve4 = util.promisify(this.resolver.resolve4.bind(this.resolver));
98
+ }
99
+ /**
100
+ * Get the lookup function compatible with dns.lookup signature
101
+ */
102
+ getLookupFunction() {
103
+ return ((hostname, options, callback) => {
104
+ // signature handling: lookup(hostname, cb) or lookup(hostname, options, cb)
105
+ if (typeof options === 'function') {
106
+ callback = options;
107
+ options = {};
108
+ }
109
+ if (typeof options === 'number') {
110
+ options = { family: options };
111
+ }
112
+ if (typeof callback !== 'function') {
113
+ throw new TypeError('callback must be a function');
114
+ }
115
+ options = options || {};
116
+ if (!options.family) {
117
+ options.family = 4;
118
+ }
119
+ // keep original dns.lookup behavior for literal IPs without hitting the network
120
+ if (IP_REGEX.test(hostname)) {
121
+ // theoretically this code will never be reached because urllib will
122
+ // directly return for literal IPs before calling lookup function
123
+ const family = typeof options.family === 'number' ? options.family : 4;
124
+ this.logger.debug(`[dns-cache] literal IP ${hostname} lookup, bypassing cache`);
125
+ if (options === null || options === void 0 ? void 0 : options.all) {
126
+ return callback(null, [{ address: hostname, family }]);
127
+ }
128
+ return callback(null, hostname, family);
129
+ }
130
+ const record = this._dnsCache.get(hostname);
131
+ const now = Date.now();
132
+ if (record) {
133
+ // Check TTL - use the first record's TTL and timestamp
134
+ const firstRecord = record.records[0];
135
+ const ttl = firstRecord.ttl || 0;
136
+ const timestamp = firstRecord.timestamp || now;
137
+ if (now - timestamp >= ttl) {
138
+ // refresh in background, keep serving cached value
139
+ this._debugLog(`[dns-cache] Cache TTL expired for ${hostname}, refreshing in background. Age: ${now - timestamp}ms, TTL: ${ttl}ms`);
140
+ this._updateDNS(hostname).catch(() => {
141
+ // do nothing, error already logged in _updateDNS
142
+ });
143
+ }
144
+ else {
145
+ this._debugLog(`[dns-cache] Cache hit for ${hostname}, remaining TTL: ${ttl - (now - timestamp)}ms, records: ${record.records.length}`);
146
+ }
147
+ return this._callbackWithRecord(record, options, callback);
148
+ }
149
+ // No cached record, resolve and respond when ready
150
+ this._debugLog(`[dns-cache] Cache miss for ${hostname}, resolving...`);
151
+ this._updateDNS(hostname)
152
+ .then(record => {
153
+ this._callbackWithRecord(record, options, callback);
154
+ })
155
+ .catch(err => {
156
+ callback(err, '');
157
+ });
158
+ });
159
+ }
160
+ /**
161
+ * This method may throw error if there is dns query in progress!
162
+ * @throws Error
163
+ * @param {string[]} servers eg. ['8.8.8.8']
164
+ */
165
+ setServers(servers) {
166
+ if (this.resolver) {
167
+ this.resolver.setServers(servers);
168
+ }
169
+ else {
170
+ this.logger.warn('[dns-cache] Cannot set DNS servers when useResolver is false');
171
+ }
172
+ }
173
+ getDnsCache() {
174
+ return this._dnsCache;
175
+ }
176
+ /**
177
+ * Callback with record, handling rotation
178
+ * @param record - DNS record with rotation state
179
+ * @param options - Lookup options
180
+ * @param callback - Callback function
181
+ * @private
182
+ */
183
+ _callbackWithRecord(record, options, callback) {
184
+ // All records use the unified structure with rotation
185
+ if (record.records && Array.isArray(record.records)) {
186
+ const records = record.records;
187
+ const currentRecord = records[record.currentIndex % records.length];
188
+ if (records.length > 1) {
189
+ this._debugLog(`[dns-cache] Address rotation: using ${currentRecord.ip} (index ${record.currentIndex % records.length}/${records.length})`);
190
+ }
191
+ // Rotate to next address for next call (if enabled)
192
+ if (this.enableAddressRotation) {
193
+ record.currentIndex = (record.currentIndex + 1) % records.length;
194
+ }
195
+ if (options.all) {
196
+ return callback(null, [
197
+ { address: currentRecord.ip, family: currentRecord.family || 4 },
198
+ ]);
199
+ }
200
+ return callback(null, currentRecord.ip, currentRecord.family || 4);
201
+ }
202
+ // Should not reach here, all records should use records structure
203
+ throw new Error('[dns_cache_error]: Invalid cache record structure');
204
+ }
205
+ async lookup(hostname) {
206
+ // handle localhost (some name servers may not resolve it)
207
+ if (hostname === 'localhost') {
208
+ this.logger.debug('[dns-cache] localhost lookup, bypassing cache');
209
+ return [{ address: '127.0.0.1', family: 4 }];
210
+ }
211
+ if (!this._lookup) {
212
+ throw new Error('DNS Resolver not initialized for lookup mode');
213
+ }
214
+ // Use { all: true } to get all addresses for rotation support
215
+ const addresses = await this._lookup(hostname, {
216
+ family: 4,
217
+ all: true,
218
+ });
219
+ return addresses;
220
+ }
221
+ async resolve4(hostname) {
222
+ // handle localhost (some name servers may not resolve it)
223
+ if (hostname === 'localhost') {
224
+ this.logger.debug('[dns-cache] localhost resolve, bypassing cache');
225
+ return [
226
+ {
227
+ address: '127.0.0.1',
228
+ ttl: Math.floor(Number.MAX_SAFE_INTEGER / 1000),
229
+ },
230
+ ]; // provide a default TTL
231
+ }
232
+ if (!this._resolve4) {
233
+ throw new Error('DNS Resolver not initialized for resolve mode');
234
+ }
235
+ const addresses = await this._resolve4(hostname, {
236
+ ttl: true,
237
+ });
238
+ return addresses;
239
+ }
240
+ /**
241
+ * Update DNS cache with fresh resolution
242
+ * Supports both dns.lookup and dns.resolve modes
243
+ * @param hostname - The hostname to resolve
244
+ * @private
245
+ */
246
+ async _updateDNS(hostname) {
247
+ // Use dns.lookup
248
+ if (!this.useResolver) {
249
+ try {
250
+ const addresses = await this.lookup(hostname);
251
+ const addressArray = Array.isArray(addresses) ? addresses : [addresses];
252
+ if (addressArray.length === 0) {
253
+ throw new Error(`empty address for ${hostname}`);
254
+ }
255
+ const records = addressArray.map((addr, index) => ({
256
+ ip: addr.address,
257
+ family: addr.family || 4,
258
+ ttl: this.dnsCacheLookupInterval,
259
+ timestamp: Date.now(),
260
+ index,
261
+ }));
262
+ const cacheEntry = {
263
+ records,
264
+ currentIndex: 0,
265
+ };
266
+ this._dnsCache.set(hostname, cacheEntry);
267
+ this._debugLog(`[dns-cache] dns.lookup succeeded for ${hostname}, resolved ${records.length} address(es): ${records.map(r => r.ip).join(', ')}, TTL: ${this.dnsCacheLookupInterval}ms`);
268
+ return cacheEntry;
269
+ }
270
+ catch (err) {
271
+ this._errorDNS(err, 'lookup', hostname);
272
+ throw err;
273
+ }
274
+ }
275
+ // Use dns.resolve
276
+ try {
277
+ const addresses = await this.resolve4(hostname);
278
+ const addressArray = Array.isArray(addresses) ? addresses : [addresses];
279
+ // Store all addresses with rotation index
280
+ const records = addressArray.map((addr, index) => {
281
+ const address = typeof addr === 'string' ? addr : addr.address;
282
+ const ttlSeconds = addr && Number.isInteger(addr.ttl) && addr.ttl >= 0 ? addr.ttl : 0;
283
+ return {
284
+ ip: address,
285
+ family: 4,
286
+ ttl: ttlSeconds * 1000,
287
+ timestamp: Date.now(),
288
+ index,
289
+ };
290
+ });
291
+ if (records.length === 0 || !records[0].ip) {
292
+ throw new Error(`empty address for ${hostname}`);
293
+ }
294
+ // Store all records with rotation state
295
+ const cacheEntry = {
296
+ records,
297
+ currentIndex: 0,
298
+ };
299
+ this._dnsCache.set(hostname, cacheEntry);
300
+ this._debugLog(`[dns-cache] dns.resolve4 succeeded for ${hostname}, resolved ${records.length} address(es): ${records
301
+ .map(r => `${r.ip} (TTL: ${r.ttl}ms)`)
302
+ .join(', ')}`);
303
+ return cacheEntry;
304
+ }
305
+ catch (err) {
306
+ this._errorDNS(err, 'resolve', hostname);
307
+ throw err;
308
+ }
309
+ }
310
+ /**
311
+ * Debug DNS errors
312
+ * @param err - Error object
313
+ * @param mode - 'lookup' or 'resolve'
314
+ * @private
315
+ */
316
+ _errorDNS(err, mode, hostname) {
317
+ this.logger.error(`error occurred when resolving ${hostname} with dns.${mode}: ${err && err.message ? err.message : err}`);
318
+ }
319
+ /**
320
+ * Clear the DNS cache
321
+ * @param recreate - Whether to recreate the cache instance, default is false.
322
+ * If true, creates a new LRU instance even if cache already exists.
323
+ */
324
+ resetCache(recreate = false) {
325
+ this._debugLog(`[dns-cache] Resetting DNS cache (recreate: ${recreate})`);
326
+ if (this._dnsCache)
327
+ this._dnsCache.reset();
328
+ if (recreate) {
329
+ this._dnsCache = new ylru_1.LRU(this._maxCacheSize);
330
+ }
331
+ }
332
+ /**
333
+ * Get a specific hostname's single record from cache
334
+ * @param hostname - Hostname to query
335
+ * @return {DnsCacheRecord | null} cache record
336
+ */
337
+ getCacheRecord(hostname) {
338
+ const entry = this._dnsCache.get(hostname);
339
+ if (entry && entry.records && Array.isArray(entry.records)) {
340
+ return entry.records[entry.currentIndex % entry.records.length];
341
+ }
342
+ return null;
343
+ }
344
+ }
345
+ exports.DnsResolver = DnsResolver;
346
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRG5zUmVzb2x2ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJEbnNSZXNvbHZlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxnREFBa0M7QUFDbEMsOENBQWdDO0FBQ2hDLCtCQUEyQjtBQUkzQixNQUFNLFFBQVEsR0FBRyxzQ0FBc0MsQ0FBQztBQXVCeEQsTUFBYSxXQUFXO0lBV3RCOzs7Ozs7OztPQVFHO0lBQ0gsWUFBWSxVQUE4QixFQUFFLEVBQUUsSUFBMkI7UUFDdkUsSUFBSSxDQUFDLGFBQWEsR0FBRyxPQUFPLENBQUMsR0FBRyxJQUFJLElBQUksQ0FBQztRQUN6QyxJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksVUFBRyxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUM3QyxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUM7UUFFMUIsa0NBQWtDO1FBQ2xDLElBQUksQ0FBQyxXQUFXLEdBQUcsT0FBTyxDQUFDLFdBQVcsS0FBSyxJQUFJLENBQUM7UUFFaEQsSUFBSSxDQUFDLHNCQUFzQixHQUFHLE9BQU8sQ0FBQyxzQkFBc0IsSUFBSSxLQUFLLENBQUM7UUFFdEUseUNBQXlDO1FBQ3pDLElBQUksQ0FBQyxxQkFBcUIsR0FBRyxPQUFPLENBQUMsZUFBZSxLQUFLLEtBQUssQ0FBQztRQUUvRCxJQUFJLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztZQUNyQixJQUFJLENBQUMsbUJBQW1CLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQzVDLENBQUM7YUFBTSxDQUFDO1lBQ04scUNBQXFDO1lBQ3JDLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDNUMsQ0FBQztRQUVELElBQUksQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJ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
package/lib/index.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './DnsResolver';
package/lib/index.js ADDED
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./DnsResolver"), exports);
18
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsZ0RBQThCIn0=
package/package.json ADDED
@@ -0,0 +1,84 @@
1
+ {
2
+ "name": "@eggjs/tegg-dns-cache",
3
+ "eggPlugin": {
4
+ "name": "dnsCache",
5
+ "dependencies": [
6
+ "tegg"
7
+ ]
8
+ },
9
+ "version": "3.68.0",
10
+ "types": "typings/index.d.ts",
11
+ "description": "tegg dns cache plugin",
12
+ "keywords": [
13
+ "egg",
14
+ "typescript",
15
+ "dns",
16
+ "cache",
17
+ "tegg"
18
+ ],
19
+ "files": [
20
+ "app.js",
21
+ "app.d.ts",
22
+ "agent.js",
23
+ "agent.d.ts",
24
+ "index.js",
25
+ "index.d.ts",
26
+ "types.js",
27
+ "types.d.ts",
28
+ "config/**/*.js",
29
+ "config/**/*.d.ts",
30
+ "lib/**/*.js",
31
+ "lib/**/*.d.ts",
32
+ "app/**/*.js",
33
+ "app/**/*.d.ts",
34
+ "typings/*.d.ts"
35
+ ],
36
+ "eggModule": {
37
+ "name": "teggDnsCache"
38
+ },
39
+ "scripts": {
40
+ "test": "cross-env NODE_ENV=test NODE_OPTIONS='--no-deprecation' mocha",
41
+ "clean": "tsc -b --clean",
42
+ "tsc": "ut run clean && tsc -p ./tsconfig.json",
43
+ "tsc:pub": "ut run clean && tsc -p ./tsconfig.pub.json",
44
+ "prepublishOnly": "ut tsc:pub"
45
+ },
46
+ "homepage": "https://github.com/eggjs/tegg",
47
+ "bugs": {
48
+ "url": "https://github.com/eggjs/tegg/issues"
49
+ },
50
+ "repository": {
51
+ "type": "git",
52
+ "url": "git@github.com:eggjs/tegg.git",
53
+ "directory": "plugin/dns-cache"
54
+ },
55
+ "egg": {
56
+ "typescript": true
57
+ },
58
+ "engines": {
59
+ "node": ">=18.0.0"
60
+ },
61
+ "peerDependencies": {
62
+ "egg": ">=3.32.0"
63
+ },
64
+ "dependencies": {
65
+ "@eggjs/tegg": "^3.68.0",
66
+ "ylru": "^2.0.0"
67
+ },
68
+ "devDependencies": {
69
+ "@eggjs/tegg-config": "^3.68.0",
70
+ "@eggjs/tegg-plugin": "^3.68.0",
71
+ "@types/mocha": "^10.0.10",
72
+ "@types/node": "^20.2.4",
73
+ "cross-env": "^7.0.3",
74
+ "egg": "^3.32.0",
75
+ "egg-mock": "^5.5.0",
76
+ "mocha": "^10.2.0",
77
+ "ts-node": "^10.9.1",
78
+ "typescript": "^5.0.4"
79
+ },
80
+ "publishConfig": {
81
+ "access": "public"
82
+ },
83
+ "gitHead": "c8c089bee4aaf48ccdea3d56d142c82044223ae3"
84
+ }
@@ -0,0 +1,34 @@
1
+ import 'egg';
2
+ import '@eggjs/tegg-plugin';
3
+ import * as dns from 'node:dns';
4
+ import { DnsResolver, DnsCacheRecord } from '../lib';
5
+ export { DnsResolver, DnsCacheRecord };
6
+
7
+ declare module 'egg' {
8
+ interface TeggDnsCacheApplication {
9
+ /**
10
+ * DNS resolver instance, provides DNS caching capabilities
11
+ */
12
+ dnsResolver: DnsResolver;
13
+ }
14
+
15
+ interface Application extends TeggDnsCacheApplication {}
16
+
17
+ interface EggAppConfig {
18
+ /**
19
+ * DNS Cache Configuration
20
+ */
21
+ dnsCache: {
22
+ /** Use dns.lookup or dns.resolve, default is 'resolve' */
23
+ mode?: 'lookup' | 'resolve';
24
+ /** Custom DNS nameservers for dns.resolve mode */
25
+ dnsServers?: string[];
26
+ /** Maximum number of DNS cache entries, default is 1000 */
27
+ maxCacheLength?: number;
28
+ /** DNS cache lookup interval in milliseconds, default is 10000 */
29
+ lookupInterval?: number;
30
+ /** Enable round-robin address rotation, default is true */
31
+ addressRotation?: boolean;
32
+ };
33
+ }
34
+ }