w-ipproxy 1.0.1 → 1.0.3

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.
Files changed (55) hide show
  1. package/.eslintrc.js +18 -17
  2. package/.github/workflows/ci-test.yml +3 -3
  3. package/README.md +64 -2
  4. package/babel.config.js +4 -2
  5. package/dist/w-ip-proxy.umd.js +7 -0
  6. package/dist/w-ip-proxy.umd.js.map +1 -0
  7. package/docs/WIpProxy.html +722 -0
  8. package/docs/WIpProxy.mjs.html +554 -0
  9. package/docs/fonts/Montserrat/Montserrat-Bold.eot +0 -0
  10. package/docs/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
  11. package/docs/fonts/Montserrat/Montserrat-Bold.woff +0 -0
  12. package/docs/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
  13. package/docs/fonts/Montserrat/Montserrat-Regular.eot +0 -0
  14. package/docs/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
  15. package/docs/fonts/Montserrat/Montserrat-Regular.woff +0 -0
  16. package/docs/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
  17. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
  18. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +978 -0
  19. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
  20. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
  21. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
  22. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
  23. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +1049 -0
  24. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
  25. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
  26. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
  27. package/docs/index.html +84 -0
  28. package/docs/scripts/collapse.js +39 -0
  29. package/docs/scripts/commonNav.js +28 -0
  30. package/docs/scripts/linenumber.js +25 -0
  31. package/docs/scripts/nav.js +12 -0
  32. package/docs/scripts/polyfill.js +4 -0
  33. package/docs/scripts/prettify/Apache-License-2.0.txt +202 -0
  34. package/docs/scripts/prettify/lang-css.js +2 -0
  35. package/docs/scripts/prettify/prettify.js +28 -0
  36. package/docs/scripts/search.js +99 -0
  37. package/docs/styles/jsdoc.css +776 -0
  38. package/docs/styles/prettify.css +80 -0
  39. package/g-getByTimer.mjs +24 -0
  40. package/g-getOnce.mjs +11 -0
  41. package/g-srv.mjs +28 -0
  42. package/package.json +11 -9
  43. package/script.txt +17 -0
  44. package/src/WIpProxy.mjs +473 -14
  45. package/src/provideServer.mjs +65 -0
  46. package/test/anonymity.test.mjs +140 -0
  47. package/test/getProxiesOnce.test.mjs +89 -0
  48. package/toolg/cleanFolder.mjs +4 -0
  49. package/toolg/gDistRollup.mjs +29 -0
  50. package/toolg/modifyReadme.mjs +4 -0
  51. package/g.mjs +0 -12
  52. package/src/getHtml.mjs +0 -84
  53. package/src/getProxyListOrg.mjs +0 -66
  54. package/src/parseHtml.mjs +0 -19
  55. package/test/all.test.mjs +0 -10
