commit 52bb816282bb0cbc0122dcfd44bc6278d3b17a03 Author: Ivan Li Date: Thu Aug 4 09:56:05 2022 +0800 feat: 多线程压测。 diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..ebe51d3 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = false +insert_final_newline = false \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c6bba59 --- /dev/null +++ b/.gitignore @@ -0,0 +1,130 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..bf2e764 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +shamefully-hoist=true diff --git a/client.js b/client.js new file mode 100644 index 0000000..524dbc0 --- /dev/null +++ b/client.js @@ -0,0 +1,44 @@ +import * as Colyseus from "colyseus.js"; +import { logError, writeLine } from "./logger.js"; +import { markReceive } from "./received-packages.js"; + +export class Client { + client; + room; + index; + packageIndex = 0; + + constructor(index) { + this.index = index; + } + + async joinRoom() { + this.client = new Colyseus.Client('wss://api-meta.sequenxe.com/socket'); + + this.room = await this.client.joinOrCreate("my_room"); + this.room.onStateChange((state) => { + if (this.index !== 0) { + return; + } + markReceive(); + writeLine(state); + }); + this.room.onError((code, message) => { + logError('error:', code, message); + }) + } + + testOnce() { + this.room.send("updatePlayer", { + x: +Math.random().toFixed(1), + y: +Math.random().toFixed(1), + z: +Math.random().toFixed(1), + rotationX: +Math.random().toFixed(1), + rotationY: +Math.random().toFixed(1), + rotationZ: +Math.random().toFixed(1), + animation: Math.random().toFixed(1), + nickname: Math.random().toFixed(1), + characterKey: `${this.index}#${this.packageIndex++}`, + }); + } +} \ No newline at end of file diff --git a/index.js b/index.js new file mode 100644 index 0000000..56dbb30 --- /dev/null +++ b/index.js @@ -0,0 +1,118 @@ +import enquirer from 'enquirer'; +const { NumberPrompt, Select } = enquirer; +import ora from 'ora'; +import { packageCounts, rps } from './received-packages.js'; +import { Worker } from 'worker_threads'; +import { dirname } from 'path'; +import { fileURLToPath } from 'url'; +import { Client } from './client.js'; + +const workerCounts = 4; + +const testGroupWorkers = generateWorkers(); + + + +const {mainClient, numberOfPlayers} = await getConnectedWorkers(); +await test(); + + +function generateWorkers() { + return new Array(workerCounts).fill(undefined).map(() => new Worker( + dirname(fileURLToPath(import.meta.url)) + '/test-group.js', + )); +} + +async function test() { + const frequency = await new Select({ + name: 'frequency', + message: 'frequency', + choices: [ + { name: '10tps', value: 10 }, + { name: '20tps', value: 20 }, + { name: '30tps', value: 30 }, + { name: '60tps', value: 60 }, + ] + }).run(); + + const spinner = ora('Testing...').start(); + + let times = 0; + let softStartup = 1; + setInterval(() => { + testGroupWorkers.forEach(worker => worker.postMessage({ + type: 'testOnce', + limit: softStartup, + })); + mainClient.testOnce(); + spinner.text = `${softStartup} player(s) sent ${++times} times,\trps:\t${rps}, counts: ${packageCounts}`; + }, 1000 / +/\d+/.exec(frequency)[0]); + + const timer = setInterval(() => { + if (++softStartup >= numberOfPlayers) { + clearInterval(timer); + } + }, 100); + +} + +async function getConnectedWorkers() { + const numberOfPlayers = await new NumberPrompt({ + name: 'number', + message: 'number of players', + }).run(); + + if (numberOfPlayers < 1) { + throw new Error('number of players must be greater than 0'); + } + const spinner = ora('Connecting server and join room.').start(); + + + const mainClient = new Client(0); + + let assignedCursor = 1; + const groupSize = Math.ceil((numberOfPlayers - assignedCursor) / workerCounts); + + await Promise.all( + testGroupWorkers.map(worker => new Promise(resolve => { + worker.on('message', message => { + if (message.type === 'workersGenerated') { + resolve(); + } + }); + worker.postMessage({ + type: 'generateWorkers', + start: assignedCursor, + end: Math.min(assignedCursor += groupSize, numberOfPlayers), + }); + })) + ); + + + let connected = 1; + await mainClient.joinRoom(); + spinner.text = `Connected ${connected}/${numberOfPlayers}.`; + + await new Promise(resolve => { + testGroupWorkers.forEach(worker => { + worker.on('message', message => { + if (message.type === 'oneWorkerJoined') { + connected++; + spinner.text = `Connected ${connected}/${numberOfPlayers}.`; + if (connected === numberOfPlayers) { + resolve(); + } + } + }); + worker.on('joinRoomFailed', err => { + throw err; + }) + worker.postMessage({ + type: 'joinRoom', + }); + }); + }) + + spinner.succeed('Connected server and join room.'); + return {mainClient, numberOfPlayers}; +} diff --git a/logger.js b/logger.js new file mode 100644 index 0000000..35a931e --- /dev/null +++ b/logger.js @@ -0,0 +1,19 @@ +import { createWriteStream } from 'fs'; +import { fileURLToPath } from 'url'; +import { dirname } from 'path'; + +const statefileStream = createWriteStream( + `${dirname(fileURLToPath(import.meta.url))}/logs/state.log`, + { flags: 'w' }, + ); +const erroutfileStream = createWriteStream( + `${dirname(fileURLToPath(import.meta.url))}/logs/error.log`, + { flags: 'w' }, + ); + +export const writeLine = (obj) => { + statefileStream.write(JSON.stringify(obj) + '\n'); +} +export const logError = (...args) => { + erroutfileStream.write(JSON.stringify(args) + '\n'); +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..c4efb2f --- /dev/null +++ b/package.json @@ -0,0 +1,22 @@ +{ + "name": "gallery_server_tester", + "version": "1.0.0", + "description": "", + "main": "index.js", + "type": "module", + "scripts": { + "start": "node index.js" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "@tweenjs/tween.js": "^18.6.4", + "colyseus.js": "^0.14.13", + "enquirer": "^2.3.6", + "log-update": "^5.0.1", + "ora": "^6.1.2", + "ramda": "^0.28.0", + "ws": "^8.8.1" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..9d47e82 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,308 @@ +lockfileVersion: 5.4 + +specifiers: + '@tweenjs/tween.js': ^18.6.4 + colyseus.js: ^0.14.13 + enquirer: ^2.3.6 + log-update: ^5.0.1 + ora: ^6.1.2 + ramda: ^0.28.0 + ws: ^8.8.1 + +dependencies: + '@tweenjs/tween.js': 18.6.4 + colyseus.js: 0.14.13 + enquirer: 2.3.6 + log-update: 5.0.1 + ora: 6.1.2 + ramda: 0.28.0 + ws: 8.8.1 + +packages: + + /@colyseus/schema/1.0.36: + resolution: {integrity: sha512-9LHDELuDCcp/EbZUsgdcekOPINvq+5Dn/Jooq+I2jHymU1zqzzwoqNq9+YYkuvI70OIJ1esPurcMTA2+o7brYg==} + hasBin: true + dev: false + + /@tweenjs/tween.js/18.6.4: + resolution: {integrity: sha512-lB9lMjuqjtuJrx7/kOkqQBtllspPIN+96OvTCeJ2j5FEzinoAXTdAMFnDAQT1KVPRlnYfBrqxtqP66vDM40xxQ==} + dev: false + + /ansi-colors/4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + dev: false + + /ansi-escapes/5.0.0: + resolution: {integrity: sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==} + engines: {node: '>=12'} + dependencies: + type-fest: 1.4.0 + dev: false + + /ansi-regex/6.0.1: + resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} + engines: {node: '>=12'} + dev: false + + /ansi-styles/6.1.0: + resolution: {integrity: sha512-VbqNsoz55SYGczauuup0MFUyXNQviSpFTj1RQtFzmQLk18qbVSpTFFGMT293rmDaQuKCT6InmbuEyUne4mTuxQ==} + engines: {node: '>=12'} + dev: false + + /base64-js/1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + dev: false + + /bl/5.0.0: + resolution: {integrity: sha512-8vxFNZ0pflFfi0WXA3WQXlj6CaMEwsmh63I1CNp0q+wWv8sD0ARx1KovSQd0l2GkwrMIOyedq0EF1FxI+RCZLQ==} + dependencies: + buffer: 6.0.3 + inherits: 2.0.4 + readable-stream: 3.6.0 + dev: false + + /buffer/6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + dev: false + + /chalk/5.0.1: + resolution: {integrity: sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + dev: false + + /cli-cursor/4.0.0: + resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + restore-cursor: 4.0.0 + dev: false + + /cli-spinners/2.7.0: + resolution: {integrity: sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==} + engines: {node: '>=6'} + dev: false + + /clone/1.0.4: + resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} + engines: {node: '>=0.8'} + dev: false + + /colyseus.js/0.14.13: + resolution: {integrity: sha512-2z1jgOfozQ02gLG5RtTHpk9VZur2b7U4KI9NNldjOZmfc2DZeKejdcKchBTwiDcSwwJQQ4SSOfVUhOcBMILDqA==} + engines: {node: '>= 12.x'} + dependencies: + '@colyseus/schema': 1.0.36 + httpie: 2.0.0-next.13 + nanoevents: 5.1.13 + notepack.io: 2.3.0 + tslib: 2.4.0 + dev: false + + /defaults/1.0.3: + resolution: {integrity: sha512-s82itHOnYrN0Ib8r+z7laQz3sdE+4FP3d9Q7VLO7U+KRT+CR0GsWuyHxzdAY82I7cXv0G/twrqomTJLOssO5HA==} + dependencies: + clone: 1.0.4 + dev: false + + /eastasianwidth/0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + dev: false + + /emoji-regex/9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + dev: false + + /enquirer/2.3.6: + resolution: {integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==} + engines: {node: '>=8.6'} + dependencies: + ansi-colors: 4.1.3 + dev: false + + /httpie/2.0.0-next.13: + resolution: {integrity: sha512-KbKOnq8wt0hVEfteYCSnEsPgzaWxcVc4qZ4OaDU9mVOYLRo3XChjWs3MiuRgFu5y+4JDo7sDKdKzkAn1ljQYFA==} + engines: {node: '>=10'} + dev: false + + /ieee754/1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + dev: false + + /inherits/2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + dev: false + + /is-fullwidth-code-point/4.0.0: + resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} + engines: {node: '>=12'} + dev: false + + /is-interactive/2.0.0: + resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==} + engines: {node: '>=12'} + dev: false + + /is-unicode-supported/1.2.0: + resolution: {integrity: sha512-wH+U77omcRzevfIG8dDhTS0V9zZyweakfD01FULl97+0EHiJTTZtJqxPSkIIo/SDPv/i07k/C9jAPY+jwLLeUQ==} + engines: {node: '>=12'} + dev: false + + /log-symbols/5.1.0: + resolution: {integrity: sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==} + engines: {node: '>=12'} + dependencies: + chalk: 5.0.1 + is-unicode-supported: 1.2.0 + dev: false + + /log-update/5.0.1: + resolution: {integrity: sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + ansi-escapes: 5.0.0 + cli-cursor: 4.0.0 + slice-ansi: 5.0.0 + strip-ansi: 7.0.1 + wrap-ansi: 8.0.1 + dev: false + + /mimic-fn/2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + dev: false + + /nanoevents/5.1.13: + resolution: {integrity: sha512-JFAeG9fp0QZnRoESHjkbVFbZ9BkOXkkagUVwZVo/pkSX+Fq1VKlY+5og/8X9CYc6C7vje/CV+bwJ5M2X0+IY9Q==} + engines: {node: '>=6.0.0'} + dev: false + + /notepack.io/2.3.0: + resolution: {integrity: sha512-9RiFDxeydHsWOqdthRUck2Kd4UW2NzVd2xxOulZiQ9mvge6ElsHXLpwD3HEJyql6sFEnEn/eMO7HSdS0M5mWkA==} + dev: false + + /onetime/5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + dependencies: + mimic-fn: 2.1.0 + dev: false + + /ora/6.1.2: + resolution: {integrity: sha512-EJQ3NiP5Xo94wJXIzAyOtSb0QEIAUu7m8t6UZ9krbz0vAJqr92JpcK/lEXg91q6B9pEGqrykkd2EQplnifDSBw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + bl: 5.0.0 + chalk: 5.0.1 + cli-cursor: 4.0.0 + cli-spinners: 2.7.0 + is-interactive: 2.0.0 + is-unicode-supported: 1.2.0 + log-symbols: 5.1.0 + strip-ansi: 7.0.1 + wcwidth: 1.0.1 + dev: false + + /ramda/0.28.0: + resolution: {integrity: sha512-9QnLuG/kPVgWvMQ4aODhsBUFKOUmnbUnsSXACv+NCQZcHbeb+v8Lodp8OVxtRULN1/xOyYLLaL6npE6dMq5QTA==} + dev: false + + /readable-stream/3.6.0: + resolution: {integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==} + engines: {node: '>= 6'} + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + dev: false + + /restore-cursor/4.0.0: + resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + dev: false + + /safe-buffer/5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + dev: false + + /signal-exit/3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + dev: false + + /slice-ansi/5.0.0: + resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.1.0 + is-fullwidth-code-point: 4.0.0 + dev: false + + /string-width/5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.0.1 + dev: false + + /string_decoder/1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /strip-ansi/7.0.1: + resolution: {integrity: sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==} + engines: {node: '>=12'} + dependencies: + ansi-regex: 6.0.1 + dev: false + + /tslib/2.4.0: + resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} + dev: false + + /type-fest/1.4.0: + resolution: {integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==} + engines: {node: '>=10'} + dev: false + + /util-deprecate/1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + dev: false + + /wcwidth/1.0.1: + resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} + dependencies: + defaults: 1.0.3 + dev: false + + /wrap-ansi/8.0.1: + resolution: {integrity: sha512-QFF+ufAqhoYHvoHdajT/Po7KoXVBPXS2bgjIam5isfWJPfIOnQZ50JtUiVvCv/sjgacf3yRrt2ZKUZ/V4itN4g==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.1.0 + string-width: 5.1.2 + strip-ansi: 7.0.1 + dev: false + + /ws/8.8.1: + resolution: {integrity: sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: false diff --git a/received-packages.js b/received-packages.js new file mode 100644 index 0000000..d294cf6 --- /dev/null +++ b/received-packages.js @@ -0,0 +1,10 @@ +let lastReceivedAt = new Date(); +export let rps = 0; +export let packageCounts = 0; + +export const markReceive = () => { + const now = new Date(); + rps = (1000 / (now.getTime() - lastReceivedAt.getTime())).toFixed(2); + lastReceivedAt = now; + packageCounts++; +} \ No newline at end of file diff --git a/test-group.js b/test-group.js new file mode 100644 index 0000000..efbbd54 --- /dev/null +++ b/test-group.js @@ -0,0 +1,37 @@ +import { splitEvery } from 'ramda'; +import { parentPort } from 'worker_threads'; +import { Client } from './client.js'; + +const clients = []; + +parentPort.on('message', message => { + switch(message.type) { + case 'testOnce': + clients.forEach(worker => { + if (worker.index < message.limit) { + worker.testOnce(); + } + }); + break; + case 'generateWorkers': + clients.splice( + 0, + clients.length, + ...new Array(message.end - message.start).fill(undefined).map((_, i) => new Client(i + message.start)), + ); + parentPort.postMessage({ type: 'workersGenerated' }); + break; + case 'joinRoom': + (async () => { + for (const group of splitEvery(4)(clients)) { + await Promise.all(group.map(async client => { + await client.joinRoom(); + parentPort.postMessage({ type: 'oneWorkerJoined', index: client.index }); + })); + } + parentPort.postMessage({ type: 'workersJoined' }); + })().catch(err => { + parentPort.postMessage({ type: 'joinRoomFailed', error: err }); + }) + } +}); \ No newline at end of file