com.jimuwd.xian.registry-proxy 1.0.108 → 1.0.111

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/dist/index.d.ts CHANGED
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { Server as HttpServer } from 'node:http';
3
3
  import { Server as HttpsServer } from 'node:https';
4
- export declare function startProxyServer(proxyConfigPath?: string, localYarnConfigPath?: string, globalYarnConfigPath?: string, port?: number): Promise<HttpServer | HttpsServer>;
4
+ export declare function startProxyServer(proxyConfigPath?: string, localYarnConfigPath?: string, globalYarnConfigPath?: string, port?: number): Promise<{
5
+ serverIpv6: HttpServer | HttpsServer;
6
+ serverIpv4: HttpServer | HttpsServer;
7
+ }>;
package/dist/index.js CHANGED
@@ -130,14 +130,17 @@ async function fetchFromRegistry(registry, targetUrl, reqFromDownstreamClient, l
130
130
  mergedHeaders.host = upstreamHost;
131
131
  }
132
132
  const response = await fetch(targetUrl, { headers: mergedHeaders });
133
- logger.info(`
134
- Response from upstream ${targetUrl}: ${response.status} ${response.statusText}
135
- content-type=${response.headers.get('content-type')}
136
- content-encoding=${response.headers.get('content-encoding')}
137
- content-length=${response.headers.get('content-length')}
138
- transfer-encoding=${response.headers.get('transfer-encoding')}
139
- `);
140
- return response.ok ? response : null;
133
+ if (response.ok) {
134
+ logger.debug(`Success response from upstream ${targetUrl}: ${response.status} ${response.statusText}
135
+ content-type=${response.headers.get('content-type')} content-encoding=${response.headers.get('content-encoding')} content-length=${response.headers.get('content-length')} transfer-encoding=${response.headers.get('transfer-encoding')}`);
136
+ return response;
137
+ }
138
+ else {
139
+ logger.info(`Failure response from upstream ${targetUrl}: ${response.status} ${response.statusText}
140
+ content-type=${response.headers.get('content-type')} content-encoding=${response.headers.get('content-encoding')} content-length=${response.headers.get('content-length')} transfer-encoding=${response.headers.get('transfer-encoding')}
141
+ body=${await response.text()}`);
142
+ return null;
143
+ }
141
144
  }
