@skrillex1224/playwright-toolkit 2.1.164 → 2.1.165
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.cjs +445 -29
- package/dist/index.cjs.map +3 -3
- package/dist/index.js +445 -29
- package/dist/index.js.map +3 -3
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1414,6 +1414,27 @@ var resolveRouteByProxy = ({
|
|
|
1414
1414
|
// src/traffic-meter.js
|
|
1415
1415
|
var logger6 = createInternalLogger("TrafficMeter");
|
|
1416
1416
|
var encoder = new TextEncoder();
|
|
1417
|
+
var MAX_DOMAIN_BUCKETS = 160;
|
|
1418
|
+
var MAX_REASON_BUCKETS = 64;
|
|
1419
|
+
var MAX_TOP_ITEMS = 12;
|
|
1420
|
+
var MAX_HINT_ITEMS = 8;
|
|
1421
|
+
var UNKNOWN_DOMAIN = "(unknown)";
|
|
1422
|
+
var OTHER_DOMAINS = "(other-domains)";
|
|
1423
|
+
var OTHER_REASONS = "(other-reasons)";
|
|
1424
|
+
var STATIC_RESOURCE_TYPES = /* @__PURE__ */ new Set([
|
|
1425
|
+
"script",
|
|
1426
|
+
"stylesheet",
|
|
1427
|
+
"image",
|
|
1428
|
+
"font",
|
|
1429
|
+
"media",
|
|
1430
|
+
"manifest"
|
|
1431
|
+
]);
|
|
1432
|
+
var BACKEND_RESOURCE_TYPES = /* @__PURE__ */ new Set([
|
|
1433
|
+
"xhr",
|
|
1434
|
+
"fetch",
|
|
1435
|
+
"websocket",
|
|
1436
|
+
"eventsource"
|
|
1437
|
+
]);
|
|
1417
1438
|
var toSafeNumber = (value) => {
|
|
1418
1439
|
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return 0;
|
|
1419
1440
|
return Math.round(value);
|
|
@@ -1457,9 +1478,77 @@ var createTrafficState = () => ({
|
|
|
1457
1478
|
directUploadBytes: 0,
|
|
1458
1479
|
totalDownloadBytes: 0,
|
|
1459
1480
|
proxyDownloadBytes: 0,
|
|
1460
|
-
directDownloadBytes: 0
|
|
1481
|
+
directDownloadBytes: 0,
|
|
1482
|
+
totalFailedRequests: 0,
|
|
1483
|
+
proxyFailedRequests: 0,
|
|
1484
|
+
directFailedRequests: 0,
|
|
1485
|
+
totalCanceledRequests: 0,
|
|
1486
|
+
proxyCanceledRequests: 0,
|
|
1487
|
+
directCanceledRequests: 0,
|
|
1488
|
+
orphanDataReceivedBytes: 0,
|
|
1489
|
+
orphanProxyDataReceivedBytes: 0,
|
|
1490
|
+
orphanFinishDeltaBytes: 0,
|
|
1491
|
+
orphanProxyFinishDeltaBytes: 0,
|
|
1492
|
+
domainStats: /* @__PURE__ */ new Map(),
|
|
1493
|
+
typeStats: /* @__PURE__ */ new Map(),
|
|
1494
|
+
failedReasonStats: /* @__PURE__ */ new Map()
|
|
1461
1495
|
});
|
|
1462
1496
|
var ensureRoute = (route) => route === "proxy" ? "proxy" : "direct";
|
|
1497
|
+
var normalizeResourceType = (value) => {
|
|
1498
|
+
const type = String(value || "").trim().toLowerCase();
|
|
1499
|
+
if (!type) return "other";
|
|
1500
|
+
if (type === "ws") return "websocket";
|
|
1501
|
+
return type;
|
|
1502
|
+
};
|
|
1503
|
+
var parseHostname = (url = "") => {
|
|
1504
|
+
try {
|
|
1505
|
+
const hostname = new URL(String(url || "")).hostname.toLowerCase();
|
|
1506
|
+
return hostname || "";
|
|
1507
|
+
} catch {
|
|
1508
|
+
return "";
|
|
1509
|
+
}
|
|
1510
|
+
};
|
|
1511
|
+
var normalizeDomainKey = (domain = "") => {
|
|
1512
|
+
const key = String(domain || "").trim().toLowerCase();
|
|
1513
|
+
return key || UNKNOWN_DOMAIN;
|
|
1514
|
+
};
|
|
1515
|
+
var isStaticType = (resourceType = "") => STATIC_RESOURCE_TYPES.has(normalizeResourceType(resourceType));
|
|
1516
|
+
var isBackendType = (resourceType = "") => BACKEND_RESOURCE_TYPES.has(normalizeResourceType(resourceType));
|
|
1517
|
+
var createDomainBucket = (domain) => ({
|
|
1518
|
+
domain,
|
|
1519
|
+
requests: 0,
|
|
1520
|
+
proxyRequests: 0,
|
|
1521
|
+
directRequests: 0,
|
|
1522
|
+
uploadBytes: 0,
|
|
1523
|
+
downloadBytes: 0,
|
|
1524
|
+
totalBytes: 0,
|
|
1525
|
+
proxyBytes: 0,
|
|
1526
|
+
directBytes: 0,
|
|
1527
|
+
failedRequests: 0,
|
|
1528
|
+
canceledRequests: 0,
|
|
1529
|
+
staticBytes: 0,
|
|
1530
|
+
backendBytes: 0
|
|
1531
|
+
});
|
|
1532
|
+
var createTypeBucket = (resourceType) => ({
|
|
1533
|
+
resourceType,
|
|
1534
|
+
requests: 0,
|
|
1535
|
+
proxyRequests: 0,
|
|
1536
|
+
directRequests: 0,
|
|
1537
|
+
uploadBytes: 0,
|
|
1538
|
+
downloadBytes: 0,
|
|
1539
|
+
totalBytes: 0,
|
|
1540
|
+
proxyBytes: 0,
|
|
1541
|
+
directBytes: 0,
|
|
1542
|
+
failedRequests: 0,
|
|
1543
|
+
canceledRequests: 0
|
|
1544
|
+
});
|
|
1545
|
+
var createReasonBucket = (reason) => ({
|
|
1546
|
+
reason,
|
|
1547
|
+
count: 0,
|
|
1548
|
+
canceledCount: 0,
|
|
1549
|
+
proxyCount: 0,
|
|
1550
|
+
directCount: 0
|
|
1551
|
+
});
|
|
1463
1552
|
var formatBytes = (bytes = 0) => {
|
|
1464
1553
|
const value = toSafeNumber(bytes);
|
|
1465
1554
|
if (value <= 0) return "0B";
|
|
@@ -1506,6 +1595,190 @@ var addDownloadBytes = (state, route, bytes = 0) => {
|
|
|
1506
1595
|
}
|
|
1507
1596
|
state.directDownloadBytes += b;
|
|
1508
1597
|
};
|
|
1598
|
+
var incrementBucketRequests = (bucket, route) => {
|
|
1599
|
+
if (!bucket) return;
|
|
1600
|
+
bucket.requests += 1;
|
|
1601
|
+
if (ensureRoute(route) === "proxy") {
|
|
1602
|
+
bucket.proxyRequests += 1;
|
|
1603
|
+
return;
|
|
1604
|
+
}
|
|
1605
|
+
bucket.directRequests += 1;
|
|
1606
|
+
};
|
|
1607
|
+
var incrementBucketBytes = (bucket, route, bytes = 0, direction = "download", resourceType = "other") => {
|
|
1608
|
+
if (!bucket) return;
|
|
1609
|
+
const b = toSafeNumber(bytes);
|
|
1610
|
+
if (b <= 0) return;
|
|
1611
|
+
if (direction === "upload") {
|
|
1612
|
+
bucket.uploadBytes += b;
|
|
1613
|
+
} else {
|
|
1614
|
+
bucket.downloadBytes += b;
|
|
1615
|
+
}
|
|
1616
|
+
bucket.totalBytes += b;
|
|
1617
|
+
if (ensureRoute(route) === "proxy") {
|
|
1618
|
+
bucket.proxyBytes += b;
|
|
1619
|
+
} else {
|
|
1620
|
+
bucket.directBytes += b;
|
|
1621
|
+
}
|
|
1622
|
+
if (bucket.domain !== void 0) {
|
|
1623
|
+
if (isStaticType(resourceType)) {
|
|
1624
|
+
bucket.staticBytes += b;
|
|
1625
|
+
} else if (isBackendType(resourceType)) {
|
|
1626
|
+
bucket.backendBytes += b;
|
|
1627
|
+
}
|
|
1628
|
+
}
|
|
1629
|
+
};
|
|
1630
|
+
var incrementBucketFailed = (bucket, canceled = false) => {
|
|
1631
|
+
if (!bucket) return;
|
|
1632
|
+
bucket.failedRequests += 1;
|
|
1633
|
+
if (canceled) {
|
|
1634
|
+
bucket.canceledRequests += 1;
|
|
1635
|
+
}
|
|
1636
|
+
};
|
|
1637
|
+
var ensureReasonText = (reason) => {
|
|
1638
|
+
const normalized = String(reason || "").trim().toLowerCase();
|
|
1639
|
+
return normalized || "unknown";
|
|
1640
|
+
};
|
|
1641
|
+
var pickDomainBucket = (state, domain = "") => {
|
|
1642
|
+
const domainKey = normalizeDomainKey(domain);
|
|
1643
|
+
const knownBucket = state.domainStats.get(domainKey);
|
|
1644
|
+
if (knownBucket) return knownBucket;
|
|
1645
|
+
if (state.domainStats.size < MAX_DOMAIN_BUCKETS) {
|
|
1646
|
+
const bucket2 = createDomainBucket(domainKey);
|
|
1647
|
+
state.domainStats.set(domainKey, bucket2);
|
|
1648
|
+
return bucket2;
|
|
1649
|
+
}
|
|
1650
|
+
const overflow = state.domainStats.get(OTHER_DOMAINS);
|
|
1651
|
+
if (overflow) return overflow;
|
|
1652
|
+
const bucket = createDomainBucket(OTHER_DOMAINS);
|
|
1653
|
+
state.domainStats.set(OTHER_DOMAINS, bucket);
|
|
1654
|
+
return bucket;
|
|
1655
|
+
};
|
|
1656
|
+
var pickTypeBucket = (state, resourceType = "other") => {
|
|
1657
|
+
const typeKey = normalizeResourceType(resourceType);
|
|
1658
|
+
const knownBucket = state.typeStats.get(typeKey);
|
|
1659
|
+
if (knownBucket) return knownBucket;
|
|
1660
|
+
const bucket = createTypeBucket(typeKey);
|
|
1661
|
+
state.typeStats.set(typeKey, bucket);
|
|
1662
|
+
return bucket;
|
|
1663
|
+
};
|
|
1664
|
+
var pickReasonBucket = (state, reason = "") => {
|
|
1665
|
+
const reasonKey = ensureReasonText(reason);
|
|
1666
|
+
const knownBucket = state.failedReasonStats.get(reasonKey);
|
|
1667
|
+
if (knownBucket) return knownBucket;
|
|
1668
|
+
if (state.failedReasonStats.size < MAX_REASON_BUCKETS) {
|
|
1669
|
+
const bucket2 = createReasonBucket(reasonKey);
|
|
1670
|
+
state.failedReasonStats.set(reasonKey, bucket2);
|
|
1671
|
+
return bucket2;
|
|
1672
|
+
}
|
|
1673
|
+
const overflow = state.failedReasonStats.get(OTHER_REASONS);
|
|
1674
|
+
if (overflow) return overflow;
|
|
1675
|
+
const bucket = createReasonBucket(OTHER_REASONS);
|
|
1676
|
+
state.failedReasonStats.set(OTHER_REASONS, bucket);
|
|
1677
|
+
return bucket;
|
|
1678
|
+
};
|
|
1679
|
+
var addRequestProfile = (state, route, domain, resourceType, uploadBytes = 0) => {
|
|
1680
|
+
const domainBucket = pickDomainBucket(state, domain);
|
|
1681
|
+
const typeBucket = pickTypeBucket(state, resourceType);
|
|
1682
|
+
incrementBucketRequests(domainBucket, route);
|
|
1683
|
+
incrementBucketRequests(typeBucket, route);
|
|
1684
|
+
incrementBucketBytes(domainBucket, route, uploadBytes, "upload", resourceType);
|
|
1685
|
+
incrementBucketBytes(typeBucket, route, uploadBytes, "upload", resourceType);
|
|
1686
|
+
};
|
|
1687
|
+
var addUploadProfile = (state, route, domain, resourceType, uploadBytes = 0) => {
|
|
1688
|
+
const domainBucket = pickDomainBucket(state, domain);
|
|
1689
|
+
const typeBucket = pickTypeBucket(state, resourceType);
|
|
1690
|
+
incrementBucketBytes(domainBucket, route, uploadBytes, "upload", resourceType);
|
|
1691
|
+
incrementBucketBytes(typeBucket, route, uploadBytes, "upload", resourceType);
|
|
1692
|
+
};
|
|
1693
|
+
var addDownloadProfile = (state, route, domain, resourceType, downloadBytes = 0) => {
|
|
1694
|
+
const domainBucket = pickDomainBucket(state, domain);
|
|
1695
|
+
const typeBucket = pickTypeBucket(state, resourceType);
|
|
1696
|
+
incrementBucketBytes(domainBucket, route, downloadBytes, "download", resourceType);
|
|
1697
|
+
incrementBucketBytes(typeBucket, route, downloadBytes, "download", resourceType);
|
|
1698
|
+
};
|
|
1699
|
+
var addFailedProfile = (state, route, domain, resourceType, reason = "unknown", canceled = false) => {
|
|
1700
|
+
const domainBucket = pickDomainBucket(state, domain);
|
|
1701
|
+
const typeBucket = pickTypeBucket(state, resourceType);
|
|
1702
|
+
const reasonBucket = pickReasonBucket(state, reason);
|
|
1703
|
+
incrementBucketFailed(domainBucket, canceled);
|
|
1704
|
+
incrementBucketFailed(typeBucket, canceled);
|
|
1705
|
+
reasonBucket.count += 1;
|
|
1706
|
+
if (ensureRoute(route) === "proxy") {
|
|
1707
|
+
reasonBucket.proxyCount += 1;
|
|
1708
|
+
} else {
|
|
1709
|
+
reasonBucket.directCount += 1;
|
|
1710
|
+
}
|
|
1711
|
+
if (canceled) {
|
|
1712
|
+
reasonBucket.canceledCount += 1;
|
|
1713
|
+
}
|
|
1714
|
+
};
|
|
1715
|
+
var toRoundedRatio = (numerator, denominator) => {
|
|
1716
|
+
if (denominator <= 0) return 0;
|
|
1717
|
+
return Number((numerator / denominator * 100).toFixed(2));
|
|
1718
|
+
};
|
|
1719
|
+
var sortByBytesAndRequests = (left, right) => {
|
|
1720
|
+
if (right.totalBytes !== left.totalBytes) return right.totalBytes - left.totalBytes;
|
|
1721
|
+
if (right.requests !== left.requests) return right.requests - left.requests;
|
|
1722
|
+
return String(left.domain || left.resourceType || "").localeCompare(String(right.domain || right.resourceType || ""));
|
|
1723
|
+
};
|
|
1724
|
+
var buildTopDomains = (state) => {
|
|
1725
|
+
return Array.from(state.domainStats.values()).filter((item) => item && item.totalBytes > 0).sort(sortByBytesAndRequests).slice(0, MAX_TOP_ITEMS).map((item) => ({
|
|
1726
|
+
domain: item.domain,
|
|
1727
|
+
requests: item.requests,
|
|
1728
|
+
proxyRequests: item.proxyRequests,
|
|
1729
|
+
directRequests: item.directRequests,
|
|
1730
|
+
uploadBytes: item.uploadBytes,
|
|
1731
|
+
downloadBytes: item.downloadBytes,
|
|
1732
|
+
totalBytes: item.totalBytes,
|
|
1733
|
+
proxyBytes: item.proxyBytes,
|
|
1734
|
+
directBytes: item.directBytes,
|
|
1735
|
+
failedRequests: item.failedRequests,
|
|
1736
|
+
canceledRequests: item.canceledRequests,
|
|
1737
|
+
staticBytes: item.staticBytes,
|
|
1738
|
+
backendBytes: item.backendBytes
|
|
1739
|
+
}));
|
|
1740
|
+
};
|
|
1741
|
+
var buildTopResourceTypes = (state) => {
|
|
1742
|
+
return Array.from(state.typeStats.values()).filter((item) => item && (item.totalBytes > 0 || item.requests > 0)).sort(sortByBytesAndRequests).slice(0, MAX_TOP_ITEMS).map((item) => ({
|
|
1743
|
+
resourceType: item.resourceType,
|
|
1744
|
+
requests: item.requests,
|
|
1745
|
+
proxyRequests: item.proxyRequests,
|
|
1746
|
+
directRequests: item.directRequests,
|
|
1747
|
+
uploadBytes: item.uploadBytes,
|
|
1748
|
+
downloadBytes: item.downloadBytes,
|
|
1749
|
+
totalBytes: item.totalBytes,
|
|
1750
|
+
proxyBytes: item.proxyBytes,
|
|
1751
|
+
directBytes: item.directBytes,
|
|
1752
|
+
failedRequests: item.failedRequests,
|
|
1753
|
+
canceledRequests: item.canceledRequests
|
|
1754
|
+
}));
|
|
1755
|
+
};
|
|
1756
|
+
var buildFailedReasons = (state) => {
|
|
1757
|
+
return Array.from(state.failedReasonStats.values()).filter((item) => item && item.count > 0).sort((left, right) => {
|
|
1758
|
+
if (right.count !== left.count) return right.count - left.count;
|
|
1759
|
+
return String(left.reason || "").localeCompare(String(right.reason || ""));
|
|
1760
|
+
}).slice(0, MAX_TOP_ITEMS).map((item) => ({
|
|
1761
|
+
reason: item.reason,
|
|
1762
|
+
count: item.count,
|
|
1763
|
+
canceledCount: item.canceledCount,
|
|
1764
|
+
proxyCount: item.proxyCount,
|
|
1765
|
+
directCount: item.directCount
|
|
1766
|
+
}));
|
|
1767
|
+
};
|
|
1768
|
+
var buildProxyByPassHints = (state) => {
|
|
1769
|
+
return Array.from(state.domainStats.values()).filter((item) => item && item.domain !== UNKNOWN_DOMAIN && item.domain !== OTHER_DOMAINS).filter((item) => item.proxyBytes >= 128 * 1024 && item.proxyRequests >= 2 && item.totalBytes > 0).filter((item) => item.staticBytes > item.backendBytes && toRoundedRatio(item.staticBytes, item.totalBytes) >= 80).sort((left, right) => {
|
|
1770
|
+
if (right.proxyBytes !== left.proxyBytes) return right.proxyBytes - left.proxyBytes;
|
|
1771
|
+
return right.proxyRequests - left.proxyRequests;
|
|
1772
|
+
}).slice(0, MAX_HINT_ITEMS).map((item) => ({
|
|
1773
|
+
domain: item.domain,
|
|
1774
|
+
proxyBytes: item.proxyBytes,
|
|
1775
|
+
proxyRequests: item.proxyRequests,
|
|
1776
|
+
totalBytes: item.totalBytes,
|
|
1777
|
+
staticBytes: item.staticBytes,
|
|
1778
|
+
backendBytes: item.backendBytes,
|
|
1779
|
+
staticRatioPct: toRoundedRatio(item.staticBytes, item.totalBytes)
|
|
1780
|
+
}));
|
|
1781
|
+
};
|
|
1509
1782
|
var createTrafficMeter = ({
|
|
1510
1783
|
enableProxy = false,
|
|
1511
1784
|
byPassRules = [],
|
|
@@ -1513,7 +1786,10 @@ var createTrafficMeter = ({
|
|
|
1513
1786
|
} = {}) => {
|
|
1514
1787
|
const state = createTrafficState();
|
|
1515
1788
|
const requestMap = /* @__PURE__ */ new Map();
|
|
1789
|
+
const orphanReceivedMap = /* @__PURE__ */ new Map();
|
|
1516
1790
|
const wsRouteMap = /* @__PURE__ */ new Map();
|
|
1791
|
+
const attachedPages = /* @__PURE__ */ new WeakSet();
|
|
1792
|
+
const attachedContexts = /* @__PURE__ */ new WeakSet();
|
|
1517
1793
|
const resolveRoute = (url = "") => {
|
|
1518
1794
|
return resolveRouteByProxy({
|
|
1519
1795
|
requestUrl: url,
|
|
@@ -1521,62 +1797,169 @@ var createTrafficMeter = ({
|
|
|
1521
1797
|
byPassRules
|
|
1522
1798
|
}).route;
|
|
1523
1799
|
};
|
|
1800
|
+
const fallbackRoute = () => enableProxy ? "proxy" : "direct";
|
|
1524
1801
|
const debugLog = (message) => {
|
|
1525
1802
|
if (!debugMode) return;
|
|
1526
1803
|
logger6.info(`[\u9010\u8BF7\u6C42\u8C03\u8BD5] ${message}`);
|
|
1527
1804
|
};
|
|
1805
|
+
const addFailed = (route, canceled = false) => {
|
|
1806
|
+
const normalizedRoute = ensureRoute(route);
|
|
1807
|
+
state.totalFailedRequests += 1;
|
|
1808
|
+
if (normalizedRoute === "proxy") {
|
|
1809
|
+
state.proxyFailedRequests += 1;
|
|
1810
|
+
} else {
|
|
1811
|
+
state.directFailedRequests += 1;
|
|
1812
|
+
}
|
|
1813
|
+
if (!canceled) return;
|
|
1814
|
+
state.totalCanceledRequests += 1;
|
|
1815
|
+
if (normalizedRoute === "proxy") {
|
|
1816
|
+
state.proxyCanceledRequests += 1;
|
|
1817
|
+
} else {
|
|
1818
|
+
state.directCanceledRequests += 1;
|
|
1819
|
+
}
|
|
1820
|
+
};
|
|
1821
|
+
const finalizeByEncodedLength = (requestId, encodedDataLength, source = "finished") => {
|
|
1822
|
+
const safeRequestId = String(requestId || "");
|
|
1823
|
+
if (!safeRequestId) return;
|
|
1824
|
+
const requestState = requestMap.get(safeRequestId);
|
|
1825
|
+
const orphanReceived = toSafeNumber(orphanReceivedMap.get(safeRequestId));
|
|
1826
|
+
const encoded = toSafeNumber(encodedDataLength);
|
|
1827
|
+
if (requestState) {
|
|
1828
|
+
const routed2 = ensureRoute(requestState.route);
|
|
1829
|
+
const downloaded = toSafeNumber(requestState.downloadBytes);
|
|
1830
|
+
const delta2 = Math.max(0, encoded - downloaded);
|
|
1831
|
+
if (delta2 > 0) {
|
|
1832
|
+
addDownloadBytes(state, routed2, delta2);
|
|
1833
|
+
addDownloadProfile(state, routed2, requestState.domain, requestState.resourceType, delta2);
|
|
1834
|
+
requestState.downloadBytes = downloaded + delta2;
|
|
1835
|
+
}
|
|
1836
|
+
const uploadBytes = toSafeNumber(requestState.uploadBytes);
|
|
1837
|
+
const total = uploadBytes + toSafeNumber(requestState.downloadBytes);
|
|
1838
|
+
debugLog(
|
|
1839
|
+
`final id=${safeRequestId} source=${source} status=ok route=${routed2} type=${requestState.resourceType || "other"} upload=${formatBytes(uploadBytes)} (${uploadBytes}) download=${formatBytes(requestState.downloadBytes)} (${requestState.downloadBytes}) total=${formatBytes(total)} (${total}) url=${requestState.url || "-"}`
|
|
1840
|
+
);
|
|
1841
|
+
requestMap.delete(safeRequestId);
|
|
1842
|
+
orphanReceivedMap.delete(safeRequestId);
|
|
1843
|
+
return;
|
|
1844
|
+
}
|
|
1845
|
+
const routed = fallbackRoute();
|
|
1846
|
+
const delta = Math.max(0, encoded - orphanReceived);
|
|
1847
|
+
if (delta > 0) {
|
|
1848
|
+
addDownloadBytes(state, routed, delta);
|
|
1849
|
+
addDownloadProfile(state, routed, UNKNOWN_DOMAIN, "other", delta);
|
|
1850
|
+
}
|
|
1851
|
+
state.orphanFinishDeltaBytes += delta;
|
|
1852
|
+
if (routed === "proxy") {
|
|
1853
|
+
state.orphanProxyFinishDeltaBytes += delta;
|
|
1854
|
+
}
|
|
1855
|
+
debugLog(
|
|
1856
|
+
`final id=${safeRequestId} source=${source} status=orphan route=${routed} encoded=${formatBytes(encoded)} (${encoded}) delta=${formatBytes(delta)} (${delta})`
|
|
1857
|
+
);
|
|
1858
|
+
orphanReceivedMap.delete(safeRequestId);
|
|
1859
|
+
};
|
|
1528
1860
|
const recordRequest = (params = {}) => {
|
|
1529
1861
|
const requestId = String(params.requestId || "");
|
|
1530
1862
|
const request = params.request && typeof params.request === "object" ? params.request : {};
|
|
1531
1863
|
const url = String(request.url || "");
|
|
1532
1864
|
const route = resolveRoute(url);
|
|
1533
|
-
const resourceType =
|
|
1865
|
+
const resourceType = normalizeResourceType(params.type || request.type || "other");
|
|
1866
|
+
const domain = normalizeDomainKey(parseHostname(url));
|
|
1867
|
+
if (requestId && requestMap.has(requestId)) {
|
|
1868
|
+
const redirectResponse = params.redirectResponse && typeof params.redirectResponse === "object" ? params.redirectResponse : null;
|
|
1869
|
+
finalizeByEncodedLength(
|
|
1870
|
+
requestId,
|
|
1871
|
+
redirectResponse ? redirectResponse.encodedDataLength : 0,
|
|
1872
|
+
"redirect"
|
|
1873
|
+
);
|
|
1874
|
+
}
|
|
1534
1875
|
addRequests(state, route, 1);
|
|
1535
1876
|
const uploadBytes = estimateRequestBytes(request);
|
|
1536
1877
|
addUploadBytes(state, route, uploadBytes);
|
|
1878
|
+
addRequestProfile(state, route, domain, resourceType, uploadBytes);
|
|
1537
1879
|
if (requestId) {
|
|
1538
1880
|
requestMap.set(requestId, {
|
|
1539
|
-
route,
|
|
1881
|
+
route: ensureRoute(route),
|
|
1540
1882
|
resourceType,
|
|
1883
|
+
domain,
|
|
1541
1884
|
url,
|
|
1542
|
-
uploadBytes
|
|
1885
|
+
uploadBytes,
|
|
1886
|
+
downloadBytes: 0
|
|
1543
1887
|
});
|
|
1544
1888
|
}
|
|
1545
1889
|
debugLog(
|
|
1546
1890
|
`request id=${requestId || "-"} route=${route} type=${resourceType} upload=${formatBytes(uploadBytes)} (${uploadBytes}) method=${String(request.method || "GET")} url=${url || "-"}`
|
|
1547
1891
|
);
|
|
1548
1892
|
};
|
|
1549
|
-
const
|
|
1893
|
+
const recordDataReceived = (params = {}) => {
|
|
1550
1894
|
const requestId = String(params.requestId || "");
|
|
1551
|
-
const
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
requestMap.delete(requestId);
|
|
1895
|
+
const bytes = toSafeNumber(params.encodedDataLength);
|
|
1896
|
+
if (bytes <= 0) return;
|
|
1897
|
+
if (!requestId) {
|
|
1898
|
+
const routed2 = fallbackRoute();
|
|
1899
|
+
addDownloadBytes(state, routed2, bytes);
|
|
1900
|
+
addDownloadProfile(state, routed2, UNKNOWN_DOMAIN, "other", bytes);
|
|
1901
|
+
state.orphanDataReceivedBytes += bytes;
|
|
1902
|
+
if (routed2 === "proxy") {
|
|
1903
|
+
state.orphanProxyDataReceivedBytes += bytes;
|
|
1904
|
+
}
|
|
1905
|
+
return;
|
|
1563
1906
|
}
|
|
1907
|
+
const requestState = requestMap.get(requestId);
|
|
1908
|
+
if (requestState) {
|
|
1909
|
+
requestState.downloadBytes = toSafeNumber(requestState.downloadBytes) + bytes;
|
|
1910
|
+
addDownloadBytes(state, requestState.route, bytes);
|
|
1911
|
+
addDownloadProfile(state, requestState.route, requestState.domain, requestState.resourceType, bytes);
|
|
1912
|
+
return;
|
|
1913
|
+
}
|
|
1914
|
+
const prev = toSafeNumber(orphanReceivedMap.get(requestId));
|
|
1915
|
+
orphanReceivedMap.set(requestId, prev + bytes);
|
|
1916
|
+
const routed = fallbackRoute();
|
|
1917
|
+
addDownloadBytes(state, routed, bytes);
|
|
1918
|
+
addDownloadProfile(state, routed, UNKNOWN_DOMAIN, "other", bytes);
|
|
1919
|
+
state.orphanDataReceivedBytes += bytes;
|
|
1920
|
+
if (routed === "proxy") {
|
|
1921
|
+
state.orphanProxyDataReceivedBytes += bytes;
|
|
1922
|
+
}
|
|
1923
|
+
};
|
|
1924
|
+
const recordLoadingFinished = (params = {}) => {
|
|
1925
|
+
finalizeByEncodedLength(params.requestId, params.encodedDataLength, "loadingFinished");
|
|
1564
1926
|
};
|
|
1565
1927
|
const recordRequestFailed = (params = {}) => {
|
|
1566
1928
|
const requestId = String(params.requestId || "");
|
|
1567
1929
|
const requestState = requestId ? requestMap.get(requestId) : null;
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
);
|
|
1930
|
+
const canceled = Boolean(params.canceled);
|
|
1931
|
+
const reason = ensureReasonText(params.errorText);
|
|
1932
|
+
const routed = ensureRoute(requestState?.route || fallbackRoute());
|
|
1933
|
+
const resourceType = normalizeResourceType(requestState?.resourceType || "other");
|
|
1934
|
+
const domain = normalizeDomainKey(requestState?.domain || "");
|
|
1935
|
+
if (requestState) {
|
|
1936
|
+
addFailed(routed, canceled);
|
|
1937
|
+
addFailedProfile(state, routed, domain, resourceType, reason, canceled);
|
|
1938
|
+
const uploadBytes = toSafeNumber(requestState.uploadBytes);
|
|
1939
|
+
const downloadBytes = toSafeNumber(requestState.downloadBytes);
|
|
1940
|
+
const totalBytes = uploadBytes + downloadBytes;
|
|
1941
|
+
debugLog(
|
|
1942
|
+
`final id=${requestId || "-"} source=loadingFailed status=failed route=${routed} type=${requestState.resourceType || "other"} upload=${formatBytes(uploadBytes)} (${uploadBytes}) download=${formatBytes(downloadBytes)} (${downloadBytes}) total=${formatBytes(totalBytes)} (${totalBytes}) canceled=${canceled} reason=${reason} url=${requestState.url || "-"}`
|
|
1943
|
+
);
|
|
1944
|
+
} else {
|
|
1945
|
+
const orphanDownload = toSafeNumber(orphanReceivedMap.get(requestId));
|
|
1946
|
+
addFailed(routed, canceled);
|
|
1947
|
+
addFailedProfile(state, routed, UNKNOWN_DOMAIN, "other", reason, canceled);
|
|
1948
|
+
debugLog(
|
|
1949
|
+
`final id=${requestId || "-"} source=loadingFailed status=orphan-failed route=${routed} upload=0B (0) download=${formatBytes(orphanDownload)} (${orphanDownload}) total=${formatBytes(orphanDownload)} (${orphanDownload}) canceled=${canceled} reason=${reason} url=-`
|
|
1950
|
+
);
|
|
1951
|
+
}
|
|
1571
1952
|
if (requestId) {
|
|
1572
1953
|
requestMap.delete(requestId);
|
|
1954
|
+
orphanReceivedMap.delete(requestId);
|
|
1573
1955
|
}
|
|
1574
1956
|
};
|
|
1575
1957
|
const bindWebSocketRoute = (params = {}) => {
|
|
1576
1958
|
const requestId = String(params.requestId || "");
|
|
1577
1959
|
if (!requestId) return;
|
|
1578
|
-
const
|
|
1579
|
-
|
|
1960
|
+
const url = String(params.url || "");
|
|
1961
|
+
const route = resolveRoute(url);
|
|
1962
|
+
wsRouteMap.set(requestId, { route, url, domain: normalizeDomainKey(parseHostname(url)) });
|
|
1580
1963
|
};
|
|
1581
1964
|
const clearWebSocketRoute = (params = {}) => {
|
|
1582
1965
|
const requestId = String(params.requestId || "");
|
|
@@ -1584,48 +1967,64 @@ var createTrafficMeter = ({
|
|
|
1584
1967
|
wsRouteMap.delete(requestId);
|
|
1585
1968
|
};
|
|
1586
1969
|
const getWebSocketMeta = (requestId = "") => {
|
|
1587
|
-
if (!requestId) return { route:
|
|
1970
|
+
if (!requestId) return { route: fallbackRoute(), url: "", domain: UNKNOWN_DOMAIN };
|
|
1588
1971
|
const meta = wsRouteMap.get(requestId);
|
|
1589
1972
|
if (!meta || typeof meta !== "object") {
|
|
1590
|
-
return { route:
|
|
1973
|
+
return { route: fallbackRoute(), url: "", domain: UNKNOWN_DOMAIN };
|
|
1591
1974
|
}
|
|
1592
1975
|
return {
|
|
1593
1976
|
route: ensureRoute(meta.route),
|
|
1594
|
-
url: String(meta.url || "")
|
|
1977
|
+
url: String(meta.url || ""),
|
|
1978
|
+
domain: normalizeDomainKey(meta.domain)
|
|
1595
1979
|
};
|
|
1596
1980
|
};
|
|
1597
1981
|
const recordWebSocketFrameSent = (params = {}) => {
|
|
1598
1982
|
const requestId = String(params.requestId || "");
|
|
1599
|
-
const { route, url } = getWebSocketMeta(requestId);
|
|
1983
|
+
const { route, url, domain } = getWebSocketMeta(requestId);
|
|
1600
1984
|
const payload = params.response && typeof params.response === "object" ? params.response.payloadData : "";
|
|
1601
1985
|
const bytes = byteLength(payload || "");
|
|
1602
1986
|
addUploadBytes(state, route, bytes);
|
|
1987
|
+
addUploadProfile(state, route, domain, "websocket", bytes);
|
|
1603
1988
|
debugLog(`ws-send id=${requestId || "-"} route=${route} bytes=${formatBytes(bytes)} (${bytes}) url=${url || "-"}`);
|
|
1604
1989
|
};
|
|
1605
1990
|
const recordWebSocketFrameReceived = (params = {}) => {
|
|
1606
1991
|
const requestId = String(params.requestId || "");
|
|
1607
|
-
const { route, url } = getWebSocketMeta(requestId);
|
|
1992
|
+
const { route, url, domain } = getWebSocketMeta(requestId);
|
|
1608
1993
|
const payload = params.response && typeof params.response === "object" ? params.response.payloadData : "";
|
|
1609
1994
|
const bytes = byteLength(payload || "");
|
|
1610
1995
|
addDownloadBytes(state, route, bytes);
|
|
1996
|
+
addDownloadProfile(state, route, domain, "websocket", bytes);
|
|
1611
1997
|
debugLog(`ws-recv id=${requestId || "-"} route=${route} bytes=${formatBytes(bytes)} (${bytes}) url=${url || "-"}`);
|
|
1612
1998
|
};
|
|
1613
1999
|
const attachPage = async (page) => {
|
|
1614
2000
|
if (!page || typeof page.context !== "function") return;
|
|
2001
|
+
if (attachedPages.has(page)) return;
|
|
2002
|
+
attachedPages.add(page);
|
|
1615
2003
|
try {
|
|
1616
2004
|
const context = page.context();
|
|
1617
2005
|
if (!context || typeof context.newCDPSession !== "function") {
|
|
1618
2006
|
return;
|
|
1619
2007
|
}
|
|
2008
|
+
if (!attachedContexts.has(context) && typeof context.on === "function") {
|
|
2009
|
+
attachedContexts.add(context);
|
|
2010
|
+
context.on("page", (nextPage) => {
|
|
2011
|
+
if (!nextPage) return;
|
|
2012
|
+
attachPage(nextPage).catch((error) => {
|
|
2013
|
+
logger6.warn(`\u5B50\u9875\u9762 CDP \u76D1\u542C\u6CE8\u518C\u5931\u8D25: ${error?.message || error}`);
|
|
2014
|
+
});
|
|
2015
|
+
});
|
|
2016
|
+
}
|
|
1620
2017
|
const session = await context.newCDPSession(page);
|
|
1621
2018
|
await session.send("Network.enable");
|
|
1622
2019
|
session.on("Network.requestWillBeSent", recordRequest);
|
|
2020
|
+
session.on("Network.dataReceived", recordDataReceived);
|
|
1623
2021
|
session.on("Network.loadingFinished", recordLoadingFinished);
|
|
1624
2022
|
session.on("Network.loadingFailed", recordRequestFailed);
|
|
1625
2023
|
session.on("Network.webSocketCreated", bindWebSocketRoute);
|
|
1626
2024
|
session.on("Network.webSocketClosed", clearWebSocketRoute);
|
|
1627
2025
|
session.on("Network.webSocketFrameSent", recordWebSocketFrameSent);
|
|
1628
2026
|
session.on("Network.webSocketFrameReceived", recordWebSocketFrameReceived);
|
|
2027
|
+
debugLog("CDP \u76D1\u542C\u5DF2\u6CE8\u518C");
|
|
1629
2028
|
} catch (error) {
|
|
1630
2029
|
logger6.warn(`CDP \u76D1\u542C\u6CE8\u518C\u5931\u8D25: ${error?.message || error}`);
|
|
1631
2030
|
}
|
|
@@ -1635,7 +2034,7 @@ var createTrafficMeter = ({
|
|
|
1635
2034
|
const proxyBytes = state.proxyUploadBytes + state.proxyDownloadBytes;
|
|
1636
2035
|
const directBytes = state.directUploadBytes + state.directDownloadBytes;
|
|
1637
2036
|
return {
|
|
1638
|
-
meter: "cdp",
|
|
2037
|
+
meter: "cdp-data-received-v3",
|
|
1639
2038
|
totalRequests: state.totalRequests,
|
|
1640
2039
|
proxyRequests: state.proxyRequests,
|
|
1641
2040
|
directRequests: state.directRequests,
|
|
@@ -1647,12 +2046,29 @@ var createTrafficMeter = ({
|
|
|
1647
2046
|
directDownloadBytes: state.directDownloadBytes,
|
|
1648
2047
|
totalBytes,
|
|
1649
2048
|
proxyBytes,
|
|
1650
|
-
directBytes
|
|
2049
|
+
directBytes,
|
|
2050
|
+
totalFailedRequests: state.totalFailedRequests,
|
|
2051
|
+
proxyFailedRequests: state.proxyFailedRequests,
|
|
2052
|
+
directFailedRequests: state.directFailedRequests,
|
|
2053
|
+
totalCanceledRequests: state.totalCanceledRequests,
|
|
2054
|
+
proxyCanceledRequests: state.proxyCanceledRequests,
|
|
2055
|
+
directCanceledRequests: state.directCanceledRequests,
|
|
2056
|
+
orphanDataReceivedBytes: state.orphanDataReceivedBytes,
|
|
2057
|
+
orphanProxyDataReceivedBytes: state.orphanProxyDataReceivedBytes,
|
|
2058
|
+
orphanFinishDeltaBytes: state.orphanFinishDeltaBytes,
|
|
2059
|
+
orphanProxyFinishDeltaBytes: state.orphanProxyFinishDeltaBytes,
|
|
2060
|
+
openRequestCount: requestMap.size,
|
|
2061
|
+
orphanOpenCount: orphanReceivedMap.size,
|
|
2062
|
+
topDomains: buildTopDomains(state),
|
|
2063
|
+
topResourceTypes: buildTopResourceTypes(state),
|
|
2064
|
+
failedReasons: buildFailedReasons(state),
|
|
2065
|
+
proxyBypassHints: buildProxyByPassHints(state)
|
|
1651
2066
|
};
|
|
1652
2067
|
};
|
|
1653
2068
|
const reset = () => {
|
|
1654
2069
|
Object.assign(state, createTrafficState());
|
|
1655
2070
|
requestMap.clear();
|
|
2071
|
+
orphanReceivedMap.clear();
|
|
1656
2072
|
wsRouteMap.clear();
|
|
1657
2073
|
};
|
|
1658
2074
|
return {
|