Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

socket.io-redis

Package Overview
Dependencies
Maintainers
2
Versions
25
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

socket.io-redis - npm Package Compare versions

Comparing version 6.0.1 to 6.1.0

13

CHANGELOG.md

@@ -0,1 +1,14 @@

# [6.1.0](https://github.com/socketio/socket.io-redis/compare/6.0.1...6.1.0) (2021-03-12)
### Features
* implement utility methods from Socket.IO v4 ([468c3c8](https://github.com/socketio/socket.io-redis/commit/468c3c8008ddd0c89b2fc2054d874e9e706f0948))
### Performance Improvements
* remove one round-trip for the requester ([6c8d770](https://github.com/socketio/socket.io-redis/commit/6c8d7701962bee4acf83568f8e998876d3549fb8))
## [6.0.1](https://github.com/socketio/socket.io-redis/compare/6.0.0...6.0.1) (2020-11-14)

@@ -2,0 +15,0 @@

4

dist/index.d.ts

@@ -115,2 +115,6 @@ import { Adapter, BroadcastOptions, Room, SocketId } from "socket.io-adapter";

remoteDisconnect(id: SocketId, close?: boolean): Promise<void>;
fetchSockets(opts: BroadcastOptions): Promise<any[]>;
addSockets(opts: BroadcastOptions, rooms: Room[]): void;
delSockets(opts: BroadcastOptions, rooms: Room[]): void;
disconnectSockets(opts: BroadcastOptions, close: boolean): void;
/**

@@ -117,0 +121,0 @@ * Get the number of subscribers of the request channel

@@ -20,2 +20,3 @@ "use strict";

RequestType[RequestType["REMOTE_DISCONNECT"] = 4] = "REMOTE_DISCONNECT";
RequestType[RequestType["REMOTE_FETCH"] = 5] = "REMOTE_FETCH";
})(RequestType || (RequestType = {}));

@@ -129,2 +130,5 @@ function createRedisClient(uri, opts) {

case RequestType.SOCKETS:
if (this.requests.has(request.requestId)) {
return;
}
const sockets = await super.sockets(new Set(request.rooms));

@@ -138,2 +142,5 @@ response = JSON.stringify({

case RequestType.ALL_ROOMS:
if (this.requests.has(request.requestId)) {
return;
}
response = JSON.stringify({

@@ -146,2 +153,9 @@ requestId: request.requestId,

case RequestType.REMOTE_JOIN:
if (request.opts) {
const opts = {
rooms: new Set(request.opts.rooms),
except: new Set(request.opts.except),
};
return super.addSockets(opts, request.rooms);
}
socket = this.nsp.sockets.get(request.sid);

@@ -158,2 +172,9 @@ if (!socket) {

case RequestType.REMOTE_LEAVE:
if (request.opts) {
const opts = {
rooms: new Set(request.opts.rooms),
except: new Set(request.opts.except),
};
return super.delSockets(opts, request.rooms);
}
socket = this.nsp.sockets.get(request.sid);

@@ -170,2 +191,9 @@ if (!socket) {

case RequestType.REMOTE_DISCONNECT:
if (request.opts) {
const opts = {
rooms: new Set(request.opts.rooms),
except: new Set(request.opts.except),
};
return super.disconnectSockets(opts, request.close);
}
socket = this.nsp.sockets.get(request.sid);

@@ -181,2 +209,22 @@ if (!socket) {

break;
case RequestType.REMOTE_FETCH:
if (this.requests.has(request.requestId)) {
return;
}
const opts = {
rooms: new Set(request.opts.rooms),
except: new Set(request.opts.except),
};
const localSockets = await super.fetchSockets(opts);
response = JSON.stringify({
requestId: request.requestId,
sockets: localSockets.map((socket) => ({
id: socket.id,
handshake: socket.handshake,
rooms: [...socket.rooms],
data: socket.data,
})),
});
this.pubClient.publish(this.responseChannel, response);
break;
default:

@@ -209,2 +257,3 @@ debug("ignoring unknown request type: %s", request.type);

case RequestType.SOCKETS:
case RequestType.REMOTE_FETCH:
request.msgCount++;

@@ -214,3 +263,8 @@ // ignore if response does not contain 'sockets' key

return;
response.sockets.forEach((s) => request.sockets.add(s));
if (request.type === RequestType.SOCKETS) {
response.sockets.forEach((s) => request.sockets.add(s));
}
else {
response.sockets.forEach((s) => request.sockets.push(s));
}
if (request.msgCount === request.numSub) {

@@ -284,5 +338,9 @@ clearTimeout(request.timeout);

async sockets(rooms) {
const requestId = uid2(6);
const localSockets = await super.sockets(rooms);
const numSub = await this.getNumSub();
debug('waiting for %d responses to "sockets" request', numSub);
if (numSub <= 1) {
return Promise.resolve(localSockets);
}
const requestId = uid2(6);
const request = JSON.stringify({

@@ -305,4 +363,4 @@ requestId,

timeout,
msgCount: 0,
sockets: new Set(),
msgCount: 1,
sockets: localSockets,
});

@@ -318,5 +376,9 @@ this.pubClient.publish(this.requestChannel, request);

async allRooms() {
const requestId = uid2(6);
const localRooms = new Set(this.rooms.keys());
const numSub = await this.getNumSub();
debug('waiting for %d responses to "allRooms" request', numSub);
if (numSub <= 1) {
return localRooms;
}
const requestId = uid2(6);
const request = JSON.stringify({

@@ -338,4 +400,4 @@ requestId,

timeout,
msgCount: 0,
rooms: new Set(),
msgCount: 1,
rooms: localRooms,
});

@@ -450,2 +512,85 @@ this.pubClient.publish(this.requestChannel, request);

}
async fetchSockets(opts) {
var _a;
const localSockets = await super.fetchSockets(opts);
if ((_a = opts.flags) === null || _a === void 0 ? void 0 : _a.local) {
return localSockets;
}
const numSub = await this.getNumSub();
debug('waiting for %d responses to "fetchSockets" request', numSub);
if (numSub <= 1) {
return localSockets;
}
const requestId = uid2(6);
const request = JSON.stringify({
requestId,
type: RequestType.REMOTE_FETCH,
opts: {
rooms: [...opts.rooms],
except: [...opts.except],
},
});
return new Promise((resolve, reject) => {
const timeout = setTimeout(() => {
if (this.requests.has(requestId)) {
reject(new Error("timeout reached while waiting for fetchSockets response"));
this.requests.delete(requestId);
}
}, this.requestsTimeout);
this.requests.set(requestId, {
type: RequestType.REMOTE_FETCH,
numSub,
resolve,
timeout,
msgCount: 1,
sockets: localSockets,
});
this.pubClient.publish(this.requestChannel, request);
});
}
addSockets(opts, rooms) {
var _a;
if ((_a = opts.flags) === null || _a === void 0 ? void 0 : _a.local) {
return super.addSockets(opts, rooms);
}
const request = JSON.stringify({
type: RequestType.REMOTE_JOIN,
opts: {
rooms: [...opts.rooms],
except: [...opts.except],
},
rooms: [...rooms],
});
this.pubClient.publish(this.requestChannel, request);
}
delSockets(opts, rooms) {
var _a;
if ((_a = opts.flags) === null || _a === void 0 ? void 0 : _a.local) {
return super.delSockets(opts, rooms);
}
const request = JSON.stringify({
type: RequestType.REMOTE_LEAVE,
opts: {
rooms: [...opts.rooms],
except: [...opts.except],
},
rooms: [...rooms],
});
this.pubClient.publish(this.requestChannel, request);
}
disconnectSockets(opts, close) {
var _a;
if ((_a = opts.flags) === null || _a === void 0 ? void 0 : _a.local) {
return super.disconnectSockets(opts, close);
}
const request = JSON.stringify({
type: RequestType.REMOTE_DISCONNECT,
opts: {
rooms: [...opts.rooms],
except: [...opts.except],
},
close,
});
this.pubClient.publish(this.requestChannel, request);
}
/**

@@ -452,0 +597,0 @@ * Get the number of subscribers of the request channel

19

package.json
{
"name": "socket.io-redis",
"version": "6.0.1",
"version": "6.1.0",
"description": "",

@@ -16,15 +16,17 @@ "license": "MIT",

"scripts": {
"test": "npm run format:check && tsc && nyc mocha test/index.js",
"format:check": "prettier --parser typescript --check 'lib/**/*.ts' 'test/**/*.js'",
"format:fix": "prettier --parser typescript --write 'lib/**/*.ts' 'test/**/*.js'",
"test": "npm run format:check && tsc && nyc mocha --require ts-node/register test/index.ts",
"format:check": "prettier --parser typescript --check 'lib/**/*.ts' 'test/**/*.ts'",
"format:fix": "prettier --parser typescript --write 'lib/**/*.ts' 'test/**/*.ts'",
"prepack": "tsc"
},
"dependencies": {
"debug": "~4.1.0",
"debug": "~4.3.1",
"notepack.io": "~2.2.0",
"redis": "^3.0.0",
"socket.io-adapter": "~2.0.0",
"socket.io-adapter": "^2.2.0",
"uid2": "0.0.3"
},
"devDependencies": {
"@types/expect.js": "^0.3.29",
"@types/mocha": "^8.2.1",
"@types/node": "^14.14.7",

@@ -36,4 +38,5 @@ "expect.js": "0.3.1",

"prettier": "^2.1.2",
"socket.io": "^3.0.1",
"socket.io-client": "^3.0.1",
"socket.io": "^4.0.0",
"socket.io-client": "^4.0.0",
"ts-node": "^9.1.1",
"typescript": "^4.0.5"

@@ -40,0 +43,0 @@ },

# socket.io-redis
[![Build Status](https://travis-ci.org/socketio/socket.io-redis.svg?branch=master)](https://travis-ci.org/socketio/socket.io-redis)
[![Build Status](https://github.com/socketio/socket.io-redis/workflows/CI/badge.svg?branch=master)](https://github.com/socketio/socket.io-redis/actions)
[![NPM version](https://badge.fury.io/js/socket.io-redis.svg)](http://badge.fury.io/js/socket.io-redis)

@@ -13,2 +13,3 @@

- [Compatibility table](#compatibility-table)
- [How does it work under the hood?](#how-does-it-work-under-the-hood)
- [API](#api)

@@ -82,3 +83,3 @@ - [adapter(uri[, opts])](#adapteruri-opts)

will properly be broadcast to the clients through the Redis Pub/Sub mechanism.
will properly be broadcast to the clients through the Redis [Pub/Sub mechanism](https://redis.io/topics/pubsub).

@@ -94,4 +95,60 @@ If you need to emit events to socket.io instances from a non-socket.io

| 5.x | 2.x |
| 6.x | 3.x |
| 6.0.x | 3.x |
| 6.1.x and above | 4.x |
## How does it work under the hood?
This adapter extends the [in-memory adapter](https://github.com/socketio/socket.io-adapter/) that is included by default with the Socket.IO server.
The in-memory adapter stores the relationships between Sockets and Rooms in two Maps.
When you run `socket.join("room21")`, here's what happens:
```
console.log(adapter.rooms); // Map { "room21" => Set { "mdpk4kxF5CmhwfCdAHD8" } }
console.log(adapter.sids); // Map { "mdpk4kxF5CmhwfCdAHD8" => Set { "mdpk4kxF5CmhwfCdAHD8", room21" } }
// "mdpk4kxF5CmhwfCdAHD8" being the ID of the given socket
```
Those two Maps are then used when broadcasting:
- a broadcast to all sockets (`io.emit()`) loops through the `sids` Map, and send the packet to all sockets
- a broadcast to a given room (`io.to("room21").emit()`) loops through the Set in the `rooms` Map, and sends the packet to all matching sockets
The Redis adapter extends the broadcast function of the in-memory adapter: the packet is also [published](https://redis.io/topics/pubsub) to a Redis channel (see [below](#protocol) for the format of the channel name).
Each Socket.IO server receives this packet and broadcasts it to its own list of connected sockets.
To check what's happening on your Redis instance:
```
$ redis-cli
127.0.0.1:6379> PSUBSCRIBE *
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "*"
3) (integer) 1
1) "pmessage"
2) "*"
3) "socket.io#/#" (a broadcast to all sockets or to a list of rooms)
4) <the packet content>
1) "pmessage"
2) "*"
3) "socket.io#/#room21#" (a broadcast to a single room)
4) <the packet content>
```
Note: **no data** is stored in Redis itself
There are 3 Redis subscriptions per namespace:
- main channel: `<prefix>#<namespace>#*` (glob)
- request channel: `<prefix>-request#<namespace>#`
- response channel: `<prefix>-response#<namespace>#`
The request and response channels are used in the additional methods exposed by the Redis adapter, like [RedisAdapter#allRooms()](#redisadapterallrooms).
## API

@@ -142,3 +199,3 @@

// this method is also exposed by the Server instance
const sockets = io.in('room3').allSockets();
const sockets = await io.in('room3').allSockets();
console.log(sockets); // a Set containing the socket ids in 'room3'

@@ -145,0 +202,0 @@ ```

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc