external-ips 0.0.3 → 0.0.5
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/index.js +40 -16
- package/package.json +27 -25
- package/test.js +34 -0
package/index.js
CHANGED
|
@@ -10,7 +10,6 @@ function normalizeFamily(family){
|
|
|
10
10
|
return false;
|
|
11
11
|
} else throw new Error('bad family='+family);
|
|
12
12
|
}
|
|
13
|
-
|
|
14
13
|
class AbstractObject {
|
|
15
14
|
constructor(family){
|
|
16
15
|
assert(this.constructor!==AbstractObject); //Abstract
|
|
@@ -22,11 +21,22 @@ class AbstractObject {
|
|
|
22
21
|
defaultFamily = normalizeFamily(defaultFamily);
|
|
23
22
|
assert.equal(typeof agent, 'object');
|
|
24
23
|
assert.equal(typeof agent.createConnection, 'function');
|
|
25
|
-
const old
|
|
24
|
+
const old = agent.createConnection;
|
|
25
|
+
const self = this;
|
|
26
26
|
agent.createConnection = (options, callback)=>{
|
|
27
|
-
const family = normalizeFamily(options.family)
|
|
28
|
-
if(!family || !
|
|
29
|
-
|
|
27
|
+
const family = options.family ? normalizeFamily(options.family)||defaultFamily : defaultFamily;
|
|
28
|
+
if((!family || !self.family || self.family===family) && !options.localAddress){
|
|
29
|
+
const ip = self.random();
|
|
30
|
+
if(ip){
|
|
31
|
+
//КОПИЯ, а не мутация. Agent уже вычислил ключ реестра (getName БЕЗ localAddress)
|
|
32
|
+
//и замкнул этот же объект options в свои слушатели. Если дописать localAddress
|
|
33
|
+
//в него, removeSocket/onFree пересчитают имя уже С адресом и попадут в другой
|
|
34
|
+
//список: закрытые сокеты никогда не удаляются из agent.sockets (на боевом
|
|
35
|
+
//mexc-гейтвее агент накопил 7744 сокета, из них 5578 мёртвых, ~1.5 ГБ/ч), а
|
|
36
|
+
//freeSockets кладутся под ключ, по которому их никто не ищет — keep-alive не
|
|
37
|
+
//переиспользуется вовсе, и каждый запрос открывает новый TLS.
|
|
38
|
+
return old.call(agent, { ...options, localAddress: ip.address ? ip.address : ip }, callback);
|
|
39
|
+
}
|
|
30
40
|
}
|
|
31
41
|
return old.call(agent, options, callback);
|
|
32
42
|
}
|
|
@@ -37,10 +47,16 @@ class AbstractObject {
|
|
|
37
47
|
return family;
|
|
38
48
|
}
|
|
39
49
|
random(family){
|
|
40
|
-
|
|
50
|
+
const ip = this._random(family);
|
|
51
|
+
if(ip){
|
|
52
|
+
return ip.address;
|
|
53
|
+
} //else console.log('!!!!!!!ip.rnd', this.constructor.name, this.length)
|
|
41
54
|
}
|
|
42
55
|
next(family){
|
|
43
|
-
|
|
56
|
+
const ip = this._next(family);
|
|
57
|
+
if(ip){
|
|
58
|
+
return ip.address;
|
|
59
|
+
} //else console.log('!!!!!!!ip.nxt', this.constructor.name, this.length)
|
|
44
60
|
}
|
|
45
61
|
_random(family){
|
|
46
62
|
return this.__random(this.checkFamily(family))
|
|
@@ -65,15 +81,18 @@ class IP extends AbstractObject{
|
|
|
65
81
|
__next(){return this}
|
|
66
82
|
};
|
|
67
83
|
|
|
84
|
+
fid = 0
|
|
68
85
|
class FamilyList extends AbstractObject{
|
|
69
|
-
ips
|
|
86
|
+
ips = [];
|
|
87
|
+
lastIndex = 0;
|
|
70
88
|
constructor(family){
|
|
71
89
|
super(family);
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
90
|
+
this.fid = fid++;
|
|
91
|
+
//Object.defineProperty(this, 'lastIndex', {
|
|
92
|
+
// value: 0,
|
|
93
|
+
// enumerable: false,
|
|
94
|
+
// writable : true,
|
|
95
|
+
//})
|
|
77
96
|
}
|
|
78
97
|
push(...ips){
|
|
79
98
|
ips.forEach(ip=>{
|
|
@@ -87,7 +106,11 @@ class FamilyList extends AbstractObject{
|
|
|
87
106
|
return this.ips.length;
|
|
88
107
|
}
|
|
89
108
|
__random(){
|
|
90
|
-
|
|
109
|
+
const pos = Math.floor(this.length*Math.random());
|
|
110
|
+
const res = this.ips[pos];
|
|
111
|
+
//console.log(this.ips);
|
|
112
|
+
//console.log('__random', 'length='+this.length, 'pos='+pos, res)
|
|
113
|
+
return res;
|
|
91
114
|
}
|
|
92
115
|
__next(){
|
|
93
116
|
const res = this.ips[this.lastIndex];
|
|
@@ -149,12 +172,13 @@ Object.values(os.networkInterfaces()).forEach(arr=>{
|
|
|
149
172
|
mainList.push(...arr.filter(ip=>!ip.internal).map(ip=>new IP(ip)))
|
|
150
173
|
});
|
|
151
174
|
|
|
175
|
+
//console.log('--------------')
|
|
152
176
|
//mainList.print();
|
|
177
|
+
//console.log('/--------------')
|
|
153
178
|
|
|
154
179
|
mainList.MainList = MainList;
|
|
155
180
|
mainList.IP = IP;
|
|
156
181
|
mainList.AbstractObject = AbstractObject;
|
|
157
182
|
mainList.FamilyList = FamilyList;
|
|
158
183
|
|
|
159
|
-
|
|
160
|
-
module.exports = mainList;
|
|
184
|
+
module.exports = mainList;
|
package/package.json
CHANGED
|
@@ -1,27 +1,29 @@
|
|
|
1
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
|
-
"
|
|
2
|
+
"name": "external-ips",
|
|
3
|
+
"version": "0.0.5",
|
|
4
|
+
"main": "./index.js",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"test": "node test.js"
|
|
7
|
+
},
|
|
8
|
+
"author": "Andrey Belousoff <a.v.belousoff@gmail.com>",
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"description": "any IPs in HTTP(s) requests or WS",
|
|
11
|
+
"keywords": [
|
|
12
|
+
"ips",
|
|
13
|
+
"ip"
|
|
14
|
+
],
|
|
15
|
+
"dependencies": {},
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=0.1.0"
|
|
18
|
+
},
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "https://github.com/Hkey1/external-ips"
|
|
22
|
+
},
|
|
23
|
+
"readme": "External IPs",
|
|
24
|
+
"readmeFilename": "README.md",
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/Hkey1/external-ips/issues"
|
|
27
|
+
},
|
|
28
|
+
"homepage": "https://github.com/Hkey1/external-ips"
|
|
27
29
|
}
|
package/test.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
//node test.js — регрессия: патч не должен ломать учёт сокетов у http.Agent
|
|
2
|
+
const assert = require("node:assert");
|
|
3
|
+
const http = require("node:http");
|
|
4
|
+
const IPs = require("./index.js");
|
|
5
|
+
|
|
6
|
+
const server = http.createServer((req, res)=>res.end("ok"));
|
|
7
|
+
server.listen(0, "127.0.0.1", async()=>{
|
|
8
|
+
const port = server.address().port;
|
|
9
|
+
try {
|
|
10
|
+
const agent = new http.Agent({ keepAlive: true });
|
|
11
|
+
//как manyIPs в ccxtPatch; random() вернёт локальный адрес этой машины
|
|
12
|
+
IPs.v4.patchAgent(agent);
|
|
13
|
+
for(let i = 0; i < 8; i++){
|
|
14
|
+
await new Promise((res, rej)=>{
|
|
15
|
+
http.get({ host: "127.0.0.1", port, agent }, r=>{ r.resume(); r.on("end", res); }).on("error", rej);
|
|
16
|
+
});
|
|
17
|
+
await new Promise(r=>setTimeout(r, 30));
|
|
18
|
+
}
|
|
19
|
+
const cnt = o=>Object.values(o).reduce((a, arr)=>a + arr.length, 0);
|
|
20
|
+
const busy = cnt(agent.sockets);
|
|
21
|
+
const free = cnt(agent.freeSockets);
|
|
22
|
+
const dead = Object.values(agent.sockets).flat().filter(s=>s.destroyed).length;
|
|
23
|
+
console.log(`sockets=${busy} (мёртвых ${dead}), freeSockets=${free}`);
|
|
24
|
+
//до фикса: sockets=8 под одним ключом, freeSockets=8 под другим, реюза ноль
|
|
25
|
+
assert.equal(busy, 0, `в agent.sockets не должно оставаться сокетов, осталось ${busy}`);
|
|
26
|
+
assert.equal(dead, 0);
|
|
27
|
+
assert.ok(free >= 1 && free <= 2, `keep-alive должен переиспользоваться: freeSockets=${free}`);
|
|
28
|
+
console.log("ok: учёт агента цел, keep-alive переиспользуется");
|
|
29
|
+
agent.destroy(); server.close();
|
|
30
|
+
} catch(err){
|
|
31
|
+
console.error("FAIL:", err.message);
|
|
32
|
+
server.close(); process.exitCode = 1;
|
|
33
|
+
}
|
|
34
|
+
});
|