UNPKG

@letsscrapedata/proxy

Version:

proxy manager used to scrape data

1,105 lines (1,097 loc) 37.9 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { DefaultDatacenterProxyPriority: () => DefaultDatacenterProxyPriority, DefaultIspProxyPriority: () => DefaultIspProxyPriority, DefaultMobileProxyPriority: () => DefaultMobileProxyPriority, DefaultProxyPackagePriority: () => DefaultProxyPackagePriority, DefaultResidentialProxyPriority: () => DefaultResidentialProxyPriority, DefaultStaticProxyPriority: () => DefaultStaticProxyPriority, GeneralAccount: () => GeneralAccount, NewProxyEvent: () => NewProxyEvent, ProxyManager: () => ProxyManager2, checkGeoLocations: () => checkGeoLocations, checkProxy: () => checkProxy, doesProxyMeetRequirements: () => doesProxyMeetRequirements, getDefaultMaxConcurrencyPerUser: () => getDefaultMaxConcurrencyPerUser, getDefaultMaxUsersPerIp: () => getDefaultMaxUsersPerIp, setProxyLogFun: () => setProxyLogFun }); module.exports = __toCommonJS(src_exports); // src/types/types.ts var DefaultStaticProxyPriority = 5; var DefaultProxyPackagePriority = 10; var DefaultResidentialProxyPriority = 10; var DefaultIspProxyPriority = 10; var DefaultDatacenterProxyPriority = 10; var DefaultMobileProxyPriority = 10; var NewProxyEvent = "newproxy"; // src/utils/log.ts var import_utils = require("@letsscrapedata/utils"); var pkgLog = import_utils.log; function setProxyLogFun(logFun) { if (typeof logFun === "function") { pkgLog = logFun; return true; } else { return false; } } async function logdbg(...args) { await pkgLog(import_utils.LogLevel.DBG, ...args); } async function loginfo(...args) { await pkgLog(import_utils.LogLevel.INF, ...args); } async function logerr(...args) { await pkgLog(import_utils.LogLevel.ERR, ...args); } // src/manager/proxyManager.ts var import_node_events = __toESM(require("events"), 1); var ProxyManager2 = class extends import_node_events.default { #proxyAccountManagerMap; #freeableProxies; #addFreeProxy(proxy) { if (!proxy.freeable) { return false; } if (!this.#freeableProxies.find((p) => p.proxyId === proxy.proxyId)) { this.#freeableProxies.push(proxy); return true; } else { return false; } } #getProxyAccountId(accountType, accountName) { return `${accountType}-${accountName}`; } #removeFreeProxy(proxy) { if (!proxy.freeable) { return false; } const idx = this.#freeableProxies.findIndex((p) => p.proxyId === proxy.proxyId); if (idx >= 0) { this.#freeableProxies.splice(idx, 1); return true; } else { return false; } } constructor() { super(); this.#proxyAccountManagerMap = /* @__PURE__ */ new Map(); this.#freeableProxies = []; } addProxyAccount(proxyAccount) { const proxyAccountId = proxyAccount.proxyAccountId(); if (!proxyAccountId) { return false; } if (this.#proxyAccountManagerMap.get(proxyAccountId)) { return false; } else { this.#proxyAccountManagerMap.set(proxyAccountId, proxyAccount); proxyAccount.on(NewProxyEvent, (proxies) => { this.emit(NewProxyEvent, proxies); }); return true; } } async getProxies(proxyRequirements, proxyNum = 1, onlyApplied = false) { const proxies = []; if (proxyNum <= 0) { throw new Error("Invalid paras"); } let toGetNum = proxyNum; let proxyPackageInfos = []; for (const pam of this.#proxyAccountManagerMap.values()) { const ppis = pam._getProxyPackages(proxyRequirements); ppis.forEach((ppi) => proxyPackageInfos.push(ppi)); } if (proxyPackageInfos.length <= 0) { return proxies; } else if (proxyPackageInfos.length > 1) { proxyPackageInfos = proxyPackageInfos.sort((a, b) => a.priority === b.priority ? a.expireTime - b.expireTime : a.priority - b.priority); } for (const ppi of proxyPackageInfos) { const proxyAccountId = this.#getProxyAccountId(ppi.accountType, ppi.accountName); const pam = this.#proxyAccountManagerMap.get(proxyAccountId); if (pam) { const ps = await pam._getProxiesFromPackage(ppi, proxyRequirements, toGetNum, onlyApplied); if (ps.length > 0) { ps.forEach((proxy) => proxies.push(proxy)); toGetNum -= ps.length; } } if (toGetNum <= 0) { if (toGetNum < 0) { logerr(`##log logic error in getProxies`); } break; } } proxies.forEach((proxy) => this.#addFreeProxy(proxy)); return proxies; } discardProxy(proxy) { const proxyAccountId = this.#getProxyAccountId(proxy.accountType, proxy.accountName); const pam = this.#proxyAccountManagerMap.get(proxyAccountId); if (!pam) { return false; } pam.discardProxy(proxy); this.#removeFreeProxy(proxy); return true; } freeProxy(proxy) { const proxyAccountId = this.#getProxyAccountId(proxy.accountType, proxy.accountName); const pam = this.#proxyAccountManagerMap.get(proxyAccountId); if (!pam) { return false; } pam.freeProxy(proxy); this.#removeFreeProxy(proxy); return true; } lockProxy(proxy) { const proxyAccountId = this.#getProxyAccountId(proxy.accountType, proxy.accountName); const pam = this.#proxyAccountManagerMap.get(proxyAccountId); if (!pam) { return false; } pam.lockProxy(proxy); this.#removeFreeProxy(proxy); return true; } adjustPriorityOfPackages(priority, proxyPackageIdentifiers) { for (const ppi of proxyPackageIdentifiers) { const proxyAccountId = this.#getProxyAccountId(ppi.accountType, ppi.accountName); const proxyAccount = this.#proxyAccountManagerMap.get(proxyAccountId); if (proxyAccount) { proxyAccount.adjustPriorityOfPackages(priority, [ppi.packageName]); } } return true; } enablePackages(proxyPackageIdentifiers) { for (const ppi of proxyPackageIdentifiers) { const proxyAccountId = this.#getProxyAccountId(ppi.accountType, ppi.accountName); const pam = this.#proxyAccountManagerMap.get(proxyAccountId); if (pam) { pam.enablePackages([ppi.packageName]); } } return true; } disablePackages(proxyPackageIdentifiers) { for (const ppi of proxyPackageIdentifiers) { const proxyAccountId = this.#getProxyAccountId(ppi.accountType, ppi.accountName); const pam = this.#proxyAccountManagerMap.get(proxyAccountId); if (pam) { pam.disablePackages([ppi.packageName]); } } return true; } enableProxyAccounts(proxyAccountIdentifiers) { for (const pai of proxyAccountIdentifiers) { const proxyAccountId = this.#getProxyAccountId(pai.accountType, pai.accountName); const pam = this.#proxyAccountManagerMap.get(proxyAccountId); if (pam) { pam.enable(); } } return true; } disableProxyAccounts(proxyAccountIdentifiers) { for (const pai of proxyAccountIdentifiers) { const proxyAccountId = this.#getProxyAccountId(pai.accountType, pai.accountName); const pam = this.#proxyAccountManagerMap.get(proxyAccountId); if (pam) { pam.disable(); } } return true; } proxyAccountManager(accountType, accountName) { const proxyAccountId = this.#getProxyAccountId(accountType, accountName); return this.#proxyAccountManagerMap.get(proxyAccountId); } proxyAccounts() { const proxyAcounts = []; for (const pam of this.#proxyAccountManagerMap.values()) { const pa = pam.proxyAccount(); proxyAcounts.push(pa); } return proxyAcounts; } proxyPackages() { const packages = []; for (const pam of this.#proxyAccountManagerMap.values()) { const pkgs = pam.proxyPackages(); pkgs.forEach((pkg) => packages.push(pkg)); } return packages; } proxies() { const proxies = []; for (const pam of this.#proxyAccountManagerMap.values()) { const ps = pam.proxies(); ps.forEach((proxy) => proxies.push(proxy)); } return proxies; } async close() { for (const pam of this.#proxyAccountManagerMap.values()) { await pam.close(); } return true; } }; // src/accounts/general.ts var import_node_events2 = __toESM(require("events"), 1); var import_node_fs = __toESM(require("fs"), 1); var import_utils3 = require("@letsscrapedata/utils"); // src/utils/util.ts var import_node_url = require("url"); var https = __toESM(require("https"), 1); var import_http_proxy_agent = require("http-proxy-agent"); var import_utils2 = require("@letsscrapedata/utils"); async function checkProxy(proxyUrl) { try { if (!proxyUrl) { return true; } await (0, import_utils2.sleep)(1e3); const p = new Promise((resolve, reject) => { const agent = new import_http_proxy_agent.HttpProxyAgent(proxyUrl); const url = "https://nodejs.org/api/"; https.get(url, { agent }, (res) => { resolve(res); }).on("error", (e) => { reject(e); }); }); await p; return true; } catch (err) { logerr(`##log failed to connnect through proxyUrl: ${proxyUrl}`); return false; } } function getProxyIpSharedType(proxyIdType, proxySharedType) { const proxyIpSharedType = `${proxyIdType[0]}${proxySharedType[0]}`; return proxyIpSharedType; } function checkGeoLocations(requiredGls, glsInPpi) { if (requiredGls.length === 0) { return true; } else if (glsInPpi.length === 0) { return false; } for (const requiredGl of requiredGls) { if (glsInPpi.find((gl) => (!requiredGl.country || requiredGl.country === gl.country) && (!requiredGl.city || requiredGl.city === gl.city))) { return true; } } return false; } function getDefaultMaxUsersPerIp(proxyIpType, proxySharedType, billingModel) { let maxUsersPerIp = 1; if (billingModel === "trafic") { return maxUsersPerIp; } if (proxyIpType === "residential") { maxUsersPerIp = proxySharedType === "dedicated" ? 8 : 2; } else if (proxyIpType === "isp") { maxUsersPerIp = proxySharedType === "dedicated" ? 4 : 1; } else if (proxyIpType === "datacenter") { maxUsersPerIp = proxySharedType === "dedicated" ? 2 : 1; } return maxUsersPerIp; } function getDefaultMaxConcurrencyPerUser(proxyIpType, proxySharedType, billingModel) { let maxConcurrencyPerUser = 10; if (billingModel === "trafic") { return maxConcurrencyPerUser; } if (proxyIpType === "residential") { maxConcurrencyPerUser = proxySharedType === "dedicated" ? 30 : 10; } else if (proxyIpType === "isp") { maxConcurrencyPerUser = proxySharedType === "dedicated" ? 20 : 10; } else if (proxyIpType === "datacenter") { maxConcurrencyPerUser = proxySharedType === "dedicated" ? 20 : 10; } return maxConcurrencyPerUser; } function doesProxyPackageMeetRequirements(proxyPackageInfo, proxyRequirements, currentTime = (0, import_utils2.getCurrentUnixTime)()) { const { status, ipBalance: balance, proxyIpSharedType, proxyDurationType, maxProxyDuration, maxSessionDuraion, geoLocations: glsInPpi, billingModel, vendorName, expireTime } = proxyPackageInfo; const { proxyIpSharedTypes = [], minProxyValidSeconds = 0, minIpValidSeconds = 0, proxyDurationTypes = [], billingModels = [], geoLocations = [], vendorNames = [] } = proxyRequirements; return status === "normal" && expireTime > currentTime && balance > 0 && (proxyIpSharedTypes.length === 0 || proxyIpSharedTypes.includes(proxyIpSharedType)) && (minProxyValidSeconds <= 0 || minProxyValidSeconds < maxProxyDuration - 10) && (proxyDurationTypes.length === 0 || proxyDurationTypes.includes(proxyDurationType)) && (minIpValidSeconds <= 0 || minIpValidSeconds <= maxSessionDuraion && minIpValidSeconds < maxProxyDuration - 10) && (billingModels.length === 0 || billingModels.includes(billingModel)) && (geoLocations.length === 0 || checkGeoLocations(geoLocations, glsInPpi)) && (vendorNames.length === 0 || vendorNames.includes(vendorName)); } function convertProxy(proxyInfo, proxyPackageInfo) { const { proxyId, proxyUrl, host, port, username, password, expireTime, geoLocation, createTime, freeable, maxSessionDuraion, priority, maxUsersPerIp, maxConcurrencyPerUser, bandwidth } = proxyInfo; const { accountType, accountName, packageName, proxyIpType, proxyDurationType, proxySharedType, proxyIpSharedType, billingModel, vendorName } = proxyPackageInfo; return { proxyId, proxyUrl, host, port, username, password, expireTime, proxyIpType, proxyDurationType, proxySharedType, proxyIpSharedType, billingModel, packageName, vendorName, maxSessionDuraion, priority, maxUsersPerIp, maxConcurrencyPerUser, bandwidth, geoLocation, createTime, freeable, accountType, accountName }; } function convertProxyPackage(proxyPackageInfo) { const { accountType, accountName, packageName, vendorName, status, proxyIpType, proxyDurationType, proxySharedType, proxyIpSharedType, billingModel, geoLocations, maxProxyDuration, expireTime, ipTotal, ipBalance, ipIdle, gbTotal, gbBalance, whenApplyProxy, description, maxSessionDuraion, priority, maxUsersPerIp, maxConcurrencyPerUser, bandwidth } = proxyPackageInfo; const proxyNum = proxyPackageInfo.proxyInfos.length; return { accountType, accountName, packageName, vendorName, status, proxyIpType, proxyDurationType, proxySharedType, proxyIpSharedType, billingModel, geoLocations, maxProxyDuration, expireTime, ipTotal, ipBalance, ipIdle, gbTotal, gbBalance, maxSessionDuraion, whenApplyProxy, description, priority, maxUsersPerIp, maxConcurrencyPerUser, bandwidth, proxyNum }; } function doesProxyMeetRequirements(proxy, proxyRequirements) { const { proxyIpSharedType, proxyDurationType, geoLocation = "", expireTime, billingModel, vendorName } = proxy; const { proxyIpSharedTypes = [], minProxyValidSeconds = 0, minIpValidSeconds = 0, proxyDurationTypes = [], geoLocations = [], billingModels = [], vendorNames = [] } = proxyRequirements; const currentTime = (0, import_utils2.getCurrentUnixTime)(); return (proxyIpSharedTypes.length === 0 || proxyIpSharedTypes.includes(proxyIpSharedType)) && (minProxyValidSeconds <= 0 || expireTime - currentTime >= minProxyValidSeconds) && (proxyDurationTypes.length === 0 || proxyDurationTypes.includes(proxyDurationType)) && (minIpValidSeconds <= 0 || proxyDurationType !== "rotating") && (billingModels.length === 0 || billingModels.includes(billingModel)) && (geoLocations.length === 0 || geoLocation !== "" && checkGeoLocations(geoLocations, [geoLocation])) && (vendorNames.length === 0 || vendorNames.includes(vendorName)); } function parseCompleteUrl(completeUrl) { try { if (!completeUrl) { return { proxyId: "noproxy", proxyUrl: "", host: "", port: 0, username: "", password: "" }; } const urlStr = completeUrl.includes("://") ? completeUrl : `http://${completeUrl}`; const { protocol, host, hostname, port: portStr, username, password } = new import_node_url.URL(urlStr); const proxyUrl = `${protocol}//${host}`; const proxyId = username ? `${protocol}//${username}@${host}` : proxyUrl; const port = portStr ? Number(portStr) : 0; return { proxyId, proxyUrl, host: hostname, port, username, password }; } catch (err) { return null; } } // src/accounts/general.ts var GeneralAccount = class _GeneralAccount extends import_node_events2.default { static #nextAccountIdx = 1; // static #nextPackageIdx: number = 1; /** * Specifying fixed value ​​in the constructor, different ProxyAccountManager must have different accountType: * 1. vendor name,such as "brightdata", "smartproxy" * 2. class name,such as "general" */ #accountType; #proxyAccountId; #status; #createTime; // from ProxyAccountManagerOptions(GeneralAccountOptions) #accountName; #description; #whenCheckProxy; #discardAbnormalProxy; #abnormalLockSeconds; #refreshIntervalSecs; #refreshIntervalId; #packageNameMap; #refreshFunc; #doesProxyExist(proxyId) { for (const pmv of this.#packageNameMap.values()) { if (pmv.proxyPackageInfo.proxyInfos.find((pi) => pi.proxyId === proxyId)) { return true; } } return false; } /** * add new proxy(completeUrl) in a package: * * ignored if new proxy exists * * check the proxy is ok if needed (refer to whenCheckProxy) * @param proxyPackageInfo * @param completeUrl * @param currentTime * @returns */ async #tryToAddProxy(proxyPackageInfo, completeUrl, currentTime) { try { const { billingModel, maxProxyDuration: maxDurationOfProxy, maxSessionDuraion, priority, maxUsersPerIp, maxConcurrencyPerUser, bandwidth } = proxyPackageInfo; const proxyInfos = proxyPackageInfo.proxyInfos; const simpleProxy = parseCompleteUrl(completeUrl); if (!simpleProxy) { return null; } const { proxyId, proxyUrl, host, port, username, password } = simpleProxy; if (this.#doesProxyExist(proxyId)) { return null; } if (this.#whenCheckProxy === "apply" || this.#whenCheckProxy === "applyAndAllocate") { const checkFlag = await checkProxy(proxyUrl); if (!checkFlag) { return null; } } let proxyInfo = { // ProxyBasic proxyId, proxyUrl, host, port, username, password, expireTime: currentTime + maxDurationOfProxy, geoLocation: void 0, createTime: currentTime, freeable: true, // DefaultProxyAttributesInPackage from ProxyPackage maxSessionDuraion, priority, maxUsersPerIp, maxConcurrencyPerUser, bandwidth, // extended status: "idle", lastAbnormalTime: 0 }; logdbg(`##net add new proxyId: ${proxyId}`); proxyInfos.push(proxyInfo); if (billingModel === "period") { proxyPackageInfo.ipTotal++; proxyPackageInfo.ipBalance++; proxyPackageInfo.ipIdle++; } return proxyInfo; } catch (err) { logerr(err); return null; } } /** * * @param proxyUrls some of proxyUrls maybe exists (added) * @param emitEvent * @returns */ async #tryToAddProxies(proxyPackageInfo, completeUrls, emitEvent = true) { const currentTime = (0, import_utils3.getCurrentUnixTime)(); const addedProxies = []; for (const completeUrl of completeUrls) { const proxyInfo = await this.#tryToAddProxy(proxyPackageInfo, completeUrl, currentTime); if (proxyInfo) { addedProxies.push(proxyInfo); } } if (addedProxies.length <= 0) { return false; } if (emitEvent) { const proxies = addedProxies.map((pi) => convertProxy(pi, proxyPackageInfo)); this.emit(NewProxyEvent, proxies); } return true; } async #getNewProxiesByRequest(requestUrl) { const response = await fetch(requestUrl); const data = await response.json(); if (!data || !Array.isArray(data.completeUrls)) { return []; } const completeUrls = data.completeUrls; if (!completeUrls.every((completeUrl) => completeUrl && typeof completeUrl === "string")) { return []; } return completeUrls; } async #refreshProxiesOfPackage(packageMapValue) { const { proxyPackageInfo, filename, requestUrl, lastFileContent } = packageMapValue; let completeUrls = []; try { if (filename) { const origContent = import_node_fs.default.readFileSync(filename, "utf8"); if (origContent === lastFileContent) { return true; } const split = /[ \t\r\n,]+/; packageMapValue.lastFileContent = origContent; completeUrls = origContent.split(split).filter((item) => item); } else if (requestUrl) { completeUrls = await this.#getNewProxiesByRequest(requestUrl); } if (completeUrls.length === 0) { return true; } await this.#tryToAddProxies(proxyPackageInfo, completeUrls); return true; } catch (err) { logerr(err); return false; } } async #refreshFuncOrig() { if (this.#packageNameMap.size === 0) { return true; } for (const pmv of this.#packageNameMap.values()) { if (pmv.proxyPackageInfo.status === "normal") { await this.#refreshProxiesOfPackage(pmv); } } return true; } /** * Manage general proxies, default options members: * * accountName = `${accountType}-${nextAccountIdx}` * * description = "", * * whenCheckProxy = "applyAndAllocate", * * discardAbnormalProxy = false, * * abnormalLockSeconds = 3600, * * refreshIntervalSecs = 60 * @param options * */ constructor(options = {}) { super(); const accountType = "general"; const { accountName = "", description = "", whenCheckProxy = "applyAndAllocate", discardAbnormalProxy = false, abnormalLockSeconds = 3600, refreshIntervalSecs = 60 } = options; const currentTime = (0, import_utils3.getCurrentUnixTime)(); this.#accountType = accountType; this.#accountName = accountName ? accountName : `${this.#accountType}-${_GeneralAccount.#nextAccountIdx++}`; this.#proxyAccountId = `${this.#accountType}-${this.#accountName}`; this.#createTime = currentTime; this.#description = description; this.#whenCheckProxy = whenCheckProxy; this.#discardAbnormalProxy = discardAbnormalProxy; this.#abnormalLockSeconds = abnormalLockSeconds; this.#refreshIntervalSecs = refreshIntervalSecs; this.#packageNameMap = /* @__PURE__ */ new Map(); this.#status = "normal"; this.#refreshIntervalId = 0; this.#refreshFunc = this.#refreshFuncOrig.bind(this); } async #addProxyPackageInfo(addPackageData) { const { proxyIpType, proxyDurationType, proxySharedType, billingModel, vendorName, completeUrls = [], filename = "" } = addPackageData; const packageName = `${proxyIpType}-${proxyDurationType}-${proxySharedType}-${billingModel}-${vendorName}`; if (this.#packageNameMap.has(packageName)) { loginfo(`##proxy packageName ${packageName} exists in ${this.#proxyAccountId}`); return false; } const defaultMaxSessionDuration = billingModel === "period" ? 3600 * 24 * 30 : 3600; const defaultPriority = DefaultProxyPackagePriority; const defaultMaxUsersPerIp = getDefaultMaxUsersPerIp(proxyIpType, proxySharedType, billingModel); const defaultMaxConcurrencyPerUser = getDefaultMaxConcurrencyPerUser(proxyIpType, proxySharedType, billingModel); const defaultMaxProxyDuration = 3600 * 24 * 365; let { maxSessionDuraion = defaultMaxSessionDuration, priority = defaultPriority, maxUsersPerIp = defaultMaxUsersPerIp, maxConcurrencyPerUser = defaultMaxConcurrencyPerUser, bandwidth = 0, maxProxyDuration = defaultMaxProxyDuration, geoLocations = [], description = "" } = addPackageData; const currentTime = (0, import_utils3.getCurrentUnixTime)(); const proxyPackageInfo = { accountType: this.#accountType, accountName: this.#accountName, packageName, vendorName, proxyIpType, proxyDurationType, proxySharedType, proxyIpSharedType: getProxyIpSharedType(proxyIpType, proxySharedType), billingModel, maxSessionDuraion, priority, maxUsersPerIp, maxConcurrencyPerUser, bandwidth, status: "normal", maxProxyDuration, geoLocations, expireTime: currentTime + maxProxyDuration, ipTotal: 0, ipBalance: 0, ipIdle: 0, gbTotal: 0, gbBalance: 0, whenApplyProxy: "apply", description, proxyInfos: [] }; const requestUrl = addPackageData.requestUrl ? addPackageData.requestUrl.replace("${packageName}", packageName) : ""; const packageMapValue = { proxyPackageInfo, filename, requestUrl, lastFileContent: "" }; this.#packageNameMap.set(packageName, packageMapValue); if (Array.isArray(completeUrls) && completeUrls.length > 0) { await this.update("addProxy", { packageName, completeUrls }); } return true; } proxyAccountId() { return this.#proxyAccountId; } setOptions(options) { const { description, whenCheckProxy, discardAbnormalProxy, abnormalLockSeconds } = options; if (typeof whenCheckProxy === "string") { this.#whenCheckProxy = whenCheckProxy; } if (typeof description === "string") { this.#description = description; } if (typeof discardAbnormalProxy === "boolean") { this.#discardAbnormalProxy = discardAbnormalProxy; } if (typeof abnormalLockSeconds === "number" && abnormalLockSeconds >= 300) { this.#abnormalLockSeconds = abnormalLockSeconds; } return true; } async startRefresh(options = {}) { this.stopRefresh(); const { refreshNow = true } = options; if (refreshNow) { await this.#refreshFunc(); } if (this.#refreshIntervalSecs > 0) { this.#refreshIntervalId = setInterval(this.#refreshFunc, this.#refreshIntervalSecs * 1e3); } return true; } stopRefresh() { if (this.#refreshIntervalId) { clearInterval(this.#refreshIntervalId); this.#refreshIntervalId = 0; } return true; } _getProxyPackages(proxyRequirements) { const proxyPackages = []; if (this.#status !== "normal") { return proxyPackages; } const currentTime = (0, import_utils3.getCurrentUnixTime)(); for (const pmv of this.#packageNameMap.values()) { if (doesProxyPackageMeetRequirements(pmv.proxyPackageInfo, proxyRequirements, currentTime)) { proxyPackages.push(pmv.proxyPackageInfo); } } return proxyPackages; } async _getProxiesFromPackage(proxyPackageInfo, proxyRequirements, proxyNum = 1, onlyApplied = false, onlyAppy = false) { const allocatedProxyInfos = []; const proxies = []; if (this.#status !== "normal") { throw new Error("Invalid paras"); } if (onlyApplied || onlyAppy) { loginfo(`onlyApplied and onlyApply are ingored in GeneralAccount`); } try { const currentTime = (0, import_utils3.getCurrentUnixTime)(); const meetReqFlag = doesProxyPackageMeetRequirements(proxyPackageInfo, proxyRequirements, currentTime); if (!meetReqFlag) { return proxies; } const { minProxyValidSeconds = 0 } = proxyRequirements; const minExpireTime = currentTime + minProxyValidSeconds; const maxAbnormalTime = currentTime - this.#abnormalLockSeconds; const compliantProxyInfos = proxyPackageInfo.proxyInfos.filter( (pi) => pi.status === "idle" && pi.expireTime >= minExpireTime && pi.lastAbnormalTime <= maxAbnormalTime ); if (compliantProxyInfos.length <= 0) { return proxies; } const needCheck = this.#whenCheckProxy === "allocate" || this.#whenCheckProxy === "applyAndAllocate"; for (const proxyInfo of compliantProxyInfos) { if (needCheck) { const checkFlag = await checkProxy(proxyInfo.proxyUrl); if (!checkFlag) { if (this.#discardAbnormalProxy) { const proxy = convertProxy(proxyInfo, proxyPackageInfo); this.discardProxy(proxy); } else { proxyInfo.lastAbnormalTime = currentTime; } continue; } else if (proxyInfo.status !== "idle") { continue; } } allocatedProxyInfos.push(proxyInfo); if (allocatedProxyInfos.length >= proxyNum) { break; } } const proxyInfos = proxyPackageInfo.proxyInfos; allocatedProxyInfos.forEach((pi) => { const proxy = convertProxy(pi, proxyPackageInfo); proxies.push(proxy); if (pi.freeable) { if (!onlyAppy) { pi.status = "busy"; } } else { const proxyIdx = proxyInfos.findIndex((p) => p.proxyId === pi.proxyId); if (proxyIdx >= 0) { proxyInfos[proxyIdx].status = "discarded"; proxyInfos.splice(proxyIdx, 1); } } }); if (proxyPackageInfo.billingModel === "period") { proxyPackageInfo.ipBalance -= proxies.length; proxyPackageInfo.ipIdle -= proxies.length; if (proxyPackageInfo.ipBalance < 0) { logerr(`##log package ${this.#accountName}-${proxyPackageInfo.packageName} has negative balance ${proxyPackageInfo.ipBalance}`); } } return proxies; } catch (err) { loginfo(err); if (!onlyAppy) { allocatedProxyInfos.forEach((pi) => pi.status = "idle"); } return []; } } async getProxies(proxyRequirements, proxyNum = 1, onlyApplied = false) { const proxies = []; if (proxyNum <= 0) { throw new Error("Invalid paras"); } let toGetNum = proxyNum; let proxyPackageInfos = this._getProxyPackages(proxyRequirements); if (proxyPackageInfos.length <= 0) { return proxies; } else if (proxyPackageInfos.length > 1) { proxyPackageInfos = proxyPackageInfos.sort((a, b) => a.priority === b.priority ? a.expireTime - b.expireTime : a.priority - b.priority); } for (const ppi of proxyPackageInfos) { const ps = await this._getProxiesFromPackage(ppi, proxyRequirements, toGetNum, onlyApplied); if (ps.length > 0) { ps.forEach((proxy) => proxies.push(proxy)); toGetNum -= ps.length; } if (toGetNum <= 0) { if (toGetNum < 0) { logerr(`##proxy logic error in getProxies`); } break; } } return proxies; } discardProxy(proxy) { const { billingModel, proxyId, packageName } = proxy; const pmv = this.#packageNameMap.get(packageName); if (!pmv) { loginfo(`##proxy invalid packageName0 ${packageName} in ${this.#proxyAccountId}`); return false; } const proxyInfos = pmv.proxyPackageInfo.proxyInfos; const proxyIdx = proxyInfos.findIndex((pi) => pi.proxyId === proxyId); if (proxyIdx >= 0) { if (proxyInfos[proxyIdx].status === "idle") { if (billingModel === "period") { pmv.proxyPackageInfo.ipBalance--; pmv.proxyPackageInfo.ipIdle--; } } proxyInfos[proxyIdx].status = "discarded"; proxyInfos.splice(proxyIdx, 1); } return true; } freeProxy(proxy) { const { billingModel, proxyId, packageName } = proxy; const pmv = this.#packageNameMap.get(packageName); if (!pmv) { loginfo(`##proxy invalid packageName0 ${packageName} in ${this.#proxyAccountId}`); return false; } const proxyInfos = pmv.proxyPackageInfo.proxyInfos; const proxyInfo = proxyInfos.find((pi) => pi.proxyId === proxyId); if (proxyInfo && proxyInfo.status === "busy") { proxyInfo.status = "idle"; if (billingModel === "period") { pmv.proxyPackageInfo.ipBalance++; pmv.proxyPackageInfo.ipIdle++; } } return true; } lockProxy(proxy) { const { billingModel, proxyId, packageName } = proxy; const pmv = this.#packageNameMap.get(packageName); if (!pmv) { loginfo(`##proxy invalid packageName0 ${packageName} in ${this.#proxyAccountId}`); return false; } const proxyInfos = pmv.proxyPackageInfo.proxyInfos; const proxyInfo = proxyInfos.find((pi) => pi.proxyId === proxyId); if (proxyInfo) { if (proxyInfo.status === "busy") { proxyInfo.status = "idle"; if (billingModel === "period") { pmv.proxyPackageInfo.ipBalance++; pmv.proxyPackageInfo.ipIdle++; } } else if (proxyInfo.status === "discarded") { return false; } const currentTime = (0, import_utils3.getCurrentUnixTime)(); proxyInfo.lastAbnormalTime = currentTime; } return true; } async update(opType, data) { if (opType === "addPackage") { return await this.#addProxyPackageInfo(data); } else if (opType === "addProxy") { const { packageName, completeUrls } = data; const pmv = this.#packageNameMap.get(packageName); if (pmv) { await this.#tryToAddProxies(pmv.proxyPackageInfo, completeUrls); return true; } else { loginfo(`##proxy invalid packageName0 ${packageName} in ${this.#proxyAccountId}`); return false; } } else { (0, import_utils3.unreachable)(opType); } } adjustPriorityOfPackages(priority, packageNames = null) { if (priority <= 0 || priority > 30) { return false; } if (!Array.isArray(packageNames)) { this.#packageNameMap.forEach((pmv) => pmv.proxyPackageInfo.priority = priority); } else { for (const packageName of packageNames) { const pmv = this.#packageNameMap.get(packageName); if (pmv) { pmv.proxyPackageInfo.priority = priority; } else { loginfo(`##proxy invalid packageName ${packageName} in ${this.#proxyAccountId}`); } } } return true; } enablePackages(packageNames = null) { if (!Array.isArray(packageNames)) { this.#packageNameMap.forEach((pmv) => pmv.proxyPackageInfo.status = "normal"); } else { for (const packageName of packageNames) { const pmv = this.#packageNameMap.get(packageName); if (pmv) { pmv.proxyPackageInfo.status = "normal"; } else { loginfo(`##proxy invalid packageName ${packageName} in ${this.#proxyAccountId}`); } } } return true; } disablePackages(packageNames = null) { if (!Array.isArray(packageNames)) { this.#packageNameMap.forEach((pmv) => pmv.proxyPackageInfo.status = "disabled"); } else { for (const packageName of packageNames) { const pmv = this.#packageNameMap.get(packageName); if (pmv) { pmv.proxyPackageInfo.status = "disabled"; } else { loginfo(`##proxy invalid packageName ${packageName} in ${this.#proxyAccountId}`); } } } return true; } enable() { this.#status = "normal"; return true; } disable() { this.#status = "disabled"; return true; } status() { return this.#status; } proxyAccount() { const ppis = Array.from(this.#packageNameMap.values()).map((pmv) => pmv.proxyPackageInfo); const ipTotal = ppis.reduce((sum, ppi) => sum + ppi.ipTotal, 0); const ipBalance = ppis.reduce((sum, ppi) => sum + ppi.ipBalance, 0); const ipIdle = ppis.reduce((sum, ppi) => sum + ppi.ipIdle, 0); const gbTotal = ppis.reduce((sum, ppi) => sum + ppi.gbTotal, 0); const gbBalance = ppis.reduce((sum, ppi) => sum + ppi.gbBalance, 0); const proxyAccount = { accountType: this.#accountType, accountName: this.#accountName, status: this.#status, proxyPackageNum: ppis.length, ipTotal, ipBalance, ipIdle, gbTotal, gbBalance, whenCheckProxy: this.#whenCheckProxy, description: this.#description, createTime: this.#createTime }; return proxyAccount; } proxyPackages() { const packages = []; for (const pmv of this.#packageNameMap.values()) { packages.push(convertProxyPackage(pmv.proxyPackageInfo)); } return packages; } proxies() { const proxies = []; for (const pmv of this.#packageNameMap.values()) { for (const proxyInfo of pmv.proxyPackageInfo.proxyInfos) { proxies.push(convertProxy(proxyInfo, pmv.proxyPackageInfo)); } } return proxies; } async close() { this.stopRefresh(); return true; } }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { DefaultDatacenterProxyPriority, DefaultIspProxyPriority, DefaultMobileProxyPriority, DefaultProxyPackagePriority, DefaultResidentialProxyPriority, DefaultStaticProxyPriority, GeneralAccount, NewProxyEvent, ProxyManager, checkGeoLocations, checkProxy, doesProxyMeetRequirements, getDefaultMaxConcurrencyPerUser, getDefaultMaxUsersPerIp, setProxyLogFun });