mirror of
https://github.com/socketio/socket.io.git
synced 2026-01-12 00:17:56 -05:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12221f296d | ||
|
|
6f4bd7f8e7 | ||
|
|
4f2e9a716d | ||
|
|
9e8f288ca9 | ||
|
|
86eb4227b2 | ||
|
|
cf873fd831 | ||
|
|
0d10e6131b | ||
|
|
10aafbbc16 | ||
|
|
f34cfca26d | ||
|
|
d412e876b8 |
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [10.x, 12.x, 14.x]
|
||||
node-version: [10.x, 12.x, 14.x, 15.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
10
CHANGELOG.md
10
CHANGELOG.md
@@ -1,3 +1,13 @@
|
||||
## [3.1.1](https://github.com/socketio/socket.io/compare/3.1.0...3.1.1) (2021-02-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* properly parse the CONNECT packet in v2 compatibility mode ([6f4bd7f](https://github.com/socketio/socket.io/commit/6f4bd7f8e7c41a075a8014565330a77c38b03a8d))
|
||||
* **typings:** add return types and general-case overload signatures ([#3776](https://github.com/socketio/socket.io/issues/3776)) ([9e8f288](https://github.com/socketio/socket.io/commit/9e8f288ca9f14f91064b8d3cce5946f7d23d407c))
|
||||
* **typings:** update the types of "query", "auth" and "headers" ([4f2e9a7](https://github.com/socketio/socket.io/commit/4f2e9a716d9835b550c8fd9a9b429ebf069c2895))
|
||||
|
||||
|
||||
# [3.1.0](https://github.com/socketio/socket.io/compare/3.0.5...3.1.0) (2021-01-15)
|
||||
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ For this purpose, it relies on [Engine.IO](https://github.com/socketio/engine.io
|
||||
|
||||
#### Auto-reconnection support
|
||||
|
||||
Unless instructed otherwise a disconnected client will try to reconnect forever, until the server is available again. Please see the available reconnection options [here](https://github.com/socketio/socket.io-client/blob/master/docs/API.md#new-managerurl-options).
|
||||
Unless instructed otherwise a disconnected client will try to reconnect forever, until the server is available again. Please see the available reconnection options [here](https://socket.io/docs/v3/client-api/#new-Manager-url-options).
|
||||
|
||||
#### Disconnection detection
|
||||
|
||||
@@ -85,7 +85,11 @@ This is a useful feature to send notifications to a group of users, or to a give
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
// with npm
|
||||
npm install socket.io
|
||||
|
||||
// with yarn
|
||||
yarn add socket.io
|
||||
```
|
||||
|
||||
## How to use
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*!
|
||||
* Socket.IO v3.1.0
|
||||
* Socket.IO v3.1.1
|
||||
* (c) 2014-2021 Guillermo Rauch
|
||||
* Released under the MIT License.
|
||||
*/
|
||||
@@ -151,7 +151,7 @@ function lookup(uri, opts) {
|
||||
}
|
||||
|
||||
opts = opts || {};
|
||||
var parsed = url_1.url(uri);
|
||||
var parsed = url_1.url(uri, opts.path);
|
||||
var source = parsed.source;
|
||||
var id = parsed.id;
|
||||
var path = parsed.path;
|
||||
@@ -172,7 +172,7 @@ function lookup(uri, opts) {
|
||||
}
|
||||
|
||||
if (parsed.query && !opts.query) {
|
||||
opts.query = parsed.query;
|
||||
opts.query = parsed.queryKey;
|
||||
}
|
||||
|
||||
return io.socket(parsed.path, opts);
|
||||
@@ -592,7 +592,6 @@ var Manager = /*#__PURE__*/function (_Emitter) {
|
||||
key: "_packet",
|
||||
value: function _packet(packet) {
|
||||
debug("writing packet %j", packet);
|
||||
if (packet.query && packet.type === 0) packet.nsp += "?" + packet.query;
|
||||
var encodedPackets = this.encoder.encode(packet);
|
||||
|
||||
for (var i = 0; i < encodedPackets.length; i++) {
|
||||
@@ -1458,13 +1457,16 @@ var debug = __webpack_require__(/*! debug */ "./node_modules/debug/src/browser.j
|
||||
* URL parser.
|
||||
*
|
||||
* @param uri - url
|
||||
* @param path - the request path of the connection
|
||||
* @param loc - An object meant to mimic window.location.
|
||||
* Defaults to window.location.
|
||||
* @public
|
||||
*/
|
||||
|
||||
|
||||
function url(uri, loc) {
|
||||
function url(uri) {
|
||||
var path = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "";
|
||||
var loc = arguments.length > 2 ? arguments[2] : undefined;
|
||||
var obj = uri; // default to window.location
|
||||
|
||||
loc = loc || typeof location !== "undefined" && location;
|
||||
@@ -1507,7 +1509,7 @@ function url(uri, loc) {
|
||||
var ipv6 = obj.host.indexOf(":") !== -1;
|
||||
var host = ipv6 ? "[" + obj.host + "]" : obj.host; // define unique id
|
||||
|
||||
obj.id = obj.protocol + "://" + host + ":" + obj.port; // define href
|
||||
obj.id = obj.protocol + "://" + host + ":" + obj.port + path; // define href
|
||||
|
||||
obj.href = obj.protocol + "://" + host + (loc && loc.port === obj.port ? "" : ":" + obj.port);
|
||||
return obj;
|
||||
@@ -1797,7 +1799,7 @@ Emitter.prototype.hasListeners = function (event) {
|
||||
/*! no static exports found */
|
||||
/***/ (function(module, exports, __webpack_require__) {
|
||||
|
||||
/* WEBPACK VAR INJECTION */(function(process) {/* eslint-env browser */
|
||||
/* eslint-env browser */
|
||||
|
||||
/**
|
||||
* This is the web browser implementation of `debug()`.
|
||||
@@ -1978,7 +1980,6 @@ formatters.j = function (v) {
|
||||
return '[UnexpectedJSONParseError]: ' + error.message;
|
||||
}
|
||||
};
|
||||
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../../process/browser.js */ "./node_modules/process/browser.js")))
|
||||
|
||||
/***/ }),
|
||||
|
||||
@@ -5188,224 +5189,6 @@ function queryKey(uri, query) {
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ "./node_modules/process/browser.js":
|
||||
/*!*****************************************!*\
|
||||
!*** ./node_modules/process/browser.js ***!
|
||||
\*****************************************/
|
||||
/*! no static exports found */
|
||||
/***/ (function(module, exports) {
|
||||
|
||||
// shim for using process in browser
|
||||
var process = module.exports = {}; // cached from whatever global is present so that test runners that stub it
|
||||
// don't break things. But we need to wrap it in a try catch in case it is
|
||||
// wrapped in strict mode code which doesn't define any globals. It's inside a
|
||||
// function because try/catches deoptimize in certain engines.
|
||||
|
||||
var cachedSetTimeout;
|
||||
var cachedClearTimeout;
|
||||
|
||||
function defaultSetTimout() {
|
||||
throw new Error('setTimeout has not been defined');
|
||||
}
|
||||
|
||||
function defaultClearTimeout() {
|
||||
throw new Error('clearTimeout has not been defined');
|
||||
}
|
||||
|
||||
(function () {
|
||||
try {
|
||||
if (typeof setTimeout === 'function') {
|
||||
cachedSetTimeout = setTimeout;
|
||||
} else {
|
||||
cachedSetTimeout = defaultSetTimout;
|
||||
}
|
||||
} catch (e) {
|
||||
cachedSetTimeout = defaultSetTimout;
|
||||
}
|
||||
|
||||
try {
|
||||
if (typeof clearTimeout === 'function') {
|
||||
cachedClearTimeout = clearTimeout;
|
||||
} else {
|
||||
cachedClearTimeout = defaultClearTimeout;
|
||||
}
|
||||
} catch (e) {
|
||||
cachedClearTimeout = defaultClearTimeout;
|
||||
}
|
||||
})();
|
||||
|
||||
function runTimeout(fun) {
|
||||
if (cachedSetTimeout === setTimeout) {
|
||||
//normal enviroments in sane situations
|
||||
return setTimeout(fun, 0);
|
||||
} // if setTimeout wasn't available but was latter defined
|
||||
|
||||
|
||||
if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
|
||||
cachedSetTimeout = setTimeout;
|
||||
return setTimeout(fun, 0);
|
||||
}
|
||||
|
||||
try {
|
||||
// when when somebody has screwed with setTimeout but no I.E. maddness
|
||||
return cachedSetTimeout(fun, 0);
|
||||
} catch (e) {
|
||||
try {
|
||||
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
|
||||
return cachedSetTimeout.call(null, fun, 0);
|
||||
} catch (e) {
|
||||
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
|
||||
return cachedSetTimeout.call(this, fun, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function runClearTimeout(marker) {
|
||||
if (cachedClearTimeout === clearTimeout) {
|
||||
//normal enviroments in sane situations
|
||||
return clearTimeout(marker);
|
||||
} // if clearTimeout wasn't available but was latter defined
|
||||
|
||||
|
||||
if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
|
||||
cachedClearTimeout = clearTimeout;
|
||||
return clearTimeout(marker);
|
||||
}
|
||||
|
||||
try {
|
||||
// when when somebody has screwed with setTimeout but no I.E. maddness
|
||||
return cachedClearTimeout(marker);
|
||||
} catch (e) {
|
||||
try {
|
||||
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
|
||||
return cachedClearTimeout.call(null, marker);
|
||||
} catch (e) {
|
||||
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
|
||||
// Some versions of I.E. have different rules for clearTimeout vs setTimeout
|
||||
return cachedClearTimeout.call(this, marker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var queue = [];
|
||||
var draining = false;
|
||||
var currentQueue;
|
||||
var queueIndex = -1;
|
||||
|
||||
function cleanUpNextTick() {
|
||||
if (!draining || !currentQueue) {
|
||||
return;
|
||||
}
|
||||
|
||||
draining = false;
|
||||
|
||||
if (currentQueue.length) {
|
||||
queue = currentQueue.concat(queue);
|
||||
} else {
|
||||
queueIndex = -1;
|
||||
}
|
||||
|
||||
if (queue.length) {
|
||||
drainQueue();
|
||||
}
|
||||
}
|
||||
|
||||
function drainQueue() {
|
||||
if (draining) {
|
||||
return;
|
||||
}
|
||||
|
||||
var timeout = runTimeout(cleanUpNextTick);
|
||||
draining = true;
|
||||
var len = queue.length;
|
||||
|
||||
while (len) {
|
||||
currentQueue = queue;
|
||||
queue = [];
|
||||
|
||||
while (++queueIndex < len) {
|
||||
if (currentQueue) {
|
||||
currentQueue[queueIndex].run();
|
||||
}
|
||||
}
|
||||
|
||||
queueIndex = -1;
|
||||
len = queue.length;
|
||||
}
|
||||
|
||||
currentQueue = null;
|
||||
draining = false;
|
||||
runClearTimeout(timeout);
|
||||
}
|
||||
|
||||
process.nextTick = function (fun) {
|
||||
var args = new Array(arguments.length - 1);
|
||||
|
||||
if (arguments.length > 1) {
|
||||
for (var i = 1; i < arguments.length; i++) {
|
||||
args[i - 1] = arguments[i];
|
||||
}
|
||||
}
|
||||
|
||||
queue.push(new Item(fun, args));
|
||||
|
||||
if (queue.length === 1 && !draining) {
|
||||
runTimeout(drainQueue);
|
||||
}
|
||||
}; // v8 likes predictible objects
|
||||
|
||||
|
||||
function Item(fun, array) {
|
||||
this.fun = fun;
|
||||
this.array = array;
|
||||
}
|
||||
|
||||
Item.prototype.run = function () {
|
||||
this.fun.apply(null, this.array);
|
||||
};
|
||||
|
||||
process.title = 'browser';
|
||||
process.browser = true;
|
||||
process.env = {};
|
||||
process.argv = [];
|
||||
process.version = ''; // empty string to avoid regexp issues
|
||||
|
||||
process.versions = {};
|
||||
|
||||
function noop() {}
|
||||
|
||||
process.on = noop;
|
||||
process.addListener = noop;
|
||||
process.once = noop;
|
||||
process.off = noop;
|
||||
process.removeListener = noop;
|
||||
process.removeAllListeners = noop;
|
||||
process.emit = noop;
|
||||
process.prependListener = noop;
|
||||
process.prependOnceListener = noop;
|
||||
|
||||
process.listeners = function (name) {
|
||||
return [];
|
||||
};
|
||||
|
||||
process.binding = function (name) {
|
||||
throw new Error('process.binding is not supported');
|
||||
};
|
||||
|
||||
process.cwd = function () {
|
||||
return '/';
|
||||
};
|
||||
|
||||
process.chdir = function (dir) {
|
||||
throw new Error('process.chdir is not supported');
|
||||
};
|
||||
|
||||
process.umask = function () {
|
||||
return 0;
|
||||
};
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ "./node_modules/socket.io-parser/dist/binary.js":
|
||||
/*!******************************************************!*\
|
||||
!*** ./node_modules/socket.io-parser/dist/binary.js ***!
|
||||
|
||||
File diff suppressed because one or more lines are too long
4
client-dist/socket.io.min.js
vendored
4
client-dist/socket.io.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
4
client-dist/socket.io.msgpack.min.js
vendored
4
client-dist/socket.io.msgpack.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
||||
FROM mhart/alpine-node:6
|
||||
FROM node:14-alpine
|
||||
|
||||
# Create app directory
|
||||
RUN mkdir -p /usr/src/app
|
||||
@@ -6,7 +6,7 @@ WORKDIR /usr/src/app
|
||||
|
||||
# Install app dependencies
|
||||
COPY package.json /usr/src/app/
|
||||
RUN npm install
|
||||
RUN npm install --prod
|
||||
|
||||
# Bundle app source
|
||||
COPY . /usr/src/app
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
"license": "BSD",
|
||||
"dependencies": {
|
||||
"express": "4.13.4",
|
||||
"socket.io": "^1.7.2",
|
||||
"socket.io-redis": "^3.0.0"
|
||||
"socket.io": "^3.1.0",
|
||||
"socket.io-redis": "^6.0.1"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node index.js"
|
||||
|
||||
@@ -3,6 +3,8 @@ Listen 80
|
||||
|
||||
ServerName localhost
|
||||
|
||||
LoadModule mpm_event_module modules/mod_mpm_event.so
|
||||
|
||||
LoadModule authn_file_module modules/mod_authn_file.so
|
||||
LoadModule authn_core_module modules/mod_authn_core.so
|
||||
LoadModule authz_host_module modules/mod_authz_host.so
|
||||
|
||||
@@ -6,7 +6,7 @@ WORKDIR /usr/src/app
|
||||
|
||||
# Install app dependencies
|
||||
COPY package.json /usr/src/app/
|
||||
RUN npm install
|
||||
RUN npm install --prod
|
||||
|
||||
# Bundle app source
|
||||
COPY . /usr/src/app
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
"license": "BSD",
|
||||
"dependencies": {
|
||||
"express": "4.13.4",
|
||||
"socket.io": "^1.7.2",
|
||||
"socket.io-redis": "^3.0.0"
|
||||
"socket.io": "^3.1.0",
|
||||
"socket.io-redis": "^6.0.1"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node index.js"
|
||||
|
||||
@@ -22,6 +22,16 @@ Each node connects to the redis backend, which will enable to broadcast to every
|
||||
$ docker-compose stop server-george
|
||||
```
|
||||
|
||||
A `client` container is included in the `docker-compose.yml` file, in order to test the routing.
|
||||
|
||||
You can create additional `client` containers with:
|
||||
|
||||
```
|
||||
$ docker-compose up -d --scale=client=10 client
|
||||
# and then
|
||||
$ docker-compose logs client
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Multiple users can join a chat room by each entering a unique username
|
||||
|
||||
15
examples/cluster-nginx/client/Dockerfile
Normal file
15
examples/cluster-nginx/client/Dockerfile
Normal file
@@ -0,0 +1,15 @@
|
||||
FROM node:14-alpine
|
||||
|
||||
# Create app directory
|
||||
RUN mkdir -p /usr/src/app
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
# Install app dependencies
|
||||
COPY package.json /usr/src/app/
|
||||
RUN npm install --prod
|
||||
|
||||
# Bundle app source
|
||||
COPY . /usr/src/app
|
||||
|
||||
EXPOSE 3000
|
||||
CMD [ "npm", "start" ]
|
||||
13
examples/cluster-nginx/client/index.js
Normal file
13
examples/cluster-nginx/client/index.js
Normal file
@@ -0,0 +1,13 @@
|
||||
const socket = require('socket.io-client')('ws://nginx');
|
||||
|
||||
socket.on('connect', () => {
|
||||
console.log('connected');
|
||||
});
|
||||
|
||||
socket.on('my-name-is', (serverName) => {
|
||||
console.log(`connected to ${serverName}`);
|
||||
});
|
||||
|
||||
socket.on('disconnect', (reason) => {
|
||||
console.log(`disconnected due to ${reason}`);
|
||||
});
|
||||
15
examples/cluster-nginx/client/package.json
Normal file
15
examples/cluster-nginx/client/package.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "socket.io-chat",
|
||||
"version": "0.0.0",
|
||||
"description": "A simple chat client using socket.io",
|
||||
"main": "index.js",
|
||||
"author": "Grant Timmerman",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"socket.io-client": "^3.1.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node index.js"
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,11 @@ server-ringo:
|
||||
environment:
|
||||
- NAME=Ringo
|
||||
|
||||
client:
|
||||
build: ./client
|
||||
links:
|
||||
- nginx
|
||||
|
||||
redis:
|
||||
image: redis:alpine
|
||||
expose:
|
||||
|
||||
@@ -24,8 +24,12 @@ http {
|
||||
}
|
||||
|
||||
upstream nodes {
|
||||
# enable sticky session
|
||||
ip_hash;
|
||||
# enable sticky session with either "hash" (uses the complete IP address)
|
||||
hash $remote_addr consistent;
|
||||
# or "ip_hash" (uses the first three octets of the client IPv4 address, or the entire IPv6 address)
|
||||
# ip_hash;
|
||||
# or "sticky" (needs commercial subscription)
|
||||
# sticky cookie srv_id expires=1h domain=.example.com path=/;
|
||||
|
||||
server server-john:3000;
|
||||
server server-paul:3000;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM mhart/alpine-node:6
|
||||
FROM node:14-alpine
|
||||
|
||||
# Create app directory
|
||||
RUN mkdir -p /usr/src/app
|
||||
@@ -6,7 +6,7 @@ WORKDIR /usr/src/app
|
||||
|
||||
# Install app dependencies
|
||||
COPY package.json /usr/src/app/
|
||||
RUN npm install
|
||||
RUN npm install --prod
|
||||
|
||||
# Bundle app source
|
||||
COPY . /usr/src/app
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"express": "4.13.4",
|
||||
"socket.io": "^1.7.2",
|
||||
"socket.io-redis": "^3.0.0"
|
||||
"socket.io": "^3.1.0",
|
||||
"socket.io-redis": "^6.0.1"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node index.js"
|
||||
|
||||
22
examples/cluster-traefik/README.md
Normal file
22
examples/cluster-traefik/README.md
Normal file
@@ -0,0 +1,22 @@
|
||||
|
||||
# Socket.IO Chat with traefik & [redis](https://redis.io/)
|
||||
|
||||
A simple chat demo for Socket.IO
|
||||
|
||||
## How to use
|
||||
|
||||
Install [Docker Compose](https://docs.docker.com/compose/install/), then:
|
||||
|
||||
```
|
||||
$ docker-compose up -d
|
||||
```
|
||||
|
||||
And then point your browser to `http://localhost:3000`.
|
||||
|
||||
You can then scale the server to multiple instances:
|
||||
|
||||
```
|
||||
$ docker-compose up -d --scale=server=7
|
||||
```
|
||||
|
||||
The session stickiness, which is [required](https://socket.io/docs/v3/using-multiple-nodes/) when using multiple Socket.IO server instances, is achieved with a cookie. More information [here](https://doc.traefik.io/traefik/v2.0/routing/services/#sticky-sessions).
|
||||
27
examples/cluster-traefik/docker-compose.yml
Normal file
27
examples/cluster-traefik/docker-compose.yml
Normal file
@@ -0,0 +1,27 @@
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
traefik:
|
||||
image: traefik:2.4
|
||||
volumes:
|
||||
- ./traefik.yml:/etc/traefik/traefik.yml
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
links:
|
||||
- server
|
||||
ports:
|
||||
- "3000:80"
|
||||
- "8080:8080"
|
||||
|
||||
server:
|
||||
build: ./server
|
||||
links:
|
||||
- redis
|
||||
labels:
|
||||
- "traefik.http.routers.chat.rule=PathPrefix(`/`)"
|
||||
- traefik.http.services.chat.loadBalancer.sticky.cookie.name=server_id
|
||||
- traefik.http.services.chat.loadBalancer.sticky.cookie.httpOnly=true
|
||||
|
||||
redis:
|
||||
image: redis:6-alpine
|
||||
labels:
|
||||
- traefik.enable=false
|
||||
15
examples/cluster-traefik/server/Dockerfile
Normal file
15
examples/cluster-traefik/server/Dockerfile
Normal file
@@ -0,0 +1,15 @@
|
||||
FROM node:14-alpine
|
||||
|
||||
# Create app directory
|
||||
RUN mkdir -p /usr/src/app
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
# Install app dependencies
|
||||
COPY package.json /usr/src/app/
|
||||
RUN npm install --prod
|
||||
|
||||
# Bundle app source
|
||||
COPY . /usr/src/app
|
||||
|
||||
EXPOSE 3000
|
||||
CMD [ "npm", "start" ]
|
||||
83
examples/cluster-traefik/server/index.js
Normal file
83
examples/cluster-traefik/server/index.js
Normal file
@@ -0,0 +1,83 @@
|
||||
// Setup basic express server
|
||||
var express = require('express');
|
||||
var app = express();
|
||||
var server = require('http').createServer(app);
|
||||
var io = require('socket.io')(server);
|
||||
var redis = require('socket.io-redis');
|
||||
var port = process.env.PORT || 3000;
|
||||
var crypto = require('crypto');
|
||||
var serverName = crypto.randomBytes(3).toString('hex');
|
||||
|
||||
io.adapter(redis({ host: 'redis', port: 6379 }));
|
||||
|
||||
server.listen(port, function () {
|
||||
console.log('Server listening at port %d', port);
|
||||
console.log('Hello, I\'m %s, how can I help?', serverName);
|
||||
});
|
||||
|
||||
// Routing
|
||||
app.use(express.static(__dirname + '/public'));
|
||||
|
||||
// Chatroom
|
||||
|
||||
var numUsers = 0;
|
||||
|
||||
io.on('connection', function (socket) {
|
||||
socket.emit('my-name-is', serverName);
|
||||
|
||||
var addedUser = false;
|
||||
|
||||
// when the client emits 'new message', this listens and executes
|
||||
socket.on('new message', function (data) {
|
||||
// we tell the client to execute 'new message'
|
||||
socket.broadcast.emit('new message', {
|
||||
username: socket.username,
|
||||
message: data
|
||||
});
|
||||
});
|
||||
|
||||
// when the client emits 'add user', this listens and executes
|
||||
socket.on('add user', function (username) {
|
||||
if (addedUser) return;
|
||||
|
||||
// we store the username in the socket session for this client
|
||||
socket.username = username;
|
||||
++numUsers;
|
||||
addedUser = true;
|
||||
socket.emit('login', {
|
||||
numUsers: numUsers
|
||||
});
|
||||
// echo globally (all clients) that a person has connected
|
||||
socket.broadcast.emit('user joined', {
|
||||
username: socket.username,
|
||||
numUsers: numUsers
|
||||
});
|
||||
});
|
||||
|
||||
// when the client emits 'typing', we broadcast it to others
|
||||
socket.on('typing', function () {
|
||||
socket.broadcast.emit('typing', {
|
||||
username: socket.username
|
||||
});
|
||||
});
|
||||
|
||||
// when the client emits 'stop typing', we broadcast it to others
|
||||
socket.on('stop typing', function () {
|
||||
socket.broadcast.emit('stop typing', {
|
||||
username: socket.username
|
||||
});
|
||||
});
|
||||
|
||||
// when the user disconnects.. perform this
|
||||
socket.on('disconnect', function () {
|
||||
if (addedUser) {
|
||||
--numUsers;
|
||||
|
||||
// echo globally that this client has left
|
||||
socket.broadcast.emit('user left', {
|
||||
username: socket.username,
|
||||
numUsers: numUsers
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
17
examples/cluster-traefik/server/package.json
Normal file
17
examples/cluster-traefik/server/package.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "socket.io-chat",
|
||||
"version": "0.0.0",
|
||||
"description": "A simple chat client using socket.io",
|
||||
"main": "index.js",
|
||||
"author": "Grant Timmerman",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"express": "4.13.4",
|
||||
"socket.io": "^3.1.0",
|
||||
"socket.io-redis": "^6.0.1"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node index.js"
|
||||
}
|
||||
}
|
||||
28
examples/cluster-traefik/server/public/index.html
Normal file
28
examples/cluster-traefik/server/public/index.html
Normal file
@@ -0,0 +1,28 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Socket.IO Chat Example</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body>
|
||||
<ul class="pages">
|
||||
<li class="chat page">
|
||||
<div class="chatArea">
|
||||
<ul class="messages"></ul>
|
||||
</div>
|
||||
<input class="inputMessage" placeholder="Type here..."/>
|
||||
</li>
|
||||
<li class="login page">
|
||||
<div class="form">
|
||||
<h3 class="title">What's your nickname?</h3>
|
||||
<input class="usernameInput" type="text" maxlength="14" />
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<script src="https://code.jquery.com/jquery-1.10.2.min.js"></script>
|
||||
<script src="/socket.io/socket.io.js"></script>
|
||||
<script src="/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
286
examples/cluster-traefik/server/public/main.js
Normal file
286
examples/cluster-traefik/server/public/main.js
Normal file
@@ -0,0 +1,286 @@
|
||||
$(function() {
|
||||
var FADE_TIME = 150; // ms
|
||||
var TYPING_TIMER_LENGTH = 400; // ms
|
||||
var COLORS = [
|
||||
'#e21400', '#91580f', '#f8a700', '#f78b00',
|
||||
'#58dc00', '#287b00', '#a8f07a', '#4ae8c4',
|
||||
'#3b88eb', '#3824aa', '#a700ff', '#d300e7'
|
||||
];
|
||||
|
||||
// Initialize variables
|
||||
var $window = $(window);
|
||||
var $usernameInput = $('.usernameInput'); // Input for username
|
||||
var $messages = $('.messages'); // Messages area
|
||||
var $inputMessage = $('.inputMessage'); // Input message input box
|
||||
|
||||
var $loginPage = $('.login.page'); // The login page
|
||||
var $chatPage = $('.chat.page'); // The chatroom page
|
||||
|
||||
// Prompt for setting a username
|
||||
var username;
|
||||
var connected = false;
|
||||
var typing = false;
|
||||
var lastTypingTime;
|
||||
var $currentInput = $usernameInput.focus();
|
||||
|
||||
var socket = io();
|
||||
|
||||
function addParticipantsMessage (data) {
|
||||
var message = '';
|
||||
if (data.numUsers === 1) {
|
||||
message += "there's 1 participant";
|
||||
} else {
|
||||
message += "there are " + data.numUsers + " participants";
|
||||
}
|
||||
log(message);
|
||||
}
|
||||
|
||||
// Sets the client's username
|
||||
function setUsername () {
|
||||
username = cleanInput($usernameInput.val().trim());
|
||||
|
||||
// If the username is valid
|
||||
if (username) {
|
||||
$loginPage.fadeOut();
|
||||
$chatPage.show();
|
||||
$loginPage.off('click');
|
||||
$currentInput = $inputMessage.focus();
|
||||
|
||||
// Tell the server your username
|
||||
socket.emit('add user', username);
|
||||
}
|
||||
}
|
||||
|
||||
// Sends a chat message
|
||||
function sendMessage () {
|
||||
var message = $inputMessage.val();
|
||||
// Prevent markup from being injected into the message
|
||||
message = cleanInput(message);
|
||||
// if there is a non-empty message and a socket connection
|
||||
if (message && connected) {
|
||||
$inputMessage.val('');
|
||||
addChatMessage({
|
||||
username: username,
|
||||
message: message
|
||||
});
|
||||
// tell server to execute 'new message' and send along one parameter
|
||||
socket.emit('new message', message);
|
||||
}
|
||||
}
|
||||
|
||||
// Log a message
|
||||
function log (message, options) {
|
||||
var $el = $('<li>').addClass('log').text(message);
|
||||
addMessageElement($el, options);
|
||||
}
|
||||
|
||||
// Adds the visual chat message to the message list
|
||||
function addChatMessage (data, options) {
|
||||
// Don't fade the message in if there is an 'X was typing'
|
||||
var $typingMessages = getTypingMessages(data);
|
||||
options = options || {};
|
||||
if ($typingMessages.length !== 0) {
|
||||
options.fade = false;
|
||||
$typingMessages.remove();
|
||||
}
|
||||
|
||||
var $usernameDiv = $('<span class="username"/>')
|
||||
.text(data.username)
|
||||
.css('color', getUsernameColor(data.username));
|
||||
var $messageBodyDiv = $('<span class="messageBody">')
|
||||
.text(data.message);
|
||||
|
||||
var typingClass = data.typing ? 'typing' : '';
|
||||
var $messageDiv = $('<li class="message"/>')
|
||||
.data('username', data.username)
|
||||
.addClass(typingClass)
|
||||
.append($usernameDiv, $messageBodyDiv);
|
||||
|
||||
addMessageElement($messageDiv, options);
|
||||
}
|
||||
|
||||
// Adds the visual chat typing message
|
||||
function addChatTyping (data) {
|
||||
data.typing = true;
|
||||
data.message = 'is typing';
|
||||
addChatMessage(data);
|
||||
}
|
||||
|
||||
// Removes the visual chat typing message
|
||||
function removeChatTyping (data) {
|
||||
getTypingMessages(data).fadeOut(function () {
|
||||
$(this).remove();
|
||||
});
|
||||
}
|
||||
|
||||
// Adds a message element to the messages and scrolls to the bottom
|
||||
// el - The element to add as a message
|
||||
// options.fade - If the element should fade-in (default = true)
|
||||
// options.prepend - If the element should prepend
|
||||
// all other messages (default = false)
|
||||
function addMessageElement (el, options) {
|
||||
var $el = $(el);
|
||||
|
||||
// Setup default options
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
if (typeof options.fade === 'undefined') {
|
||||
options.fade = true;
|
||||
}
|
||||
if (typeof options.prepend === 'undefined') {
|
||||
options.prepend = false;
|
||||
}
|
||||
|
||||
// Apply options
|
||||
if (options.fade) {
|
||||
$el.hide().fadeIn(FADE_TIME);
|
||||
}
|
||||
if (options.prepend) {
|
||||
$messages.prepend($el);
|
||||
} else {
|
||||
$messages.append($el);
|
||||
}
|
||||
$messages[0].scrollTop = $messages[0].scrollHeight;
|
||||
}
|
||||
|
||||
// Prevents input from having injected markup
|
||||
function cleanInput (input) {
|
||||
return $('<div/>').text(input).text();
|
||||
}
|
||||
|
||||
// Updates the typing event
|
||||
function updateTyping () {
|
||||
if (connected) {
|
||||
if (!typing) {
|
||||
typing = true;
|
||||
socket.emit('typing');
|
||||
}
|
||||
lastTypingTime = (new Date()).getTime();
|
||||
|
||||
setTimeout(function () {
|
||||
var typingTimer = (new Date()).getTime();
|
||||
var timeDiff = typingTimer - lastTypingTime;
|
||||
if (timeDiff >= TYPING_TIMER_LENGTH && typing) {
|
||||
socket.emit('stop typing');
|
||||
typing = false;
|
||||
}
|
||||
}, TYPING_TIMER_LENGTH);
|
||||
}
|
||||
}
|
||||
|
||||
// Gets the 'X is typing' messages of a user
|
||||
function getTypingMessages (data) {
|
||||
return $('.typing.message').filter(function (i) {
|
||||
return $(this).data('username') === data.username;
|
||||
});
|
||||
}
|
||||
|
||||
// Gets the color of a username through our hash function
|
||||
function getUsernameColor (username) {
|
||||
// Compute hash code
|
||||
var hash = 7;
|
||||
for (var i = 0; i < username.length; i++) {
|
||||
hash = username.charCodeAt(i) + (hash << 5) - hash;
|
||||
}
|
||||
// Calculate color
|
||||
var index = Math.abs(hash % COLORS.length);
|
||||
return COLORS[index];
|
||||
}
|
||||
|
||||
// Keyboard events
|
||||
|
||||
$window.keydown(function (event) {
|
||||
// Auto-focus the current input when a key is typed
|
||||
if (!(event.ctrlKey || event.metaKey || event.altKey)) {
|
||||
$currentInput.focus();
|
||||
}
|
||||
// When the client hits ENTER on their keyboard
|
||||
if (event.which === 13) {
|
||||
if (username) {
|
||||
sendMessage();
|
||||
socket.emit('stop typing');
|
||||
typing = false;
|
||||
} else {
|
||||
setUsername();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$inputMessage.on('input', function() {
|
||||
updateTyping();
|
||||
});
|
||||
|
||||
// Click events
|
||||
|
||||
// Focus input when clicking anywhere on login page
|
||||
$loginPage.click(function () {
|
||||
$currentInput.focus();
|
||||
});
|
||||
|
||||
// Focus input when clicking on the message input's border
|
||||
$inputMessage.click(function () {
|
||||
$inputMessage.focus();
|
||||
});
|
||||
|
||||
// Socket events
|
||||
|
||||
// Whenever the server emits 'login', log the login message
|
||||
socket.on('login', function (data) {
|
||||
connected = true;
|
||||
// Display the welcome message
|
||||
var message = "Welcome to Socket.IO Chat – ";
|
||||
log(message, {
|
||||
prepend: true
|
||||
});
|
||||
addParticipantsMessage(data);
|
||||
});
|
||||
|
||||
// Whenever the server emits 'new message', update the chat body
|
||||
socket.on('new message', function (data) {
|
||||
addChatMessage(data);
|
||||
});
|
||||
|
||||
// Whenever the server emits 'user joined', log it in the chat body
|
||||
socket.on('user joined', function (data) {
|
||||
log(data.username + ' joined');
|
||||
addParticipantsMessage(data);
|
||||
});
|
||||
|
||||
// Whenever the server emits 'user left', log it in the chat body
|
||||
socket.on('user left', function (data) {
|
||||
log(data.username + ' left');
|
||||
addParticipantsMessage(data);
|
||||
removeChatTyping(data);
|
||||
});
|
||||
|
||||
// Whenever the server emits 'typing', show the typing message
|
||||
socket.on('typing', function (data) {
|
||||
addChatTyping(data);
|
||||
});
|
||||
|
||||
// Whenever the server emits 'stop typing', kill the typing message
|
||||
socket.on('stop typing', function (data) {
|
||||
removeChatTyping(data);
|
||||
});
|
||||
|
||||
socket.on('disconnect', function () {
|
||||
log('you have been disconnected');
|
||||
});
|
||||
|
||||
socket.on('connect', function () {
|
||||
if (username) {
|
||||
log('you have been reconnected');
|
||||
socket.emit('add user', username);
|
||||
}
|
||||
});
|
||||
|
||||
socket.io.on('reconnect_error', function () {
|
||||
log('attempt to reconnect has failed');
|
||||
});
|
||||
|
||||
socket.on('my-name-is', function (serverName) {
|
||||
log('host is now ' + serverName);
|
||||
})
|
||||
|
||||
});
|
||||
149
examples/cluster-traefik/server/public/style.css
Normal file
149
examples/cluster-traefik/server/public/style.css
Normal file
@@ -0,0 +1,149 @@
|
||||
/* Fix user-agent */
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
font-weight: 300;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
html, input {
|
||||
font-family:
|
||||
"HelveticaNeue-Light",
|
||||
"Helvetica Neue Light",
|
||||
"Helvetica Neue",
|
||||
Helvetica,
|
||||
Arial,
|
||||
"Lucida Grande",
|
||||
sans-serif;
|
||||
}
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
/* Pages */
|
||||
|
||||
.pages {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.page {
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Login Page */
|
||||
|
||||
.login.page {
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
.login.page .form {
|
||||
height: 100px;
|
||||
margin-top: -100px;
|
||||
position: absolute;
|
||||
|
||||
text-align: center;
|
||||
top: 50%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.login.page .form .usernameInput {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
border-bottom: 2px solid #fff;
|
||||
outline: none;
|
||||
padding-bottom: 15px;
|
||||
text-align: center;
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
.login.page .title {
|
||||
font-size: 200%;
|
||||
}
|
||||
|
||||
.login.page .usernameInput {
|
||||
font-size: 200%;
|
||||
letter-spacing: 3px;
|
||||
}
|
||||
|
||||
.login.page .title, .login.page .usernameInput {
|
||||
color: #fff;
|
||||
font-weight: 100;
|
||||
}
|
||||
|
||||
/* Chat page */
|
||||
|
||||
.chat.page {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Font */
|
||||
|
||||
.messages {
|
||||
font-size: 150%;
|
||||
}
|
||||
|
||||
.inputMessage {
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
.log {
|
||||
color: gray;
|
||||
font-size: 70%;
|
||||
margin: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Messages */
|
||||
|
||||
.chatArea {
|
||||
height: 100%;
|
||||
padding-bottom: 60px;
|
||||
}
|
||||
|
||||
.messages {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
overflow-y: scroll;
|
||||
padding: 10px 20px 10px 20px;
|
||||
}
|
||||
|
||||
.message.typing .messageBody {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.username {
|
||||
font-weight: 700;
|
||||
overflow: hidden;
|
||||
padding-right: 15px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* Input */
|
||||
|
||||
.inputMessage {
|
||||
border: 10px solid #000;
|
||||
bottom: 0;
|
||||
height: 60px;
|
||||
left: 0;
|
||||
outline: none;
|
||||
padding-left: 10px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
}
|
||||
10
examples/cluster-traefik/traefik.yml
Normal file
10
examples/cluster-traefik/traefik.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
api:
|
||||
insecure: true
|
||||
|
||||
entryPoints:
|
||||
web:
|
||||
address: ":80"
|
||||
|
||||
providers:
|
||||
docker: {}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Decoder, Encoder, Packet, PacketType } from "socket.io-parser";
|
||||
import debugModule = require("debug");
|
||||
import url = require("url");
|
||||
import type { IncomingMessage } from "http";
|
||||
import type { Namespace, Server } from "./index";
|
||||
import type { Socket } from "./socket";
|
||||
@@ -77,7 +78,7 @@ export class Client {
|
||||
* @param {Object} auth - the auth parameters
|
||||
* @private
|
||||
*/
|
||||
private connect(name: string, auth: object = {}) {
|
||||
private connect(name: string, auth: object = {}): void {
|
||||
if (this.server._nsps.has(name)) {
|
||||
debug("connecting to namespace %s", name);
|
||||
return this.doConnect(name, auth);
|
||||
@@ -112,7 +113,7 @@ export class Client {
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
private doConnect(name: string, auth: object) {
|
||||
private doConnect(name: string, auth: object): void {
|
||||
const nsp = this.server.of(name);
|
||||
|
||||
const socket = nsp._add(this, auth, () => {
|
||||
@@ -131,7 +132,7 @@ export class Client {
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_disconnect() {
|
||||
_disconnect(): void {
|
||||
for (const socket of this.sockets.values()) {
|
||||
socket.disconnect();
|
||||
}
|
||||
@@ -144,7 +145,7 @@ export class Client {
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_remove(socket: Socket) {
|
||||
_remove(socket: Socket): void {
|
||||
if (this.sockets.has(socket.id)) {
|
||||
const nsp = this.sockets.get(socket.id)!.nsp.name;
|
||||
this.sockets.delete(socket.id);
|
||||
@@ -159,7 +160,7 @@ export class Client {
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
private close() {
|
||||
private close(): void {
|
||||
if ("open" === this.conn.readyState) {
|
||||
debug("forcing transport close");
|
||||
this.conn.close();
|
||||
@@ -174,12 +175,13 @@ export class Client {
|
||||
* @param {Object} opts
|
||||
* @private
|
||||
*/
|
||||
_packet(packet, opts?) {
|
||||
_packet(packet: Packet, opts?: any): void {
|
||||
opts = opts || {};
|
||||
const self = this;
|
||||
|
||||
// this writes to the actual connection
|
||||
function writeToEngine(encodedPackets) {
|
||||
function writeToEngine(encodedPackets: any) {
|
||||
// TODO clarify this.
|
||||
if (opts.volatile && !self.conn.transport.writable) return;
|
||||
for (let i = 0; i < encodedPackets.length; i++) {
|
||||
self.conn.write(encodedPackets[i], { compress: opts.compress });
|
||||
@@ -205,7 +207,7 @@ export class Client {
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
private ondata(data) {
|
||||
private ondata(data): void {
|
||||
// try/catch is needed for protocol violations (GH-1880)
|
||||
try {
|
||||
this.decoder.add(data);
|
||||
@@ -219,9 +221,14 @@ export class Client {
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
private ondecoded(packet: Packet) {
|
||||
private ondecoded(packet: Packet): void {
|
||||
if (PacketType.CONNECT === packet.type) {
|
||||
this.connect(packet.nsp, packet.data);
|
||||
if (this.conn.protocol === 3) {
|
||||
const parsed = url.parse(packet.nsp, true);
|
||||
this.connect(parsed.pathname!, parsed.query);
|
||||
} else {
|
||||
this.connect(packet.nsp, packet.data);
|
||||
}
|
||||
} else {
|
||||
const socket = this.nsps.get(packet.nsp);
|
||||
if (socket) {
|
||||
@@ -240,7 +247,7 @@ export class Client {
|
||||
* @param {Object} err object
|
||||
* @private
|
||||
*/
|
||||
private onerror(err) {
|
||||
private onerror(err): void {
|
||||
for (const socket of this.sockets.values()) {
|
||||
socket._onerror(err);
|
||||
}
|
||||
@@ -253,7 +260,7 @@ export class Client {
|
||||
* @param reason
|
||||
* @private
|
||||
*/
|
||||
private onclose(reason: string) {
|
||||
private onclose(reason: string): void {
|
||||
debug("client close with reason %s", reason);
|
||||
|
||||
// ignore a potential subsequent `close` event
|
||||
@@ -272,7 +279,7 @@ export class Client {
|
||||
* Cleans up event listeners.
|
||||
* @private
|
||||
*/
|
||||
private destroy() {
|
||||
private destroy(): void {
|
||||
this.conn.removeListener("data", this.ondata);
|
||||
this.conn.removeListener("error", this.onerror);
|
||||
this.conn.removeListener("close", this.onclose);
|
||||
|
||||
71
lib/index.ts
71
lib/index.ts
@@ -25,7 +25,7 @@ const dotMapRegex = /\.map/;
|
||||
type Transport = "polling" | "websocket";
|
||||
type ParentNspNameMatchFn = (
|
||||
name: string,
|
||||
query: object,
|
||||
auth: { [key: string]: any },
|
||||
fn: (err: Error | null, success: boolean) => void
|
||||
) => void;
|
||||
|
||||
@@ -191,6 +191,10 @@ export class Server extends EventEmitter {
|
||||
*/
|
||||
constructor(opts?: Partial<ServerOptions>);
|
||||
constructor(srv?: http.Server | number, opts?: Partial<ServerOptions>);
|
||||
constructor(
|
||||
srv: undefined | Partial<ServerOptions> | http.Server | number,
|
||||
opts?: Partial<ServerOptions>
|
||||
);
|
||||
constructor(
|
||||
srv: undefined | Partial<ServerOptions> | http.Server | number,
|
||||
opts: Partial<ServerOptions> = {}
|
||||
@@ -222,9 +226,10 @@ export class Server extends EventEmitter {
|
||||
* @return self when setting or value when getting
|
||||
* @public
|
||||
*/
|
||||
public serveClient(v: boolean): Server;
|
||||
public serveClient(v: boolean): this;
|
||||
public serveClient(): boolean;
|
||||
public serveClient(v?: boolean): Server | boolean {
|
||||
public serveClient(v?: boolean): this | boolean;
|
||||
public serveClient(v?: boolean): this | boolean {
|
||||
if (!arguments.length) return this._serveClient;
|
||||
this._serveClient = v!;
|
||||
return this;
|
||||
@@ -234,16 +239,16 @@ export class Server extends EventEmitter {
|
||||
* Executes the middleware for an incoming namespace not already created on the server.
|
||||
*
|
||||
* @param name - name of incoming namespace
|
||||
* @param {Object} auth - the auth parameters
|
||||
* @param auth - the auth parameters
|
||||
* @param fn - callback
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_checkNamespace(
|
||||
name: string,
|
||||
auth: object,
|
||||
auth: { [key: string]: any },
|
||||
fn: (nsp: Namespace | false) => void
|
||||
) {
|
||||
): void {
|
||||
if (this.parentNsps.size === 0) return fn(false);
|
||||
|
||||
const keysIterator = this.parentNsps.keys();
|
||||
@@ -272,9 +277,10 @@ export class Server extends EventEmitter {
|
||||
* @return {Server|String} self when setting or value when getting
|
||||
* @public
|
||||
*/
|
||||
public path(v: string): Server;
|
||||
public path(v: string): this;
|
||||
public path(): string;
|
||||
public path(v?: string): Server | string {
|
||||
public path(v?: string): this | string;
|
||||
public path(v?: string): this | string {
|
||||
if (!arguments.length) return this._path;
|
||||
|
||||
this._path = v!.replace(/\/$/, "");
|
||||
@@ -293,9 +299,10 @@ export class Server extends EventEmitter {
|
||||
* @param v
|
||||
* @public
|
||||
*/
|
||||
public connectTimeout(v: number): Server;
|
||||
public connectTimeout(v: number): this;
|
||||
public connectTimeout(): number;
|
||||
public connectTimeout(v?: number): Server | number {
|
||||
public connectTimeout(v?: number): this | number;
|
||||
public connectTimeout(v?: number): this | number {
|
||||
if (v === undefined) return this._connectTimeout;
|
||||
this._connectTimeout = v;
|
||||
return this;
|
||||
@@ -309,8 +316,9 @@ export class Server extends EventEmitter {
|
||||
* @public
|
||||
*/
|
||||
public adapter(): typeof Adapter | undefined;
|
||||
public adapter(v: typeof Adapter): Server;
|
||||
public adapter(v?: typeof Adapter): typeof Adapter | undefined | Server {
|
||||
public adapter(v: typeof Adapter): this;
|
||||
public adapter(v?: typeof Adapter): typeof Adapter | undefined | this;
|
||||
public adapter(v?: typeof Adapter): typeof Adapter | undefined | this {
|
||||
if (!arguments.length) return this._adapter;
|
||||
this._adapter = v;
|
||||
for (const nsp of this._nsps.values()) {
|
||||
@@ -330,7 +338,7 @@ export class Server extends EventEmitter {
|
||||
public listen(
|
||||
srv: http.Server | number,
|
||||
opts: Partial<ServerOptions> = {}
|
||||
): Server {
|
||||
): this {
|
||||
return this.attach(srv, opts);
|
||||
}
|
||||
|
||||
@@ -345,7 +353,7 @@ export class Server extends EventEmitter {
|
||||
public attach(
|
||||
srv: http.Server | number,
|
||||
opts: Partial<ServerOptions> = {}
|
||||
): Server {
|
||||
): this {
|
||||
if ("function" == typeof srv) {
|
||||
const msg =
|
||||
"You are trying to attach socket.io to an express " +
|
||||
@@ -385,7 +393,10 @@ export class Server extends EventEmitter {
|
||||
* @param opts - options passed to engine.io
|
||||
* @private
|
||||
*/
|
||||
private initEngine(srv: http.Server, opts: Partial<EngineAttachOptions>) {
|
||||
private initEngine(
|
||||
srv: http.Server,
|
||||
opts: Partial<EngineAttachOptions>
|
||||
): void {
|
||||
// initialize engine
|
||||
debug("creating engine.io instance with opts %j", opts);
|
||||
this.eio = engine.attach(srv, opts);
|
||||
@@ -406,7 +417,7 @@ export class Server extends EventEmitter {
|
||||
* @param srv http server
|
||||
* @private
|
||||
*/
|
||||
private attachServe(srv: http.Server) {
|
||||
private attachServe(srv: http.Server): void {
|
||||
debug("attaching client serving req handler");
|
||||
|
||||
const evs = srv.listeners("request").slice(0);
|
||||
@@ -429,7 +440,7 @@ export class Server extends EventEmitter {
|
||||
* @param res
|
||||
* @private
|
||||
*/
|
||||
private serve(req: http.IncomingMessage, res: http.ServerResponse) {
|
||||
private serve(req: http.IncomingMessage, res: http.ServerResponse): void {
|
||||
const filename = req.url!.replace(this._path, "");
|
||||
const isMap = dotMapRegex.test(filename);
|
||||
const type = isMap ? "map" : "source";
|
||||
@@ -474,7 +485,7 @@ export class Server extends EventEmitter {
|
||||
filename: string,
|
||||
req: http.IncomingMessage,
|
||||
res: http.ServerResponse
|
||||
) {
|
||||
): void {
|
||||
const readStream = createReadStream(
|
||||
path.join(__dirname, "../client-dist/", filename)
|
||||
);
|
||||
@@ -513,7 +524,7 @@ export class Server extends EventEmitter {
|
||||
* @return self
|
||||
* @public
|
||||
*/
|
||||
public bind(engine): Server {
|
||||
public bind(engine): this {
|
||||
this.engine = engine;
|
||||
this.engine.on("connection", this.onconnection.bind(this));
|
||||
return this;
|
||||
@@ -526,7 +537,7 @@ export class Server extends EventEmitter {
|
||||
* @return self
|
||||
* @private
|
||||
*/
|
||||
private onconnection(conn): Server {
|
||||
private onconnection(conn): this {
|
||||
debug("incoming connection with id %s", conn.id);
|
||||
const client = new Client(this, conn);
|
||||
if (conn.protocol === 3) {
|
||||
@@ -540,13 +551,13 @@ export class Server extends EventEmitter {
|
||||
* Looks up a namespace.
|
||||
*
|
||||
* @param {String|RegExp|Function} name nsp name
|
||||
* @param [fn] optional, nsp `connection` ev handler
|
||||
* @param fn optional, nsp `connection` ev handler
|
||||
* @public
|
||||
*/
|
||||
public of(
|
||||
name: string | RegExp | ParentNspNameMatchFn,
|
||||
fn?: (socket: Socket) => void
|
||||
) {
|
||||
): Namespace {
|
||||
if (typeof name === "function" || name instanceof RegExp) {
|
||||
const parentNsp = new ParentNamespace(this);
|
||||
debug("initializing parent namespace %s", parentNsp.name);
|
||||
@@ -605,7 +616,7 @@ export class Server extends EventEmitter {
|
||||
*/
|
||||
public use(
|
||||
fn: (socket: Socket, next: (err?: ExtendedError) => void) => void
|
||||
): Server {
|
||||
): this {
|
||||
this.sockets.use(fn);
|
||||
return this;
|
||||
}
|
||||
@@ -617,7 +628,7 @@ export class Server extends EventEmitter {
|
||||
* @return self
|
||||
* @public
|
||||
*/
|
||||
public to(name: Room): Server {
|
||||
public to(name: Room): this {
|
||||
this.sockets.to(name);
|
||||
return this;
|
||||
}
|
||||
@@ -629,7 +640,7 @@ export class Server extends EventEmitter {
|
||||
* @return self
|
||||
* @public
|
||||
*/
|
||||
public in(name: Room): Server {
|
||||
public in(name: Room): this {
|
||||
this.sockets.in(name);
|
||||
return this;
|
||||
}
|
||||
@@ -640,7 +651,7 @@ export class Server extends EventEmitter {
|
||||
* @return self
|
||||
* @public
|
||||
*/
|
||||
public send(...args: readonly any[]): Server {
|
||||
public send(...args: readonly any[]): this {
|
||||
this.sockets.emit("message", ...args);
|
||||
return this;
|
||||
}
|
||||
@@ -651,7 +662,7 @@ export class Server extends EventEmitter {
|
||||
* @return self
|
||||
* @public
|
||||
*/
|
||||
public write(...args: readonly any[]): Server {
|
||||
public write(...args: readonly any[]): this {
|
||||
this.sockets.emit("message", ...args);
|
||||
return this;
|
||||
}
|
||||
@@ -672,7 +683,7 @@ export class Server extends EventEmitter {
|
||||
* @return self
|
||||
* @public
|
||||
*/
|
||||
public compress(compress: boolean): Server {
|
||||
public compress(compress: boolean): this {
|
||||
this.sockets.compress(compress);
|
||||
return this;
|
||||
}
|
||||
@@ -685,7 +696,7 @@ export class Server extends EventEmitter {
|
||||
* @return self
|
||||
* @public
|
||||
*/
|
||||
public get volatile(): Server {
|
||||
public get volatile(): this {
|
||||
this.sockets.volatile;
|
||||
return this;
|
||||
}
|
||||
@@ -696,7 +707,7 @@ export class Server extends EventEmitter {
|
||||
* @return self
|
||||
* @public
|
||||
*/
|
||||
public get local(): Server {
|
||||
public get local(): this {
|
||||
this.sockets.local;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ export class Namespace extends EventEmitter {
|
||||
*/
|
||||
public use(
|
||||
fn: (socket: Socket, next: (err?: ExtendedError) => void) => void
|
||||
): Namespace {
|
||||
): this {
|
||||
this._fns.push(fn);
|
||||
return this;
|
||||
}
|
||||
@@ -106,7 +106,7 @@ export class Namespace extends EventEmitter {
|
||||
* @return self
|
||||
* @public
|
||||
*/
|
||||
public to(name: Room): Namespace {
|
||||
public to(name: Room): this {
|
||||
this._rooms.add(name);
|
||||
return this;
|
||||
}
|
||||
@@ -118,7 +118,7 @@ export class Namespace extends EventEmitter {
|
||||
* @return self
|
||||
* @public
|
||||
*/
|
||||
public in(name: Room): Namespace {
|
||||
public in(name: Room): this {
|
||||
this._rooms.add(name);
|
||||
return this;
|
||||
}
|
||||
@@ -222,7 +222,7 @@ export class Namespace extends EventEmitter {
|
||||
* @return self
|
||||
* @public
|
||||
*/
|
||||
public send(...args: readonly any[]): Namespace {
|
||||
public send(...args: readonly any[]): this {
|
||||
this.emit("message", ...args);
|
||||
return this;
|
||||
}
|
||||
@@ -233,7 +233,7 @@ export class Namespace extends EventEmitter {
|
||||
* @return self
|
||||
* @public
|
||||
*/
|
||||
public write(...args: readonly any[]): Namespace {
|
||||
public write(...args: readonly any[]): this {
|
||||
this.emit("message", ...args);
|
||||
return this;
|
||||
}
|
||||
@@ -262,7 +262,7 @@ export class Namespace extends EventEmitter {
|
||||
* @return self
|
||||
* @public
|
||||
*/
|
||||
public compress(compress: boolean): Namespace {
|
||||
public compress(compress: boolean): this {
|
||||
this._flags.compress = compress;
|
||||
return this;
|
||||
}
|
||||
@@ -275,7 +275,7 @@ export class Namespace extends EventEmitter {
|
||||
* @return self
|
||||
* @public
|
||||
*/
|
||||
public get volatile(): Namespace {
|
||||
public get volatile(): this {
|
||||
this._flags.volatile = true;
|
||||
return this;
|
||||
}
|
||||
@@ -286,7 +286,7 @@ export class Namespace extends EventEmitter {
|
||||
* @return self
|
||||
* @public
|
||||
*/
|
||||
public get local(): Namespace {
|
||||
public get local(): this {
|
||||
this._flags.local = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { EventEmitter } from "events";
|
||||
import { PacketType } from "socket.io-parser";
|
||||
import { Packet, PacketType } from "socket.io-parser";
|
||||
import url = require("url");
|
||||
import debugModule from "debug";
|
||||
import type { Server } from "./index";
|
||||
import type { Client } from "./client";
|
||||
import type { Namespace } from "./namespace";
|
||||
import type { IncomingMessage } from "http";
|
||||
import type { IncomingMessage, IncomingHttpHeaders } from "http";
|
||||
import type {
|
||||
Adapter,
|
||||
BroadcastFlags,
|
||||
@@ -13,6 +13,7 @@ import type {
|
||||
SocketId,
|
||||
} from "socket.io-adapter";
|
||||
import base64id from "base64id";
|
||||
import type { ParsedUrlQuery } from "querystring";
|
||||
|
||||
const debug = debugModule("socket.io:socket");
|
||||
|
||||
@@ -33,7 +34,7 @@ export interface Handshake {
|
||||
/**
|
||||
* The headers sent as part of the handshake
|
||||
*/
|
||||
headers: object;
|
||||
headers: IncomingHttpHeaders;
|
||||
|
||||
/**
|
||||
* The date of creation (as string)
|
||||
@@ -68,12 +69,12 @@ export interface Handshake {
|
||||
/**
|
||||
* The query object
|
||||
*/
|
||||
query: object;
|
||||
query: ParsedUrlQuery;
|
||||
|
||||
/**
|
||||
* The auth object
|
||||
*/
|
||||
auth: object;
|
||||
auth: { [key: string]: any };
|
||||
}
|
||||
|
||||
export class Socket extends EventEmitter {
|
||||
@@ -190,7 +191,7 @@ export class Socket extends EventEmitter {
|
||||
* @return self
|
||||
* @public
|
||||
*/
|
||||
public to(name: Room): Socket {
|
||||
public to(name: Room): this {
|
||||
this._rooms.add(name);
|
||||
return this;
|
||||
}
|
||||
@@ -202,7 +203,7 @@ export class Socket extends EventEmitter {
|
||||
* @return self
|
||||
* @public
|
||||
*/
|
||||
public in(name: Room): Socket {
|
||||
public in(name: Room): this {
|
||||
this._rooms.add(name);
|
||||
return this;
|
||||
}
|
||||
@@ -213,7 +214,7 @@ export class Socket extends EventEmitter {
|
||||
* @return self
|
||||
* @public
|
||||
*/
|
||||
public send(...args: readonly any[]): Socket {
|
||||
public send(...args: readonly any[]): this {
|
||||
this.emit("message", ...args);
|
||||
return this;
|
||||
}
|
||||
@@ -224,7 +225,7 @@ export class Socket extends EventEmitter {
|
||||
* @return self
|
||||
* @public
|
||||
*/
|
||||
public write(...args: readonly any[]): Socket {
|
||||
public write(...args: readonly any[]): this {
|
||||
this.emit("message", ...args);
|
||||
return this;
|
||||
}
|
||||
@@ -236,10 +237,13 @@ export class Socket extends EventEmitter {
|
||||
* @param {Object} opts - options
|
||||
* @private
|
||||
*/
|
||||
private packet(packet, opts: any = {}) {
|
||||
private packet(
|
||||
packet: Omit<Packet, "nsp"> & Partial<Pick<Packet, "nsp">>,
|
||||
opts: any = {}
|
||||
): void {
|
||||
packet.nsp = this.nsp.name;
|
||||
opts.compress = false !== opts.compress;
|
||||
this.client._packet(packet, opts);
|
||||
this.client._packet(packet as Packet, opts);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -304,7 +308,7 @@ export class Socket extends EventEmitter {
|
||||
* @param {Object} packet
|
||||
* @private
|
||||
*/
|
||||
_onpacket(packet) {
|
||||
_onpacket(packet: Packet): void {
|
||||
debug("got packet %j", packet);
|
||||
switch (packet.type) {
|
||||
case PacketType.EVENT:
|
||||
@@ -335,10 +339,10 @@ export class Socket extends EventEmitter {
|
||||
/**
|
||||
* Called upon event packet.
|
||||
*
|
||||
* @param {Object} packet - packet object
|
||||
* @param {Packet} packet - packet object
|
||||
* @private
|
||||
*/
|
||||
private onevent(packet): void {
|
||||
private onevent(packet: Packet): void {
|
||||
const args = packet.data || [];
|
||||
debug("emitting event %j", args);
|
||||
|
||||
@@ -362,7 +366,7 @@ export class Socket extends EventEmitter {
|
||||
* @param {Number} id - packet id
|
||||
* @private
|
||||
*/
|
||||
private ack(id: number) {
|
||||
private ack(id: number): () => void {
|
||||
const self = this;
|
||||
let sent = false;
|
||||
return function () {
|
||||
@@ -386,12 +390,12 @@ export class Socket extends EventEmitter {
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
private onack(packet): void {
|
||||
const ack = this.acks.get(packet.id);
|
||||
private onack(packet: Packet): void {
|
||||
const ack = this.acks.get(packet.id!);
|
||||
if ("function" == typeof ack) {
|
||||
debug("calling ack %s with %j", packet.id, packet.data);
|
||||
ack.apply(this, packet.data);
|
||||
this.acks.delete(packet.id);
|
||||
this.acks.delete(packet.id!);
|
||||
} else {
|
||||
debug("bad ack %s", packet.id);
|
||||
}
|
||||
@@ -429,7 +433,7 @@ export class Socket extends EventEmitter {
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_onclose(reason: string): Socket | undefined {
|
||||
_onclose(reason: string): this | undefined {
|
||||
if (!this.connected) return this;
|
||||
debug("closing socket - reason %s", reason);
|
||||
super.emit("disconnecting", reason);
|
||||
@@ -449,7 +453,7 @@ export class Socket extends EventEmitter {
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_error(err) {
|
||||
_error(err): void {
|
||||
this.packet({ type: PacketType.CONNECT_ERROR, data: err });
|
||||
}
|
||||
|
||||
@@ -461,7 +465,7 @@ export class Socket extends EventEmitter {
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
public disconnect(close = false): Socket {
|
||||
public disconnect(close = false): this {
|
||||
if (!this.connected) return this;
|
||||
if (close) {
|
||||
this.client._disconnect();
|
||||
@@ -479,7 +483,7 @@ export class Socket extends EventEmitter {
|
||||
* @return {Socket} self
|
||||
* @public
|
||||
*/
|
||||
public compress(compress: boolean): Socket {
|
||||
public compress(compress: boolean): this {
|
||||
this.flags.compress = compress;
|
||||
return this;
|
||||
}
|
||||
@@ -492,7 +496,7 @@ export class Socket extends EventEmitter {
|
||||
* @return {Socket} self
|
||||
* @public
|
||||
*/
|
||||
public get volatile(): Socket {
|
||||
public get volatile(): this {
|
||||
this.flags.volatile = true;
|
||||
return this;
|
||||
}
|
||||
@@ -504,7 +508,7 @@ export class Socket extends EventEmitter {
|
||||
* @return {Socket} self
|
||||
* @public
|
||||
*/
|
||||
public get broadcast(): Socket {
|
||||
public get broadcast(): this {
|
||||
this.flags.broadcast = true;
|
||||
return this;
|
||||
}
|
||||
@@ -515,7 +519,7 @@ export class Socket extends EventEmitter {
|
||||
* @return {Socket} self
|
||||
* @public
|
||||
*/
|
||||
public get local(): Socket {
|
||||
public get local(): this {
|
||||
this.flags.local = true;
|
||||
return this;
|
||||
}
|
||||
@@ -526,7 +530,7 @@ export class Socket extends EventEmitter {
|
||||
* @param {Array} event - event that will get emitted
|
||||
* @private
|
||||
*/
|
||||
private dispatch(event): void {
|
||||
private dispatch(event: [eventName: string, ...args: any[]]): void {
|
||||
debug("dispatching an event %j", event);
|
||||
this.run(event, (err) => {
|
||||
process.nextTick(() => {
|
||||
@@ -547,7 +551,7 @@ export class Socket extends EventEmitter {
|
||||
*/
|
||||
public use(
|
||||
fn: (event: Array<any>, next: (err: Error) => void) => void
|
||||
): Socket {
|
||||
): this {
|
||||
this.fns.push(fn);
|
||||
return this;
|
||||
}
|
||||
@@ -559,11 +563,14 @@ export class Socket extends EventEmitter {
|
||||
* @param {Function} fn - last fn call in the middleware
|
||||
* @private
|
||||
*/
|
||||
private run(event: Array<any>, fn: (err: Error | null) => void) {
|
||||
private run(
|
||||
event: [eventName: string, ...args: any[]],
|
||||
fn: (err: Error | null) => void
|
||||
): void {
|
||||
const fns = this.fns.slice(0);
|
||||
if (!fns.length) return fn(null);
|
||||
|
||||
function run(i) {
|
||||
function run(i: number) {
|
||||
fns[i](event, function (err) {
|
||||
// upon error, short-circuit
|
||||
if (err) return fn(err);
|
||||
@@ -611,7 +618,7 @@ export class Socket extends EventEmitter {
|
||||
* @param listener
|
||||
* @public
|
||||
*/
|
||||
public onAny(listener: (...args: any[]) => void): Socket {
|
||||
public onAny(listener: (...args: any[]) => void): this {
|
||||
this._anyListeners = this._anyListeners || [];
|
||||
this._anyListeners.push(listener);
|
||||
return this;
|
||||
@@ -624,7 +631,7 @@ export class Socket extends EventEmitter {
|
||||
* @param listener
|
||||
* @public
|
||||
*/
|
||||
public prependAny(listener: (...args: any[]) => void): Socket {
|
||||
public prependAny(listener: (...args: any[]) => void): this {
|
||||
this._anyListeners = this._anyListeners || [];
|
||||
this._anyListeners.unshift(listener);
|
||||
return this;
|
||||
@@ -636,7 +643,7 @@ export class Socket extends EventEmitter {
|
||||
* @param listener
|
||||
* @public
|
||||
*/
|
||||
public offAny(listener?: (...args: any[]) => void): Socket {
|
||||
public offAny(listener?: (...args: any[]) => void): this {
|
||||
if (!this._anyListeners) {
|
||||
return this;
|
||||
}
|
||||
|
||||
14
package-lock.json
generated
14
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "socket.io",
|
||||
"version": "3.1.0",
|
||||
"version": "3.1.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -874,9 +874,9 @@
|
||||
}
|
||||
},
|
||||
"engine.io-client": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-4.1.0.tgz",
|
||||
"integrity": "sha512-OUmn4m71/lW3ixICv4h3DuBRuh3ri0w3cDuepjsrINSbbqbni4Xw1shTFiKhl0v58lEtNpwJTpSKJJ3fondu5Q==",
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-4.1.1.tgz",
|
||||
"integrity": "sha512-iYasV/EttP/2pLrdowe9G3zwlNIFhwny8VSIh+vPlMnYZqSzLsTzSLa9hFy015OrH1s4fzoYxeHjVkO8hSFKwg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"base64-arraybuffer": "0.1.4",
|
||||
@@ -2258,9 +2258,9 @@
|
||||
"integrity": "sha512-+vDov/aTsLjViYTwS9fPy5pEtTkrbEKsw2M+oVSoFGw6OD1IpvlV1VPhUzNbofCQ8oyMbdYJqDtGdmHQK6TdPg=="
|
||||
},
|
||||
"socket.io-client": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-3.1.0.tgz",
|
||||
"integrity": "sha512-T4qPOL80KnoBwkdR70zMpiR6aH6zv3ZqLNriofHqsO9wvQllNTOez0mpV4GdVqo1Y55Z+h8YOlBo7c8pOxDlHw==",
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-3.1.1.tgz",
|
||||
"integrity": "sha512-BLgIuCjI7Sf3mDHunKddX9zKR/pbkP7IACM3sJS3jha+zJ6/pGKRV6Fz5XSBHCfUs9YzT8kYIqNwOOuFNLtnYA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/component-emitter": "^1.2.10",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "socket.io",
|
||||
"version": "3.1.0",
|
||||
"version": "3.1.1",
|
||||
"description": "node.js realtime framework server",
|
||||
"keywords": [
|
||||
"realtime",
|
||||
@@ -63,7 +63,7 @@
|
||||
"nyc": "^15.1.0",
|
||||
"prettier": "^2.2.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"socket.io-client": "3.1.0",
|
||||
"socket.io-client": "3.1.1",
|
||||
"socket.io-client-v2": "npm:socket.io-client@^2.4.0",
|
||||
"superagent": "^6.1.0",
|
||||
"supertest": "^6.0.1",
|
||||
|
||||
@@ -2479,6 +2479,32 @@ describe("socket.io", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("should be able to connect to a namespace with a query", (done) => {
|
||||
const srv = createServer();
|
||||
const sio = new Server(srv, {
|
||||
allowEIO3: true,
|
||||
});
|
||||
|
||||
srv.listen(async () => {
|
||||
const port = (srv.address() as AddressInfo).port;
|
||||
const clientSocket = io_v2.connect(
|
||||
`http://localhost:${port}/the-namespace`,
|
||||
{
|
||||
multiplex: false,
|
||||
}
|
||||
);
|
||||
clientSocket.query = { test: "123" };
|
||||
|
||||
const [socket]: Array<any> = await Promise.all([
|
||||
waitFor(sio.of("/the-namespace"), "connection"),
|
||||
waitFor(clientSocket, "connect"),
|
||||
]);
|
||||
|
||||
expect(socket.handshake.auth).to.eql({ test: "123" });
|
||||
success(sio, clientSocket, done);
|
||||
});
|
||||
});
|
||||
|
||||
it("should not connect if `allowEIO3` is false (default)", (done) => {
|
||||
const srv = createServer();
|
||||
const sio = new Server(srv);
|
||||
|
||||
Reference in New Issue
Block a user