JM Tech Power

jm-tech-power-official/Flash Download

A desktop download manager that opens up to 32 connections against one file and can send each of them out a different proxy route.

Public Uncategorized
Clone jm-tech-power-official/flash-download.jmproj
src/main/engine/agents.js
'use strict';

const { HttpsProxyAgent } = require('https-proxy-agent');
const { HttpProxyAgent } = require('http-proxy-agent');
const { SocksProxyAgent } = require('socks-proxy-agent');

// One agent per (route, revision, target protocol) so sockets are reused across
// lanes that share a route. Bumping route.rev invalidates the cached agent.
const cache = new Map();

function proxyUrl(route) {
  const auth = route.username
    ? `${encodeURIComponent(route.username)}:${encodeURIComponent(route.password || '')}@`
    : '';
  const scheme =
    route.type === 'socks5' ? 'socks5' :
    route.type === 'socks4' ? 'socks4' : 'http';
  return `${scheme}://${auth}${route.host}:${route.port}`;
}

/**
 * @param {object|null} route  route record, or null/`direct` for no proxy
 * @param {URL} target         the URL this socket will fetch
 * @returns {import('http').Agent|undefined} undefined means "go direct"
 */
function agentFor(route, target) {
  if (!route || route.type === 'direct') return undefined;

  const key = `${route.id}|${route.rev || 0}|${target.protocol}`;
  const hit = cache.get(key);
  if (hit) return hit;

  const url = proxyUrl(route);
  const opts = { keepAlive: true, timeout: 20000 };
  let agent;

  if (route.type === 'socks5' || route.type === 'socks4') {
    agent = new SocksProxyAgent(url, opts);
  } else if (target.protocol === 'https:') {
    // CONNECT tunnel through the HTTP proxy
    agent = new HttpsProxyAgent(url, opts);
  } else {
    // plain HTTP: absolute-URI request to the proxy
    agent = new HttpProxyAgent(url, opts);
  }

  cache.set(key, agent);
  return agent;
}

function dropAgents(routeId) {
  for (const key of [...cache.keys()]) {
    if (key.startsWith(`${routeId}|`)) {
      const agent = cache.get(key);
      cache.delete(key);
      try { agent.destroy(); } catch { /* already gone */ }
    }
  }
}

module.exports = { agentFor, dropAgents, proxyUrl };