@letsscrapedata/proxy
Version:
proxy manager used to scrape data
1,105 lines (1,097 loc) • 37.9 kB
JavaScript
"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
});