142
145
  catch (e) {
143
146
  if (e instanceof Error) {
@@ -250,7 +253,7 @@ async function writeResponseToDownstreamClient(registryInfo, targetUrl, resToDow
250
253
  // pipe upstream body to downstream client
251
254
  upstreamResponse.body.pipe(resToDownstreamClient, { end: true });
252
255
  upstreamResponse.body
253
- .on('data', (chunk) => logger.info(`Chunk transferred from ${targetUrl} to downstream client size=${chunk.length}`))
256
+ .on('data', (chunk) => logger.debug(`Chunk transferred from ${targetUrl} to downstream client size=${chunk.length}`))
254
257
  .on('end', () => {
255
258
  logger.info(`Upstream server ${targetUrl} response.body ended.`);
256
259
  // resToDownstreamClient.end();
@@ -296,6 +299,7 @@ function getDownstreamClientIp(req) {
296
299
  // 直接连接时,取 socket.remoteAddress
297
300
  return req.socket.remoteAddress;
298
301
  }
302
+ // 同时启动ipv6,ipv4监听,比如当客户端访问http://localhost:port时,无论客户端DNS解析到IPV4-127.0.0.1还是IPV6-::1地址,咱server都能轻松应对!
299
303
  export async function startProxyServer(proxyConfigPath, localYarnConfigPath, globalYarnConfigPath, port = 0) {
300
304
  const proxyInfo = await loadProxyInfo(proxyConfigPath, localYarnConfigPath, globalYarnConfigPath);
301
305
  const registryInfos = proxyInfo.registries;
@@ -303,6 +307,7 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
303
307
  logger.info('Active registries:', registryInfos.map(r => r.normalizedRegistryUrl));
304
308
  logger.info('Proxy base path:', basePathPrefixedWithSlash);
305
309
  logger.info('HTTPS:', !!proxyInfo.https);
310
+ // the real port server is listening on if configured port is empty or 0
306
311
  let proxyPort;
307
312
  const requestHandler = async (reqFromDownstreamClient, resToDownstreamClient) => {
308
313
  const downstreamUserAgent = reqFromDownstreamClient.headers["user-agent"]; // "curl/x.x.x"
@@ -355,7 +360,9 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
355
360
  resToDownstreamClient.writeHead(404).end('All upstream registries failed');
356
361
  }
357
362
  };
358
- let server;
363
+ // 同时启动ipv6,ipv4监听,比如当客户端访问http://localhost:port时,无论客户端DNS解析到IPV4-127.0.0.1还是IPV6-::1地址,咱server都能轻松应对!
364
+ let serverIpv6;
365
+ let serverIpv4;
359
366
  if (proxyInfo.https) {
360
367
  const { key, cert } = proxyInfo.https;
361
368
  const keyPath = resolvePath(key);
@@ -372,40 +379,57 @@ export async function startProxyServer(proxyConfigPath, localYarnConfigPath, glo
372
379
  key: readFileSync(keyPath),
373
380
  cert: readFileSync(certPath),
374
381
  };
375
- server = createHttpsServer(httpsOptions, requestHandler);
382
+ serverIpv6 = createHttpsServer(httpsOptions, requestHandler);
383
+ serverIpv4 = createHttpsServer(httpsOptions, requestHandler);
376
384
  logger.info("Proxy server's maxSockets is", https.globalAgent.maxSockets);
377
385
  }
378
386
  else {
379
- server = createServer(requestHandler);
387
+ serverIpv6 = createServer(requestHandler);
388
+ serverIpv4 = createServer(requestHandler);
380
389
  logger.info("Proxy server's maxSockets is", http.globalAgent.maxSockets);
381
390
  }
382
- logger.info(`Proxy server's initial maxConnections is ${server.maxConnections}, adjusting to 10000`);
383
- server.maxConnections = 10000;
384
- logger.info(`Proxy server's initial timeout is ${server.timeout}, adjusting to 60000ms`);
385
- server.timeout = 60000;
391
+ // server参数暂时写死
392
+ const serverMaxConnections = 10000;
393
+ const serverTimeoutMs = 60000;
394
+ logger.info(`Proxy server's initial maxConnections is ${serverIpv4.maxConnections}, adjusting to ${serverMaxConnections}`);
395
+ serverIpv6.maxConnections = serverMaxConnections;
396
+ serverIpv4.maxConnections = serverMaxConnections;
397
+ logger.info(`Proxy server's initial timeout is ${serverIpv4.timeout}, adjusting to ${serverTimeoutMs}ms`);
398
+ serverIpv6.timeout = serverTimeoutMs;
399
+ serverIpv4.timeout = serverTimeoutMs;
386
400
  const promisedServer = new Promise((resolve, reject) => {
387
- server.on('error', (err) => {
401
+ const errHandler = (err) => {
388
402
  if (err.code === 'EADDRINUSE') {
389
403
  logger.error(`Port ${port} is in use, please specify a different port or free it.`);
390
404
  process.exit(1);
391
405
  }
392
406
  logger.error('Server error:', err);
393
407
  reject(err);
394
- });
395
- server.on('connection', (socket) => {
408
+ };
409
+ const connectionHandler = (socket) => {
396
410
  logger.info("Server on connection");
397
411
  socket.setTimeout(60000);
398
412
  socket.setKeepAlive(true, 30000);
399
- });
400
- // ipv4和ipv6双栈支持
401
- server.listen(port, '::', () => {
402
- const address = server.address();
403
- proxyPort = address.port;
413
+ };
414
+ // 嵌套的回调函数,在ipv6监听器启动之后会被回调调用
415
+ const nestedListener = () => {
404
416
  const portFile = join(process.env.PROJECT_ROOT || process.cwd(), '.registry-proxy-port');
405
- writeFile(portFile, proxyPort.toString()).catch(e => logger.error('Failed to write port file:', e));
406
- logger.info(`Proxy server running on ${proxyInfo.https ? 'https' : 'http'}://127.0.0.1:${proxyPort}${basePathPrefixedWithSlash === '/' ? '' : basePathPrefixedWithSlash}`);
407
- resolve(server);
408
- });
417
+ writeFile(portFile, proxyPort.toString()).catch(e => logger.error(`Failed to write port file: ${portFile}`, e));
418
+ logger.info(`Proxy server running on ${proxyInfo.https ? 'https' : 'http'}://localhost:${proxyPort}${basePathPrefixedWithSlash === '/' ? '' : basePathPrefixedWithSlash}`);
419
+ resolve({ serverIpv6, serverIpv4, });
420
+ };
421
+ const listenerCallback = () => {
422
+ const address = serverIpv6.address();
423
+ proxyPort = address.port;
424
+ // 前面已经监听了ipv6端口,追加监听Ipv4同端口号
425
+ serverIpv4.listen(proxyPort, '0.0.0.0', nestedListener);
426
+ };
427
+ serverIpv6.on('error', errHandler);
428
+ serverIpv4.on('error', errHandler);
429
+ serverIpv6.on('connection', connectionHandler);
430
+ serverIpv4.on('connection', connectionHandler);
431
+ // 为了代理服务器的健壮性,先启动ipv6监听,然后再在其回调函数中启动ipv4监听
432
+ serverIpv6.listen(port, '::', listenerCallback);
409
433
  });
410
434
  return promisedServer;
411
435
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "com.jimuwd.xian.registry-proxy",
3
- "version": "1.0.108",
3
+ "version": "1.0.111",
4
4
  "description": "A lightweight npm registry proxy with fallback support",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",