@@ -0,0 +1,80 @@
1
+ .pln {
2
+ color: #ddd;
3
+ }
4
+
5
+ /* string content */
6
+ .str {
7
+ color: #61ce3c;
8
+ }
9
+
10
+ /* a keyword */
11
+ .kwd {
12
+ color: #fbde2d;
13
+ }
14
+
15
+ /* a comment */
16
+ .com {
17
+ color: #aeaeae;
18
+ }
19
+
20
+ /* a type name */
21
+ .typ {
22
+ color: #8da6ce;
23
+ }
24
+
25
+ /* a literal value */
26
+ .lit {
27
+ color: #fbde2d;
28
+ }
29
+
30
+ /* punctuation */
31
+ .pun {
32
+ color: #ddd;
33
+ }
34
+
35
+ /* lisp open bracket */
36
+ .opn {
37
+ color: #000000;
38
+ }
39
+
40
+ /* lisp close bracket */
41
+ .clo {
42
+ color: #000000;
43
+ }
44
+
45
+ /* a markup tag name */
46
+ .tag {
47
+ color: #8da6ce;
48
+ }
49
+
50
+ /* a markup attribute name */
51
+ .atn {
52
+ color: #fbde2d;
53
+ }
54
+
55
+ /* a markup attribute value */
56
+ .atv {
57
+ color: #ddd;
58
+ }
59
+
60
+ /* a declaration */
61
+ .dec {
62
+ color: #EF5050;
63
+ }
64
+
65
+ /* a variable name */
66
+ .var {
67
+ color: #c82829;
68
+ }
69
+
70
+ /* a function name */
71
+ .fun {
72
+ color: #4271ae;
73
+ }
74
+
75
+ /* Specify class=linenums on a pre to get line numbering */
76
+ ol.linenums {
77
+ margin-top: 0;
78
+ margin-bottom: 0;
79
+ padding-bottom: 2px;
80
+ }
@@ -0,0 +1,24 @@
1
+ import _ from 'lodash-es'
2
+ import wip from './src/WIpProxy.mjs'
3
+
4
+
5
+ let wo = wip({
6
+ // tar: `https://www.google.com`,
7
+ })
8
+ wo.init()
9
+ wo.on('getRawProxies', (prxsRaw) => {
10
+ console.log(`已抓取公開代理共 ${_.size(prxsRaw)} 個...`)
11
+ })
12
+ wo.on('add', (p, proxies) => {
13
+ // console.log('新加入代理', { host: p.host, port: p.port }, _.map(proxies, 'proxy'))
14
+ })
15
+ wo.on('delete', (p, proxies) => {
16
+ // console.log('刪除代理', { host: p.host, port: p.port }, _.map(proxies, 'proxy'))
17
+ })
18
+ wo.on('change', (proxies) => {
19
+ // console.log(`有效代理`, _.map(proxies, 'proxy'))
20
+ console.log(`已檢測有效代理共 ${_.size(proxies)} 個...`)
21
+ })
22
+
23
+
24
+ //node g-getByTimer.mjs
package/g-getOnce.mjs ADDED
@@ -0,0 +1,11 @@
1
+ import wip from './src/WIpProxy.mjs'
2
+
3
+
4
+ let wo = wip({
5
+ // tar: `https://www.google.com`,
6
+ })
7
+ let ps = await wo.getProxiesOnce()
8
+ console.log('ps', ps)
9
+
10
+
11
+ //node g-getOnce.mjs
package/g-srv.mjs ADDED
@@ -0,0 +1,28 @@
1
+ import _ from 'lodash-es'
2
+ import wip from './src/WIpProxy.mjs'
3
+
4
+
5
+ let wo = wip({
6
+ // tar: `https://www.google.com`,
7
+ withServer: true,
8
+ serverPort: 9000,
9
+ serverCorsOrigins: ['*'],
10
+ })
11
+ wo.on('getRawProxies', (prxsRaw) => {
12
+ console.log(`已抓取公開代理共 ${_.size(prxsRaw)} 個...`)
13
+ })
14
+ wo.on('add', (p, proxies) => {
15
+ // console.log('新加入代理', { host: p.host, port: p.port }, _.map(proxies, 'proxy'))
16
+ })
17
+ wo.on('delete', (p, proxies) => {
18
+ // console.log('刪除代理', { host: p.host, port: p.port }, _.map(proxies, 'proxy'))
19
+ })
20
+ wo.on('change', (proxies) => {
21
+ // console.log(`有效代理`, _.map(proxies, 'proxy'))
22
+ console.log(`已檢測有效代理共 ${_.size(proxies)} 個...`)
23
+ })
24
+
25
+ //browser view: http://localhost:9000/getProxies
26
+
27
+
28
+ //node g-srv.mjs
package/package.json CHANGED
@@ -1,19 +1,19 @@
1
1
  {
2
2
  "name": "w-ipproxy",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "main": "dist/w-ipproxy.umd.js",
5
5
  "dependencies": {
6
- "axios": "^1.2.3",
7
- "cheerio": "^1.0.0-rc.12",
8
- "lodash": "^4.17.21",
9
- "puppeteer": "^19.5.2",
10
- "wsemi": "^1.6.87"
6
+ "@hapi/hapi": "^21.4.8",
7
+ "axios": "^1.13.6",
8
+ "cheerio": "^1.2.0",
9
+ "lodash-es": "^4.18.1",
10
+ "wsemi": "^1.8.47"
11
11
  },
12
12
  "devDependencies": {
13
- "w-package-tools": "^1.0.66"
13
+ "w-package-tools": "^1.1.5"
14
14
  },
15
15
  "scripts": {
16
- "test": "mocha --parallel --timeout 60000 --experimental-modules --es-module-specifier-resolution=node",
16
+ "test": "mocha --parallel --timeout 60000",
17
17
  "deploy": "gh-pages -d docs"
18
18
  },
19
19
  "repository": {
@@ -24,7 +24,9 @@
24
24
  "package",
25
25
  "tool",
26
26
  "ip",
27
- "proxy"
27
+ "proxy",
28
+ "hapi",
29
+ "nodejs"
28
30
  ],
29
31
  "author": "yuda-lyu(semisphere)",
30
32
  "license": "MIT"
package/script.txt ADDED
@@ -0,0 +1,17 @@
1
+ #node toolg/addVersion.mjs
2
+ node toolg/modifyReadme.mjs
3
+
4
+ node toolg/cleanFolder.mjs
5
+ ./node_modules/.bin/jsdoc -c .jsdoc
6
+
7
+ node toolg/gDistRollup.mjs
8
+
9
+ git add . -A
10
+ git commit -m 'modify: '
11
+ git push origin master:master
12
+
13
+ npm run deploy
14
+
15
+ #npm test
16
+
17
+ #npm publish
package/src/WIpProxy.mjs CHANGED
@@ -1,23 +1,482 @@
1
- import getProxyListOrg from './getProxyListOrg.mjs'
1
+ import axios from 'axios'
2
+ import https from 'https'
3
+ import get from 'lodash-es/get.js'
4
+ import size from 'lodash-es/size.js'
5
+ import each from 'lodash-es/each.js'
6
+ import map from 'lodash-es/map.js'
7
+ import trim from 'lodash-es/trim.js'
8
+ import values from 'lodash-es/values.js'
9
+ import evem from 'wsemi/src/evem.mjs'
10
+ import sep from 'wsemi/src/sep.mjs'
11
+ import isestr from 'wsemi/src/isestr.mjs'
12
+ import ispint from 'wsemi/src/ispint.mjs'
13
+ import isbol from 'wsemi/src/isbol.mjs'
14
+ import isearr from 'wsemi/src/isearr.mjs'
15
+ import iseobj from 'wsemi/src/iseobj.mjs'
16
+ import cint from 'wsemi/src/cint.mjs'
17
+ import waitFun from 'wsemi/src/waitFun.mjs'
18
+ import provideServer from './provideServer.mjs'
2
19
 
3
- //freeproxylists
4
- //http://www.freeproxylists.net/zh/?c=&pt=&pr=&a%5B%5D=0&a%5B%5D=1&a%5B%5D=2&u=0
5
20
 
6
- //aliveproxy
7
- //http://www.aliveproxy.com/proxy-list/proxies.aspx/Taiwan-tw
21
+ /**
22
+ * 抓取代理伺服器
23
+ *
24
+ * @class
25
+ * @param {Object} [opt={}] 輸入設定物件,預設{}
26
+ * @param {String} [opt.src='https://api.proxyscrape.com/v2/?request=displayproxies&protocol=http&timeout=5000&anonymity=all'] 輸入取得代理伺服器API字串,預設'https://api.proxyscrape.com/v2/?request=displayproxies&protocol=http&timeout=5000&anonymity=all'
27
+ * @param {String} [opt.tar='https://httpbin.org/ip'] 輸入檢測目標網址字串,預設'https://httpbin.org/ip'
28
+ * @param {Integer} [opt.timeGetProxies=30*1000] 輸入輪循抓取代理伺服器時間間隔整數,單位ms,預設30*1000
29
+ * @param {Integer} [opt.timeTestProxies=60*1000] 輸入輪循測試代理伺服器時間間隔整數,單位ms,預設60*1000
30
+ * @param {Boolean} [opt.anonymityCheck=true] 輸入是否對代理做匿名性檢測布林值,開啟時會先打https://httpbin.org/ip驗證代理不會將本機真實IP透過X-Forwarded-For等方式洩漏給目標端,預設true
31
+ * @param {Integer} [opt.anonymityCheckRepeats=2] 輸入匿名性檢測重複次數整數,用以偵測負載平衡型代理的機率性洩漏,任一次洩漏即判定失敗,預設2
32
+ * @param {Boolean} [opt.withServer=false] 輸入是否創建供數據供給伺服器布林值,預設false
33
+ * @param {Integer} [opt.serverPort=8080] 輸入創建伺服器所用port整數,預設8080
34
+ * @param {String} [opt.serverApiName='getProxies'] 輸入供給數據API名稱字串,預設'getProxies'
35
+ * @param {Array} [opt.serverCorsOrigins=['*']] 輸入允許跨域網域陣列,若給予['*']代表允許全部,預設['*']
36
+ * @returns {Object} 回傳事件物件,提供函數getProxies,可監聽事件getRawProxies、add、delete、change
37
+ * @example
38
+ *
39
+ * import _ from 'lodash-es'
40
+ * import wip from './src/WIpProxy.mjs'
41
+ *
42
+ * let wo = wip({
43
+ * // tar: `https://www.google.com`,
44
+ * withServer: true,
45
+ * serverPort: 9000,
46
+ * serverCorsOrigins: ['*'],
47
+ * })
48
+ * wo.on('getRawProxies', (prxsRaw) => {
49
+ * console.log(`已抓取公開代理共 ${_.size(prxsRaw)} 個...`)
50
+ * })
51
+ * wo.on('add', (p, proxies) => {
52
+ * // console.log('新加入代理', { host: p.host, port: p.port }, _.map(proxies, 'proxy'))
53
+ * })
54
+ * wo.on('delete', (p, proxies) => {
55
+ * // console.log('刪除代理', { host: p.host, port: p.port }, _.map(proxies, 'proxy'))
56
+ * })
57
+ * wo.on('change', (proxies) => {
58
+ * // console.log(`有效代理`, _.map(proxies, 'proxy'))
59
+ * console.log(`已檢測有效代理共 ${_.size(proxies)} 個...`)
60
+ * })
61
+ *
62
+ * //browser view: http://localhost:9000/getProxies
63
+ *
64
+ */
65
+ function WIpProxy(opt = {}) {
8
66
 
9
- //cnproxy
10
- //http://www.cnproxy.com/proxy1.html
67
+ //src
68
+ let src = get(opt, 'src', '')
69
+ if (!isestr(src)) {
70
+ src = 'https://api.proxyscrape.com/v2/?request=displayproxies' +
71
+ `&protocol=http` +
72
+ // `&protocol=https` +
73
+ `&timeout=5000` +
74
+ // `&country=${join(['tw', 'cn', 'hk', 'jp', 'kr', 'sg', 'my', 'in', 'id', 'th', 'vn'])}` +
75
+ // `&ssl=yes` +
76
+ `&anonymity=elite` //elite匿名代理, all會使用X-Forwarded-For儲存原本ip導致被識別
77
+ }
11
78
 
12
- async function WIpProxy() {
13
- let rs = []
14
- let r
79
+ //tar
80
+ let tar = get(opt, 'tar', '')
81
+ if (!isestr(tar)) {
82
+ tar = 'https://httpbin.org/ip' //'https://www.google.com'
83
+ }
15
84
 
16
- //getProxyListOrg
17
- r = await getProxyListOrg()
18
- rs = [...rs, ...r]
85
+ //timeGetProxies
86
+ let timeGetProxies = get(opt, 'timeGetProxies')
87
+ if (!ispint(timeGetProxies)) {
88
+ timeGetProxies = 30 * 1000 //30s
89
+ }
90
+ timeGetProxies = cint(timeGetProxies)
19
91
 
20
- return rs
92
+ //timeTestProxies
93
+ let timeTestProxies = get(opt, 'timeTestProxies')
94
+ if (!ispint(timeTestProxies)) {
95
+ timeTestProxies = 60 * 1000 //1min
96
+ }
97
+ timeTestProxies = cint(timeTestProxies)
98
+
99
+ //anonymityCheck
100
+ let anonymityCheck = get(opt, 'anonymityCheck')
101
+ if (!isbol(anonymityCheck)) {
102
+ anonymityCheck = true
103
+ }
104
+
105
+ //anonymityCheckRepeats
106
+ let anonymityCheckRepeats = get(opt, 'anonymityCheckRepeats')
107
+ if (!ispint(anonymityCheckRepeats)) {
108
+ anonymityCheckRepeats = 2
109
+ }
110
+ anonymityCheckRepeats = cint(anonymityCheckRepeats)
111
+
112
+ //withServer
113
+ let withServer = get(opt, 'withServer')
114
+ if (!isbol(withServer)) {
115
+ withServer = false
116
+ }
117
+
118
+ //serverPort
119
+ let serverPort = get(opt, 'serverPort')
120
+ if (!ispint(serverPort)) {
121
+ serverPort = 8080
122
+ }
123
+ serverPort = cint(serverPort)
124
+
125
+ //serverApiName
126
+ let serverApiName = get(opt, 'serverApiName')
127
+ if (!isestr(serverApiName)) {
128
+ serverApiName = 'getProxies'
129
+ }
130
+
131
+ //serverCorsOrigins
132
+ let serverCorsOrigins = get(opt, 'serverCorsOrigins', [])
133
+ if (!isearr(serverCorsOrigins)) {
134
+ serverCorsOrigins = ['*']
135
+ }
136
+
137
+ //prxsRaw, kpPrx
138
+ let prxsRaw = []
139
+ let kpPrx = {}
140
+
141
+ //myRealIp: 本機真實公網IP, 用於匿名性檢測時比對代理egress是否洩漏
142
+ let myRealIp = ''
143
+ let myRealIpReady = false
144
+ let myRealIpPm = null
145
+ async function _fetchMyRealIp() {
146
+ if (myRealIpReady) {
147
+ return
148
+ }
149
+ if (!myRealIpPm) {
150
+ myRealIpPm = (async () => {
151
+ try {
152
+ let res = await axios.get('https://httpbin.org/ip', { timeout: 10000 })
153
+ let origin = get(res, 'data.origin', '')
154
+ if (isestr(origin)) {
155
+ //origin可能為"1.2.3.4"或"1.2.3.4:port", 取首個逗號前且去port
156
+ myRealIp = origin.split(',')[0].trim().split(':')[0]
157
+ }
158
+ }
159
+ catch (err) {
160
+ //取不到就算了, 匿名性檢查會自動跳過
161
+ }
162
+ myRealIpReady = true
163
+ })()
164
+ }
165
+ await myRealIpPm
166
+ }
167
+
168
+ async function _anonymityCheckCore(host, port) {
169
+ if (!anonymityCheck) {
170
+ return { ok: true }
171
+ }
172
+ if (!isestr(myRealIp)) {
173
+ return { ok: true } //沒抓到自己IP就無從比對, 放行
174
+ }
175
+ let agent = new https.Agent({ rejectUnauthorized: false })
176
+ for (let i = 0; i < anonymityCheckRepeats; i++) {
177
+ try {
178
+ let res = await axios.get('https://httpbin.org/ip', {
179
+ proxy: { host, port, protocol: 'http' },
180
+ httpsAgent: agent,
181
+ timeout: 5000,
182
+ headers: {
183
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/122.0.0.0 Safari/537.36',
184
+ 'Accept': 'application/json',
185
+ },
186
+ validateStatus: () => true,
187
+ })
188
+ if (res.status !== 200) {
189
+ return { ok: false, reason: `anonymity status[${res.status}]` }
190
+ }
191
+ let origin = get(res, 'data.origin', '')
192
+ if (!isestr(origin)) {
193
+ return { ok: false, reason: 'anonymity non-json' }
194
+ }
195
+ if (origin.indexOf(myRealIp) >= 0) {
196
+ return { ok: false, reason: `leaks real IP` }
197
+ }
198
+ }
199
+ catch (err) {
200
+ return { ok: false, reason: trim(err.message || '') }
201
+ }
202
+ }
203
+ return { ok: true }
204
+ }
205
+
206
+ async function _getProxiesCore(src) {
207
+ let ps = []
208
+
209
+ try {
210
+
211
+ //res
212
+ let res = await axios.get(src)
213
+
214
+ //c
215
+ let c = res.data
216
+ // console.log('c', c)
217
+
218
+ //sep
219
+ let ss = sep(c, '\n')
220
+ // console.log('ss', ss)
221
+
222
+ //ps
223
+ ps = map(ss, (v) => {
224
+ let [host, port] = v.split(':')
225
+ port = cint(port)
226
+ return {
227
+ proxy: v,
228
+ host,
229
+ port,
230
+ }
231
+ })
232
+ // console.log('ps', ps)
233
+
234
+ }
235
+ catch (err) {
236
+ console.log('_getProxiesCore catch', err.message)
237
+ }
238
+ // console.log('ps', ps)
239
+
240
+ return ps
241
+ }
242
+
243
+ let b_getProxies = false
244
+ async function _getProxies() {
245
+ // console.log('call getProxies...')
246
+
247
+ let core = async() => {
248
+
249
+ //get
250
+ prxsRaw = await _getProxiesCore(src)
251
+
252
+ //emit
253
+ ev.emit('getRawProxies', prxsRaw)
254
+
255
+ }
256
+
257
+ //core
258
+ if (b_getProxies) {
259
+ return
260
+ }
261
+ b_getProxies = true
262
+ await core()
263
+ .catch(() => {}) //吃掉錯誤
264
+ .finally(() => {
265
+ b_getProxies = false
266
+ })
267
+
268
+ }
269
+
270
+ async function _testProxyCore(host, port, url) {
271
+
272
+ //ret
273
+ let ret = (state, msg) => {
274
+ return {
275
+ state,
276
+ msg,
277
+ p: {
278
+ proxy: `${host}:${port}`,
279
+ host,
280
+ port,
281
+ },
282
+ }
283
+ }
284
+
285
+ //匿名性預檢: 先確認代理不會透過X-Forwarded-For等洩漏本機真實IP
286
+ let ac = await _anonymityCheckCore(host, port)
287
+ if (!ac.ok) {
288
+ return ret('error', ac.reason)
289
+ }
290
+
291
+ //r
292
+ let r = {}
293
+ try {
294
+
295
+ //agent
296
+ let agent = new https.Agent({ rejectUnauthorized: false }) //避免證書錯誤中止
297
+
298
+ //get
299
+ let res = await axios.get(url, {
300
+ proxy: {
301
+ host,
302
+ port,
303
+ protocol: 'http',
304
+ },
305
+ httpsAgent: agent,
306
+ timeout: 5000,
307
+ headers: {
308
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/122.0.0.0 Safari/537.36',
309
+ 'Accept': 'application/json',
310
+ },
311
+ })
312
+
313
+ if (res.status === 200) {
314
+ r = ret('success', res.data)
315
+ }
316
+ else {
317
+ r = ret('error', `status[${res.status}] error`)
318
+ }
319
+
320
+ }
321
+ catch (err) {
322
+ r = ret('error', trim(err.message))
323
+ // if (r.msg.indexOf(`ssl3_get_record`) >= 0) {
324
+ // r.msg = `ssl3_get_record error`
325
+ // }
326
+ }
327
+ // console.log(r)
328
+
329
+ return r
330
+ }
331
+
332
+ async function _testProxiesCore(prxs) {
333
+
334
+ //pms
335
+ let pms = map(prxs, (p) => {
336
+ let pm = _testProxyCore(p.host, p.port, tar)
337
+ return pm
338
+ })
339
+
340
+ //rrs, allSettled
341
+ let rrs = await Promise.allSettled(pms)
342
+ // console.log('rrs', rrs)
343
+
344
+ //psValid, psInvalid
345
+ let psValid = []
346
+ let psInvalid = []
347
+ each(rrs, (v) => {
348
+
349
+ //be
350
+ let p = get(v, 'value.p', null)
351
+ let be = iseobj(p) && isestr(get(p, 'proxy'))
352
+
353
+ //check
354
+ if (!be) {
355
+ return true //跳出換下一個
356
+ }
357
+
358
+ //b
359
+ let status = get(v, 'status', '')
360
+ let b1 = status === 'fulfilled'
361
+ let state = get(v, 'value.state', '')
362
+ let b2 = state === 'success'
363
+ let b = b1 && b2
364
+
365
+ //push
366
+ if (b) {
367
+ psValid.push(p)
368
+ }
369
+ else {
370
+ psInvalid.push(p)
371
+ }
372
+
373
+ })
374
+
375
+ return {
376
+ psValid,
377
+ psInvalid,
378
+ }
379
+ }
380
+
381
+ let b_testProxies = false
382
+ async function _testProxies() {
383
+ // console.log('call testProxies...')
384
+
385
+ let core = async() => {
386
+
387
+ //確保本機真實IP已取得, 供匿名性檢查比對
388
+ await _fetchMyRealIp()
389
+
390
+ //get
391
+ let r = await _testProxiesCore(prxsRaw)
392
+
393
+ //emit add
394
+ each(r.psValid, (p) => {
395
+ kpPrx[p.proxy] = p
396
+ ev.emit('add', p, values(kpPrx))
397
+ })
398
+
399
+ //emit delete
400
+ each(r.psInvalid, (p) => {
401
+ delete kpPrx[p.proxy]
402
+ ev.emit('delete', p, values(kpPrx))
403
+ })
404
+
405
+ //emit change
406
+ ev.emit('change', values(kpPrx))
407
+
408
+ }
409
+
410
+ //core
411
+ if (b_testProxies) {
412
+ return
413
+ }
414
+ b_testProxies = true
415
+ await core()
416
+ .catch(() => {}) //吃掉錯誤
417
+ .finally(() => {
418
+ b_testProxies = false
419
+ })
420
+
421
+ }
422
+
423
+ function init() {
424
+
425
+ //取得代理清單
426
+ if (true) {
427
+ _getProxies()
428
+ setInterval(() => {
429
+ _getProxies()
430
+ }, timeGetProxies)
431
+ }
432
+
433
+ //過濾出有效代理清單, 延遲3s觸發, 給時間抓取
434
+ if (true) {
435
+ setTimeout(() => {
436
+ _testProxies()
437
+ setInterval(() => {
438
+ _testProxies()
439
+ }, timeTestProxies)
440
+ }, 3000)
441
+ }
442
+
443
+ }
444
+
445
+ async function getProxies() {
446
+ let vs
447
+ await waitFun(() => {
448
+ vs = values(kpPrx)
449
+ return size(vs) > 0
450
+ })
451
+ return vs
452
+ }
453
+
454
+ //ev
455
+ let ev = evem()
456
+
457
+ //withServer
458
+ if (withServer) {
459
+ provideServer(getProxies, {
460
+ port: serverPort,
461
+ apiName: serverApiName,
462
+ corsOrigins: serverCorsOrigins,
463
+ })
464
+ }
465
+
466
+ async function getProxiesOnce() {
467
+ await _getProxies()
468
+ await _testProxies()
469
+ let ps = await getProxies()
470
+ return ps
471
+ }
472
+
473
+ //save
474
+ ev.init = init
475
+ ev.getProxies = getProxies
476
+ ev.getProxiesOnce = getProxiesOnce
477
+
478
+ return ev
21
479
  }
22
480
 
481
+
23
482
  export default WIpProxy