@vpalmisano/webrtcperf 4.4.1 → 4.4.3

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/src/session.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { getSessionThrottleValues, throttleLauncher } from '@vpalmisano/throttler'
1
+ import { getSessionThrottleValues, throttleLauncher, throttleNotifier } from '@vpalmisano/throttler'
2
2
  import assert from 'assert'
3
3
  import axios from 'axios'
4
4
  import EventEmitter from 'events'
@@ -30,8 +30,8 @@ import { gunzipSync } from 'zlib'
30
30
  import { RtcStats, rtcStatKey, updateRtcStats } from './rtcstats'
31
31
  import { FastStats } from './stats'
32
32
  import {
33
- PeerConnectionExternal,
34
- PeerConnectionExternalMethod,
33
+ /* PeerConnectionExternal,
34
+ PeerConnectionExternalMethod, */
35
35
  checkChromeExecutable,
36
36
  downloadUrl,
37
37
  enabledForSession,
@@ -163,6 +163,7 @@ export interface SessionParams {
163
163
  userAgent: string
164
164
  id: number
165
165
  throttleIndex: number
166
+ useBrowserThrottling: boolean
166
167
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
167
168
  evaluateAfter?: any[]
168
169
  exposedFunctions?: string
@@ -279,6 +280,8 @@ export class Session extends EventEmitter {
279
280
  readonly id: number
280
281
  /** The throttle configuration index assigned to the session. */
281
282
  readonly throttleIndex: number
283
+ /** If true, the network will be throttled using the browser internal throttling mechanism. */
284
+ readonly useBrowserThrottling: boolean
282
285
  /** The test page url. */
283
286
  readonly url: string
284
287
  /** The url query. */
@@ -378,6 +381,7 @@ export class Session extends EventEmitter {
378
381
  userAgent,
379
382
  id,
380
383
  throttleIndex,
384
+ useBrowserThrottling,
381
385
  evaluateAfter,
382
386
  exposedFunctions,
383
387
  scriptParams,
@@ -475,6 +479,7 @@ export class Session extends EventEmitter {
475
479
  this.emulateCpuThrottling = emulateCpuThrottling
476
480
 
477
481
  this.throttleIndex = throttleIndex
482
+ this.useBrowserThrottling = useBrowserThrottling
478
483
  this.evaluateAfter = evaluateAfter || []
479
484
  this.exposedFunctions = exposedFunctions || {}
480
485
  if (scriptParams) {
@@ -892,6 +897,9 @@ webrtcperf.config.AUDIO_URL = "http${this.serverUseHttps ? 's' : ''}://localhost
892
897
 
893
898
  const page = await this.getNewPage(tabIndex)
894
899
 
900
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
901
+ const pageCDPSession = (page as any)._client() as CDPSession
902
+
895
903
  await page.setBypassCSP(true)
896
904
 
897
905
  if (this.userAgent) {
@@ -932,8 +940,7 @@ Object.defineProperty(window.screen.orientation, 'type', { value: 'landscape-pri
932
940
  // Clear cookies.
933
941
  if (this.clearCookies) {
934
942
  try {
935
- const client = await page.target().createCDPSession()
936
- await client.send('Network.clearBrowserCookies')
943
+ await pageCDPSession.send('Network.clearBrowserCookies')
937
944
  } catch (err) {
938
945
  log.error(`clearCookies error: ${(err as Error).stack}`)
939
946
  }
@@ -977,8 +984,6 @@ Object.defineProperty(window.screen.orientation, 'type', { value: 'landscape-pri
977
984
  // Enable request interception.
978
985
  let setRequestInterceptionState = true
979
986
 
980
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
981
- const pageCDPSession = (page as any)._client() as CDPSession
982
987
  await pageCDPSession.send('Network.setBypassServiceWorker', {
983
988
  bypass: true,
984
989
  })
@@ -1181,7 +1186,7 @@ Object.defineProperty(window.screen.orientation, 'type', { value: 'landscape-pri
1181
1186
  }
1182
1187
 
1183
1188
  // PeerConnectionExternal
1184
- await page.exposeFunction(
1189
+ /* await page.exposeFunction(
1185
1190
  'createPeerConnectionExternal',
1186
1191
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
1187
1192
  async (options: any) => {
@@ -1199,7 +1204,7 @@ Object.defineProperty(window.screen.orientation, 'type', { value: 'landscape-pri
1199
1204
  return pc[name](arg)
1200
1205
  }
1201
1206
  },
1202
- )
1207
+ )*/
1203
1208
 
1204
1209
  // Simulate keypress
1205
1210
  await page.exposeFunction('keypressText', async (selector: string, text: string, delay = 20) => {
@@ -1362,77 +1367,32 @@ Object.defineProperty(window.screen.orientation, 'type', { value: 'landscape-pri
1362
1367
  }
1363
1368
  })
1364
1369
 
1365
- // HTTP stats.
1366
- const resourcesStats = {
1367
- sentBytes: 0,
1368
- recvBytes: 0,
1369
- recvLatency: new FastStats({ store_data: false }),
1370
- wsSentBytes: 0,
1371
- wsRecvBytes: 0,
1372
- wsRecvLatency: new FastStats({ store_data: false }),
1373
- }
1374
- this.httpResourcesStats.set(index, resourcesStats)
1375
-
1376
- const pendingRequests = new Map<string, { url: string; timestamp: number }>()
1377
- pageCDPSession.on('Network.requestWillBeSent', event => {
1378
- if (event.request.url.startsWith('data:')) return
1379
- const { requestId, request, timestamp } = event
1380
- const sentBytes = request.postDataEntries?.reduce((acc, entry) => acc + (entry.bytes?.length || 0), 0)
1381
- //log.log('Network.requestWillBeSent', event.type, request.url, sentBytes)
1382
- if (sentBytes) resourcesStats.sentBytes += sentBytes
1383
- pendingRequests.set(requestId, { url: request.url, timestamp })
1384
- })
1385
-
1386
- pageCDPSession.on('Network.responseReceived', event => {
1387
- const request = pendingRequests.get(event.requestId)
1388
- if (!request) return
1389
- const { response } = event
1390
- if (response.fromDiskCache) {
1391
- pendingRequests.delete(event.requestId)
1392
- return
1393
- }
1394
- resourcesStats.recvBytes += response.encodedDataLength
1370
+ await page.exposeFunction('webrtcperf_reload', () => {
1371
+ return page.reload()
1395
1372
  })
1396
1373
 
1397
- pageCDPSession.on('Network.dataReceived', event => {
1398
- const request = pendingRequests.get(event.requestId)
1399
- if (!request) return
1400
- resourcesStats.recvBytes += event.encodedDataLength
1401
- })
1402
-
1403
- pageCDPSession.on('Network.loadingFinished', event => {
1404
- const request = pendingRequests.get(event.requestId)
1405
- if (!request) return
1406
- pendingRequests.delete(event.requestId)
1407
- const { timestamp } = event
1408
- resourcesStats.recvLatency.push(timestamp - request.timestamp)
1409
- })
1410
-
1411
- pageCDPSession.on('Network.webSocketCreated', event => {
1412
- pendingRequests.set(event.requestId, { url: event.url, timestamp: Date.now() })
1413
- })
1414
-
1415
- pageCDPSession.on('Network.webSocketHandshakeResponseReceived', event => {
1416
- const request = pendingRequests.get(event.requestId)
1417
- if (!request) return
1418
- pendingRequests.delete(event.requestId)
1419
- resourcesStats.wsRecvLatency.push((Date.now() - request.timestamp) / 1000)
1420
- })
1421
-
1422
- pageCDPSession.on('Network.webSocketFrameSent', event => {
1423
- resourcesStats.wsSentBytes += event.response.payloadData.length
1424
- })
1425
-
1426
- pageCDPSession.on('Network.webSocketFrameReceived', event => {
1427
- resourcesStats.wsRecvBytes += event.response.payloadData.length
1428
- })
1374
+ // HTTP stats.
1375
+ this.setupPageNetworkStats(pageCDPSession, index)
1429
1376
 
1430
- // hardware concurrency
1377
+ // Hardware concurrency.
1431
1378
  if (this.hardwareConcurrency) {
1432
1379
  const plugin = NavigatorHardwareConcurrency({ hardwareConcurrency: this.hardwareConcurrency })
1433
1380
  await plugin.onPageCreated(page)
1434
1381
  }
1435
1382
 
1383
+ // Network throttling.
1384
+ if (this.throttleIndex > -1 && (process.platform !== 'linux' || this.useBrowserThrottling)) {
1385
+ log.debug(`Using internal network throttling`)
1386
+ await pageCDPSession.send('Network.emulateNetworkConditions', {
1387
+ offline: false,
1388
+ uploadThroughput: 100000000 / 8,
1389
+ downloadThroughput: 100000000 / 8,
1390
+ latency: 0,
1391
+ packetLoss: 0,
1392
+ packetQueueLength: 0,
1393
+ })
1394
+ }
1395
+
1436
1396
  // Load page script.
1437
1397
  {
1438
1398
  const filePath = resolvePackagePath('node_modules/@vpalmisano/webrtcperf-js/dist/webrtcperf.js')
@@ -1492,6 +1452,13 @@ Object.defineProperty(window.screen.orientation, 'type', { value: 'landscape-pri
1492
1452
  // add to pages map
1493
1453
  this.pages.set(index, page)
1494
1454
 
1455
+ if (this.throttleIndex > -1 && (process.platform !== 'linux' || this.useBrowserThrottling)) {
1456
+ await this.applyNetworkThrottling(pageCDPSession)
1457
+ throttleNotifier.on('change', async () => {
1458
+ await this.applyNetworkThrottling(pageCDPSession)
1459
+ })
1460
+ }
1461
+
1495
1462
  log.debug(`Page ${index + 1} "${url}" loaded in ${(Date.now() - pageLoadTime) / 1000}s`)
1496
1463
 
1497
1464
  for (let i = 0; i < this.evaluateAfter.length; i++) {
@@ -1503,6 +1470,91 @@ Object.defineProperty(window.screen.orientation, 'type', { value: 'landscape-pri
1503
1470
  }
1504
1471
  }
1505
1472
 
1473
+ private setupPageNetworkStats(pageCDPSession: CDPSession, index: number) {
1474
+ const resourcesStats = {
1475
+ sentBytes: 0,
1476
+ recvBytes: 0,
1477
+ recvLatency: new FastStats({ store_data: false }),
1478
+ wsSentBytes: 0,
1479
+ wsRecvBytes: 0,
1480
+ wsRecvLatency: new FastStats({ store_data: false }),
1481
+ }
1482
+ this.httpResourcesStats.set(index, resourcesStats)
1483
+
1484
+ const pendingRequests = new Map<string, { url: string; timestamp: number }>()
1485
+ pageCDPSession.on('Network.requestWillBeSent', event => {
1486
+ if (event.request.url.startsWith('data:')) return
1487
+ const { requestId, request, timestamp } = event
1488
+ const sentBytes = request.postDataEntries?.reduce((acc, entry) => acc + (entry.bytes?.length || 0), 0)
1489
+ //log.log('Network.requestWillBeSent', event.type, request.url, sentBytes)
1490
+ if (sentBytes) resourcesStats.sentBytes += sentBytes
1491
+ pendingRequests.set(requestId, { url: request.url, timestamp })
1492
+ })
1493
+
1494
+ pageCDPSession.on('Network.responseReceived', event => {
1495
+ const request = pendingRequests.get(event.requestId)
1496
+ if (!request) return
1497
+ const { response } = event
1498
+ if (response.fromDiskCache) {
1499
+ pendingRequests.delete(event.requestId)
1500
+ return
1501
+ }
1502
+ resourcesStats.recvBytes += response.encodedDataLength
1503
+ })
1504
+
1505
+ pageCDPSession.on('Network.dataReceived', event => {
1506
+ const request = pendingRequests.get(event.requestId)
1507
+ if (!request) return
1508
+ resourcesStats.recvBytes += event.encodedDataLength
1509
+ })
1510
+
1511
+ pageCDPSession.on('Network.loadingFinished', event => {
1512
+ const request = pendingRequests.get(event.requestId)
1513
+ if (!request) return
1514
+ pendingRequests.delete(event.requestId)
1515
+ const { timestamp } = event
1516
+ resourcesStats.recvLatency.push(timestamp - request.timestamp)
1517
+ })
1518
+
1519
+ pageCDPSession.on('Network.webSocketCreated', event => {
1520
+ pendingRequests.set(event.requestId, { url: event.url, timestamp: Date.now() })
1521
+ })
1522
+
1523
+ pageCDPSession.on('Network.webSocketHandshakeResponseReceived', event => {
1524
+ const request = pendingRequests.get(event.requestId)
1525
+ if (!request) return
1526
+ pendingRequests.delete(event.requestId)
1527
+ resourcesStats.wsRecvLatency.push((Date.now() - request.timestamp) / 1000)
1528
+ })
1529
+
1530
+ pageCDPSession.on('Network.webSocketFrameSent', event => {
1531
+ resourcesStats.wsSentBytes += event.response.payloadData.length
1532
+ })
1533
+
1534
+ pageCDPSession.on('Network.webSocketFrameReceived', event => {
1535
+ resourcesStats.wsRecvBytes += event.response.payloadData.length
1536
+ })
1537
+ }
1538
+
1539
+ private async applyNetworkThrottling(pageCDPSession: CDPSession) {
1540
+ const throttleUpValues = getSessionThrottleValues(this.throttleIndex, 'up')
1541
+ const throttleDownValues = getSessionThrottleValues(this.throttleIndex, 'down')
1542
+ const params = {
1543
+ offline: false,
1544
+ uploadThroughput: throttleUpValues.rate || -1,
1545
+ downloadThroughput: throttleDownValues.rate || -1,
1546
+ latency: Math.max(throttleUpValues.delay || 0, throttleDownValues.delay || 0),
1547
+ packetLoss: Math.max(throttleUpValues.loss || 0, throttleDownValues.loss || 0),
1548
+ packetQueueLength: Math.max(throttleUpValues.queue || 0, throttleDownValues.queue || 0),
1549
+ }
1550
+ log.debug(`Apply internal network throttling: ${JSON.stringify(params)}`)
1551
+ await pageCDPSession.send('Network.emulateNetworkConditions', {
1552
+ ...params,
1553
+ uploadThroughput: params.uploadThroughput !== -1 ? params.uploadThroughput / 8 : -1,
1554
+ downloadThroughput: params.downloadThroughput !== -1 ? params.downloadThroughput / 8 : -1,
1555
+ })
1556
+ }
1557
+
1506
1558
  private async getNewPage(tabIndex: number): Promise<Page> {
1507
1559
  log.debug(`getNewPage ${tabIndex}`)
1508
1560
  assert(this.context, 'NoBrowserContextCreated')