mirror of
https://github.com/socketio/socket.io.git
synced 2026-01-11 07:58:13 -05:00
Compare commits
43 Commits
@socket.io
...
engine.io-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c251ae7ba7 | ||
|
|
8a2f5a3da0 | ||
|
|
b04fa64365 | ||
|
|
7085f0e3e4 | ||
|
|
4f66708210 | ||
|
|
1a95db2145 | ||
|
|
282ae922a4 | ||
|
|
93010ca3c4 | ||
|
|
132d05fc0b | ||
|
|
d5095fe98c | ||
|
|
da613810fd | ||
|
|
19c48a44e6 | ||
|
|
9b3c9abeca | ||
|
|
043b55c418 | ||
|
|
32c761f02f | ||
|
|
1f54ee08c6 | ||
|
|
923a12e2de | ||
|
|
13c6d2e89d | ||
|
|
8adcfbfde5 | ||
|
|
7a23dde6ef | ||
|
|
60c757f718 | ||
|
|
04c8dd979c | ||
|
|
2194264820 | ||
|
|
09f573cad8 | ||
|
|
fcbecd4f46 | ||
|
|
fd99f2e15f | ||
|
|
02d59a0e99 | ||
|
|
7160eb7eb0 | ||
|
|
a1ccba3a77 | ||
|
|
e347a3c24e | ||
|
|
b5ccfd4838 | ||
|
|
5d9a2d5544 | ||
|
|
d5b22f5a76 | ||
|
|
582655f679 | ||
|
|
b79d80aa59 | ||
|
|
7fd75e6aac | ||
|
|
b7577556e3 | ||
|
|
6e9bff4fcf | ||
|
|
8b0a40fd4a | ||
|
|
1f09a3e979 | ||
|
|
0af50758f6 | ||
|
|
b9b16132c2 | ||
|
|
be1e4cb24d |
2
.github/workflows/ci-browser.yml
vendored
2
.github/workflows/ci-browser.yml
vendored
@@ -14,7 +14,7 @@ permissions:
|
||||
jobs:
|
||||
test-browser:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
timeout-minutes: 20
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
|
||||
13
.github/workflows/ci.yml
vendored
13
.github/workflows/ci.yml
vendored
@@ -44,13 +44,16 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
# in order to test our compliance with TypeScript v4.2 (older versions are not tested)
|
||||
- name: Install TypeScript 4.2
|
||||
run: npm i typescript@4.2
|
||||
if: ${{ matrix.node-version == '16' }}
|
||||
|
||||
- name: Compile each package
|
||||
run: npm run compile --workspaces --if-present
|
||||
|
||||
- name: Run tests
|
||||
run: npm test --workspaces
|
||||
|
||||
- name: Run tests with uws (engine.io)
|
||||
run: npm run test:uws --workspace=engine.io
|
||||
if: ${{ matrix.node-version == '18' }}
|
||||
|
||||
- name: Run tests with fetch instead of XHR (engine.io-client)
|
||||
run: npm run test:node-fetch --workspace=engine.io-client
|
||||
if: ${{ matrix.node-version == '18' }}
|
||||
|
||||
5
.github/workflows/publish.yml
vendored
5
.github/workflows/publish.yml
vendored
@@ -6,7 +6,7 @@ on:
|
||||
push:
|
||||
tags:
|
||||
# expected format: <package>@<version> (example: socket.io@1.2.3)
|
||||
- '*@*'
|
||||
- '**@*'
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
@@ -28,6 +28,9 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Compile each package
|
||||
run: npm run compile --workspaces --if-present
|
||||
|
||||
- name: Publish package
|
||||
run: npm publish --workspace=${GITHUB_REF_NAME%@*} --provenance --access public
|
||||
env:
|
||||
|
||||
@@ -150,3 +150,18 @@ For a specific workspace:
|
||||
```bash
|
||||
npm test --workspace=socket.io
|
||||
```
|
||||
|
||||
### Generate the changelog
|
||||
|
||||
Install the [`conventional-changelog-cli`](https://www.npmjs.com/package/conventional-changelog-cli) package:
|
||||
|
||||
```bash
|
||||
npm i -g conventional-changelog-cli
|
||||
```
|
||||
|
||||
Then run:
|
||||
|
||||
```bash
|
||||
cd packages/engine.io-client
|
||||
conventional-changelog -p angular --tag-prefix "engine.io-client@" --commit-path .
|
||||
```
|
||||
|
||||
19
examples/cluster-engine-node-cluster/README.md
Normal file
19
examples/cluster-engine-node-cluster/README.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Example with `@socket.io/cluster-engine` and Node.js cluster
|
||||
|
||||
## How to use
|
||||
|
||||
```bash
|
||||
# run the server
|
||||
$ node server.js
|
||||
|
||||
# run the client
|
||||
$ node client.js
|
||||
```
|
||||
|
||||
## Explanation
|
||||
|
||||
The `server.js` script will create one Socket.IO server per core, each listening on the same port (`3000`).
|
||||
|
||||
With the default engine (provided by the `engine.io` package), sticky sessions would be required, so that each HTTP request of the same Engine.IO session reaches the same worker.
|
||||
|
||||
The `NodeClusterEngine` is a custom engine which takes care of the synchronization between the servers by using [the IPC channel](https://nodejs.org/api/cluster.html#workersendmessage-sendhandle-options-callback) and removes the need for sticky sessions when scaling horizontally.
|
||||
26
examples/cluster-engine-node-cluster/client.js
Normal file
26
examples/cluster-engine-node-cluster/client.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import { io } from "socket.io-client";
|
||||
|
||||
const CLIENTS_COUNT = 3;
|
||||
|
||||
for (let i = 0; i < CLIENTS_COUNT; i++) {
|
||||
const socket = io("ws://localhost:3000/", {
|
||||
// transports: ["polling"],
|
||||
// transports: ["websocket"],
|
||||
});
|
||||
|
||||
socket.on("connect", () => {
|
||||
console.log(`connected as ${socket.id}`);
|
||||
});
|
||||
|
||||
socket.on("disconnect", (reason) => {
|
||||
console.log(`disconnected due to ${reason}`);
|
||||
});
|
||||
|
||||
socket.on("hello", (socketId, workerId) => {
|
||||
console.log(`received "hello" from ${socketId} (worker: ${workerId})`);
|
||||
});
|
||||
|
||||
setInterval(() => {
|
||||
socket.emit("hello");
|
||||
}, 2000);
|
||||
}
|
||||
12
examples/cluster-engine-node-cluster/package.json
Normal file
12
examples/cluster-engine-node-cluster/package.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "cluster-engine-node-cluster",
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@socket.io/cluster-adapter": "^0.2.2",
|
||||
"@socket.io/cluster-engine": "^0.1.0",
|
||||
"socket.io": "^4.7.5",
|
||||
"socket.io-client": "^4.7.5"
|
||||
}
|
||||
}
|
||||
63
examples/cluster-engine-node-cluster/server.js
Normal file
63
examples/cluster-engine-node-cluster/server.js
Normal file
@@ -0,0 +1,63 @@
|
||||
import cluster from "node:cluster";
|
||||
import process from "node:process";
|
||||
import { availableParallelism } from "node:os";
|
||||
import {
|
||||
setupPrimary as setupPrimaryEngine,
|
||||
NodeClusterEngine,
|
||||
} from "@socket.io/cluster-engine";
|
||||
import {
|
||||
setupPrimary as setupPrimaryAdapter,
|
||||
createAdapter,
|
||||
} from "@socket.io/cluster-adapter";
|
||||
import { createServer } from "node:http";
|
||||
import { Server } from "socket.io";
|
||||
|
||||
if (cluster.isPrimary) {
|
||||
console.log(`Primary ${process.pid} is running`);
|
||||
|
||||
const numCPUs = availableParallelism();
|
||||
|
||||
// fork workers
|
||||
for (let i = 0; i < numCPUs; i++) {
|
||||
cluster.fork();
|
||||
}
|
||||
|
||||
setupPrimaryEngine();
|
||||
setupPrimaryAdapter();
|
||||
|
||||
// needed for packets containing Buffer objects (you can ignore it if you only send plaintext objects)
|
||||
cluster.setupPrimary({
|
||||
serialization: "advanced",
|
||||
});
|
||||
|
||||
cluster.on("exit", (worker, code, signal) => {
|
||||
console.log(`worker ${worker.process.pid} died`);
|
||||
});
|
||||
} else {
|
||||
const httpServer = createServer((req, res) => {
|
||||
res.writeHead(404).end();
|
||||
});
|
||||
|
||||
const engine = new NodeClusterEngine();
|
||||
|
||||
engine.attach(httpServer, {
|
||||
path: "/socket.io/",
|
||||
});
|
||||
|
||||
const io = new Server({
|
||||
adapter: createAdapter(),
|
||||
});
|
||||
|
||||
io.bind(engine);
|
||||
|
||||
io.on("connection", (socket) => {
|
||||
socket.on("hello", () => {
|
||||
socket.broadcast.emit("hello", socket.id, process.pid);
|
||||
});
|
||||
});
|
||||
|
||||
// workers will share the same port
|
||||
httpServer.listen(3000);
|
||||
|
||||
console.log(`Worker ${process.pid} started`);
|
||||
}
|
||||
22
examples/cluster-engine-redis/README.md
Normal file
22
examples/cluster-engine-redis/README.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Example with `@socket.io/cluster-engine` and Redis
|
||||
|
||||
## How to use
|
||||
|
||||
```bash
|
||||
# start the redis server
|
||||
$ docker compose up -d
|
||||
|
||||
# run the server
|
||||
$ node server.js
|
||||
|
||||
# run the client
|
||||
$ node client.js
|
||||
```
|
||||
|
||||
## Explanation
|
||||
|
||||
The `server.js` script will create 3 Socket.IO servers, each listening on a distinct port (`3001`, `3002` and `3003`), and a proxy server listening on port `3000` which randomly redirects to one of those servers.
|
||||
|
||||
With the default engine (provided by the `engine.io` package), sticky sessions would be required, so that each HTTP request of the same Engine.IO session reaches the same server.
|
||||
|
||||
The `RedisEngine` is a custom engine which takes care of the synchronization between the servers by using [Redis pub/sub](https://redis.io/docs/latest/develop/interact/pubsub/) and removes the need for sticky sessions when scaling horizontally.
|
||||
26
examples/cluster-engine-redis/client.js
Normal file
26
examples/cluster-engine-redis/client.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import { io } from "socket.io-client";
|
||||
|
||||
const CLIENTS_COUNT = 3;
|
||||
|
||||
for (let i = 0; i < CLIENTS_COUNT; i++) {
|
||||
const socket = io("ws://localhost:3000/", {
|
||||
// transports: ["polling"],
|
||||
// transports: ["websocket"],
|
||||
});
|
||||
|
||||
socket.on("connect", () => {
|
||||
console.log(`connected as ${socket.id}`);
|
||||
});
|
||||
|
||||
socket.on("disconnect", (reason) => {
|
||||
console.log(`disconnected due to ${reason}`);
|
||||
});
|
||||
|
||||
socket.on("hello", (socketId, workerId) => {
|
||||
console.log(`received "hello" from ${socketId} (worker: ${workerId})`);
|
||||
});
|
||||
|
||||
setInterval(() => {
|
||||
socket.emit("hello");
|
||||
}, 2000);
|
||||
}
|
||||
5
examples/cluster-engine-redis/compose.yaml
Normal file
5
examples/cluster-engine-redis/compose.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
services:
|
||||
redis:
|
||||
image: redis:7
|
||||
ports:
|
||||
- "6379:6379"
|
||||
14
examples/cluster-engine-redis/package.json
Normal file
14
examples/cluster-engine-redis/package.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "cluster-engine-redis",
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@socket.io/cluster-engine": "^0.1.0",
|
||||
"@socket.io/redis-adapter": "^8.3.0",
|
||||
"http-proxy": "^1.18.1",
|
||||
"redis": "^4.6.15",
|
||||
"socket.io": "^4.7.5",
|
||||
"socket.io-client": "^4.7.5"
|
||||
}
|
||||
}
|
||||
65
examples/cluster-engine-redis/server.js
Normal file
65
examples/cluster-engine-redis/server.js
Normal file
@@ -0,0 +1,65 @@
|
||||
import { RedisEngine } from "@socket.io/cluster-engine";
|
||||
import { createServer } from "node:http";
|
||||
import { createClient } from "redis";
|
||||
import { Server } from "socket.io";
|
||||
import { createAdapter } from "@socket.io/redis-adapter";
|
||||
import proxyModule from "http-proxy";
|
||||
|
||||
const { createProxyServer } = proxyModule;
|
||||
|
||||
async function initServer(port) {
|
||||
const httpServer = createServer((req, res) => {
|
||||
res.writeHead(404).end();
|
||||
});
|
||||
|
||||
const pubClient = createClient();
|
||||
const subClient = pubClient.duplicate();
|
||||
|
||||
await Promise.all([pubClient.connect(), subClient.connect()]);
|
||||
|
||||
const engine = new RedisEngine(pubClient, subClient);
|
||||
|
||||
engine.attach(httpServer, {
|
||||
path: "/socket.io/",
|
||||
});
|
||||
|
||||
const io = new Server({
|
||||
adapter: createAdapter(pubClient, subClient),
|
||||
});
|
||||
|
||||
io.bind(engine);
|
||||
|
||||
io.on("connection", (socket) => {
|
||||
socket.on("hello", () => {
|
||||
socket.broadcast.emit("hello", socket.id, port);
|
||||
});
|
||||
});
|
||||
|
||||
httpServer.listen(port);
|
||||
}
|
||||
|
||||
function initProxy() {
|
||||
const proxy = createProxyServer();
|
||||
|
||||
function randomTarget() {
|
||||
return [
|
||||
"http://localhost:3001",
|
||||
"http://localhost:3002",
|
||||
"http://localhost:3003",
|
||||
][Math.floor(Math.random() * 3)];
|
||||
}
|
||||
|
||||
const httpServer = createServer((req, res) => {
|
||||
proxy.web(req, res, { target: randomTarget() });
|
||||
});
|
||||
|
||||
httpServer.on("upgrade", function (req, socket, head) {
|
||||
proxy.ws(req, socket, head, { target: randomTarget() });
|
||||
});
|
||||
|
||||
httpServer.listen(3000);
|
||||
}
|
||||
|
||||
await Promise.all([initServer(3001), initServer(3002), initServer(3003)]);
|
||||
|
||||
initProxy();
|
||||
25
examples/nestjs-example/.eslintrc.js
Normal file
25
examples/nestjs-example/.eslintrc.js
Normal file
@@ -0,0 +1,25 @@
|
||||
module.exports = {
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
project: 'tsconfig.json',
|
||||
tsconfigRootDir: __dirname,
|
||||
sourceType: 'module',
|
||||
},
|
||||
plugins: ['@typescript-eslint/eslint-plugin'],
|
||||
extends: [
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:prettier/recommended',
|
||||
],
|
||||
root: true,
|
||||
env: {
|
||||
node: true,
|
||||
jest: true,
|
||||
},
|
||||
ignorePatterns: ['.eslintrc.js'],
|
||||
rules: {
|
||||
'@typescript-eslint/interface-name-prefix': 'off',
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
},
|
||||
};
|
||||
56
examples/nestjs-example/.gitignore
vendored
Normal file
56
examples/nestjs-example/.gitignore
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
# compiled output
|
||||
/dist
|
||||
/node_modules
|
||||
/build
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
pnpm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
|
||||
# Tests
|
||||
/coverage
|
||||
/.nyc_output
|
||||
|
||||
# IDEs and editors
|
||||
/.idea
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# IDE - VSCode
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
|
||||
# dotenv environment variable files
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# temp directory
|
||||
.temp
|
||||
.tmp
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
4
examples/nestjs-example/.prettierrc
Normal file
4
examples/nestjs-example/.prettierrc
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all"
|
||||
}
|
||||
73
examples/nestjs-example/README.md
Normal file
73
examples/nestjs-example/README.md
Normal file
@@ -0,0 +1,73 @@
|
||||
<p align="center">
|
||||
<a href="http://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo-small.svg" width="200" alt="Nest Logo" /></a>
|
||||
</p>
|
||||
|
||||
[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
|
||||
[circleci-url]: https://circleci.com/gh/nestjs/nest
|
||||
|
||||
<p align="center">A progressive <a href="http://nodejs.org" target="_blank">Node.js</a> framework for building efficient and scalable server-side applications.</p>
|
||||
<p align="center">
|
||||
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/v/@nestjs/core.svg" alt="NPM Version" /></a>
|
||||
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/l/@nestjs/core.svg" alt="Package License" /></a>
|
||||
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/dm/@nestjs/common.svg" alt="NPM Downloads" /></a>
|
||||
<a href="https://circleci.com/gh/nestjs/nest" target="_blank"><img src="https://img.shields.io/circleci/build/github/nestjs/nest/master" alt="CircleCI" /></a>
|
||||
<a href="https://coveralls.io/github/nestjs/nest?branch=master" target="_blank"><img src="https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9" alt="Coverage" /></a>
|
||||
<a href="https://discord.gg/G7Qnnhy" target="_blank"><img src="https://img.shields.io/badge/discord-online-brightgreen.svg" alt="Discord"/></a>
|
||||
<a href="https://opencollective.com/nest#backer" target="_blank"><img src="https://opencollective.com/nest/backers/badge.svg" alt="Backers on Open Collective" /></a>
|
||||
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://opencollective.com/nest/sponsors/badge.svg" alt="Sponsors on Open Collective" /></a>
|
||||
<a href="https://paypal.me/kamilmysliwiec" target="_blank"><img src="https://img.shields.io/badge/Donate-PayPal-ff3f59.svg"/></a>
|
||||
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg" alt="Support us"></a>
|
||||
<a href="https://twitter.com/nestframework" target="_blank"><img src="https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow"></a>
|
||||
</p>
|
||||
<!--[](https://opencollective.com/nest#backer)
|
||||
[](https://opencollective.com/nest#sponsor)-->
|
||||
|
||||
## Description
|
||||
|
||||
[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
$ npm install
|
||||
```
|
||||
|
||||
## Running the app
|
||||
|
||||
```bash
|
||||
# development
|
||||
$ npm run start
|
||||
|
||||
# watch mode
|
||||
$ npm run start:dev
|
||||
|
||||
# production mode
|
||||
$ npm run start:prod
|
||||
```
|
||||
|
||||
## Test
|
||||
|
||||
```bash
|
||||
# unit tests
|
||||
$ npm run test
|
||||
|
||||
# e2e tests
|
||||
$ npm run test:e2e
|
||||
|
||||
# test coverage
|
||||
$ npm run test:cov
|
||||
```
|
||||
|
||||
## Support
|
||||
|
||||
Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
|
||||
|
||||
## Stay in touch
|
||||
|
||||
- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)
|
||||
- Website - [https://nestjs.com](https://nestjs.com/)
|
||||
- Twitter - [@nestframework](https://twitter.com/nestframework)
|
||||
|
||||
## License
|
||||
|
||||
Nest is [MIT licensed](LICENSE).
|
||||
8
examples/nestjs-example/nest-cli.json
Normal file
8
examples/nestjs-example/nest-cli.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/nest-cli",
|
||||
"collection": "@nestjs/schematics",
|
||||
"sourceRoot": "src",
|
||||
"compilerOptions": {
|
||||
"deleteOutDir": true
|
||||
}
|
||||
}
|
||||
72
examples/nestjs-example/package.json
Normal file
72
examples/nestjs-example/package.json
Normal file
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"name": "nestjs-example",
|
||||
"version": "0.0.1",
|
||||
"description": "",
|
||||
"author": "",
|
||||
"private": true,
|
||||
"license": "UNLICENSED",
|
||||
"scripts": {
|
||||
"build": "nest build",
|
||||
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
||||
"start": "nest start",
|
||||
"start:dev": "nest start --watch",
|
||||
"start:debug": "nest start --debug --watch",
|
||||
"start:prod": "node dist/main",
|
||||
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch",
|
||||
"test:cov": "jest --coverage",
|
||||
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
|
||||
"test:e2e": "jest --config ./test/jest-e2e.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "^10.0.0",
|
||||
"@nestjs/core": "^10.0.0",
|
||||
"@nestjs/platform-express": "^10.0.0",
|
||||
"@nestjs/platform-socket.io": "^10.3.10",
|
||||
"@nestjs/websockets": "^10.3.10",
|
||||
"hbs": "^4.2.0",
|
||||
"reflect-metadata": "^0.2.0",
|
||||
"rxjs": "^7.8.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "^10.0.0",
|
||||
"@nestjs/schematics": "^10.0.0",
|
||||
"@nestjs/testing": "^10.0.0",
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/jest": "^29.5.2",
|
||||
"@types/node": "^20.3.1",
|
||||
"@types/supertest": "^6.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^7.0.0",
|
||||
"@typescript-eslint/parser": "^7.0.0",
|
||||
"eslint": "^8.42.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-plugin-prettier": "^5.0.0",
|
||||
"jest": "^29.5.0",
|
||||
"prettier": "^3.0.0",
|
||||
"source-map-support": "^0.5.21",
|
||||
"supertest": "^7.0.0",
|
||||
"ts-jest": "^29.1.0",
|
||||
"ts-loader": "^9.4.3",
|
||||
"ts-node": "^10.9.1",
|
||||
"tsconfig-paths": "^4.2.0",
|
||||
"typescript": "^5.1.3"
|
||||
},
|
||||
"jest": {
|
||||
"moduleFileExtensions": [
|
||||
"js",
|
||||
"json",
|
||||
"ts"
|
||||
],
|
||||
"rootDir": "src",
|
||||
"testRegex": ".*\\.spec\\.ts$",
|
||||
"transform": {
|
||||
"^.+\\.(t|j)s$": "ts-jest"
|
||||
},
|
||||
"collectCoverageFrom": [
|
||||
"**/*.(t|j)s"
|
||||
],
|
||||
"coverageDirectory": "../coverage",
|
||||
"testEnvironment": "node"
|
||||
}
|
||||
}
|
||||
22
examples/nestjs-example/src/app.controller.spec.ts
Normal file
22
examples/nestjs-example/src/app.controller.spec.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { AppController } from './app.controller';
|
||||
import { AppService } from './app.service';
|
||||
|
||||
describe('AppController', () => {
|
||||
let appController: AppController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const app: TestingModule = await Test.createTestingModule({
|
||||
controllers: [AppController],
|
||||
providers: [AppService],
|
||||
}).compile();
|
||||
|
||||
appController = app.get<AppController>(AppController);
|
||||
});
|
||||
|
||||
describe('root', () => {
|
||||
it('should return "Hello World!"', () => {
|
||||
expect(appController.getHello()).toBe('Hello World!');
|
||||
});
|
||||
});
|
||||
});
|
||||
13
examples/nestjs-example/src/app.controller.ts
Normal file
13
examples/nestjs-example/src/app.controller.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { Controller, Get, Render } from '@nestjs/common';
|
||||
import { AppService } from './app.service';
|
||||
|
||||
@Controller()
|
||||
export class AppController {
|
||||
constructor(private readonly appService: AppService) {}
|
||||
|
||||
@Get()
|
||||
@Render('index')
|
||||
root() {
|
||||
return { message: 'Hello world2!' };
|
||||
}
|
||||
}
|
||||
11
examples/nestjs-example/src/app.module.ts
Normal file
11
examples/nestjs-example/src/app.module.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { AppController } from './app.controller';
|
||||
import { AppService } from './app.service';
|
||||
import { EventsModule } from './events/events.module';
|
||||
|
||||
@Module({
|
||||
imports: [EventsModule],
|
||||
controllers: [AppController],
|
||||
providers: [AppService],
|
||||
})
|
||||
export class AppModule {}
|
||||
8
examples/nestjs-example/src/app.service.ts
Normal file
8
examples/nestjs-example/src/app.service.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class AppService {
|
||||
getHello(): string {
|
||||
return 'Hello World!';
|
||||
}
|
||||
}
|
||||
18
examples/nestjs-example/src/events/events.gateway.ts
Normal file
18
examples/nestjs-example/src/events/events.gateway.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import {
|
||||
MessageBody,
|
||||
SubscribeMessage,
|
||||
WebSocketGateway,
|
||||
WebSocketServer,
|
||||
} from '@nestjs/websockets';
|
||||
import { Server } from 'socket.io';
|
||||
|
||||
@WebSocketGateway({})
|
||||
export class EventsGateway {
|
||||
@WebSocketServer()
|
||||
io: Server;
|
||||
|
||||
@SubscribeMessage('hello')
|
||||
handleEvent(@MessageBody() data: string): string {
|
||||
return data.split('').reverse().join('');
|
||||
}
|
||||
}
|
||||
7
examples/nestjs-example/src/events/events.module.ts
Normal file
7
examples/nestjs-example/src/events/events.module.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { EventsGateway } from './events.gateway';
|
||||
|
||||
@Module({
|
||||
providers: [EventsGateway],
|
||||
})
|
||||
export class EventsModule {}
|
||||
15
examples/nestjs-example/src/main.ts
Normal file
15
examples/nestjs-example/src/main.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { AppModule } from './app.module';
|
||||
import { NestExpressApplication } from '@nestjs/platform-express';
|
||||
import { join } from 'node:path';
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create<NestExpressApplication>(AppModule);
|
||||
|
||||
app.setBaseViewsDir(join(__dirname, '..', 'views'));
|
||||
app.setViewEngine('hbs');
|
||||
|
||||
await app.listen(3000);
|
||||
}
|
||||
|
||||
bootstrap();
|
||||
24
examples/nestjs-example/test/app.e2e-spec.ts
Normal file
24
examples/nestjs-example/test/app.e2e-spec.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import * as request from 'supertest';
|
||||
import { AppModule } from './../src/app.module';
|
||||
|
||||
describe('AppController (e2e)', () => {
|
||||
let app: INestApplication;
|
||||
|
||||
beforeEach(async () => {
|
||||
const moduleFixture: TestingModule = await Test.createTestingModule({
|
||||
imports: [AppModule],
|
||||
}).compile();
|
||||
|
||||
app = moduleFixture.createNestApplication();
|
||||
await app.init();
|
||||
});
|
||||
|
||||
it('/ (GET)', () => {
|
||||
return request(app.getHttpServer())
|
||||
.get('/')
|
||||
.expect(200)
|
||||
.expect('Hello World!');
|
||||
});
|
||||
});
|
||||
9
examples/nestjs-example/test/jest-e2e.json
Normal file
9
examples/nestjs-example/test/jest-e2e.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"moduleFileExtensions": ["js", "json", "ts"],
|
||||
"rootDir": ".",
|
||||
"testEnvironment": "node",
|
||||
"testRegex": ".e2e-spec.ts$",
|
||||
"transform": {
|
||||
"^.+\\.(t|j)s$": "ts-jest"
|
||||
}
|
||||
}
|
||||
4
examples/nestjs-example/tsconfig.build.json
Normal file
4
examples/nestjs-example/tsconfig.build.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
|
||||
}
|
||||
21
examples/nestjs-example/tsconfig.json
Normal file
21
examples/nestjs-example/tsconfig.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"declaration": true,
|
||||
"removeComments": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"target": "ES2021",
|
||||
"sourceMap": true,
|
||||
"outDir": "./dist",
|
||||
"baseUrl": "./",
|
||||
"incremental": true,
|
||||
"skipLibCheck": true,
|
||||
"strictNullChecks": false,
|
||||
"noImplicitAny": false,
|
||||
"strictBindCallApply": false,
|
||||
"forceConsistentCasingInFileNames": false,
|
||||
"noFallthroughCasesInSwitch": false
|
||||
}
|
||||
}
|
||||
47
examples/nestjs-example/views/index.hbs
Normal file
47
examples/nestjs-example/views/index.hbs
Normal file
@@ -0,0 +1,47 @@
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>App</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Status: <span id="status"></span></p>
|
||||
<p>Transport: <span id="transport"></span></p>
|
||||
<script src="/socket.io/socket.io.js"></script>
|
||||
<script>
|
||||
const statusSpan = document.getElementById("status");
|
||||
const transportSpan = document.getElementById("transport");
|
||||
const socket = io({
|
||||
// transports: ["polling"],
|
||||
// transports: ["websocket"],
|
||||
});
|
||||
|
||||
statusSpan.innerText = "Disconnected";
|
||||
transportSpan.innerText = "N/A";
|
||||
|
||||
socket.on("connect", () => {
|
||||
statusSpan.innerText = "Connected";
|
||||
transportSpan.innerText = socket.io.engine.transport.name;
|
||||
socket.io.engine.on("upgrade", (transport) => {
|
||||
transportSpan.innerText = transport.name;
|
||||
});
|
||||
console.log(`connect ${socket.id}`);
|
||||
|
||||
socket.emit("hello", "world", (val) => {
|
||||
console.log(`got ${val}`);
|
||||
});
|
||||
});
|
||||
|
||||
socket.on("connect_error", (err) => {
|
||||
console.log(`connect_error due to ${err.message}`);
|
||||
});
|
||||
|
||||
socket.on("disconnect", (reason) => {
|
||||
statusSpan.innerText = "Disconnected";
|
||||
transportSpan.innerText = "N/A";
|
||||
console.log(`disconnect due to ${reason}`);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
25
examples/postgres-adapter-example/README.md
Normal file
25
examples/postgres-adapter-example/README.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Example with `@socket.io/postgres-adapter`
|
||||
|
||||
**Table of contents**
|
||||
|
||||
<!-- TOC -->
|
||||
* [How to use](#how-to-use)
|
||||
* [Documentation](#documentation)
|
||||
<!-- TOC -->
|
||||
|
||||
## How to use
|
||||
|
||||
```bash
|
||||
# start the postgres server
|
||||
$ docker compose up -d
|
||||
|
||||
# run the cluster
|
||||
$ node cluster.js
|
||||
|
||||
# run the client
|
||||
$ node client.js
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
The documentation can be found here: https://socket.io/docs/v4/postgres-adapter/
|
||||
31
examples/postgres-adapter-example/client.js
Normal file
31
examples/postgres-adapter-example/client.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import { io } from "socket.io-client";
|
||||
|
||||
const CLIENTS_COUNT = 3;
|
||||
const PORTS = [3000, 3001, 3002];
|
||||
|
||||
for (let i = 0; i < CLIENTS_COUNT; i++) {
|
||||
const socket = io(`ws://localhost:${PORTS[i % 3]}`, {
|
||||
// transports: ["polling"],
|
||||
// transports: ["websocket"],
|
||||
});
|
||||
|
||||
socket.on("connect", () => {
|
||||
console.log(`connected as ${socket.id}`);
|
||||
});
|
||||
|
||||
socket.on("connect_error", () => {
|
||||
console.log(`connect_error`);
|
||||
});
|
||||
|
||||
socket.on("disconnect", (reason) => {
|
||||
console.log(`disconnected due to ${reason}`);
|
||||
});
|
||||
|
||||
socket.on("hello", (socketId, pid) => {
|
||||
console.log(`received "hello" from ${socketId} (process: ${pid})`);
|
||||
});
|
||||
|
||||
setInterval(() => {
|
||||
socket.emit("hello");
|
||||
}, 2000);
|
||||
}
|
||||
13
examples/postgres-adapter-example/cluster.js
Normal file
13
examples/postgres-adapter-example/cluster.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import cluster from 'node:cluster';
|
||||
|
||||
const SERVERS_COUNT = 3;
|
||||
|
||||
cluster.setupPrimary({
|
||||
exec: 'server.js',
|
||||
});
|
||||
|
||||
for (let i = 0; i < SERVERS_COUNT; i++) {
|
||||
cluster.fork({
|
||||
PORT: 3000 + i
|
||||
});
|
||||
}
|
||||
7
examples/postgres-adapter-example/compose.yaml
Normal file
7
examples/postgres-adapter-example/compose.yaml
Normal file
@@ -0,0 +1,7 @@
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:14
|
||||
ports:
|
||||
- "5432:5432"
|
||||
environment:
|
||||
POSTGRES_PASSWORD: "changeit"
|
||||
12
examples/postgres-adapter-example/package.json
Normal file
12
examples/postgres-adapter-example/package.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "postgres-adapter-example",
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@socket.io/postgres-adapter": "^0.4.0",
|
||||
"pg": "^8.12.0",
|
||||
"socket.io": "^4.7.5",
|
||||
"socket.io-client": "^4.7.5"
|
||||
}
|
||||
}
|
||||
40
examples/postgres-adapter-example/server.js
Normal file
40
examples/postgres-adapter-example/server.js
Normal file
@@ -0,0 +1,40 @@
|
||||
import { Server } from "socket.io";
|
||||
import { createAdapter } from "@socket.io/postgres-adapter";
|
||||
import pg from "pg";
|
||||
import process from "node:process";
|
||||
|
||||
const PORT = process.env.PORT || 3000;
|
||||
|
||||
const pool = new pg.Pool({
|
||||
user: "postgres",
|
||||
host: "localhost",
|
||||
database: "postgres",
|
||||
password: "changeit",
|
||||
port: 5432,
|
||||
});
|
||||
|
||||
await pool.query(`
|
||||
CREATE TABLE IF NOT EXISTS socket_io_attachments (
|
||||
id bigserial UNIQUE,
|
||||
created_at timestamptz DEFAULT NOW(),
|
||||
payload bytea
|
||||
);
|
||||
`);
|
||||
|
||||
pool.on("error", (err) => {
|
||||
console.error("Postgres error", err);
|
||||
});
|
||||
|
||||
const io = new Server({
|
||||
adapter: createAdapter(pool)
|
||||
});
|
||||
|
||||
io.on("connection", (socket) => {
|
||||
socket.on("hello", () => {
|
||||
// send to anyone except the sender
|
||||
socket.broadcast.emit("hello", socket.id, process.pid);
|
||||
});
|
||||
});
|
||||
|
||||
io.listen(PORT);
|
||||
console.log(`server listening on port ${PORT}`);
|
||||
95
package-lock.json
generated
95
package-lock.json
generated
@@ -4,6 +4,7 @@
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "socket.io",
|
||||
"workspaces": [
|
||||
"packages/socket.io-component-emitter",
|
||||
"packages/engine.io-parser",
|
||||
@@ -51,7 +52,7 @@
|
||||
"mocha": "^10.6.0",
|
||||
"node-forge": "^1.3.1",
|
||||
"nyc": "^17.0.0",
|
||||
"prettier": "^2.8.8",
|
||||
"prettier": "^3.3.2",
|
||||
"redis": "^4.6.15",
|
||||
"rimraf": "^6.0.0",
|
||||
"rollup": "^2.79.1",
|
||||
@@ -66,7 +67,7 @@
|
||||
"ts-node": "^10.9.2",
|
||||
"tsd": "^0.31.1",
|
||||
"typescript": "^5.5.3",
|
||||
"uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.30.0",
|
||||
"uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.48.0",
|
||||
"wdio-geckodriver-service": "^5.0.2"
|
||||
}
|
||||
},
|
||||
@@ -11320,15 +11321,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/prettier": {
|
||||
"version": "2.8.8",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
|
||||
"integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz",
|
||||
"integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"prettier": "bin-prettier.js"
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||
@@ -14206,9 +14207,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/uWebSockets.js": {
|
||||
"version": "20.30.0",
|
||||
"resolved": "git+ssh://git@github.com/uNetworking/uWebSockets.js.git#d39d4181daf5b670d44cbc1b18f8c28c85fd4142",
|
||||
"dev": true
|
||||
"version": "20.48.0",
|
||||
"resolved": "git+ssh://git@github.com/uNetworking/uWebSockets.js.git#51ae1d1fd92dff77cbbdc7c431021f85578da1a6",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/v8-compile-cache-lib": {
|
||||
"version": "3.0.1",
|
||||
@@ -14945,14 +14947,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/xmlhttprequest-ssl": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz",
|
||||
"integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/xtend": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||
@@ -15194,34 +15188,24 @@
|
||||
"debug": "~4.3.1",
|
||||
"engine.io-parser": "~5.2.1",
|
||||
"ws": "~8.17.1",
|
||||
"xmlhttprequest-ssl": "~2.0.0"
|
||||
"xmlhttprequest-ssl": "~2.1.1"
|
||||
}
|
||||
},
|
||||
"packages/engine.io-client/node_modules/xmlhttprequest-ssl": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.1.tgz",
|
||||
"integrity": "sha512-ptjR8YSJIXoA3Mbv5po7RtSYHO6mZr8s7i5VGmEk7QY2pQWyT1o0N+W1gKbOyJPUCGXGnuw0wqe8f0L6Y0ny7g==",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"packages/engine.io-parser": {
|
||||
"version": "5.2.3",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"prettier": "^3.3.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"packages/engine.io-parser/node_modules/prettier": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz",
|
||||
"integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||
}
|
||||
},
|
||||
"packages/engine.io/node_modules/debug": {
|
||||
"version": "4.3.3",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
|
||||
@@ -15246,7 +15230,7 @@
|
||||
"base64id": "~2.0.0",
|
||||
"cors": "~2.8.5",
|
||||
"debug": "~4.3.2",
|
||||
"engine.io": "~6.5.2",
|
||||
"engine.io": "~6.6.0",
|
||||
"socket.io-adapter": "~2.5.2",
|
||||
"socket.io-parser": "~4.2.4"
|
||||
},
|
||||
@@ -15268,7 +15252,7 @@
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.2",
|
||||
"engine.io-client": "~6.5.2",
|
||||
"engine.io-client": "~6.6.0",
|
||||
"socket.io-parser": "~4.2.4"
|
||||
},
|
||||
"engines": {
|
||||
@@ -15291,19 +15275,8 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"packages/socket.io-client/node_modules/engine.io-client": {
|
||||
"version": "6.5.4",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.4.tgz",
|
||||
"integrity": "sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ==",
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.1",
|
||||
"engine.io-parser": "~5.2.1",
|
||||
"ws": "~8.17.1",
|
||||
"xmlhttprequest-ssl": "~2.0.0"
|
||||
}
|
||||
},
|
||||
"packages/socket.io-cluster-engine": {
|
||||
"name": "@socket.io/cluster-engine",
|
||||
"version": "0.1.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -15359,26 +15332,6 @@
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"packages/socket.io/node_modules/engine.io": {
|
||||
"version": "6.5.5",
|
||||
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz",
|
||||
"integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==",
|
||||
"dependencies": {
|
||||
"@types/cookie": "^0.4.1",
|
||||
"@types/cors": "^2.8.12",
|
||||
"@types/node": ">=10.0.0",
|
||||
"accepts": "~1.3.4",
|
||||
"base64id": "2.0.0",
|
||||
"cookie": "~0.4.1",
|
||||
"cors": "~2.8.5",
|
||||
"debug": "~4.3.1",
|
||||
"engine.io-parser": "~5.2.1",
|
||||
"ws": "~8.17.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.2.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"name": "socket.io",
|
||||
"private": true,
|
||||
"workspaces": [
|
||||
"packages/socket.io-component-emitter",
|
||||
@@ -52,7 +53,7 @@
|
||||
"mocha": "^10.6.0",
|
||||
"node-forge": "^1.3.1",
|
||||
"nyc": "^17.0.0",
|
||||
"prettier": "^2.8.8",
|
||||
"prettier": "^3.3.2",
|
||||
"redis": "^4.6.15",
|
||||
"rimraf": "^6.0.0",
|
||||
"rollup": "^2.79.1",
|
||||
@@ -67,7 +68,7 @@
|
||||
"ts-node": "^10.9.2",
|
||||
"tsd": "^0.31.1",
|
||||
"typescript": "^5.5.3",
|
||||
"uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.30.0",
|
||||
"uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.48.0",
|
||||
"wdio-geckodriver-service": "^5.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
| Version | Release date | Bundle size (UMD min+gzip) |
|
||||
|-------------------------------------------------------------------------------------------------------------|----------------|----------------------------|
|
||||
| [6.6.1](#661-2024-09-21) | September 2024 | `8.7 KB` |
|
||||
| [6.6.0](#660-2024-06-21) | June 2024 | `8.6 KB` |
|
||||
| [6.5.4](#654-2024-06-18) (from the [6.5.x](https://github.com/socketio/engine.io-client/tree/6.5.x) branch) | June 2024 | `8.8 KB` |
|
||||
| [3.5.4](#354-2024-06-18) (from the [3.5.x](https://github.com/socketio/engine.io-client/tree/3.5.x) branch) | June 2024 | `-` |
|
||||
@@ -38,6 +39,27 @@
|
||||
|
||||
# Release notes
|
||||
|
||||
## [6.6.1](https://github.com/socketio/socket.io/compare/engine.io-client@6.6.0...engine.io-client@6.6.1) (2024-09-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* move 'offline' event listener at the top ([8a2f5a3](https://github.com/socketio/socket.io/commit/8a2f5a3da0addb386e7a0f4970e1a9696b82797e))
|
||||
* only remove the event listener if it exists ([9b3c9ab](https://github.com/socketio/socket.io/commit/9b3c9abecab028822357beb6e2b502f548e312eb)), closes [/github.com/socketio/socket.io/issues/5088#issuecomment-2217202350](https://github.com//github.com/socketio/socket.io/issues/5088/issues/issuecomment-2217202350)
|
||||
* do not send a packet on an expired connection ([#5134](https://github.com/socketio/socket.io/issues/5134)) ([8adcfbf](https://github.com/socketio/socket.io/commit/8adcfbfde50679095ec2abe376650cf2b6814325))
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* do not reset the heartbeat timer on each packet ([7a23dde](https://github.com/socketio/socket.io/commit/7a23dde6efff3079edeeda951fe0ee25516da833))
|
||||
|
||||
|
||||
### Dependencies
|
||||
|
||||
- [`ws@~8.17.1`](https://github.com/websockets/ws/releases/tag/8.17.1) (no change)
|
||||
|
||||
|
||||
|
||||
## [6.6.0](https://github.com/socketio/engine.io-client/compare/6.5.3...6.6.0) (2024-06-21)
|
||||
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
726
packages/engine.io-client/dist/engine.io.js
vendored
726
packages/engine.io-client/dist/engine.io.js
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -55,7 +55,7 @@ export function parse(setCookieString: string): Cookie {
|
||||
case "Max-Age":
|
||||
const expiration = new Date();
|
||||
expiration.setUTCSeconds(
|
||||
expiration.getUTCSeconds() + parseInt(value, 10)
|
||||
expiration.getUTCSeconds() + parseInt(value, 10),
|
||||
);
|
||||
cookie.expires = expiration;
|
||||
break;
|
||||
|
||||
@@ -10,11 +10,34 @@ import {
|
||||
CookieJar,
|
||||
createCookieJar,
|
||||
defaultBinaryType,
|
||||
nextTick,
|
||||
} from "./globals.node.js";
|
||||
import debugModule from "debug"; // debug()
|
||||
|
||||
const debug = debugModule("engine.io-client:socket"); // debug()
|
||||
|
||||
const withEventListeners =
|
||||
typeof addEventListener === "function" &&
|
||||
typeof removeEventListener === "function";
|
||||
|
||||
const OFFLINE_EVENT_LISTENERS = [];
|
||||
|
||||
if (withEventListeners) {
|
||||
// within a ServiceWorker, any event handler for the 'offline' event must be added on the initial evaluation of the
|
||||
// script, so we create one single event listener here which will forward the event to the socket instances
|
||||
addEventListener(
|
||||
"offline",
|
||||
() => {
|
||||
debug(
|
||||
"closing %d connection(s) because the network was lost",
|
||||
OFFLINE_EVENT_LISTENERS.length,
|
||||
);
|
||||
OFFLINE_EVENT_LISTENERS.forEach((listener) => listener());
|
||||
},
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
export interface SocketOptions {
|
||||
/**
|
||||
* The host that we're connecting to. Set from the URI passed when connecting
|
||||
@@ -85,7 +108,9 @@ export interface SocketOptions {
|
||||
*
|
||||
* @default ['polling','websocket', 'webtransport']
|
||||
*/
|
||||
transports?: string[] | TransportCtor[];
|
||||
transports?:
|
||||
| ("polling" | "websocket" | "webtransport" | string)[]
|
||||
| TransportCtor[];
|
||||
|
||||
/**
|
||||
* Whether all the transports should be tested, instead of just the first one.
|
||||
@@ -318,6 +343,11 @@ export class SocketWithoutUpgrade extends Emitter<
|
||||
private _pingTimeout: number = -1;
|
||||
private _maxPayload?: number = -1;
|
||||
private _pingTimeoutTimer: NodeJS.Timer;
|
||||
/**
|
||||
* The expiration timestamp of the {@link _pingTimeoutTimer} object is tracked, in case the timer is throttled and the
|
||||
* callback is not fired on time. This can happen for example when a laptop is suspended or when a phone is locked.
|
||||
*/
|
||||
private _pingTimeoutTime = Infinity;
|
||||
private clearTimeoutFn: typeof clearTimeout;
|
||||
private readonly _beforeunloadEventListener: () => void;
|
||||
private readonly _offlineEventListener: () => void;
|
||||
@@ -379,8 +409,8 @@ export class SocketWithoutUpgrade extends Emitter<
|
||||
(typeof location !== "undefined" && location.port
|
||||
? location.port
|
||||
: this.secure
|
||||
? "443"
|
||||
: "80");
|
||||
? "443"
|
||||
: "80");
|
||||
|
||||
this.transports = [];
|
||||
this._transportsByName = {};
|
||||
@@ -406,7 +436,7 @@ export class SocketWithoutUpgrade extends Emitter<
|
||||
transportOptions: {},
|
||||
closeOnBeforeunload: false,
|
||||
},
|
||||
opts
|
||||
opts,
|
||||
);
|
||||
|
||||
this.opts.path =
|
||||
@@ -417,7 +447,7 @@ export class SocketWithoutUpgrade extends Emitter<
|
||||
this.opts.query = decode(this.opts.query);
|
||||
}
|
||||
|
||||
if (typeof addEventListener === "function") {
|
||||
if (withEventListeners) {
|
||||
if (this.opts.closeOnBeforeunload) {
|
||||
// Firefox closes the connection when the "beforeunload" event is emitted but not Chrome. This event listener
|
||||
// ensures every browser behaves the same (no "disconnect" event at the Socket.IO level when the page is
|
||||
@@ -432,16 +462,17 @@ export class SocketWithoutUpgrade extends Emitter<
|
||||
addEventListener(
|
||||
"beforeunload",
|
||||
this._beforeunloadEventListener,
|
||||
false
|
||||
false,
|
||||
);
|
||||
}
|
||||
if (this.hostname !== "localhost") {
|
||||
debug("adding listener for the 'offline' event");
|
||||
this._offlineEventListener = () => {
|
||||
this._onClose("transport close", {
|
||||
description: "network connection lost",
|
||||
});
|
||||
};
|
||||
addEventListener("offline", this._offlineEventListener, false);
|
||||
OFFLINE_EVENT_LISTENERS.push(this._offlineEventListener);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -482,7 +513,7 @@ export class SocketWithoutUpgrade extends Emitter<
|
||||
secure: this.secure,
|
||||
port: this.port,
|
||||
},
|
||||
this.opts.transportOptions[name]
|
||||
this.opts.transportOptions[name],
|
||||
);
|
||||
|
||||
debug("options: %j", opts);
|
||||
@@ -572,7 +603,6 @@ export class SocketWithoutUpgrade extends Emitter<
|
||||
|
||||
// Socket is live - any packet counts
|
||||
this.emitReserved("heartbeat");
|
||||
this._resetPingTimeout();
|
||||
|
||||
switch (packet.type) {
|
||||
case "open":
|
||||
@@ -583,6 +613,7 @@ export class SocketWithoutUpgrade extends Emitter<
|
||||
this._sendPacket("pong");
|
||||
this.emitReserved("ping");
|
||||
this.emitReserved("pong");
|
||||
this._resetPingTimeout();
|
||||
break;
|
||||
|
||||
case "error":
|
||||
@@ -628,9 +659,11 @@ export class SocketWithoutUpgrade extends Emitter<
|
||||
*/
|
||||
private _resetPingTimeout() {
|
||||
this.clearTimeoutFn(this._pingTimeoutTimer);
|
||||
const delay = this._pingInterval + this._pingTimeout;
|
||||
this._pingTimeoutTime = Date.now() + delay;
|
||||
this._pingTimeoutTimer = this.setTimeoutFn(() => {
|
||||
this._onClose("ping timeout");
|
||||
}, this._pingInterval + this._pingTimeout);
|
||||
}, delay);
|
||||
if (this.opts.autoUnref) {
|
||||
this._pingTimeoutTimer.unref();
|
||||
}
|
||||
@@ -708,6 +741,31 @@ export class SocketWithoutUpgrade extends Emitter<
|
||||
return this.writeBuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the heartbeat timer has expired but the socket has not yet been notified.
|
||||
*
|
||||
* Note: this method is private for now because it does not really fit the WebSocket API, but if we put it in the
|
||||
* `write()` method then the message would not be buffered by the Socket.IO client.
|
||||
*
|
||||
* @return {boolean}
|
||||
* @private
|
||||
*/
|
||||
/* private */ _hasPingExpired() {
|
||||
if (!this._pingTimeoutTime) return true;
|
||||
|
||||
const hasExpired = Date.now() > this._pingTimeoutTime;
|
||||
if (hasExpired) {
|
||||
debug("throttled timer detected, scheduling connection close");
|
||||
this._pingTimeoutTime = 0;
|
||||
|
||||
nextTick(() => {
|
||||
this._onClose("ping timeout");
|
||||
}, this.setTimeoutFn);
|
||||
}
|
||||
|
||||
return hasExpired;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message.
|
||||
*
|
||||
@@ -747,7 +805,7 @@ export class SocketWithoutUpgrade extends Emitter<
|
||||
type: PacketType,
|
||||
data?: RawData,
|
||||
options?: WriteOptions,
|
||||
fn?: () => void
|
||||
fn?: () => void,
|
||||
) {
|
||||
if ("function" === typeof data) {
|
||||
fn = data;
|
||||
@@ -868,13 +926,21 @@ export class SocketWithoutUpgrade extends Emitter<
|
||||
// ignore further transport communication
|
||||
this.transport.removeAllListeners();
|
||||
|
||||
if (typeof removeEventListener === "function") {
|
||||
removeEventListener(
|
||||
"beforeunload",
|
||||
this._beforeunloadEventListener,
|
||||
false
|
||||
);
|
||||
removeEventListener("offline", this._offlineEventListener, false);
|
||||
if (withEventListeners) {
|
||||
if (this._beforeunloadEventListener) {
|
||||
removeEventListener(
|
||||
"beforeunload",
|
||||
this._beforeunloadEventListener,
|
||||
false,
|
||||
);
|
||||
}
|
||||
if (this._offlineEventListener) {
|
||||
const i = OFFLINE_EVENT_LISTENERS.indexOf(this._offlineEventListener);
|
||||
if (i !== -1) {
|
||||
debug("removing listener for the 'offline' event");
|
||||
OFFLINE_EVENT_LISTENERS.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set ready state
|
||||
|
||||
@@ -14,7 +14,7 @@ export class TransportError extends Error {
|
||||
constructor(
|
||||
reason: string,
|
||||
readonly description: any,
|
||||
readonly context: any
|
||||
readonly context: any,
|
||||
) {
|
||||
super(reason);
|
||||
}
|
||||
@@ -79,7 +79,7 @@ export abstract class Transport extends Emitter<
|
||||
protected onError(reason: string, description: any, context?: any) {
|
||||
super.emitReserved(
|
||||
"error",
|
||||
new TransportError(reason, description, context)
|
||||
new TransportError(reason, description, context),
|
||||
);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -15,12 +15,12 @@ export class XHR extends BaseXHR {
|
||||
Object.assign(
|
||||
opts,
|
||||
{ xd: this.xd, cookieJar: this.socket?._cookieJar },
|
||||
this.opts
|
||||
this.opts,
|
||||
);
|
||||
return new Request(
|
||||
(opts) => new XMLHttpRequest(opts),
|
||||
this.uri(),
|
||||
opts as RequestOptions
|
||||
opts as RequestOptions,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ export class Request extends Emitter<
|
||||
constructor(
|
||||
private readonly createRequest: (opts: RequestOptions) => XMLHttpRequest,
|
||||
uri: string,
|
||||
opts: RequestOptions
|
||||
opts: RequestOptions,
|
||||
) {
|
||||
super();
|
||||
installTimerFunctions(this, opts);
|
||||
@@ -151,7 +151,7 @@ export class Request extends Emitter<
|
||||
"ca",
|
||||
"ciphers",
|
||||
"rejectUnauthorized",
|
||||
"autoUnref"
|
||||
"autoUnref",
|
||||
);
|
||||
opts.xdomain = !!this._opts.xd;
|
||||
|
||||
@@ -197,7 +197,7 @@ export class Request extends Emitter<
|
||||
if (xhr.readyState === 3) {
|
||||
this._opts.cookieJar?.parseCookies(
|
||||
// @ts-ignore
|
||||
xhr.getResponseHeader("set-cookie")
|
||||
xhr.getResponseHeader("set-cookie"),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -354,7 +354,7 @@ function newRequest(opts) {
|
||||
if (!xdomain) {
|
||||
try {
|
||||
return new globalThis[["Active"].concat("Object").join("X")](
|
||||
"Microsoft.XMLHTTP"
|
||||
"Microsoft.XMLHTTP",
|
||||
);
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ export class WS extends BaseWS {
|
||||
createSocket(
|
||||
uri: string,
|
||||
protocols: string | string[] | undefined,
|
||||
opts: Record<string, any>
|
||||
opts: Record<string, any>,
|
||||
) {
|
||||
if (this.socket?._cookieJar) {
|
||||
opts.headers = opts.headers || {};
|
||||
|
||||
@@ -43,7 +43,7 @@ export abstract class BaseWS extends Transport {
|
||||
"origin",
|
||||
"maxPayload",
|
||||
"family",
|
||||
"checkServerIdentity"
|
||||
"checkServerIdentity",
|
||||
);
|
||||
|
||||
if (this.opts.extraHeaders) {
|
||||
@@ -64,7 +64,7 @@ export abstract class BaseWS extends Transport {
|
||||
abstract createSocket(
|
||||
uri: string,
|
||||
protocols: string | string[] | undefined,
|
||||
opts: Record<string, any>
|
||||
opts: Record<string, any>,
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -166,7 +166,7 @@ export class WS extends BaseWS {
|
||||
createSocket(
|
||||
uri: string,
|
||||
protocols: string | string[] | undefined,
|
||||
opts: Record<string, any>
|
||||
opts: Record<string, any>,
|
||||
) {
|
||||
return !isReactNative
|
||||
? protocols
|
||||
|
||||
@@ -30,7 +30,7 @@ export class WT extends Transport {
|
||||
// @ts-ignore
|
||||
this._transport = new WebTransport(
|
||||
this.createUri("https"),
|
||||
this.opts.transportOptions[this.name]
|
||||
this.opts.transportOptions[this.name],
|
||||
);
|
||||
} catch (err) {
|
||||
return this.emitReserved("error", err);
|
||||
@@ -51,7 +51,7 @@ export class WT extends Transport {
|
||||
this._transport.createBidirectionalStream().then((stream) => {
|
||||
const decoderStream = createPacketDecoderStream(
|
||||
Number.MAX_SAFE_INTEGER,
|
||||
this.socket.binaryType
|
||||
this.socket.binaryType,
|
||||
);
|
||||
const reader = stream.readable.pipeThrough(decoderStream).getReader();
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "engine.io-client",
|
||||
"description": "Client for the realtime Engine",
|
||||
"license": "MIT",
|
||||
"version": "6.6.0",
|
||||
"version": "6.6.1",
|
||||
"main": "./build/cjs/index.js",
|
||||
"module": "./build/esm/index.js",
|
||||
"exports": {
|
||||
@@ -56,7 +56,7 @@
|
||||
"debug": "~4.3.1",
|
||||
"engine.io-parser": "~5.2.1",
|
||||
"ws": "~8.17.1",
|
||||
"xmlhttprequest-ssl": "~2.0.0"
|
||||
"xmlhttprequest-ssl": "~2.1.1"
|
||||
},
|
||||
"scripts": {
|
||||
"compile": "rimraf ./build && tsc && tsc -p tsconfig.esm.json && ./postcompile.sh",
|
||||
|
||||
@@ -34,12 +34,12 @@ describe("connection", function () {
|
||||
const socket = new Socket();
|
||||
socket.on("open", () => {
|
||||
socket.send(
|
||||
"\uD800\uDC00-\uDB7F\uDFFF\uDB80\uDC00-\uDBFF\uDFFF\uE000-\uF8FF"
|
||||
"\uD800\uDC00-\uDB7F\uDFFF\uDB80\uDC00-\uDBFF\uDFFF\uE000-\uF8FF",
|
||||
);
|
||||
socket.on("message", (data) => {
|
||||
if ("hi" === data) return;
|
||||
expect(data).to.be(
|
||||
"\uD800\uDC00-\uDB7F\uDFFF\uDB80\uDC00-\uDBFF\uDFFF\uE000-\uF8FF"
|
||||
"\uD800\uDC00-\uDB7F\uDFFF\uDB80\uDC00-\uDBFF\uDFFF\uE000-\uF8FF",
|
||||
);
|
||||
socket.close();
|
||||
done();
|
||||
@@ -59,7 +59,7 @@ describe("connection", function () {
|
||||
setTimeout(() => {
|
||||
expect(noPacket).to.be(true);
|
||||
done();
|
||||
}, 1200);
|
||||
}, 200);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -177,7 +177,7 @@ describe("connection", function () {
|
||||
setTimeout(() => {
|
||||
expect(noPacket).to.be(true);
|
||||
done();
|
||||
}, 1200);
|
||||
}, 200);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -5,4 +5,4 @@ const socket = new Socket("http://localhost:3000", {
|
||||
|
||||
setTimeout(() => {
|
||||
console.log("process should not exit");
|
||||
}, 500);
|
||||
}, 50);
|
||||
|
||||
@@ -10,4 +10,4 @@ socket.on("open", () => {
|
||||
|
||||
setTimeout(() => {
|
||||
console.log("process should exit now");
|
||||
}, 500);
|
||||
}, 50);
|
||||
|
||||
@@ -10,4 +10,4 @@ socket.on("open", () => {
|
||||
|
||||
setTimeout(() => {
|
||||
console.log("process should exit now");
|
||||
}, 500);
|
||||
}, 50);
|
||||
|
||||
@@ -9,4 +9,4 @@ socket.on("open", () => {
|
||||
|
||||
setTimeout(() => {
|
||||
console.log("process should exit now");
|
||||
}, 500);
|
||||
}, 50);
|
||||
|
||||
@@ -34,7 +34,7 @@ describe("node.js", () => {
|
||||
isComplete = true;
|
||||
process.kill();
|
||||
done();
|
||||
}, 1000);
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ describe("Socket", function () {
|
||||
|
||||
socket.on("error", (err) => {
|
||||
expect(err.message).to.eql(
|
||||
useFetch ? "fetch read error" : "xhr poll error"
|
||||
useFetch ? "fetch read error" : "xhr poll error",
|
||||
);
|
||||
done();
|
||||
});
|
||||
@@ -237,7 +237,7 @@ describe("Socket", function () {
|
||||
// err.context is a XMLHttpRequest object
|
||||
expect(err.context.readyState).to.eql(4);
|
||||
expect(err.context.responseText).to.eql(
|
||||
'{"code":1,"message":"Session ID unknown"}'
|
||||
'{"code":1,"message":"Session ID unknown"}',
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -270,4 +270,30 @@ describe("Socket", function () {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("throttled timer", () => {
|
||||
it("checks the state of the timer", (done) => {
|
||||
const socket = new Socket();
|
||||
|
||||
expect(socket._hasPingExpired()).to.be(false);
|
||||
|
||||
socket.on("open", () => {
|
||||
expect(socket._hasPingExpired()).to.be(false);
|
||||
|
||||
// simulate a throttled timer
|
||||
socket._pingTimeoutTime = Date.now() - 1;
|
||||
|
||||
expect(socket._hasPingExpired()).to.be(true);
|
||||
|
||||
// subsequent calls should not trigger more 'close' events
|
||||
expect(socket._hasPingExpired()).to.be(true);
|
||||
expect(socket._hasPingExpired()).to.be(true);
|
||||
});
|
||||
|
||||
socket.on("close", (reason) => {
|
||||
expect(reason).to.eql("ping timeout");
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -21,7 +21,7 @@ exports.mochaHooks = {
|
||||
maxHttpBufferSize: 100,
|
||||
allowRequest: (req, fn) => {
|
||||
const denyRequest = new URL(`http://${req.url}`).searchParams.has(
|
||||
"deny"
|
||||
"deny",
|
||||
);
|
||||
fn(null, !denyRequest);
|
||||
},
|
||||
|
||||
@@ -100,7 +100,7 @@ describe("Transport", () => {
|
||||
timestampRequests: false,
|
||||
});
|
||||
expect(polling.uri()).to.contain(
|
||||
"http://localhost:3000/engine.io?sid=test"
|
||||
"http://localhost:3000/engine.io?sid=test",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -124,7 +124,7 @@ describe("Transport", () => {
|
||||
timestampRequests: true,
|
||||
});
|
||||
expect(polling.uri()).to.match(
|
||||
/http:\/\/localhost\/engine\.io\?(j=[0-9]+&)?(t=[0-9A-Za-z-_]+)/
|
||||
/http:\/\/localhost\/engine\.io\?(j=[0-9]+&)?(t=[0-9A-Za-z-_]+)/,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -180,7 +180,7 @@ describe("Transport", () => {
|
||||
timestampRequests: true,
|
||||
});
|
||||
expect(ws.uri()).to.match(
|
||||
/ws:\/\/localhost\/engine\.io\?woot=[0-9A-Za-z-_]+/
|
||||
/ws:\/\/localhost\/engine\.io\?woot=[0-9A-Za-z-_]+/,
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ async function setup(opts, cb) {
|
||||
[{ shortName: "CN", value: "localhost" }],
|
||||
{
|
||||
days: 14, // the total length of the validity period MUST NOT exceed two weeks (https://w3c.github.io/webtransport/#custom-certificate-requirements)
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const engine = new Server(opts);
|
||||
@@ -73,8 +73,8 @@ function createSocket(port, certificate, opts) {
|
||||
},
|
||||
},
|
||||
},
|
||||
opts
|
||||
)
|
||||
opts,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ describe("WebTransport", () => {
|
||||
httpServer.close();
|
||||
success(engine, h3Server, done);
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -137,7 +137,7 @@ describe("WebTransport", () => {
|
||||
httpServer.close();
|
||||
success(engine, h3Server, done);
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -160,7 +160,7 @@ describe("WebTransport", () => {
|
||||
success(engine, h3Server, done);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const browsers = require('socket.io-browsers');
|
||||
|
||||
const zuulConfig = module.exports = {
|
||||
ui: 'mocha-bdd',
|
||||
|
||||
// test on localhost by default
|
||||
local: true,
|
||||
open: true,
|
||||
|
||||
concurrency: 2, // ngrok only accepts two tunnels by default
|
||||
// if browser does not sends output in 120s since last output:
|
||||
// stop testing, something is wrong
|
||||
browser_output_timeout: 120 * 1000,
|
||||
browser_open_timeout: 60 * 4 * 1000,
|
||||
// we want to be notified something is wrong asap, so no retry
|
||||
browser_retries: 1,
|
||||
|
||||
server: './test/support/server.js',
|
||||
builder: 'zuul-builder-webpack',
|
||||
webpack: require('./support/webpack.config.js')
|
||||
};
|
||||
|
||||
if (process.env.CI === 'true') {
|
||||
zuulConfig.local = false;
|
||||
zuulConfig.tunnel = {
|
||||
type: 'ngrok',
|
||||
bind_tls: true
|
||||
};
|
||||
}
|
||||
|
||||
zuulConfig.browsers = [
|
||||
{
|
||||
name: 'firefox',
|
||||
version: 'latest'
|
||||
}, {
|
||||
name: 'internet explorer',
|
||||
version: '9..11'
|
||||
}, {
|
||||
name: 'safari',
|
||||
version: '14'
|
||||
}, {
|
||||
name: 'iphone',
|
||||
version: '14'
|
||||
}, {
|
||||
name: 'android',
|
||||
version: '5.1..6.0'
|
||||
}, {
|
||||
name: 'ipad',
|
||||
version: '14'
|
||||
}, {
|
||||
name: 'MicrosoftEdge',
|
||||
version: 'latest'
|
||||
}
|
||||
];
|
||||
@@ -10,9 +10,6 @@
|
||||
"require": "./build/cjs/index.js"
|
||||
},
|
||||
"types": "build/esm/index.d.ts",
|
||||
"devDependencies": {
|
||||
"prettier": "^3.3.2"
|
||||
},
|
||||
"scripts": {
|
||||
"compile": "rimraf ./build && tsc && tsc -p tsconfig.esm.json && ./postcompile.sh",
|
||||
"test": "npm run format:check && npm run compile && if test \"$BROWSERS\" = \"1\" ; then npm run test:browser; else npm run test:node; fi",
|
||||
|
||||
@@ -78,7 +78,7 @@ export interface ServerOptions {
|
||||
*/
|
||||
allowRequest?: (
|
||||
req: IncomingMessage,
|
||||
fn: (err: string | null | undefined, success: boolean) => void
|
||||
fn: (err: string | null | undefined, success: boolean) => void,
|
||||
) => void;
|
||||
/**
|
||||
* The low-level transports that are enabled. WebTransport is disabled by default and must be manually enabled:
|
||||
@@ -146,7 +146,7 @@ export interface ServerOptions {
|
||||
type Middleware = (
|
||||
req: IncomingMessage,
|
||||
res: ServerResponse,
|
||||
next: (err?: any) => void
|
||||
next: (err?: any) => void,
|
||||
) => void;
|
||||
|
||||
function parseSessionId(data: string) {
|
||||
@@ -192,7 +192,7 @@ export abstract class BaseServer extends EventEmitter {
|
||||
cors: false,
|
||||
allowEIO3: false,
|
||||
},
|
||||
opts
|
||||
opts,
|
||||
);
|
||||
|
||||
if (opts.cookie) {
|
||||
@@ -204,7 +204,7 @@ export abstract class BaseServer extends EventEmitter {
|
||||
httpOnly: opts.cookie.path !== false,
|
||||
sameSite: "lax",
|
||||
},
|
||||
opts.cookie
|
||||
opts.cookie,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -217,7 +217,7 @@ export abstract class BaseServer extends EventEmitter {
|
||||
{
|
||||
threshold: 1024,
|
||||
},
|
||||
opts.perMessageDeflate
|
||||
opts.perMessageDeflate,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -263,7 +263,7 @@ export abstract class BaseServer extends EventEmitter {
|
||||
protected verify(
|
||||
req: any,
|
||||
upgrade: boolean,
|
||||
fn: (errorCode?: number, errorContext?: any) => void
|
||||
fn: (errorCode?: number, errorContext?: any) => void,
|
||||
) {
|
||||
// transport check
|
||||
const transport = req._query.transport;
|
||||
@@ -361,7 +361,7 @@ export abstract class BaseServer extends EventEmitter {
|
||||
protected _applyMiddlewares(
|
||||
req: IncomingMessage,
|
||||
res: ServerResponse,
|
||||
callback: (err?: any) => void
|
||||
callback: (err?: any) => void,
|
||||
) {
|
||||
if (this.middlewares.length === 0) {
|
||||
debug("no middleware to apply, skipping");
|
||||
@@ -424,7 +424,7 @@ export abstract class BaseServer extends EventEmitter {
|
||||
protected async handshake(
|
||||
transportName: string,
|
||||
req: any,
|
||||
closeConnection: (errorCode?: number, errorContext?: any) => void
|
||||
closeConnection: (errorCode?: number, errorContext?: any) => void,
|
||||
) {
|
||||
const protocol = req._query.EIO === "4" ? 4 : 3; // 3rd revision by default
|
||||
if (protocol === 3 && !this.opts.allowEIO3) {
|
||||
@@ -519,7 +519,7 @@ export abstract class BaseServer extends EventEmitter {
|
||||
public async onWebTransportSession(session: any) {
|
||||
const timeout = setTimeout(() => {
|
||||
debug(
|
||||
"the client failed to establish a bidirectional stream in the given period"
|
||||
"the client failed to establish a bidirectional stream in the given period",
|
||||
);
|
||||
session.close();
|
||||
}, this.opts.upgradeTimeout);
|
||||
@@ -535,7 +535,7 @@ export abstract class BaseServer extends EventEmitter {
|
||||
const stream = result.value;
|
||||
const transformStream = createPacketDecoderStream(
|
||||
this.opts.maxHttpBufferSize,
|
||||
"nodebuffer"
|
||||
"nodebuffer",
|
||||
);
|
||||
const reader = stream.readable.pipeThrough(transformStream).getReader();
|
||||
|
||||
@@ -632,7 +632,10 @@ export abstract class BaseServer extends EventEmitter {
|
||||
* @see https://nodejs.org/api/http.html#class-httpserverresponse
|
||||
*/
|
||||
class WebSocketResponse {
|
||||
constructor(readonly req, readonly socket: Duplex) {
|
||||
constructor(
|
||||
readonly req,
|
||||
readonly socket: Duplex,
|
||||
) {
|
||||
// temporarily store the response headers on the req object (see the "headers" event)
|
||||
req[kResponseHeaders] = {};
|
||||
}
|
||||
@@ -659,6 +662,9 @@ class WebSocketResponse {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An Engine.IO server based on Node.js built-in HTTP server and the `ws` package for WebSocket connections.
|
||||
*/
|
||||
export class Server extends BaseServer {
|
||||
public httpServer?: HttpServer;
|
||||
private ws: any;
|
||||
@@ -776,7 +782,7 @@ export class Server extends BaseServer {
|
||||
public handleUpgrade(
|
||||
req: EngineRequest,
|
||||
socket: Duplex,
|
||||
upgradeHead: Buffer
|
||||
upgradeHead: Buffer,
|
||||
) {
|
||||
this.prepare(req);
|
||||
|
||||
@@ -953,7 +959,7 @@ function abortRequest(res, errorCode, errorContext) {
|
||||
JSON.stringify({
|
||||
code: errorCode,
|
||||
message,
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -968,7 +974,7 @@ function abortRequest(res, errorCode, errorContext) {
|
||||
function abortUpgrade(
|
||||
socket,
|
||||
errorCode,
|
||||
errorContext: { message?: string } = {}
|
||||
errorContext: { message?: string } = {},
|
||||
) {
|
||||
socket.on("error", () => {
|
||||
debug("ignoring error from closed connection");
|
||||
@@ -984,7 +990,7 @@ function abortUpgrade(
|
||||
length +
|
||||
"\r\n" +
|
||||
"\r\n" +
|
||||
message
|
||||
message,
|
||||
);
|
||||
}
|
||||
socket.destroy();
|
||||
|
||||
@@ -80,7 +80,7 @@ export class Socket extends EventEmitter {
|
||||
server: BaseServer,
|
||||
transport: Transport,
|
||||
req: EngineRequest,
|
||||
protocol: number
|
||||
protocol: number,
|
||||
) {
|
||||
super();
|
||||
this.id = id;
|
||||
@@ -125,7 +125,7 @@ export class Socket extends EventEmitter {
|
||||
pingInterval: this.server.opts.pingInterval,
|
||||
pingTimeout: this.server.opts.pingTimeout,
|
||||
maxPayload: this.server.opts.maxHttpBufferSize,
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
if (this.server.opts.initialPacket) {
|
||||
@@ -212,7 +212,7 @@ export class Socket extends EventEmitter {
|
||||
this.pingIntervalTimer = setTimeout(() => {
|
||||
debug(
|
||||
"writing ping packet - expecting pong within %sms",
|
||||
this.server.opts.pingTimeout
|
||||
this.server.opts.pingTimeout,
|
||||
);
|
||||
this.sendPacket("ping");
|
||||
this.resetPingTimeout();
|
||||
@@ -233,7 +233,7 @@ export class Socket extends EventEmitter {
|
||||
},
|
||||
this.protocol === 3
|
||||
? this.server.opts.pingInterval + this.server.opts.pingTimeout
|
||||
: this.server.opts.pingTimeout
|
||||
: this.server.opts.pingTimeout,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -293,7 +293,7 @@ export class Socket extends EventEmitter {
|
||||
debug(
|
||||
'might upgrade socket transport from "%s" to "%s"',
|
||||
this.transport.name,
|
||||
transport.name
|
||||
transport.name,
|
||||
);
|
||||
|
||||
this.upgrading = true;
|
||||
@@ -468,7 +468,7 @@ export class Socket extends EventEmitter {
|
||||
type: PacketType,
|
||||
data?: RawData,
|
||||
options: SendOptions = {},
|
||||
callback?: SendCallback
|
||||
callback?: SendCallback,
|
||||
) {
|
||||
if ("function" === typeof options) {
|
||||
callback = options;
|
||||
@@ -554,6 +554,13 @@ export class Socket extends EventEmitter {
|
||||
* @return {Socket} for chaining
|
||||
*/
|
||||
public close(discard?: boolean) {
|
||||
if (
|
||||
discard &&
|
||||
(this.readyState === "open" || this.readyState === "closing")
|
||||
) {
|
||||
return this.closeTransport(discard);
|
||||
}
|
||||
|
||||
if ("open" !== this.readyState) return;
|
||||
|
||||
this.readyState = "closing";
|
||||
@@ -561,7 +568,7 @@ export class Socket extends EventEmitter {
|
||||
if (this.writeBuffer.length) {
|
||||
debug(
|
||||
"there are %d remaining packets in the buffer, waiting for the 'drain' event",
|
||||
this.writeBuffer.length
|
||||
this.writeBuffer.length,
|
||||
);
|
||||
this.once("drain", () => {
|
||||
debug("all packets have been sent, closing the transport");
|
||||
@@ -570,7 +577,7 @@ export class Socket extends EventEmitter {
|
||||
return;
|
||||
}
|
||||
|
||||
debug("the buffer is empty, closing the transport right away", discard);
|
||||
debug("the buffer is empty, closing the transport right away");
|
||||
this.closeTransport(discard);
|
||||
}
|
||||
|
||||
@@ -581,7 +588,7 @@ export class Socket extends EventEmitter {
|
||||
* @private
|
||||
*/
|
||||
private closeTransport(discard: boolean) {
|
||||
debug("closing the transport (discard? %s)", discard);
|
||||
debug("closing the transport (discard? %s)", !!discard);
|
||||
if (discard) this.transport.discard();
|
||||
this.transport.close(this.onClose.bind(this, "forced close"));
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ export abstract class Transport extends EventEmitter {
|
||||
"readyState updated from %s to %s (%s)",
|
||||
this._readyState,
|
||||
state,
|
||||
this.name
|
||||
this.name,
|
||||
);
|
||||
this._readyState = state;
|
||||
}
|
||||
|
||||
@@ -54,13 +54,13 @@ export class WebSocket extends Transport {
|
||||
this.socket._sender.sendFrame(
|
||||
// @ts-ignore
|
||||
packet.options.wsPreEncodedFrame,
|
||||
isLast ? this._onSentLast : this._onSent
|
||||
isLast ? this._onSentLast : this._onSent,
|
||||
);
|
||||
} else {
|
||||
this.parser.encodePacket(
|
||||
packet,
|
||||
this.supportsBinary,
|
||||
isLast ? this._doSendLast : this._doSend
|
||||
isLast ? this._doSendLast : this._doSend,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,11 @@ const debug = debugModule("engine:webtransport");
|
||||
export class WebTransport extends Transport {
|
||||
private readonly writer;
|
||||
|
||||
constructor(private readonly session, stream, reader) {
|
||||
constructor(
|
||||
private readonly session,
|
||||
stream,
|
||||
reader,
|
||||
) {
|
||||
super({ _query: { EIO: "4" } });
|
||||
|
||||
const transformStream = createPacketEncoderStream();
|
||||
|
||||
@@ -23,6 +23,10 @@ export interface uOptions {
|
||||
maxBackpressure?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* An Engine.IO server based on the `uWebSockets.js` package.
|
||||
*/
|
||||
// TODO export it into its own package
|
||||
export class uServer extends BaseServer {
|
||||
protected init() {}
|
||||
protected cleanup() {}
|
||||
@@ -64,7 +68,7 @@ export class uServer extends BaseServer {
|
||||
*/
|
||||
public attach(
|
||||
app /* : TemplatedApp */,
|
||||
options: AttachOptions & uOptions = {}
|
||||
options: AttachOptions & uOptions = {},
|
||||
) {
|
||||
const path = this._computePath(options);
|
||||
(app as TemplatedApp)
|
||||
@@ -84,7 +88,7 @@ export class uServer extends BaseServer {
|
||||
},
|
||||
message: (ws, message, isBinary) => {
|
||||
ws.getUserData().transport.onData(
|
||||
isBinary ? message : Buffer.from(message).toString()
|
||||
isBinary ? message : Buffer.from(message).toString(),
|
||||
);
|
||||
},
|
||||
close: (ws, code, message) => {
|
||||
@@ -96,7 +100,7 @@ export class uServer extends BaseServer {
|
||||
override _applyMiddlewares(
|
||||
req: any,
|
||||
res: any,
|
||||
callback: (err?: any) => void
|
||||
callback: (err?: any) => void,
|
||||
): void {
|
||||
if (this.middlewares.length === 0) {
|
||||
return callback();
|
||||
@@ -116,7 +120,7 @@ export class uServer extends BaseServer {
|
||||
|
||||
private handleRequest(
|
||||
res: HttpResponse,
|
||||
req: HttpRequest & { res: any; _query: any }
|
||||
req: HttpRequest & { res: any; _query: any },
|
||||
) {
|
||||
debug('handling "%s" http request "%s"', req.getMethod(), req.getUrl());
|
||||
this.prepare(req, res);
|
||||
@@ -158,7 +162,7 @@ export class uServer extends BaseServer {
|
||||
private handleUpgrade(
|
||||
res: HttpResponse,
|
||||
req: HttpRequest & { res: any; _query: any },
|
||||
context
|
||||
context,
|
||||
) {
|
||||
debug("on upgrade");
|
||||
|
||||
@@ -185,13 +189,13 @@ export class uServer extends BaseServer {
|
||||
const client = this.clients[id];
|
||||
if (!client) {
|
||||
debug("upgrade attempt for closed client");
|
||||
res.close();
|
||||
return res.close();
|
||||
} else if (client.upgrading) {
|
||||
debug("transport has already been trying to upgrade");
|
||||
res.close();
|
||||
return res.close();
|
||||
} else if (client.upgraded) {
|
||||
debug("transport had already been upgraded");
|
||||
res.close();
|
||||
return res.close();
|
||||
} else {
|
||||
debug("upgrading existing transport");
|
||||
transport = this.createTransport(req._query.transport, req);
|
||||
@@ -202,7 +206,7 @@ export class uServer extends BaseServer {
|
||||
req._query.transport,
|
||||
req,
|
||||
(errorCode, errorContext) =>
|
||||
this.abortRequest(res, errorCode, errorContext)
|
||||
this.abortRequest(res, errorCode, errorContext),
|
||||
);
|
||||
if (!transport) {
|
||||
return;
|
||||
@@ -219,7 +223,7 @@ export class uServer extends BaseServer {
|
||||
req.getHeader("sec-websocket-key"),
|
||||
req.getHeader("sec-websocket-protocol"),
|
||||
req.getHeader("sec-websocket-extensions"),
|
||||
context
|
||||
context,
|
||||
);
|
||||
};
|
||||
|
||||
@@ -235,7 +239,7 @@ export class uServer extends BaseServer {
|
||||
private abortRequest(
|
||||
res: HttpResponse | ResponseWrapper,
|
||||
errorCode,
|
||||
errorContext
|
||||
errorContext,
|
||||
) {
|
||||
const statusCode =
|
||||
errorCode === Server.errors.FORBIDDEN
|
||||
@@ -252,7 +256,7 @@ export class uServer extends BaseServer {
|
||||
JSON.stringify({
|
||||
code: errorCode,
|
||||
message,
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,17 @@ const { Socket } =
|
||||
? require("engine.io-client-v3")
|
||||
: require("engine.io-client");
|
||||
|
||||
switch (process.env.EIO_WS_ENGINE) {
|
||||
case "uws":
|
||||
console.log(
|
||||
"[WARN] testing with uWebSockets.js instead of Node.js built-in HTTP server",
|
||||
);
|
||||
break;
|
||||
case "eiows":
|
||||
console.log("[WARN] testing with eiows instead of ws");
|
||||
break;
|
||||
}
|
||||
|
||||
/**
|
||||
* Listen shortcut that fires a callback on an ephemeral port.
|
||||
*/
|
||||
|
||||
@@ -93,7 +93,7 @@ describe("engine", () => {
|
||||
"Upgrade: IRC/6.9",
|
||||
"",
|
||||
"",
|
||||
].join("\r\n")
|
||||
].join("\r\n"),
|
||||
);
|
||||
|
||||
const check = setTimeout(() => {
|
||||
@@ -122,7 +122,7 @@ describe("engine", () => {
|
||||
"Upgrade: IRC/6.9",
|
||||
"",
|
||||
"",
|
||||
].join("\r\n")
|
||||
].join("\r\n"),
|
||||
);
|
||||
|
||||
setTimeout(() => {
|
||||
@@ -154,7 +154,7 @@ describe("engine", () => {
|
||||
"Upgrade: IRC/6.9",
|
||||
"",
|
||||
"",
|
||||
].join("\r\n")
|
||||
].join("\r\n"),
|
||||
);
|
||||
|
||||
// send from client to server
|
||||
@@ -198,7 +198,7 @@ describe("engine", () => {
|
||||
"Upgrade: IRC/6.9",
|
||||
"",
|
||||
"",
|
||||
].join("\r\n")
|
||||
].join("\r\n"),
|
||||
);
|
||||
|
||||
// test that socket is still open by writing after the timeout period
|
||||
@@ -245,7 +245,7 @@ describe("engine", () => {
|
||||
server.once("close", done);
|
||||
server.close();
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -38,7 +38,7 @@ describe("middlewares", () => {
|
||||
});
|
||||
|
||||
const socket = new WebSocket(
|
||||
`ws://localhost:${port}/engine.io/?EIO=4&transport=websocket`
|
||||
`ws://localhost:${port}/engine.io/?EIO=4&transport=websocket`,
|
||||
);
|
||||
|
||||
socket.on("upgrade", (res) => {
|
||||
@@ -131,7 +131,7 @@ describe("middlewares", () => {
|
||||
});
|
||||
|
||||
const socket = new WebSocket(
|
||||
`ws://localhost:${port}/engine.io/?EIO=4&transport=websocket`
|
||||
`ws://localhost:${port}/engine.io/?EIO=4&transport=websocket`,
|
||||
);
|
||||
|
||||
socket.addEventListener("error", () => {
|
||||
@@ -169,7 +169,7 @@ describe("middlewares", () => {
|
||||
engine.use(helmet());
|
||||
|
||||
const socket = new WebSocket(
|
||||
`ws://localhost:${port}/engine.io/?EIO=4&transport=websocket`
|
||||
`ws://localhost:${port}/engine.io/?EIO=4&transport=websocket`,
|
||||
);
|
||||
|
||||
socket.on("upgrade", (res) => {
|
||||
@@ -196,7 +196,7 @@ describe("middlewares", () => {
|
||||
resave: false,
|
||||
saveUninitialized: true,
|
||||
cookie: {},
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
request
|
||||
@@ -206,7 +206,7 @@ describe("middlewares", () => {
|
||||
expect(err).to.be(null);
|
||||
// expect(res.status).to.eql(200);
|
||||
expect(res.headers["set-cookie"][0].startsWith("connect.sid=")).to.be(
|
||||
true
|
||||
true,
|
||||
);
|
||||
|
||||
if (engine.httpServer) {
|
||||
@@ -225,16 +225,16 @@ describe("middlewares", () => {
|
||||
resave: false,
|
||||
saveUninitialized: true,
|
||||
cookie: {},
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
const socket = new WebSocket(
|
||||
`ws://localhost:${port}/engine.io/?EIO=4&transport=websocket`
|
||||
`ws://localhost:${port}/engine.io/?EIO=4&transport=websocket`,
|
||||
);
|
||||
|
||||
socket.on("upgrade", (res) => {
|
||||
expect(res.headers["set-cookie"][0].startsWith("connect.sid=")).to.be(
|
||||
true
|
||||
true,
|
||||
);
|
||||
|
||||
if (engine.httpServer) {
|
||||
@@ -280,7 +280,7 @@ describe("middlewares", () => {
|
||||
});
|
||||
|
||||
const socket = new WebSocket(
|
||||
`ws://localhost:${port}/engine.io/?EIO=4&transport=websocket`
|
||||
`ws://localhost:${port}/engine.io/?EIO=4&transport=websocket`,
|
||||
);
|
||||
|
||||
socket.addEventListener("error", () => {
|
||||
|
||||
@@ -16,7 +16,7 @@ describe("parser", () => {
|
||||
expect(decoded.data).to.eql("€€€€");
|
||||
done();
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -143,7 +143,7 @@ describe("server", () => {
|
||||
expect(res.body.message).to.be("Thou shall not pass");
|
||||
partialDone();
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -161,7 +161,7 @@ describe("server", () => {
|
||||
client.on("error", () => {
|
||||
done();
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -205,6 +205,26 @@ describe("server", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("should prevent the client from upgrading twice", (done) => {
|
||||
engine = listen((port) => {
|
||||
const client = new ClientSocket(`ws://localhost:${port}`);
|
||||
|
||||
client.on("upgrade", () => {
|
||||
const socket = new WebSocket(
|
||||
`ws://localhost:${port}/engine.io/?EIO=4&transport=websocket&sid=${client.id}`,
|
||||
);
|
||||
|
||||
socket.on("error", () => {});
|
||||
|
||||
socket.on("close", () => {
|
||||
client.close();
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should disallow `__proto__` as transport (polling)", (done) => {
|
||||
const partialDone = createPartialDone(done, 2);
|
||||
|
||||
@@ -243,7 +263,7 @@ describe("server", () => {
|
||||
});
|
||||
|
||||
const socket = new WebSocket(
|
||||
`ws://localhost:${port}/engine.io/?EIO=4&transport=__proto__`
|
||||
`ws://localhost:${port}/engine.io/?EIO=4&transport=__proto__`,
|
||||
);
|
||||
|
||||
socket.onerror = partialDone;
|
||||
@@ -262,7 +282,7 @@ describe("server", () => {
|
||||
// hack-obtain sid
|
||||
const sid = res.text.match(/"sid":"([^"]+)"/)[1];
|
||||
expect(res.headers["set-cookie"][0]).to.be(
|
||||
`io=${sid}; Path=/; HttpOnly; SameSite=Lax`
|
||||
`io=${sid}; Path=/; HttpOnly; SameSite=Lax`,
|
||||
);
|
||||
done();
|
||||
});
|
||||
@@ -278,7 +298,7 @@ describe("server", () => {
|
||||
expect(err).to.be(null);
|
||||
const sid = res.text.match(/"sid":"([^"]+)"/)[1];
|
||||
expect(res.headers["set-cookie"][0]).to.be(
|
||||
`woot=${sid}; Path=/; HttpOnly; SameSite=Lax`
|
||||
`woot=${sid}; Path=/; HttpOnly; SameSite=Lax`,
|
||||
);
|
||||
done();
|
||||
});
|
||||
@@ -294,7 +314,7 @@ describe("server", () => {
|
||||
expect(err).to.be(null);
|
||||
const sid = res.text.match(/"sid":"([^"]+)"/)[1];
|
||||
expect(res.headers["set-cookie"][0]).to.be(
|
||||
`io=${sid}; Path=/custom; HttpOnly; SameSite=Lax`
|
||||
`io=${sid}; Path=/custom; HttpOnly; SameSite=Lax`,
|
||||
);
|
||||
done();
|
||||
});
|
||||
@@ -310,7 +330,7 @@ describe("server", () => {
|
||||
expect(err).to.be(null);
|
||||
const sid = res.text.match(/"sid":"([^"]+)"/)[1];
|
||||
expect(res.headers["set-cookie"][0]).to.be(
|
||||
`io=${sid}; SameSite=Lax`
|
||||
`io=${sid}; SameSite=Lax`,
|
||||
);
|
||||
done();
|
||||
});
|
||||
@@ -326,7 +346,7 @@ describe("server", () => {
|
||||
expect(err).to.be(null);
|
||||
const sid = res.text.match(/"sid":"([^"]+)"/)[1];
|
||||
expect(res.headers["set-cookie"][0]).to.be(
|
||||
`io=${sid}; Path=/; HttpOnly; SameSite=Lax`
|
||||
`io=${sid}; Path=/; HttpOnly; SameSite=Lax`,
|
||||
);
|
||||
done();
|
||||
});
|
||||
@@ -342,7 +362,7 @@ describe("server", () => {
|
||||
expect(err).to.be(null);
|
||||
const sid = res.text.match(/"sid":"([^"]+)"/)[1];
|
||||
expect(res.headers["set-cookie"][0]).to.be(
|
||||
`io=${sid}; Path=/; HttpOnly; SameSite=Strict`
|
||||
`io=${sid}; Path=/; HttpOnly; SameSite=Strict`,
|
||||
);
|
||||
done();
|
||||
});
|
||||
@@ -358,7 +378,7 @@ describe("server", () => {
|
||||
expect(err).to.be(null);
|
||||
const sid = res.text.match(/"sid":"([^"]+)"/)[1];
|
||||
expect(res.headers["set-cookie"][0]).to.be(
|
||||
`io=${sid}; Path=/; SameSite=Lax`
|
||||
`io=${sid}; Path=/; SameSite=Lax`,
|
||||
);
|
||||
done();
|
||||
});
|
||||
@@ -374,7 +394,7 @@ describe("server", () => {
|
||||
expect(err).to.be(null);
|
||||
const sid = res.text.match(/"sid":"([^"]+)"/)[1];
|
||||
expect(res.headers["set-cookie"][0]).to.be(
|
||||
`io=${sid}; Path=/; HttpOnly; SameSite=Lax`
|
||||
`io=${sid}; Path=/; HttpOnly; SameSite=Lax`,
|
||||
);
|
||||
done();
|
||||
});
|
||||
@@ -681,14 +701,14 @@ describe("server", () => {
|
||||
expect(res.body.code).to.be(3);
|
||||
expect(res.body.message).to.be("Bad request");
|
||||
expect(res.header["access-control-allow-credentials"]).to.be(
|
||||
"true"
|
||||
"true",
|
||||
);
|
||||
expect(res.header["access-control-allow-origin"]).to.be(
|
||||
"http://engine.io"
|
||||
"http://engine.io",
|
||||
);
|
||||
partialDone();
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -817,7 +837,7 @@ describe("server", () => {
|
||||
.end((err, res) => {
|
||||
if (process.env.EIO_WS_ENGINE === "uws") {
|
||||
expect(err).to.not.be(null);
|
||||
expect(err.message).to.be("socket hang up");
|
||||
expect(err.status).to.be(404);
|
||||
} else {
|
||||
expect(err).to.be(null);
|
||||
// this should not work, but it is kept for backward-compatibility
|
||||
@@ -1130,7 +1150,7 @@ describe("server", () => {
|
||||
expect(res.statusCode).to.eql(400);
|
||||
res.resume();
|
||||
res.on("end", done);
|
||||
}
|
||||
},
|
||||
);
|
||||
req.end();
|
||||
});
|
||||
@@ -1174,7 +1194,7 @@ describe("server", () => {
|
||||
// OPENED readyState is expected - we are actually polling
|
||||
expect(
|
||||
socket.transport.pollXhr[IS_CLIENT_V3 ? "xhr" : "_xhr"]
|
||||
.readyState
|
||||
.readyState,
|
||||
).to.be(1);
|
||||
|
||||
// 2 requests sent to the server over an unique port means
|
||||
@@ -1194,7 +1214,7 @@ describe("server", () => {
|
||||
}, 50);
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
it("should not trigger with connection: close header", ($done) => {
|
||||
@@ -1260,7 +1280,7 @@ describe("server", () => {
|
||||
done();
|
||||
}, 200);
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
it(
|
||||
@@ -1295,7 +1315,7 @@ describe("server", () => {
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
it(
|
||||
@@ -1331,7 +1351,7 @@ describe("server", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
if (IS_CLIENT_V3) {
|
||||
@@ -1370,7 +1390,7 @@ describe("server", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
} else {
|
||||
it(
|
||||
@@ -1408,7 +1428,7 @@ describe("server", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1435,7 +1455,7 @@ describe("server", () => {
|
||||
socket.send("test");
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// tests https://github.com/LearnBoost/engine.io-client/issues/207
|
||||
@@ -1634,6 +1654,67 @@ describe("server", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("should discard the packets in the writeBuffer when stopping the server", (done) => {
|
||||
engine = listen((port) => {
|
||||
const clientSocket = new ClientSocket(`ws://localhost:${port}`);
|
||||
|
||||
clientSocket.on("data", () => {
|
||||
done(new Error("should not happen"));
|
||||
});
|
||||
|
||||
clientSocket.on("close", (reason) => {
|
||||
expect(reason).to.eql("transport error");
|
||||
|
||||
clientSocket.close();
|
||||
done();
|
||||
});
|
||||
|
||||
engine.on("connection", (socket) => {
|
||||
socket.write("hello");
|
||||
engine.close();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should discard the packets in the writeBuffer when stopping the server (2)", (done) => {
|
||||
engine = listen((port) => {
|
||||
const clientSocket = new ClientSocket(`ws://localhost:${port}`);
|
||||
|
||||
clientSocket.on("data", () => {
|
||||
done(new Error("should not happen"));
|
||||
});
|
||||
|
||||
clientSocket.on("close", (reason) => {
|
||||
expect(reason).to.eql("transport error");
|
||||
|
||||
clientSocket.close();
|
||||
done();
|
||||
});
|
||||
|
||||
engine.on("connection", (socket) => {
|
||||
socket.write("hello");
|
||||
socket.close(); // readyState is now "closing"
|
||||
engine.close();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should not discard the packets in the writeBuffer when closing gracefully", (done) => {
|
||||
engine = listen((port) => {
|
||||
const clientSocket = new ClientSocket(`ws://localhost:${port}`);
|
||||
|
||||
clientSocket.on("data", (val) => {
|
||||
expect(val).to.eql("hello");
|
||||
done();
|
||||
});
|
||||
|
||||
engine.on("connection", (socket) => {
|
||||
socket.write("hello");
|
||||
socket.close();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("graceful close", () => {
|
||||
before(function () {
|
||||
if (process.env.EIO_WS_ENGINE === "uws") {
|
||||
@@ -1727,7 +1808,7 @@ describe("server", () => {
|
||||
engine.on("connection", (conn) => {
|
||||
conn.on("message", (msg) => {
|
||||
done(
|
||||
new Error("Test invalidation (message is longer than allowed)")
|
||||
new Error("Test invalidation (message is longer than allowed)"),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1749,7 +1830,7 @@ describe("server", () => {
|
||||
engine.on("connection", (conn) => {
|
||||
conn.on("message", (msg) => {
|
||||
done(
|
||||
new Error("Test invalidation (message is longer than allowed)")
|
||||
new Error("Test invalidation (message is longer than allowed)"),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -2060,7 +2141,7 @@ describe("server", () => {
|
||||
client.on("open", () => {
|
||||
client.send("a".repeat(1e6));
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -2202,7 +2283,7 @@ describe("server", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
it("should support chinese", (done) => {
|
||||
@@ -2546,7 +2627,7 @@ describe("server", () => {
|
||||
j,
|
||||
((value) => {
|
||||
j++;
|
||||
})(j)
|
||||
})(j),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2585,7 +2666,7 @@ describe("server", () => {
|
||||
j,
|
||||
((value) => {
|
||||
j++;
|
||||
})(j)
|
||||
})(j),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2999,7 +3080,7 @@ describe("server", () => {
|
||||
done();
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -3031,7 +3112,7 @@ describe("server", () => {
|
||||
done();
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -3174,11 +3255,11 @@ describe("server", () => {
|
||||
.on("error", done)
|
||||
.on("end", done)
|
||||
.resume();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -3212,11 +3293,11 @@ describe("server", () => {
|
||||
.on("error", done)
|
||||
.on("end", done)
|
||||
.resume();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -3250,11 +3331,11 @@ describe("server", () => {
|
||||
(res) => {
|
||||
expect(res.headers["content-encoding"]).to.equal("gzip");
|
||||
done();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -3284,11 +3365,11 @@ describe("server", () => {
|
||||
(res) => {
|
||||
expect(res.headers["content-encoding"]).to.be(undefined);
|
||||
done();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -3318,11 +3399,11 @@ describe("server", () => {
|
||||
(res) => {
|
||||
expect(res.headers["content-encoding"]).to.be(undefined);
|
||||
done();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -3352,11 +3433,11 @@ describe("server", () => {
|
||||
(res) => {
|
||||
expect(res.headers["content-encoding"]).to.be(undefined);
|
||||
done();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -3599,20 +3680,20 @@ describe("server", () => {
|
||||
expect(res.status).to.be(204);
|
||||
expect(res.body).to.be.empty();
|
||||
expect(res.header["access-control-allow-origin"]).to.be(
|
||||
"http://engine.io"
|
||||
"http://engine.io",
|
||||
);
|
||||
expect(res.header["access-control-allow-methods"]).to.be(
|
||||
"GET,HEAD,PUT,PATCH,POST,DELETE"
|
||||
"GET,HEAD,PUT,PATCH,POST,DELETE",
|
||||
);
|
||||
expect(res.header["access-control-allow-headers"]).to.be(
|
||||
"my-header"
|
||||
"my-header",
|
||||
);
|
||||
expect(res.header["access-control-allow-credentials"]).to.be(
|
||||
"true"
|
||||
"true",
|
||||
);
|
||||
done();
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -3629,20 +3710,20 @@ describe("server", () => {
|
||||
expect(res.status).to.be(200);
|
||||
expect(res.body).to.be.empty();
|
||||
expect(res.header["access-control-allow-origin"]).to.be(
|
||||
"http://engine.io"
|
||||
"http://engine.io",
|
||||
);
|
||||
expect(res.header["access-control-allow-methods"]).to.be(
|
||||
undefined
|
||||
undefined,
|
||||
);
|
||||
expect(res.header["access-control-allow-headers"]).to.be(
|
||||
undefined
|
||||
undefined,
|
||||
);
|
||||
expect(res.header["access-control-allow-credentials"]).to.be(
|
||||
"true"
|
||||
"true",
|
||||
);
|
||||
done();
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -3663,14 +3744,14 @@ describe("server", () => {
|
||||
expect(res.status).to.be(204);
|
||||
expect(res.body).to.be.empty();
|
||||
expect(res.header["access-control-allow-origin"]).to.be(
|
||||
undefined
|
||||
undefined,
|
||||
);
|
||||
expect(res.header["access-control-allow-credentials"]).to.be(
|
||||
undefined
|
||||
undefined,
|
||||
);
|
||||
done();
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -3697,24 +3778,24 @@ describe("server", () => {
|
||||
expect(res.status).to.be(200);
|
||||
expect(res.body).to.be.empty();
|
||||
expect(res.header["access-control-allow-origin"]).to.be(
|
||||
"http://good-domain.com"
|
||||
"http://good-domain.com",
|
||||
);
|
||||
expect(res.header["access-control-allow-methods"]).to.be(
|
||||
"GET,PUT,POST"
|
||||
"GET,PUT,POST",
|
||||
);
|
||||
expect(res.header["access-control-allow-headers"]).to.be(
|
||||
"my-header"
|
||||
"my-header",
|
||||
);
|
||||
expect(res.header["access-control-expose-headers"]).to.be(
|
||||
"my-exposed-header"
|
||||
"my-exposed-header",
|
||||
);
|
||||
expect(res.header["access-control-allow-credentials"]).to.be(
|
||||
"true"
|
||||
"true",
|
||||
);
|
||||
expect(res.header["access-control-max-age"]).to.be("123");
|
||||
done();
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -3739,7 +3820,7 @@ describe("server", () => {
|
||||
client.close();
|
||||
done();
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -3767,7 +3848,7 @@ describe("server", () => {
|
||||
done();
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -31,7 +31,7 @@ async function setupServer(opts, cb) {
|
||||
[{ shortName: "CN", value: "localhost" }],
|
||||
{
|
||||
days: 14, // the total length of the validity period MUST NOT exceed two weeks (https://w3c.github.io/webtransport/#custom-certificate-requirements)
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const engine = new eio.Server(opts);
|
||||
@@ -76,7 +76,7 @@ function setup(opts, cb) {
|
||||
value: certificate.hash,
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
await client.ready;
|
||||
@@ -106,7 +106,7 @@ describe("WebTransport", () => {
|
||||
setupServer({}, async ({ engine, h3Server, certificate }) => {
|
||||
const partialDone = createPartialDone(
|
||||
() => success(engine, h3Server, done),
|
||||
2
|
||||
2,
|
||||
);
|
||||
|
||||
engine.on("connection", (socket) => {
|
||||
@@ -123,7 +123,7 @@ describe("WebTransport", () => {
|
||||
value: certificate.hash,
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
await client.ready;
|
||||
@@ -188,7 +188,7 @@ describe("WebTransport", () => {
|
||||
value: certificate.hash,
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
await client.ready;
|
||||
@@ -216,14 +216,14 @@ describe("WebTransport", () => {
|
||||
|
||||
await writer.write(Uint8Array.of(31));
|
||||
await writer.write(
|
||||
TEXT_ENCODER.encode(`0{"sid":"${payload.sid}"}`)
|
||||
TEXT_ENCODER.encode(`0{"sid":"${payload.sid}"}`),
|
||||
);
|
||||
await writer.write(Uint8Array.of(6));
|
||||
await writer.write(TEXT_ENCODER.encode(`2probe`));
|
||||
await writer.write(Uint8Array.of(1));
|
||||
await writer.write(TEXT_ENCODER.encode(`5`));
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -242,7 +242,7 @@ describe("WebTransport", () => {
|
||||
value: certificate.hash,
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
await client.ready;
|
||||
@@ -250,7 +250,7 @@ describe("WebTransport", () => {
|
||||
client.closed.then(() => {
|
||||
success(engine, h3Server, done);
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -269,7 +269,7 @@ describe("WebTransport", () => {
|
||||
value: certificate.hash,
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
await client.ready;
|
||||
@@ -281,7 +281,7 @@ describe("WebTransport", () => {
|
||||
client.closed.then(() => {
|
||||
success(engine, h3Server, done);
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -304,7 +304,7 @@ describe("WebTransport", () => {
|
||||
}
|
||||
|
||||
success(engine, h3Server, done);
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -322,7 +322,7 @@ describe("WebTransport", () => {
|
||||
});
|
||||
|
||||
client.closed.then(() => success(engine, h3Server, partialDone));
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -440,7 +440,7 @@ describe("WebTransport", () => {
|
||||
|
||||
const header = await reader.read();
|
||||
expect(header.value).to.eql(
|
||||
Uint8Array.of(255, 0, 0, 0, 0, 0, 15, 66, 64)
|
||||
Uint8Array.of(255, 0, 0, 0, 0, 0, 15, 66, 64),
|
||||
);
|
||||
|
||||
const chunk1 = await reader.read();
|
||||
|
||||
@@ -203,7 +203,7 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
"[%s] new event of type %d from %s",
|
||||
this.uid,
|
||||
message.type,
|
||||
message.uid
|
||||
message.uid,
|
||||
);
|
||||
|
||||
switch (message.type) {
|
||||
@@ -217,7 +217,7 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
debug(
|
||||
"[%s] waiting for %d client acknowledgements",
|
||||
this.uid,
|
||||
clientCount
|
||||
clientCount,
|
||||
);
|
||||
this.publishResponse(message.uid, {
|
||||
type: MessageType.BROADCAST_CLIENT_COUNT,
|
||||
@@ -231,7 +231,7 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
debug(
|
||||
"[%s] received acknowledgement with value %j",
|
||||
this.uid,
|
||||
arg
|
||||
arg,
|
||||
);
|
||||
this.publishResponse(message.uid, {
|
||||
type: MessageType.BROADCAST_ACK,
|
||||
@@ -240,7 +240,7 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
packet: arg,
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
} else {
|
||||
const packet = message.data.packet;
|
||||
@@ -264,7 +264,7 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
case MessageType.DISCONNECT_SOCKETS:
|
||||
super.disconnectSockets(
|
||||
decodeOptions(message.data.opts),
|
||||
message.data.close
|
||||
message.data.close,
|
||||
);
|
||||
break;
|
||||
|
||||
@@ -272,7 +272,7 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
debug(
|
||||
"[%s] calling fetchSockets with opts %j",
|
||||
this.uid,
|
||||
message.data.opts
|
||||
message.data.opts,
|
||||
);
|
||||
super
|
||||
.fetchSockets(decodeOptions(message.data.opts))
|
||||
@@ -356,7 +356,7 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
"[%s] received response %s to request %s",
|
||||
this.uid,
|
||||
response.type,
|
||||
requestId
|
||||
requestId,
|
||||
);
|
||||
|
||||
switch (response.type) {
|
||||
@@ -381,7 +381,7 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
|
||||
request.current++;
|
||||
response.data.sockets.forEach((socket) =>
|
||||
request.responses.push(socket)
|
||||
request.responses.push(socket),
|
||||
);
|
||||
|
||||
if (request.current === request.expected) {
|
||||
@@ -433,7 +433,7 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
return debug(
|
||||
"[%s] error while broadcasting message: %s",
|
||||
this.uid,
|
||||
e.message
|
||||
e.message,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -453,7 +453,7 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
private addOffsetIfNecessary(
|
||||
packet: any,
|
||||
opts: BroadcastOptions,
|
||||
offset: Offset
|
||||
offset: Offset,
|
||||
) {
|
||||
if (!this.nsp.server.opts.connectionStateRecovery) {
|
||||
return;
|
||||
@@ -473,7 +473,7 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
packet: any,
|
||||
opts: BroadcastOptions,
|
||||
clientCountCallback: (clientCount: number) => void,
|
||||
ack: (...args: any[]) => void
|
||||
ack: (...args: any[]) => void,
|
||||
) {
|
||||
const onlyLocal = opts?.flags?.local;
|
||||
if (!onlyLocal) {
|
||||
@@ -582,8 +582,8 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
if (storedRequest) {
|
||||
reject(
|
||||
new Error(
|
||||
`timeout reached: only ${storedRequest.current} responses received out of ${storedRequest.expected}`
|
||||
)
|
||||
`timeout reached: only ${storedRequest.current} responses received out of ${storedRequest.expected}`,
|
||||
),
|
||||
);
|
||||
this.requests.delete(requestId);
|
||||
}
|
||||
@@ -627,7 +627,7 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
debug(
|
||||
'[%s] waiting for %d responses to "serverSideEmit" request',
|
||||
this.uid,
|
||||
expectedResponseCount
|
||||
expectedResponseCount,
|
||||
);
|
||||
|
||||
if (expectedResponseCount <= 0) {
|
||||
@@ -641,9 +641,9 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
if (storedRequest) {
|
||||
ack(
|
||||
new Error(
|
||||
`timeout reached: only ${storedRequest.current} responses received out of ${storedRequest.expected}`
|
||||
`timeout reached: only ${storedRequest.current} responses received out of ${storedRequest.expected}`,
|
||||
),
|
||||
storedRequest.responses
|
||||
storedRequest.responses,
|
||||
);
|
||||
this.requests.delete(requestId);
|
||||
}
|
||||
@@ -669,7 +669,7 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
}
|
||||
|
||||
protected publish(
|
||||
message: DistributiveOmit<ClusterMessage, "nsp" | "uid">
|
||||
message: DistributiveOmit<ClusterMessage, "nsp" | "uid">,
|
||||
): void {
|
||||
this.publishAndReturnOffset(message).catch((err) => {
|
||||
debug("[%s] error while publishing message: %s", this.uid, err);
|
||||
@@ -677,7 +677,7 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
}
|
||||
|
||||
protected publishAndReturnOffset(
|
||||
message: DistributiveOmit<ClusterMessage, "nsp" | "uid">
|
||||
message: DistributiveOmit<ClusterMessage, "nsp" | "uid">,
|
||||
) {
|
||||
(message as ClusterMessage).uid = this.uid;
|
||||
(message as ClusterMessage).nsp = this.nsp.name;
|
||||
@@ -695,14 +695,14 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
|
||||
protected publishResponse(
|
||||
requesterUid: ServerId,
|
||||
response: Omit<ClusterResponse, "nsp" | "uid">
|
||||
response: Omit<ClusterResponse, "nsp" | "uid">,
|
||||
) {
|
||||
(response as ClusterResponse).uid = this.uid;
|
||||
(response as ClusterResponse).nsp = this.nsp.name;
|
||||
this.doPublishResponse(requesterUid, response as ClusterResponse).catch(
|
||||
(err) => {
|
||||
debug("[%s] error while publishing response: %s", this.uid, err);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -715,7 +715,7 @@ export abstract class ClusterAdapter extends Adapter {
|
||||
*/
|
||||
protected abstract doPublishResponse(
|
||||
requesterUid: ServerId,
|
||||
response: ClusterResponse
|
||||
response: ClusterResponse,
|
||||
): Promise<void>;
|
||||
}
|
||||
|
||||
@@ -742,7 +742,7 @@ export abstract class ClusterAdapterWithHeartbeat extends ClusterAdapter {
|
||||
heartbeatInterval: 5_000,
|
||||
heartbeatTimeout: 10_000,
|
||||
},
|
||||
opts
|
||||
opts,
|
||||
);
|
||||
this.cleanupTimer = setInterval(() => {
|
||||
const now = Date.now();
|
||||
@@ -798,7 +798,7 @@ export abstract class ClusterAdapterWithHeartbeat extends ClusterAdapter {
|
||||
"[%s] new event of type %d from %s",
|
||||
this.uid,
|
||||
message.type,
|
||||
message.uid
|
||||
message.uid,
|
||||
);
|
||||
|
||||
switch (message.type) {
|
||||
@@ -846,7 +846,7 @@ export abstract class ClusterAdapterWithHeartbeat extends ClusterAdapter {
|
||||
debug(
|
||||
'[%s] waiting for %d responses to "serverSideEmit" request',
|
||||
this.uid,
|
||||
expectedResponseCount
|
||||
expectedResponseCount,
|
||||
);
|
||||
|
||||
if (expectedResponseCount <= 0) {
|
||||
@@ -860,9 +860,9 @@ export abstract class ClusterAdapterWithHeartbeat extends ClusterAdapter {
|
||||
if (storedRequest) {
|
||||
ack(
|
||||
new Error(
|
||||
`timeout reached: missing ${storedRequest.missingUids.size} responses`
|
||||
`timeout reached: missing ${storedRequest.missingUids.size} responses`,
|
||||
),
|
||||
storedRequest.responses
|
||||
storedRequest.responses,
|
||||
);
|
||||
this.customRequests.delete(requestId);
|
||||
}
|
||||
@@ -911,8 +911,8 @@ export abstract class ClusterAdapterWithHeartbeat extends ClusterAdapter {
|
||||
if (storedRequest) {
|
||||
reject(
|
||||
new Error(
|
||||
`timeout reached: missing ${storedRequest.missingUids.size} responses`
|
||||
)
|
||||
`timeout reached: missing ${storedRequest.missingUids.size} responses`,
|
||||
),
|
||||
);
|
||||
this.customRequests.delete(requestId);
|
||||
}
|
||||
@@ -944,7 +944,7 @@ export abstract class ClusterAdapterWithHeartbeat extends ClusterAdapter {
|
||||
"[%s] received response %s to request %s",
|
||||
this.uid,
|
||||
response.type,
|
||||
requestId
|
||||
requestId,
|
||||
);
|
||||
|
||||
switch (response.type) {
|
||||
@@ -956,7 +956,7 @@ export abstract class ClusterAdapterWithHeartbeat extends ClusterAdapter {
|
||||
}
|
||||
|
||||
(response.data.sockets as any[]).forEach((socket) =>
|
||||
request.responses.push(socket)
|
||||
request.responses.push(socket),
|
||||
);
|
||||
|
||||
request.missingUids.delete(response.uid);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
const alphabet =
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_".split(
|
||||
""
|
||||
"",
|
||||
),
|
||||
length = 64,
|
||||
map = {};
|
||||
|
||||
@@ -198,7 +198,7 @@ export class Adapter extends EventEmitter {
|
||||
packet: any,
|
||||
opts: BroadcastOptions,
|
||||
clientCountCallback: (clientCount: number) => void,
|
||||
ack: (...args: any[]) => void
|
||||
ack: (...args: any[]) => void,
|
||||
) {
|
||||
const flags = opts.flags || {};
|
||||
const packetOpts = {
|
||||
@@ -375,7 +375,7 @@ export class Adapter extends EventEmitter {
|
||||
*/
|
||||
public serverSideEmit(packet: any[]): void {
|
||||
console.warn(
|
||||
"this adapter does not support the serverSideEmit() functionality"
|
||||
"this adapter does not support the serverSideEmit() functionality",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -391,7 +391,7 @@ export class Adapter extends EventEmitter {
|
||||
*/
|
||||
public restoreSession(
|
||||
pid: PrivateSessionId,
|
||||
offset: string
|
||||
offset: string,
|
||||
): Promise<Session> {
|
||||
return null;
|
||||
}
|
||||
@@ -444,7 +444,7 @@ export class SessionAwareAdapter extends Adapter {
|
||||
|
||||
override restoreSession(
|
||||
pid: PrivateSessionId,
|
||||
offset: string
|
||||
offset: string,
|
||||
): Promise<Session> {
|
||||
const session = this.sessions.get(pid);
|
||||
if (!session) {
|
||||
@@ -500,7 +500,7 @@ export class SessionAwareAdapter extends Adapter {
|
||||
|
||||
function shouldIncludePacket(
|
||||
sessionRooms: Room[],
|
||||
opts: BroadcastOptions
|
||||
opts: BroadcastOptions,
|
||||
): boolean {
|
||||
const included =
|
||||
opts.rooms.size === 0 || sessionRooms.some((room) => opts.rooms.has(room));
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"ws": "~8.17.1"
|
||||
},
|
||||
"scripts": {
|
||||
"compile": "tsc",
|
||||
"compile": "rimraf ./dist && tsc",
|
||||
"test": "npm run format:check && npm run compile && nyc mocha --require ts-node/register test/*.ts",
|
||||
"format:check": "prettier --parser typescript --check 'lib/**/*.ts' 'test/**/*.ts'",
|
||||
"format:fix": "prettier --parser typescript --write 'lib/**/*.ts' 'test/**/*.ts'",
|
||||
|
||||
@@ -16,7 +16,10 @@ const NODES_COUNT = 3;
|
||||
class EventEmitterAdapter extends ClusterAdapterWithHeartbeat {
|
||||
private offset = 1;
|
||||
|
||||
constructor(nsp, readonly eventBus) {
|
||||
constructor(
|
||||
nsp,
|
||||
readonly eventBus,
|
||||
) {
|
||||
super(nsp, {});
|
||||
this.eventBus.on("message", (message) => {
|
||||
this.onMessage(message as ClusterMessage);
|
||||
@@ -30,7 +33,7 @@ class EventEmitterAdapter extends ClusterAdapterWithHeartbeat {
|
||||
|
||||
protected doPublishResponse(
|
||||
requesterUid: string,
|
||||
response: ClusterResponse
|
||||
response: ClusterResponse,
|
||||
): Promise<void> {
|
||||
this.eventBus.emit("message", response);
|
||||
return Promise.resolve();
|
||||
|
||||
@@ -153,7 +153,7 @@ describe("socket.io-adapter", () => {
|
||||
expect(opts.wsPreEncodedFrame.length).to.eql(2);
|
||||
expect(opts.wsPreEncodedFrame[0]).to.eql(Buffer.from([129, 4]));
|
||||
expect(opts.wsPreEncodedFrame[1]).to.eql(
|
||||
Buffer.from([52, 49, 50, 51])
|
||||
Buffer.from([52, 49, 50, 51]),
|
||||
);
|
||||
},
|
||||
},
|
||||
@@ -352,7 +352,7 @@ describe("socket.io-adapter", () => {
|
||||
{
|
||||
rooms: new Set(),
|
||||
except: new Set(),
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const offset = packetData[1];
|
||||
@@ -398,7 +398,7 @@ describe("socket.io-adapter", () => {
|
||||
{
|
||||
rooms: new Set(),
|
||||
except: new Set(),
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
adapter.broadcast(
|
||||
@@ -410,7 +410,7 @@ describe("socket.io-adapter", () => {
|
||||
{
|
||||
rooms: new Set(),
|
||||
except: new Set(),
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
adapter.broadcast(
|
||||
@@ -422,7 +422,7 @@ describe("socket.io-adapter", () => {
|
||||
{
|
||||
rooms: new Set(["r1"]),
|
||||
except: new Set(),
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
adapter.broadcast(
|
||||
@@ -434,7 +434,7 @@ describe("socket.io-adapter", () => {
|
||||
{
|
||||
rooms: new Set(),
|
||||
except: new Set(["r2"]),
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
adapter.broadcast(
|
||||
@@ -446,7 +446,7 @@ describe("socket.io-adapter", () => {
|
||||
{
|
||||
rooms: new Set(),
|
||||
except: new Set(["r3"]),
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
adapter.broadcast(
|
||||
@@ -459,7 +459,7 @@ describe("socket.io-adapter", () => {
|
||||
{
|
||||
rooms: new Set(),
|
||||
except: new Set(),
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
adapter.broadcast(
|
||||
@@ -471,7 +471,7 @@ describe("socket.io-adapter", () => {
|
||||
{
|
||||
rooms: new Set(),
|
||||
except: new Set(),
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
adapter.broadcast(
|
||||
@@ -486,7 +486,7 @@ describe("socket.io-adapter", () => {
|
||||
flags: {
|
||||
volatile: true,
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const offset = packetData[1];
|
||||
|
||||
@@ -1,69 +1,51 @@
|
||||
# History
|
||||
|
||||
## 2024
|
||||
|
||||
- [4.7.5](#475-2024-03-14) (Mar 2024)
|
||||
- [4.7.4](#474-2024-01-12) (Jan 2024)
|
||||
- [4.7.3](#473-2024-01-03) (Jan 2024)
|
||||
|
||||
## 2023
|
||||
|
||||
- [4.7.2](#472-2023-08-02) (Aug 2023)
|
||||
- [4.7.1](#471-2023-06-28) (Jun 2023)
|
||||
- [4.7.0](#470-2023-06-22) (Jun 2023)
|
||||
- [4.6.2](#462-2023-05-31) (May 2023)
|
||||
- [4.6.1](#461-2023-02-20) (Feb 2023)
|
||||
- [4.6.0](#460-2023-02-07) (Feb 2023)
|
||||
|
||||
## 2022
|
||||
|
||||
- [4.5.4](#454-2022-11-22) (Nov 2022)
|
||||
- [4.5.3](#453-2022-10-15) (Oct 2022)
|
||||
- [4.5.2](#452-2022-09-02) (Sep 2022)
|
||||
- [2.5.0](#250-2022-06-26) (Jun 2022) (from the [2.x](https://github.com/socketio/socket.io-client/tree/2.x) branch)
|
||||
- [4.5.1](#451-2022-05-17) (May 2022)
|
||||
- [4.5.0](#450-2022-04-23) (Apr 2022)
|
||||
- [4.4.1](#441-2022-01-06) (Jan 2022)
|
||||
|
||||
## 2021
|
||||
|
||||
- [4.4.0](#440-2021-11-18) (Nov 2021)
|
||||
- [4.3.2](#432-2021-10-16) (Oct 2021)
|
||||
- [4.3.1](#431-2021-10-15) (Oct 2021)
|
||||
- [4.3.0](#430-2021-10-14) (Oct 2021)
|
||||
- [4.2.0](#420-2021-08-30) (Aug 2021)
|
||||
- [4.1.3](#413-2021-07-10) (Jul 2021)
|
||||
- [4.1.2](#412-2021-05-17) (May 2021)
|
||||
- [4.1.1](#411-2021-05-11) (May 2021)
|
||||
- [4.1.0](#410-2021-05-11) (May 2021)
|
||||
- [4.0.2](#402-2021-05-06) (May 2021)
|
||||
- [4.0.1](#401-2021-03-31) (Mar 2021)
|
||||
- [3.1.3](#313-2021-03-12) (Mar 2021) (from the [3.1.x](https://github.com/socketio/socket.io-client/tree/3.1.x) branch)
|
||||
- [**4.0.0**](#400-2021-03-10) (Mar 2021)
|
||||
- [3.1.2](#312-2021-02-26) (Feb 2021)
|
||||
- [3.1.1](#311-2021-02-03) (Feb 2021)
|
||||
- [3.1.0](#310-2021-01-15) (Jan 2021)
|
||||
- [3.0.5](#305-2021-01-05) (Jan 2021)
|
||||
- [2.4.0](#240-2021-01-04) (Jan 2021) (from the [2.x](https://github.com/socketio/socket.io-client/tree/2.x) branch)
|
||||
|
||||
## 2020
|
||||
|
||||
- [3.0.4](#304-2020-12-07) (Dec 2020)
|
||||
- [3.0.3](#303-2020-11-19) (Nov 2020)
|
||||
- [3.0.2](#302-2020-11-17) (Nov 2020)
|
||||
- [3.0.1](#301-2020-11-09) (Nov 2020)
|
||||
- [**3.0.0**](#300-2020-11-05) (Nov 2020)
|
||||
- [2.3.1](#231-2020-09-30) (Sep 2020)
|
||||
|
||||
## 2019
|
||||
|
||||
- [2.3.0](#230-2019-09-20) (Sep 2019)
|
||||
|
||||
## 2018
|
||||
|
||||
- [2.2.0](#220-2018-11-29) (Nov 2018)
|
||||
- [2.1.1](#211-2018-05-17) (May 2018)
|
||||
- [2.1.0](#210-2018-03-29) (Mar 2018)
|
||||
| Version | Release date | Bundle size (UMD min+gzip) |
|
||||
|-------------------------------------------------------------------------------------------------------------|----------------|----------------------------|
|
||||
| [4.7.5](#475-2024-03-14) | March 2024 | `14.6 KB` |
|
||||
| [4.7.4](#474-2024-01-12) | January 2024 | `14.5 KB` |
|
||||
| [4.7.3](#473-2024-01-03) | January 2024 | `14.5 KB` |
|
||||
| [4.7.2](#472-2023-08-02) | August 2023 | `14.5 KB` |
|
||||
| [4.7.1](#471-2023-06-28) | June 2023 | `14.1 KB` |
|
||||
| [4.7.0](#470-2023-06-22) | June 2023 | `14.0 KB` |
|
||||
| [4.6.2](#462-2023-05-31) | May 2023 | `13.4 KB` |
|
||||
| [4.6.1](#461-2023-02-20) | February 2023 | `13.3 KB` |
|
||||
| [4.6.0](#460-2023-02-07) | February 2023 | `13.3 KB` |
|
||||
| [4.5.4](#454-2022-11-22) | November 2022 | `12.8 KB` |
|
||||
| [4.5.3](#453-2022-10-15) | October 2022 | `12.8 KB` |
|
||||
| [4.5.2](#452-2022-09-02) | September 2022 | `12.7 KB` |
|
||||
| [2.5.0](#250-2022-06-26) (from the [2.x](https://github.com/socketio/socket.io-client/tree/2.x) branch) | June 2022 | `18.8 KB` |
|
||||
| [4.5.1](#451-2022-05-17) | May 2022 | `12.7 KB` |
|
||||
| [4.5.0](#450-2022-04-23) | April 2022 | `12.7 KB` |
|
||||
| [4.4.1](#441-2022-01-06) | January 2022 | `12.3 KB` |
|
||||
| [4.4.0](#440-2021-11-18) | November 2021 | `12.3 KB` |
|
||||
| [4.3.2](#432-2021-10-16) | October 2021 | `12.1 KB` |
|
||||
| [4.3.1](#431-2021-10-15) | October 2021 | `12.1 KB` |
|
||||
| [4.3.0](#430-2021-10-14) | October 2021 | `12.1 KB` |
|
||||
| [4.2.0](#420-2021-08-30) | August 2021 | `15.2 KB` |
|
||||
| [4.1.3](#413-2021-07-10) | July 2021 | `14.9 KB` |
|
||||
| [4.1.2](#412-2021-05-17) | May 2021 | `14.9 KB` |
|
||||
| [4.1.1](#411-2021-05-11) | May 2021 | `14.9 KB` |
|
||||
| [4.1.0](#410-2021-05-11) | May 2021 | `14.9 KB` |
|
||||
| [4.0.2](#402-2021-05-06) | May 2021 | `14.9 KB` |
|
||||
| [4.0.1](#401-2021-03-31) | March 2021 | `14.9 KB` |
|
||||
| [3.1.3](#313-2021-03-12) (from the [3.1.x](https://github.com/socketio/socket.io-client/tree/3.1.x) branch) | March 2021 | `14.6 KB` |
|
||||
| [**4.0.0**](#400-2021-03-10) | March 2021 | `14.9 KB` |
|
||||
| [3.1.2](#312-2021-02-26) | February 2021 | `14.6 KB` |
|
||||
| [3.1.1](#311-2021-02-03) | February 2021 | `14.5 KB` |
|
||||
| [3.1.0](#310-2021-01-15) | January 2021 | `14.5 KB` |
|
||||
| [3.0.5](#305-2021-01-05) | January 2021 | `14.5 KB` |
|
||||
| [2.4.0](#240-2021-01-04) (from the [2.x](https://github.com/socketio/socket.io-client/tree/2.x) branch) | January 2021 | `18.8 KB` |
|
||||
| [3.0.4](#304-2020-12-07) | December 2020 | `14.6 KB` |
|
||||
| [3.0.3](#303-2020-11-19) | November 2020 | `14.5 KB` |
|
||||
| [3.0.2](#302-2020-11-17) | November 2020 | `14.5 KB` |
|
||||
| [3.0.1](#301-2020-11-09) | November 2020 | `14.7 KB` |
|
||||
| [**3.0.0**](#300-2020-11-05) | November 2020 | `14.6 KB` |
|
||||
| [2.3.1](#231-2020-09-30) | September 2020 | `18.8 KB` |
|
||||
| [2.3.0](#230-2019-09-20) | September 2019 | `19.6 KB` |
|
||||
| [2.2.0](#220-2018-11-29) | November 2018 | `18.6 KB` |
|
||||
| [2.1.1](#211-2018-05-17) | May 2018 | `18.7 KB` |
|
||||
| [2.1.0](#210-2018-03-29) | March 2018 | `18.7 KB` |
|
||||
|
||||
|
||||
# Release notes
|
||||
|
||||
@@ -24,12 +24,12 @@ const cache: Record<string, Manager> = {};
|
||||
*/
|
||||
function lookup(opts?: Partial<ManagerOptions & SocketOptions>): Socket;
|
||||
function lookup(
|
||||
uri: string,
|
||||
opts?: Partial<ManagerOptions & SocketOptions>
|
||||
uri?: string,
|
||||
opts?: Partial<ManagerOptions & SocketOptions>,
|
||||
): Socket;
|
||||
function lookup(
|
||||
uri?: string | Partial<ManagerOptions & SocketOptions>,
|
||||
opts?: Partial<ManagerOptions & SocketOptions>
|
||||
opts?: Partial<ManagerOptions & SocketOptions>,
|
||||
): Socket {
|
||||
if (typeof uri === "object") {
|
||||
opts = uri;
|
||||
|
||||
@@ -100,7 +100,7 @@ interface ManagerReservedEvents {
|
||||
|
||||
export class Manager<
|
||||
ListenEvents extends EventsMap = DefaultEventsMap,
|
||||
EmitEvents extends EventsMap = ListenEvents
|
||||
EmitEvents extends EventsMap = ListenEvents,
|
||||
> extends Emitter<{}, {}, ManagerReservedEvents> {
|
||||
/**
|
||||
* The Engine.IO client instance
|
||||
@@ -152,11 +152,11 @@ export class Manager<
|
||||
constructor(uri?: string, opts?: Partial<ManagerOptions>);
|
||||
constructor(
|
||||
uri?: string | Partial<ManagerOptions>,
|
||||
opts?: Partial<ManagerOptions>
|
||||
opts?: Partial<ManagerOptions>,
|
||||
);
|
||||
constructor(
|
||||
uri?: string | Partial<ManagerOptions>,
|
||||
opts?: Partial<ManagerOptions>
|
||||
opts?: Partial<ManagerOptions>,
|
||||
) {
|
||||
super();
|
||||
if (uri && "object" === typeof uri) {
|
||||
@@ -201,6 +201,9 @@ export class Manager<
|
||||
public reconnection(v?: boolean): this | boolean {
|
||||
if (!arguments.length) return this._reconnection;
|
||||
this._reconnection = !!v;
|
||||
if (!v) {
|
||||
this.skipReconnect = true;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -405,7 +408,7 @@ export class Manager<
|
||||
on(socket, "error", this.onerror.bind(this)),
|
||||
on(socket, "close", this.onclose.bind(this)),
|
||||
// @ts-ignore
|
||||
on(this.decoder, "decoded", this.ondecoded.bind(this))
|
||||
on(this.decoder, "decoded", this.ondecoded.bind(this)),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -531,7 +534,6 @@ export class Manager<
|
||||
this.skipReconnect = true;
|
||||
this._reconnecting = false;
|
||||
this.onclose("forced close");
|
||||
if (this.engine) this.engine.close();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -544,7 +546,11 @@ export class Manager<
|
||||
}
|
||||
|
||||
/**
|
||||
* Called upon engine close.
|
||||
* Called when:
|
||||
*
|
||||
* - the low-level engine is closed
|
||||
* - the parser encountered a badly formatted packet
|
||||
* - all sockets are disconnected
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
@@ -552,6 +558,7 @@ export class Manager<
|
||||
debug("closed due to %s", reason);
|
||||
|
||||
this.cleanup();
|
||||
this.engine?.close();
|
||||
this.backoff.reset();
|
||||
this._readyState = "closed";
|
||||
this.emitReserved("close", reason, description);
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Emitter } from "@socket.io/component-emitter";
|
||||
export function on(
|
||||
obj: Emitter<any, any>,
|
||||
ev: string,
|
||||
fn: (err?: any) => any
|
||||
fn: (err?: any) => any,
|
||||
): VoidFunction {
|
||||
obj.on(ev, fn);
|
||||
return function subDestroy(): void {
|
||||
|
||||
@@ -116,7 +116,7 @@ interface SocketReservedEvents {
|
||||
connect_error: (err: Error) => void;
|
||||
disconnect: (
|
||||
reason: Socket.DisconnectReason,
|
||||
description?: DisconnectDescription
|
||||
description?: DisconnectDescription,
|
||||
) => void;
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ interface SocketReservedEvents {
|
||||
*/
|
||||
export class Socket<
|
||||
ListenEvents extends EventsMap = DefaultEventsMap,
|
||||
EmitEvents extends EventsMap = ListenEvents
|
||||
EmitEvents extends EventsMap = ListenEvents,
|
||||
> extends Emitter<ListenEvents, EmitEvents, SocketReservedEvents> {
|
||||
public readonly io: Manager<ListenEvents, EmitEvents>;
|
||||
|
||||
@@ -440,16 +440,13 @@ export class Socket<
|
||||
packet.id = id;
|
||||
}
|
||||
|
||||
const isTransportWritable =
|
||||
this.io.engine &&
|
||||
this.io.engine.transport &&
|
||||
this.io.engine.transport.writable;
|
||||
const isTransportWritable = this.io.engine?.transport?.writable;
|
||||
const isConnected = this.connected && !this.io.engine?._hasPingExpired();
|
||||
|
||||
const discardPacket =
|
||||
this.flags.volatile && (!isTransportWritable || !this.connected);
|
||||
const discardPacket = this.flags.volatile && !isTransportWritable;
|
||||
if (discardPacket) {
|
||||
debug("discard packet as the transport is not currently writable");
|
||||
} else if (this.connected) {
|
||||
} else if (isConnected) {
|
||||
this.notifyOutgoingListeners(packet);
|
||||
this.packet(packet);
|
||||
} else {
|
||||
@@ -554,7 +551,7 @@ export class Socket<
|
||||
debug(
|
||||
"packet [%d] is discarded after %d tries",
|
||||
packet.id,
|
||||
packet.tryCount
|
||||
packet.tryCount,
|
||||
);
|
||||
this._queue.shift();
|
||||
if (ack) {
|
||||
@@ -591,7 +588,7 @@ export class Socket<
|
||||
if (packet.pending && !force) {
|
||||
debug(
|
||||
"packet [%d] has already been sent and is waiting for an ack",
|
||||
packet.id
|
||||
packet.id,
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -665,7 +662,7 @@ export class Socket<
|
||||
*/
|
||||
private onclose(
|
||||
reason: Socket.DisconnectReason,
|
||||
description?: DisconnectDescription
|
||||
description?: DisconnectDescription,
|
||||
): void {
|
||||
debug("close (%s)", reason);
|
||||
this.connected = false;
|
||||
@@ -683,7 +680,7 @@ export class Socket<
|
||||
private _clearAcks() {
|
||||
Object.keys(this.acks).forEach((id) => {
|
||||
const isBuffered = this.sendBuffer.some(
|
||||
(packet) => String(packet.id) === id
|
||||
(packet) => String(packet.id) === id,
|
||||
);
|
||||
if (!isBuffered) {
|
||||
// note: handlers that do not accept an error as first argument are ignored here
|
||||
@@ -716,8 +713,8 @@ export class Socket<
|
||||
this.emitReserved(
|
||||
"connect_error",
|
||||
new Error(
|
||||
"It seems you are trying to reach a Socket.IO server in v2.x with a v3.x client, but they are not compatible (more information here: https://socket.io/docs/v3/migrating-from-2-x-to-3-0/)"
|
||||
)
|
||||
"It seems you are trying to reach a Socket.IO server in v2.x with a v3.x client, but they are not compatible (more information here: https://socket.io/docs/v3/migrating-from-2-x-to-3-0/)",
|
||||
),
|
||||
);
|
||||
}
|
||||
break;
|
||||
@@ -967,7 +964,7 @@ export class Socket<
|
||||
* @returns self
|
||||
*/
|
||||
public timeout(
|
||||
timeout: number
|
||||
timeout: number,
|
||||
): Socket<ListenEvents, DecorateAcknowledgements<EmitEvents>> {
|
||||
this.flags.timeout = timeout;
|
||||
return this;
|
||||
|
||||
@@ -39,7 +39,7 @@ type ParsedUrl = {
|
||||
export function url(
|
||||
uri: string | ParsedUrl,
|
||||
path: string = "",
|
||||
loc?: Location
|
||||
loc?: Location,
|
||||
): ParsedUrl {
|
||||
let obj = uri as ParsedUrl;
|
||||
|
||||
|
||||
@@ -47,16 +47,17 @@
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.2",
|
||||
"engine.io-client": "~6.5.2",
|
||||
"engine.io-client": "~6.6.0",
|
||||
"socket.io-parser": "~4.2.4"
|
||||
},
|
||||
"scripts": {
|
||||
"compile": "rimraf ./build && tsc && tsc -p tsconfig.esm.json && ./postcompile.sh",
|
||||
"test": "npm run format:check && npm run compile && if test \"$BROWSERS\" = \"1\" ; then npm run test:browser; else npm run test:node; fi",
|
||||
"test:node": "mocha --require ts-node/register --reporter dot --require test/support/hooks.ts --timeout 5000 --exit test/index.ts",
|
||||
"test:node": "mocha --require ts-node/register --require test/support/hooks.ts --exit test/index.ts",
|
||||
"test:browser": "ts-node test/browser-runner.ts",
|
||||
"test:types": "tsd",
|
||||
"build": "rollup -c support/rollup.config.umd.js && rollup -c support/rollup.config.esm.js && rollup -c support/rollup.config.umd.msgpack.js",
|
||||
"bundle-size": "node support/bundle-size.js",
|
||||
"format:check": "prettier --check \"*.js\" \"lib/**/*.ts\" \"test/**/*.ts\" \"support/**/*.js\"",
|
||||
"format:fix": "prettier --write \"*.js\" \"lib/**/*.ts\" \"test/**/*.ts\" \"support/**/*.js\"",
|
||||
"prepack": "npm run compile"
|
||||
|
||||
35
packages/socket.io-client/support/bundle-size.js
Normal file
35
packages/socket.io-client/support/bundle-size.js
Normal file
@@ -0,0 +1,35 @@
|
||||
const { resolve } = require("node:path");
|
||||
const { readFile } = require("node:fs/promises");
|
||||
const { gzipSync, brotliCompressSync } = require("node:zlib");
|
||||
|
||||
const bundles = [
|
||||
{
|
||||
name: "UMD bundle",
|
||||
path: "dist/socket.io.min.js",
|
||||
},
|
||||
{
|
||||
name: "ESM bundle",
|
||||
path: "dist/socket.io.esm.min.js",
|
||||
},
|
||||
];
|
||||
|
||||
function format(size) {
|
||||
return (size / 1024).toFixed(1);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
for (const bundle of bundles) {
|
||||
const path = resolve(bundle.path);
|
||||
const content = await readFile(path);
|
||||
const gzip = gzipSync(content);
|
||||
const brotli = brotliCompressSync(content);
|
||||
|
||||
console.log(`${bundle.name}`);
|
||||
console.log(`min: ${format(content.length)} KB`);
|
||||
console.log(`min+gzip: ${format(gzip.length)} KB`);
|
||||
console.log(`min+br: ${format(brotli.length)} KB`);
|
||||
console.log();
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -15,7 +15,15 @@ module.exports = {
|
||||
file: "./dist/socket.io.esm.min.js",
|
||||
format: "esm",
|
||||
sourcemap: true,
|
||||
plugins: [terser()],
|
||||
plugins: [
|
||||
terser({
|
||||
mangle: {
|
||||
properties: {
|
||||
regex: /^_/,
|
||||
},
|
||||
},
|
||||
}),
|
||||
],
|
||||
banner,
|
||||
},
|
||||
plugins: [
|
||||
|
||||
@@ -10,25 +10,15 @@ const banner = `/*!
|
||||
* Released under the MIT License.
|
||||
*/`;
|
||||
|
||||
module.exports = {
|
||||
input: "./build/esm/browser-entrypoint.js",
|
||||
output: [
|
||||
{
|
||||
file: "./dist/socket.io.js",
|
||||
format: "umd",
|
||||
name: "io",
|
||||
sourcemap: true,
|
||||
banner,
|
||||
},
|
||||
{
|
||||
file: "./dist/socket.io.min.js",
|
||||
format: "umd",
|
||||
name: "io",
|
||||
sourcemap: true,
|
||||
plugins: [terser()],
|
||||
banner,
|
||||
},
|
||||
],
|
||||
const devBundle = {
|
||||
input: "./build/esm-debug/browser-entrypoint.js",
|
||||
output: {
|
||||
file: "./dist/socket.io.js",
|
||||
format: "umd",
|
||||
name: "io",
|
||||
sourcemap: true,
|
||||
banner,
|
||||
},
|
||||
plugins: [
|
||||
nodeResolve({
|
||||
browser: true,
|
||||
@@ -37,7 +27,55 @@ module.exports = {
|
||||
babel({
|
||||
babelHelpers: "bundled",
|
||||
presets: [["@babel/env"]],
|
||||
plugins: ["@babel/plugin-transform-object-assign"],
|
||||
plugins: [
|
||||
"@babel/plugin-transform-object-assign",
|
||||
[
|
||||
"@babel/plugin-transform-classes",
|
||||
{
|
||||
loose: true,
|
||||
},
|
||||
],
|
||||
],
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
const prodBundle = {
|
||||
input: "./build/esm/browser-entrypoint.js",
|
||||
output: {
|
||||
file: "./dist/socket.io.min.js",
|
||||
format: "umd",
|
||||
name: "io",
|
||||
sourcemap: true,
|
||||
plugins: [
|
||||
terser({
|
||||
mangle: {
|
||||
properties: {
|
||||
regex: /^_/,
|
||||
},
|
||||
},
|
||||
}),
|
||||
],
|
||||
banner,
|
||||
},
|
||||
plugins: [
|
||||
nodeResolve({
|
||||
browser: true,
|
||||
}),
|
||||
babel({
|
||||
babelHelpers: "bundled",
|
||||
presets: [["@babel/env"]],
|
||||
plugins: [
|
||||
"@babel/plugin-transform-object-assign",
|
||||
[
|
||||
"@babel/plugin-transform-classes",
|
||||
{
|
||||
loose: true,
|
||||
},
|
||||
],
|
||||
],
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
module.exports = [devBundle, prodBundle];
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
const base = require("./rollup.config.umd.js");
|
||||
const base = require("./rollup.config.umd.js")[1];
|
||||
const alias = require("@rollup/plugin-alias");
|
||||
const commonjs = require("@rollup/plugin-commonjs");
|
||||
|
||||
module.exports = {
|
||||
...base,
|
||||
output: {
|
||||
...base.output[1],
|
||||
...base.output,
|
||||
file: "./dist/socket.io.msgpack.min.js",
|
||||
},
|
||||
plugins: [
|
||||
commonjs(),
|
||||
alias({
|
||||
entries: [
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import expect from "expect.js";
|
||||
import expect = require("expect.js");
|
||||
import { io } from "..";
|
||||
import { wrap, BASE_URL, success } from "./support/util";
|
||||
|
||||
@@ -7,6 +7,7 @@ describe("connection state recovery", () => {
|
||||
return wrap((done) => {
|
||||
const socket = io(BASE_URL, {
|
||||
forceNew: true,
|
||||
reconnectionDelay: 10,
|
||||
});
|
||||
|
||||
expect(socket.recovered).to.eql(false);
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import expect from "expect.js";
|
||||
import expect = require("expect.js");
|
||||
import { io, Manager, ManagerOptions } from "..";
|
||||
import hasCORS from "has-cors";
|
||||
import { install } from "@sinonjs/fake-timers";
|
||||
import textBlobBuilder from "text-blob-builder";
|
||||
import { BASE_URL, wrap } from "./support/util";
|
||||
import { nextTick } from "engine.io-client";
|
||||
|
||||
describe("connection", () => {
|
||||
it("should connect to localhost", () => {
|
||||
@@ -158,7 +159,7 @@ describe("connection", () => {
|
||||
|
||||
it("should reconnect by default", () => {
|
||||
return wrap((done) => {
|
||||
const socket = io(BASE_URL, { forceNew: true, reconnectionDelay: 0 });
|
||||
const socket = io(BASE_URL, { forceNew: true, reconnectionDelay: 10 });
|
||||
socket.io.on("reconnect", () => {
|
||||
socket.disconnect();
|
||||
done();
|
||||
@@ -166,7 +167,7 @@ describe("connection", () => {
|
||||
|
||||
setTimeout(() => {
|
||||
socket.io.engine.close();
|
||||
}, 500);
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -189,7 +190,7 @@ describe("connection", () => {
|
||||
|
||||
it("should reconnect automatically after reconnecting manually", () => {
|
||||
return wrap((done) => {
|
||||
const socket = io(BASE_URL, { forceNew: true });
|
||||
const socket = io(BASE_URL, { forceNew: true, reconnectionDelay: 10 });
|
||||
socket
|
||||
.once("connect", () => {
|
||||
socket.disconnect();
|
||||
@@ -202,7 +203,7 @@ describe("connection", () => {
|
||||
socket.connect();
|
||||
setTimeout(() => {
|
||||
socket.io.engine.close();
|
||||
}, 500);
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -281,13 +282,13 @@ describe("connection", () => {
|
||||
});
|
||||
socket.io.once("error", () => {
|
||||
socket.io.on("reconnect_attempt", () => {
|
||||
expect().fail();
|
||||
done(new Error("should not happen"));
|
||||
});
|
||||
socket.disconnect();
|
||||
// set a timeout to let reconnection possibly fire
|
||||
setTimeout(() => {
|
||||
done();
|
||||
}, 500);
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -301,13 +302,13 @@ describe("connection", () => {
|
||||
});
|
||||
socket.io.once("reconnect_attempt", () => {
|
||||
socket.io.on("reconnect_attempt", () => {
|
||||
expect().fail();
|
||||
done(new Error("should not happen"));
|
||||
});
|
||||
socket.disconnect();
|
||||
// set a timeout to let reconnection possibly fire
|
||||
setTimeout(() => {
|
||||
done();
|
||||
}, 500);
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -332,27 +333,29 @@ describe("connection", () => {
|
||||
|
||||
it("should stop reconnecting on a socket and keep to reconnect on another", () => {
|
||||
return wrap((done) => {
|
||||
const manager = new Manager(BASE_URL);
|
||||
const manager = new Manager(BASE_URL, {
|
||||
reconnectionDelay: 10,
|
||||
});
|
||||
const socket1 = manager.socket("/");
|
||||
const socket2 = manager.socket("/asd");
|
||||
|
||||
manager.on("reconnect_attempt", () => {
|
||||
socket1.on("connect", () => {
|
||||
expect().fail();
|
||||
done(new Error("should not happen"));
|
||||
});
|
||||
socket2.on("connect", () => {
|
||||
setTimeout(() => {
|
||||
socket2.disconnect();
|
||||
manager._close();
|
||||
done();
|
||||
}, 500);
|
||||
}, 50);
|
||||
});
|
||||
socket1.disconnect();
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
manager.engine.close();
|
||||
}, 1000);
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -441,20 +444,19 @@ describe("connection", () => {
|
||||
reconnection: true,
|
||||
reconnectionDelay: 10,
|
||||
});
|
||||
const cb = () => {
|
||||
socket.close();
|
||||
expect().fail();
|
||||
};
|
||||
manager.on("reconnect_attempt", cb);
|
||||
|
||||
var socket = manager.socket("/valid");
|
||||
manager.on("reconnect_attempt", () => {
|
||||
done(new Error("should not happen"));
|
||||
});
|
||||
|
||||
const socket = manager.socket("/valid");
|
||||
socket.on("connect", () => {
|
||||
// set a timeout to let reconnection possibly fire
|
||||
setTimeout(() => {
|
||||
socket.close();
|
||||
manager._close();
|
||||
done();
|
||||
}, 1000);
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -518,6 +520,28 @@ describe("connection", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("should stop trying to reconnect", () => {
|
||||
return wrap((done) => {
|
||||
const manager = new Manager("http://localhost:9823", {
|
||||
reconnectionDelay: 10,
|
||||
});
|
||||
|
||||
manager.on("reconnect_error", () => {
|
||||
// disable current reconnection loop
|
||||
manager.reconnection(false);
|
||||
|
||||
manager.on("reconnect_attempt", () => {
|
||||
done(new Error("should not happen"));
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
manager._close();
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Ignore incorrect connection test for old IE due to no support for
|
||||
// `script.onerror` (see: http://requirejs.org/docs/api.html#ieloadfail)
|
||||
if (!global.document || hasCORS) {
|
||||
@@ -549,12 +573,12 @@ describe("connection", () => {
|
||||
return wrap((done) => {
|
||||
const manager = new Manager("http://localhost:9823", {
|
||||
reconnection: false,
|
||||
reconnectionDelay: 10,
|
||||
});
|
||||
|
||||
manager.on("reconnect_attempt", () => {
|
||||
done(new Error("should not happen"));
|
||||
});
|
||||
const cb = () => {
|
||||
socket.close();
|
||||
expect().fail();
|
||||
};
|
||||
manager.on("reconnect_attempt", cb);
|
||||
|
||||
manager.on("error", () => {
|
||||
// set a timeout to let reconnection possibly fire
|
||||
@@ -562,7 +586,7 @@ describe("connection", () => {
|
||||
socket.disconnect();
|
||||
manager._close();
|
||||
done();
|
||||
}, 1000);
|
||||
}, 100);
|
||||
});
|
||||
|
||||
var socket = manager.socket("/invalid");
|
||||
@@ -574,9 +598,10 @@ describe("connection", () => {
|
||||
const manager = new Manager("http://localhost:9823", {
|
||||
reconnection: true,
|
||||
reconnectionAttempts: 2,
|
||||
reconnectionDelay: 10,
|
||||
});
|
||||
let delay = Math.floor(
|
||||
manager.reconnectionDelay() * manager.randomizationFactor() * 0.5
|
||||
manager.reconnectionDelay() * manager.randomizationFactor() * 0.5,
|
||||
);
|
||||
delay = Math.max(delay, 10);
|
||||
|
||||
@@ -894,4 +919,30 @@ describe("connection", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should close the engine upon decoding exception", () => {
|
||||
return wrap((done) => {
|
||||
const manager = new Manager(BASE_URL, {
|
||||
autoConnect: true,
|
||||
reconnectionDelay: 50,
|
||||
});
|
||||
|
||||
let engine = manager.engine;
|
||||
|
||||
manager.on("open", () => {
|
||||
nextTick(() => {
|
||||
// @ts-expect-error emit() is private
|
||||
manager.engine.emit("data", "bad");
|
||||
});
|
||||
});
|
||||
|
||||
manager.on("reconnect", () => {
|
||||
expect(manager.engine === engine).to.be(false);
|
||||
expect(engine.readyState).to.eql("closed");
|
||||
|
||||
manager._close();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,4 +5,4 @@ const socket = io("http://localhost:3211", {
|
||||
|
||||
setTimeout(() => {
|
||||
console.log("process should not exit");
|
||||
}, 500);
|
||||
}, 50);
|
||||
|
||||
@@ -9,4 +9,4 @@ socket.on("open", () => {
|
||||
|
||||
setTimeout(() => {
|
||||
console.log("process should exit now");
|
||||
}, 500);
|
||||
}, 50);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user