mirror of
https://github.com/socketio/socket.io.git
synced 2026-01-11 16:08:24 -05:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dbd2a07cda | ||
|
|
94e27cd072 | ||
|
|
a4dffc6527 | ||
|
|
7c44893d78 | ||
|
|
b833f918c8 | ||
|
|
24d8d1f67f | ||
|
|
6f2a50b932 | ||
|
|
1633150b2b | ||
|
|
0cb6ac95b4 | ||
|
|
a2cf2486c3 | ||
|
|
995f38f4cc | ||
|
|
891b1870e9 | ||
|
|
b84ed1e41c | ||
|
|
fb6b0efec9 | ||
|
|
95d9e4a42f | ||
|
|
499c89250d | ||
|
|
93cce05fb3 | ||
|
|
dc381b72c6 |
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@@ -12,12 +12,12 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [10.x, 12.x, 14.x, 15.x]
|
||||
node-version: [12, 14, 16]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- run: npm ci
|
||||
|
||||
43
CHANGELOG.md
43
CHANGELOG.md
@@ -1,3 +1,46 @@
|
||||
## [4.1.3](https://github.com/socketio/socket.io/compare/4.1.2...4.1.3) (2021-07-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix io.except() method ([94e27cd](https://github.com/socketio/socket.io/commit/94e27cd072c8a4eeb9636f6ffbb7a21d382f36b0))
|
||||
* remove x-sourcemap header ([a4dffc6](https://github.com/socketio/socket.io/commit/a4dffc6527f412d51a786ae5bf2e9080fe1ca63c))
|
||||
|
||||
|
||||
## [4.1.2](https://github.com/socketio/socket.io/compare/4.1.1...4.1.2) (2021-05-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **typings:** ensure compatibility with TypeScript 3.x ([0cb6ac9](https://github.com/socketio/socket.io/commit/0cb6ac95b49a27483b6f1b6402fa54b35f82e36f))
|
||||
* ensure compatibility with previous versions of the adapter ([a2cf248](https://github.com/socketio/socket.io/commit/a2cf2486c366cb62293101c10520c57f6984a3fc))
|
||||
|
||||
|
||||
## [4.1.1](https://github.com/socketio/socket.io/compare/4.1.0...4.1.1) (2021-05-11)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **typings:** properly type server-side events ([b84ed1e](https://github.com/socketio/socket.io/commit/b84ed1e41c9053792caf58974c5de9395bfd509f))
|
||||
* **typings:** properly type the adapter attribute ([891b187](https://github.com/socketio/socket.io/commit/891b1870e92d1ec38910f03bb839817e2d6be65a))
|
||||
|
||||
|
||||
# [4.1.0](https://github.com/socketio/socket.io/compare/4.0.2...4.1.0) (2021-05-11)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add support for inter-server communication ([93cce05](https://github.com/socketio/socket.io/commit/93cce05fb3faf91f21fa71212275c776aa161107))
|
||||
* notify upon namespace creation ([499c892](https://github.com/socketio/socket.io/commit/499c89250d2db1ab7725ab2b74840e188c267c46))
|
||||
* add a "connection_error" event ([7096e98](https://github.com/socketio/engine.io/commit/7096e98a02295a62c8ea2aa56461d4875887092d), from `engine.io`)
|
||||
* add the "initial_headers" and "headers" events ([2527543](https://github.com/socketio/engine.io/commit/252754353a0e88eb036ebb3082e9d6a9a5f497db), from `engine.io`)
|
||||
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* add support for the "wsPreEncoded" writing option ([dc381b7](https://github.com/socketio/socket.io/commit/dc381b72c6b2f8172001dedd84116122e4cc95b3))
|
||||
|
||||
|
||||
## [4.0.2](https://github.com/socketio/socket.io/compare/4.0.1...4.0.2) (2021-05-06)
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
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
20
examples/webpack-build-server/index.js
Normal file
20
examples/webpack-build-server/index.js
Normal file
@@ -0,0 +1,20 @@
|
||||
const { Server } = require("socket.io");
|
||||
|
||||
const clientFile = require("./node_modules/socket.io/client-dist/socket.io.min?raw");
|
||||
const clientMap = require("./node_modules/socket.io/client-dist/socket.io.min.js.map?raw");
|
||||
|
||||
Server.sendFile = (filename, req, res) => {
|
||||
res.end(filename.endsWith(".map") ? clientMap : clientFile);
|
||||
};
|
||||
|
||||
const io = new Server();
|
||||
|
||||
io.on("connection", socket => {
|
||||
console.log(`connect ${socket.id}`);
|
||||
|
||||
socket.on("disconnect", (reason) => {
|
||||
console.log(`disconnect ${socket.id} due to ${reason}`);
|
||||
});
|
||||
});
|
||||
|
||||
io.listen(3000);
|
||||
@@ -1,15 +0,0 @@
|
||||
|
||||
const server = require('http').createServer();
|
||||
const io = require('socket.io')(server, {
|
||||
serveClient: false
|
||||
});
|
||||
const port = process.env.PORT || 3000;
|
||||
|
||||
io.on('connect', onConnect);
|
||||
server.listen(port, () => console.log('server listening on port ' + port));
|
||||
|
||||
function onConnect(socket){
|
||||
console.log('connect ' + socket.id);
|
||||
|
||||
socket.on('disconnect', () => console.log('disconnect ' + socket.id));
|
||||
}
|
||||
@@ -4,13 +4,15 @@
|
||||
"description": "A sample Webpack build (for the server)",
|
||||
"scripts": {
|
||||
"start": "node dist/server.js",
|
||||
"build": "webpack --config ./support/webpack.config.js"
|
||||
"build": "webpack"
|
||||
},
|
||||
"author": "Damien Arrachequesne",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"bufferutil": "^4.0.3",
|
||||
"socket.io": "^4.0.0",
|
||||
"webpack": "~4.43.0",
|
||||
"webpack-cli": "~3.3.11"
|
||||
"utf-8-validate": "^5.0.5",
|
||||
"webpack": "^5.39.0",
|
||||
"webpack-cli": "^4.7.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
|
||||
module.exports = {
|
||||
entry: './lib/index.js',
|
||||
target: 'node',
|
||||
output: {
|
||||
path: require('path').join(__dirname, '../dist'),
|
||||
filename: 'server.js'
|
||||
},
|
||||
mode: 'production'
|
||||
};
|
||||
19
examples/webpack-build-server/webpack.config.js
Normal file
19
examples/webpack-build-server/webpack.config.js
Normal file
@@ -0,0 +1,19 @@
|
||||
const path = require("path");
|
||||
|
||||
module.exports = {
|
||||
entry: "./index.js",
|
||||
target: "node",
|
||||
mode: "production",
|
||||
output: {
|
||||
path: path.resolve(__dirname, "dist"),
|
||||
filename: "index.js",
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
resourceQuery: /raw/,
|
||||
type: "asset/source",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
@@ -10,7 +10,8 @@ import type {
|
||||
} from "./typed-events";
|
||||
|
||||
export class BroadcastOperator<EmitEvents extends EventsMap>
|
||||
implements TypedEventBroadcaster<EmitEvents> {
|
||||
implements TypedEventBroadcaster<EmitEvents>
|
||||
{
|
||||
constructor(
|
||||
private readonly adapter: Adapter,
|
||||
private readonly rooms: Set<Room> = new Set<Room>(),
|
||||
@@ -186,7 +187,7 @@ export class BroadcastOperator<EmitEvents extends EventsMap>
|
||||
return sockets.map((socket) => {
|
||||
if (socket instanceof Socket) {
|
||||
// FIXME the TypeScript compiler complains about missing private properties
|
||||
return (socket as unknown) as RemoteSocket<EmitEvents>;
|
||||
return socket as unknown as RemoteSocket<EmitEvents>;
|
||||
} else {
|
||||
return new RemoteSocket(this.adapter, socket as SocketDetails);
|
||||
}
|
||||
@@ -257,7 +258,8 @@ interface SocketDetails {
|
||||
* Expose of subset of the attributes and methods of the Socket class
|
||||
*/
|
||||
export class RemoteSocket<EmitEvents extends EventsMap>
|
||||
implements TypedEventBroadcaster<EmitEvents> {
|
||||
implements TypedEventBroadcaster<EmitEvents>
|
||||
{
|
||||
public readonly id: SocketId;
|
||||
public readonly handshake: Handshake;
|
||||
public readonly rooms: Set<Room>;
|
||||
|
||||
@@ -10,18 +10,32 @@ import type { SocketId } from "socket.io-adapter";
|
||||
|
||||
const debug = debugModule("socket.io:client");
|
||||
|
||||
interface WriteOptions {
|
||||
compress?: boolean;
|
||||
volatile?: boolean;
|
||||
preEncoded?: boolean;
|
||||
wsPreEncoded?: string;
|
||||
}
|
||||
|
||||
export class Client<
|
||||
ListenEvents extends EventsMap,
|
||||
EmitEvents extends EventsMap
|
||||
EmitEvents extends EventsMap,
|
||||
ServerSideEvents extends EventsMap
|
||||
> {
|
||||
public readonly conn;
|
||||
|
||||
private readonly id: string;
|
||||
private readonly server: Server<ListenEvents, EmitEvents>;
|
||||
private readonly server: Server<ListenEvents, EmitEvents, ServerSideEvents>;
|
||||
private readonly encoder: Encoder;
|
||||
private readonly decoder: Decoder;
|
||||
private sockets: Map<SocketId, Socket<ListenEvents, EmitEvents>> = new Map();
|
||||
private nsps: Map<string, Socket<ListenEvents, EmitEvents>> = new Map();
|
||||
private sockets: Map<
|
||||
SocketId,
|
||||
Socket<ListenEvents, EmitEvents, ServerSideEvents>
|
||||
> = new Map();
|
||||
private nsps: Map<
|
||||
string,
|
||||
Socket<ListenEvents, EmitEvents, ServerSideEvents>
|
||||
> = new Map();
|
||||
private connectTimeout?: NodeJS.Timeout;
|
||||
|
||||
/**
|
||||
@@ -31,7 +45,10 @@ export class Client<
|
||||
* @param conn
|
||||
* @package
|
||||
*/
|
||||
constructor(server: Server<ListenEvents, EmitEvents>, conn: any) {
|
||||
constructor(
|
||||
server: Server<ListenEvents, EmitEvents, ServerSideEvents>,
|
||||
conn: any
|
||||
) {
|
||||
this.server = server;
|
||||
this.conn = conn;
|
||||
this.encoder = server.encoder;
|
||||
@@ -92,7 +109,11 @@ export class Client<
|
||||
this.server._checkNamespace(
|
||||
name,
|
||||
auth,
|
||||
(dynamicNspName: Namespace<ListenEvents, EmitEvents> | false) => {
|
||||
(
|
||||
dynamicNspName:
|
||||
| Namespace<ListenEvents, EmitEvents, ServerSideEvents>
|
||||
| false
|
||||
) => {
|
||||
if (dynamicNspName) {
|
||||
debug("dynamic namespace %s was created", dynamicNspName);
|
||||
this.doConnect(name, auth);
|
||||
@@ -150,7 +171,7 @@ export class Client<
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_remove(socket: Socket<ListenEvents, EmitEvents>): void {
|
||||
_remove(socket: Socket<ListenEvents, EmitEvents, ServerSideEvents>): void {
|
||||
if (this.sockets.has(socket.id)) {
|
||||
const nsp = this.sockets.get(socket.id)!.nsp.name;
|
||||
this.sockets.delete(socket.id);
|
||||
@@ -180,31 +201,30 @@ export class Client<
|
||||
* @param {Object} opts
|
||||
* @private
|
||||
*/
|
||||
_packet(packet: Packet, opts?: any): void {
|
||||
opts = opts || {};
|
||||
const self = this;
|
||||
|
||||
// this writes to the actual connection
|
||||
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 });
|
||||
}
|
||||
}
|
||||
|
||||
if ("open" === this.conn.readyState) {
|
||||
debug("writing packet %j", packet);
|
||||
if (!opts.preEncoded) {
|
||||
// not broadcasting, need to encode
|
||||
writeToEngine(this.encoder.encode(packet)); // encode, then write results to engine
|
||||
} else {
|
||||
// a broadcast pre-encodes a packet
|
||||
writeToEngine(packet);
|
||||
}
|
||||
} else {
|
||||
_packet(packet: Packet | any[], opts: WriteOptions = {}): void {
|
||||
if (this.conn.readyState !== "open") {
|
||||
debug("ignoring packet write %j", packet);
|
||||
return;
|
||||
}
|
||||
const encodedPackets = opts.preEncoded
|
||||
? (packet as any[]) // previous versions of the adapter incorrectly used socket.packet() instead of writeToEngine()
|
||||
: this.encoder.encode(packet as Packet);
|
||||
for (const encodedPacket of encodedPackets) {
|
||||
this.writeToEngine(encodedPacket, opts);
|
||||
}
|
||||
}
|
||||
|
||||
private writeToEngine(
|
||||
encodedPacket: String | Buffer,
|
||||
opts: WriteOptions
|
||||
): void {
|
||||
if (opts.volatile && !this.conn.transport.writable) {
|
||||
debug(
|
||||
"volatile packet is discarded since the transport is not currently writable"
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.conn.write(encodedPacket, opts);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
83
lib/index.ts
83
lib/index.ts
@@ -7,11 +7,7 @@ import path = require("path");
|
||||
import engine = require("engine.io");
|
||||
import { Client } from "./client";
|
||||
import { EventEmitter } from "events";
|
||||
import {
|
||||
ExtendedError,
|
||||
Namespace,
|
||||
NamespaceReservedEventsMap,
|
||||
} from "./namespace";
|
||||
import { ExtendedError, Namespace, ServerReservedEventsMap } from "./namespace";
|
||||
import { ParentNamespace } from "./parent-namespace";
|
||||
import { Adapter, Room, SocketId } from "socket.io-adapter";
|
||||
import * as parser from "socket.io-parser";
|
||||
@@ -26,6 +22,7 @@ import {
|
||||
DefaultEventsMap,
|
||||
EventParams,
|
||||
StrictEventEmitter,
|
||||
EventNames,
|
||||
} from "./typed-events";
|
||||
|
||||
const debug = debugModule("socket.io:server");
|
||||
@@ -40,6 +37,8 @@ type ParentNspNameMatchFn = (
|
||||
fn: (err: Error | null, success: boolean) => void
|
||||
) => void;
|
||||
|
||||
type AdapterConstructor = typeof Adapter | ((nsp: Namespace) => Adapter);
|
||||
|
||||
interface EngineOptions {
|
||||
/**
|
||||
* how many ms without a pong packet to consider the connection closed
|
||||
@@ -155,7 +154,7 @@ interface ServerOptions extends EngineAttachOptions {
|
||||
* the adapter to use
|
||||
* @default the in-memory adapter (https://github.com/socketio/socket.io-adapter)
|
||||
*/
|
||||
adapter: any;
|
||||
adapter: AdapterConstructor;
|
||||
/**
|
||||
* the parser to use
|
||||
* @default the default parser (https://github.com/socketio/socket.io-parser)
|
||||
@@ -170,13 +169,18 @@ interface ServerOptions extends EngineAttachOptions {
|
||||
|
||||
export class Server<
|
||||
ListenEvents extends EventsMap = DefaultEventsMap,
|
||||
EmitEvents extends EventsMap = ListenEvents
|
||||
EmitEvents extends EventsMap = ListenEvents,
|
||||
ServerSideEvents extends EventsMap = DefaultEventsMap
|
||||
> extends StrictEventEmitter<
|
||||
{},
|
||||
ServerSideEvents,
|
||||
EmitEvents,
|
||||
NamespaceReservedEventsMap<ListenEvents, EmitEvents>
|
||||
ServerReservedEventsMap<ListenEvents, EmitEvents, ServerSideEvents>
|
||||
> {
|
||||
public readonly sockets: Namespace<ListenEvents, EmitEvents>;
|
||||
public readonly sockets: Namespace<
|
||||
ListenEvents,
|
||||
EmitEvents,
|
||||
ServerSideEvents
|
||||
>;
|
||||
/**
|
||||
* A reference to the underlying Engine.IO server.
|
||||
*
|
||||
@@ -197,12 +201,13 @@ export class Server<
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_nsps: Map<string, Namespace<ListenEvents, EmitEvents>> = new Map();
|
||||
_nsps: Map<string, Namespace<ListenEvents, EmitEvents, ServerSideEvents>> =
|
||||
new Map();
|
||||
private parentNsps: Map<
|
||||
ParentNspNameMatchFn,
|
||||
ParentNamespace<ListenEvents, EmitEvents>
|
||||
ParentNamespace<ListenEvents, EmitEvents, ServerSideEvents>
|
||||
> = new Map();
|
||||
private _adapter?: typeof Adapter;
|
||||
private _adapter?: AdapterConstructor;
|
||||
private _serveClient: boolean;
|
||||
private opts: Partial<EngineOptions>;
|
||||
private eio;
|
||||
@@ -280,7 +285,9 @@ export class Server<
|
||||
_checkNamespace(
|
||||
name: string,
|
||||
auth: { [key: string]: any },
|
||||
fn: (nsp: Namespace<ListenEvents, EmitEvents> | false) => void
|
||||
fn: (
|
||||
nsp: Namespace<ListenEvents, EmitEvents, ServerSideEvents> | false
|
||||
) => void
|
||||
): void {
|
||||
if (this.parentNsps.size === 0) return fn(false);
|
||||
|
||||
@@ -295,7 +302,12 @@ export class Server<
|
||||
if (err || !allow) {
|
||||
run();
|
||||
} else {
|
||||
fn(this.parentNsps.get(nextFn.value)!.createChild(name));
|
||||
const namespace = this.parentNsps
|
||||
.get(nextFn.value)!
|
||||
.createChild(name);
|
||||
// @ts-ignore
|
||||
this.sockets.emitReserved("new_namespace", namespace);
|
||||
fn(namespace);
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -348,10 +360,11 @@ export class Server<
|
||||
* @return self when setting or value when getting
|
||||
* @public
|
||||
*/
|
||||
public adapter(): typeof Adapter | undefined;
|
||||
public adapter(v: typeof Adapter): this;
|
||||
public adapter(v?: typeof Adapter): typeof Adapter | undefined | this;
|
||||
public adapter(v?: typeof Adapter): typeof Adapter | undefined | this {
|
||||
public adapter(): AdapterConstructor | undefined;
|
||||
public adapter(v: AdapterConstructor): this;
|
||||
public adapter(
|
||||
v?: AdapterConstructor
|
||||
): AdapterConstructor | undefined | this {
|
||||
if (!arguments.length) return this._adapter;
|
||||
this._adapter = v;
|
||||
for (const nsp of this._nsps.values()) {
|
||||
@@ -502,9 +515,6 @@ export class Server<
|
||||
);
|
||||
res.setHeader("ETag", expectedEtag);
|
||||
|
||||
if (!isMap) {
|
||||
res.setHeader("X-SourceMap", filename.substring(1) + ".map");
|
||||
}
|
||||
Server.sendFile(filename, req, res);
|
||||
}
|
||||
|
||||
@@ -589,8 +599,8 @@ export class Server<
|
||||
*/
|
||||
public of(
|
||||
name: string | RegExp | ParentNspNameMatchFn,
|
||||
fn?: (socket: Socket<ListenEvents, EmitEvents>) => void
|
||||
): Namespace<ListenEvents, EmitEvents> {
|
||||
fn?: (socket: Socket<ListenEvents, EmitEvents, ServerSideEvents>) => void
|
||||
): Namespace<ListenEvents, EmitEvents, ServerSideEvents> {
|
||||
if (typeof name === "function" || name instanceof RegExp) {
|
||||
const parentNsp = new ParentNamespace(this);
|
||||
debug("initializing parent namespace %s", parentNsp.name);
|
||||
@@ -616,6 +626,10 @@ export class Server<
|
||||
debug("initializing namespace %s", name);
|
||||
nsp = new Namespace(this, name);
|
||||
this._nsps.set(name, nsp);
|
||||
if (name !== "/") {
|
||||
// @ts-ignore
|
||||
this.sockets.emitReserved("new_namespace", nsp);
|
||||
}
|
||||
}
|
||||
if (fn) nsp.on("connect", fn);
|
||||
return nsp;
|
||||
@@ -649,7 +663,7 @@ export class Server<
|
||||
*/
|
||||
public use(
|
||||
fn: (
|
||||
socket: Socket<ListenEvents, EmitEvents>,
|
||||
socket: Socket<ListenEvents, EmitEvents, ServerSideEvents>,
|
||||
next: (err?: ExtendedError) => void
|
||||
) => void
|
||||
): this {
|
||||
@@ -686,9 +700,8 @@ export class Server<
|
||||
* @return self
|
||||
* @public
|
||||
*/
|
||||
public except(name: Room | Room[]): Server<ListenEvents, EmitEvents> {
|
||||
this.sockets.except(name);
|
||||
return this;
|
||||
public except(name: Room | Room[]): BroadcastOperator<EmitEvents> {
|
||||
return this.sockets.except(name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -713,6 +726,20 @@ export class Server<
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit a packet to other Socket.IO servers
|
||||
*
|
||||
* @param ev - the event name
|
||||
* @param args - an array of arguments, which may include an acknowledgement callback at the end
|
||||
* @public
|
||||
*/
|
||||
public serverSideEmit<Ev extends EventNames<ServerSideEvents>>(
|
||||
ev: Ev,
|
||||
...args: EventParams<ServerSideEvents, Ev>
|
||||
): boolean {
|
||||
return this.sockets.serverSideEmit(ev, ...args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of socket ids.
|
||||
*
|
||||
|
||||
@@ -20,35 +20,57 @@ export interface ExtendedError extends Error {
|
||||
|
||||
export interface NamespaceReservedEventsMap<
|
||||
ListenEvents extends EventsMap,
|
||||
EmitEvents extends EventsMap
|
||||
EmitEvents extends EventsMap,
|
||||
ServerSideEvents extends EventsMap
|
||||
> {
|
||||
connect: (socket: Socket<ListenEvents, EmitEvents>) => void;
|
||||
connection: (socket: Socket<ListenEvents, EmitEvents>) => void;
|
||||
connect: (socket: Socket<ListenEvents, EmitEvents, ServerSideEvents>) => void;
|
||||
connection: (
|
||||
socket: Socket<ListenEvents, EmitEvents, ServerSideEvents>
|
||||
) => void;
|
||||
}
|
||||
|
||||
export interface ServerReservedEventsMap<
|
||||
ListenEvents,
|
||||
EmitEvents,
|
||||
ServerSideEvents
|
||||
> extends NamespaceReservedEventsMap<
|
||||
ListenEvents,
|
||||
EmitEvents,
|
||||
ServerSideEvents
|
||||
> {
|
||||
new_namespace: (
|
||||
namespace: Namespace<ListenEvents, EmitEvents, ServerSideEvents>
|
||||
) => void;
|
||||
}
|
||||
|
||||
export const RESERVED_EVENTS: ReadonlySet<string | Symbol> = new Set<
|
||||
keyof ServerReservedEventsMap<never, never, never>
|
||||
>(<const>["connect", "connection", "new_namespace"]);
|
||||
|
||||
export class Namespace<
|
||||
ListenEvents extends EventsMap = DefaultEventsMap,
|
||||
EmitEvents extends EventsMap = ListenEvents
|
||||
EmitEvents extends EventsMap = ListenEvents,
|
||||
ServerSideEvents extends EventsMap = DefaultEventsMap
|
||||
> extends StrictEventEmitter<
|
||||
{},
|
||||
ServerSideEvents,
|
||||
EmitEvents,
|
||||
NamespaceReservedEventsMap<ListenEvents, EmitEvents>
|
||||
NamespaceReservedEventsMap<ListenEvents, EmitEvents, ServerSideEvents>
|
||||
> {
|
||||
public readonly name: string;
|
||||
public readonly sockets: Map<
|
||||
SocketId,
|
||||
Socket<ListenEvents, EmitEvents>
|
||||
Socket<ListenEvents, EmitEvents, ServerSideEvents>
|
||||
> = new Map();
|
||||
|
||||
public adapter: Adapter;
|
||||
|
||||
/** @private */
|
||||
readonly server: Server<ListenEvents, EmitEvents>;
|
||||
readonly server: Server<ListenEvents, EmitEvents, ServerSideEvents>;
|
||||
|
||||
/** @private */
|
||||
_fns: Array<
|
||||
(
|
||||
socket: Socket<ListenEvents, EmitEvents>,
|
||||
socket: Socket<ListenEvents, EmitEvents, ServerSideEvents>,
|
||||
next: (err?: ExtendedError) => void
|
||||
) => void
|
||||
> = [];
|
||||
@@ -62,7 +84,10 @@ export class Namespace<
|
||||
* @param server instance
|
||||
* @param name
|
||||
*/
|
||||
constructor(server: Server<ListenEvents, EmitEvents>, name: string) {
|
||||
constructor(
|
||||
server: Server<ListenEvents, EmitEvents, ServerSideEvents>,
|
||||
name: string
|
||||
) {
|
||||
super();
|
||||
this.server = server;
|
||||
this.name = name;
|
||||
@@ -77,6 +102,7 @@ export class Namespace<
|
||||
* @private
|
||||
*/
|
||||
_initAdapter(): void {
|
||||
// @ts-ignore
|
||||
this.adapter = new (this.server.adapter()!)(this);
|
||||
}
|
||||
|
||||
@@ -88,7 +114,7 @@ export class Namespace<
|
||||
*/
|
||||
public use(
|
||||
fn: (
|
||||
socket: Socket<ListenEvents, EmitEvents>,
|
||||
socket: Socket<ListenEvents, EmitEvents, ServerSideEvents>,
|
||||
next: (err?: ExtendedError) => void
|
||||
) => void
|
||||
): this {
|
||||
@@ -104,7 +130,7 @@ export class Namespace<
|
||||
* @private
|
||||
*/
|
||||
private run(
|
||||
socket: Socket<ListenEvents, EmitEvents>,
|
||||
socket: Socket<ListenEvents, EmitEvents, ServerSideEvents>,
|
||||
fn: (err: ExtendedError | null) => void
|
||||
) {
|
||||
const fns = this._fns.slice(0);
|
||||
@@ -166,10 +192,10 @@ export class Namespace<
|
||||
* @private
|
||||
*/
|
||||
_add(
|
||||
client: Client<ListenEvents, EmitEvents>,
|
||||
client: Client<ListenEvents, EmitEvents, ServerSideEvents>,
|
||||
query,
|
||||
fn?: () => void
|
||||
): Socket<ListenEvents, EmitEvents> {
|
||||
): Socket<ListenEvents, EmitEvents, ServerSideEvents> {
|
||||
debug("adding socket to nsp %s", this.name);
|
||||
const socket = new Socket(this, client, query);
|
||||
this.run(socket, (err) => {
|
||||
@@ -212,7 +238,7 @@ export class Namespace<
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_remove(socket: Socket<ListenEvents, EmitEvents>): void {
|
||||
_remove(socket: Socket<ListenEvents, EmitEvents, ServerSideEvents>): void {
|
||||
if (this.sockets.has(socket.id)) {
|
||||
this.sockets.delete(socket.id);
|
||||
} else {
|
||||
@@ -255,6 +281,36 @@ export class Namespace<
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit a packet to other Socket.IO servers
|
||||
*
|
||||
* @param ev - the event name
|
||||
* @param args - an array of arguments, which may include an acknowledgement callback at the end
|
||||
* @public
|
||||
*/
|
||||
public serverSideEmit<Ev extends EventNames<ServerSideEvents>>(
|
||||
ev: Ev,
|
||||
...args: EventParams<ServerSideEvents, Ev>
|
||||
): boolean {
|
||||
if (RESERVED_EVENTS.has(ev)) {
|
||||
throw new Error(`"${ev}" is a reserved event name`);
|
||||
}
|
||||
args.unshift(ev);
|
||||
this.adapter.serverSideEmit(args);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a packet is received from another Socket.IO server
|
||||
*
|
||||
* @param args - an array of arguments, which may include an acknowledgement callback at the end
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_onServerSideEmit(args: [string, ...any[]]) {
|
||||
super.emitUntyped.apply(this, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of clients.
|
||||
*
|
||||
|
||||
@@ -10,12 +10,14 @@ import type { BroadcastOptions } from "socket.io-adapter";
|
||||
|
||||
export class ParentNamespace<
|
||||
ListenEvents extends EventsMap = DefaultEventsMap,
|
||||
EmitEvents extends EventsMap = ListenEvents
|
||||
> extends Namespace<ListenEvents, EmitEvents> {
|
||||
EmitEvents extends EventsMap = ListenEvents,
|
||||
ServerSideEvents extends EventsMap = DefaultEventsMap
|
||||
> extends Namespace<ListenEvents, EmitEvents, ServerSideEvents> {
|
||||
private static count: number = 0;
|
||||
private children: Set<Namespace<ListenEvents, EmitEvents>> = new Set();
|
||||
private children: Set<Namespace<ListenEvents, EmitEvents, ServerSideEvents>> =
|
||||
new Set();
|
||||
|
||||
constructor(server: Server<ListenEvents, EmitEvents>) {
|
||||
constructor(server: Server<ListenEvents, EmitEvents, ServerSideEvents>) {
|
||||
super(server, "/_" + ParentNamespace.count++);
|
||||
}
|
||||
|
||||
@@ -43,7 +45,9 @@ export class ParentNamespace<
|
||||
return true;
|
||||
}
|
||||
|
||||
createChild(name: string): Namespace<ListenEvents, EmitEvents> {
|
||||
createChild(
|
||||
name: string
|
||||
): Namespace<ListenEvents, EmitEvents, ServerSideEvents> {
|
||||
const namespace = new Namespace(this.server, name);
|
||||
namespace._fns = this._fns.slice(0);
|
||||
this.listeners("connect").forEach((listener) =>
|
||||
|
||||
@@ -46,7 +46,7 @@ export interface EventEmitterReservedEventsMap {
|
||||
|
||||
export const RESERVED_EVENTS: ReadonlySet<string | Symbol> = new Set<
|
||||
| ClientReservedEvents
|
||||
| keyof NamespaceReservedEventsMap<never, never>
|
||||
| keyof NamespaceReservedEventsMap<never, never, never>
|
||||
| keyof SocketReservedEventsMap
|
||||
| keyof EventEmitterReservedEventsMap
|
||||
>(<const>[
|
||||
@@ -110,7 +110,8 @@ export interface Handshake {
|
||||
|
||||
export class Socket<
|
||||
ListenEvents extends EventsMap = DefaultEventsMap,
|
||||
EmitEvents extends EventsMap = ListenEvents
|
||||
EmitEvents extends EventsMap = ListenEvents,
|
||||
ServerSideEvents extends EventsMap = DefaultEventsMap
|
||||
> extends StrictEventEmitter<
|
||||
ListenEvents,
|
||||
EmitEvents,
|
||||
@@ -126,12 +127,11 @@ export class Socket<
|
||||
public connected: boolean;
|
||||
public disconnected: boolean;
|
||||
|
||||
private readonly server: Server<ListenEvents, EmitEvents>;
|
||||
private readonly server: Server<ListenEvents, EmitEvents, ServerSideEvents>;
|
||||
private readonly adapter: Adapter;
|
||||
private acks: Map<number, () => void> = new Map();
|
||||
private fns: Array<
|
||||
(event: Array<any>, next: (err?: Error) => void) => void
|
||||
> = [];
|
||||
private fns: Array<(event: Array<any>, next: (err?: Error) => void) => void> =
|
||||
[];
|
||||
private flags: BroadcastFlags = {};
|
||||
private _anyListeners?: Array<(...args: any[]) => void>;
|
||||
|
||||
@@ -144,8 +144,8 @@ export class Socket<
|
||||
* @package
|
||||
*/
|
||||
constructor(
|
||||
readonly nsp: Namespace<ListenEvents, EmitEvents>,
|
||||
readonly client: Client<ListenEvents, EmitEvents>,
|
||||
readonly nsp: Namespace<ListenEvents, EmitEvents, ServerSideEvents>,
|
||||
readonly client: Client<ListenEvents, EmitEvents, ServerSideEvents>,
|
||||
auth: object
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -91,7 +91,8 @@ export abstract class StrictEventEmitter<
|
||||
ReservedEvents extends EventsMap = {}
|
||||
>
|
||||
extends EventEmitter
|
||||
implements TypedEventBroadcaster<EmitEvents> {
|
||||
implements TypedEventBroadcaster<EmitEvents>
|
||||
{
|
||||
/**
|
||||
* Adds the `listener` function as an event listener for `ev`.
|
||||
*
|
||||
|
||||
1754
package-lock.json
generated
1754
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
27
package.json
27
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "socket.io",
|
||||
"version": "4.0.2",
|
||||
"version": "4.1.3",
|
||||
"description": "node.js realtime framework server",
|
||||
"keywords": [
|
||||
"realtime",
|
||||
@@ -46,32 +46,29 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/cookie": "^0.4.0",
|
||||
"@types/cors": "^2.8.8",
|
||||
"@types/cors": "^2.8.10",
|
||||
"@types/node": ">=10.0.0",
|
||||
"accepts": "~1.3.4",
|
||||
"base64id": "~2.0.0",
|
||||
"debug": "~4.3.1",
|
||||
"engine.io": "~5.0.0",
|
||||
"socket.io-adapter": "~2.2.0",
|
||||
"socket.io-parser": "~4.0.3"
|
||||
"engine.io": "~5.1.1",
|
||||
"socket.io-adapter": "~2.3.1",
|
||||
"socket.io-parser": "~4.0.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mocha": "^8.0.4",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"eslint": "^7.14.0",
|
||||
"eslint-config-prettier": "^6.11.0",
|
||||
"@types/mocha": "^8.2.2",
|
||||
"expect.js": "0.3.1",
|
||||
"mocha": "^3.5.3",
|
||||
"nyc": "^15.1.0",
|
||||
"prettier": "^2.2.0",
|
||||
"prettier": "^2.3.2",
|
||||
"rimraf": "^3.0.2",
|
||||
"socket.io-client": "4.0.2",
|
||||
"socket.io-client": "4.1.3",
|
||||
"socket.io-client-v2": "npm:socket.io-client@^2.4.0",
|
||||
"superagent": "^6.1.0",
|
||||
"supertest": "^6.0.1",
|
||||
"ts-node": "^9.0.0",
|
||||
"tsd": "^0.14.0",
|
||||
"typescript": "^4.1.2"
|
||||
"supertest": "^6.1.3",
|
||||
"ts-node": "^10.0.0",
|
||||
"tsd": "^0.17.0",
|
||||
"typescript": "^4.3.5"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
"use strict";
|
||||
import { Server, Socket } from "..";
|
||||
import { Namespace, Server, Socket } from "..";
|
||||
import type { DefaultEventsMap } from "../lib/typed-events";
|
||||
import { createServer } from "http";
|
||||
import { expectError, expectType } from "tsd";
|
||||
import { Adapter } from "socket.io-adapter";
|
||||
|
||||
// This file is run by tsd, not mocha.
|
||||
|
||||
@@ -117,7 +118,9 @@ describe("server", () => {
|
||||
|
||||
it("does not accept arguments of wrong types", (done) => {
|
||||
const srv = createServer();
|
||||
const sio = new Server<BidirectionalEvents>(srv);
|
||||
const sio = new Server<BidirectionalEvents, BidirectionalEvents, {}>(
|
||||
srv
|
||||
);
|
||||
expectError(sio.on("random", (a, b, c) => {}));
|
||||
srv.listen(() => {
|
||||
expectError(sio.on("wrong name", (s) => {}));
|
||||
@@ -229,4 +232,69 @@ describe("server", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("listen and emit event maps", () => {
|
||||
interface ClientToServerEvents {
|
||||
helloFromClient: (message: string) => void;
|
||||
}
|
||||
|
||||
interface ServerToClientEvents {
|
||||
helloFromServer: (message: string, x: number) => void;
|
||||
}
|
||||
|
||||
interface InterServerEvents {
|
||||
helloFromServerToServer: (message: string, x: number) => void;
|
||||
}
|
||||
|
||||
describe("on", () => {
|
||||
it("infers correct types for listener parameters", () => {
|
||||
const srv = createServer();
|
||||
const sio = new Server<
|
||||
ClientToServerEvents,
|
||||
ServerToClientEvents,
|
||||
InterServerEvents
|
||||
>(srv);
|
||||
|
||||
expectType<
|
||||
Server<ClientToServerEvents, ServerToClientEvents, InterServerEvents>
|
||||
>(sio);
|
||||
srv.listen(() => {
|
||||
sio.serverSideEmit("helloFromServerToServer", "hello", 10);
|
||||
sio
|
||||
.of("/test")
|
||||
.serverSideEmit("helloFromServerToServer", "hello", 10);
|
||||
|
||||
sio.on("helloFromServerToServer", (message, x) => {
|
||||
expectType<string>(message);
|
||||
expectType<number>(x);
|
||||
});
|
||||
sio.of("/test").on("helloFromServerToServer", (message, x) => {
|
||||
expectType<string>(message);
|
||||
expectType<number>(x);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("adapter", () => {
|
||||
it("accepts arguments of the correct types", () => {
|
||||
const io = new Server({
|
||||
adapter: (nsp) => new Adapter(nsp),
|
||||
});
|
||||
io.adapter(Adapter);
|
||||
|
||||
class MyCustomAdapter extends Adapter {
|
||||
constructor(nsp, readonly opts) {
|
||||
super(nsp);
|
||||
}
|
||||
}
|
||||
io.adapter((nsp) => new MyCustomAdapter(nsp, { test: "123" }));
|
||||
});
|
||||
|
||||
it("does not accept arguments of wrong types", () => {
|
||||
const io = new Server();
|
||||
expectError(io.adapter((nsp) => "nope"));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -59,7 +59,7 @@ describe("socket.io", () => {
|
||||
if (err) return done(err);
|
||||
expect(res.headers["content-type"]).to.be("application/javascript");
|
||||
expect(res.headers.etag).to.be('"' + clientVersion + '"');
|
||||
expect(res.headers["x-sourcemap"]).to.be(filename + ".map");
|
||||
expect(res.headers["x-sourcemap"]).to.be(undefined);
|
||||
expect(res.text).to.match(/engine\.io/);
|
||||
expect(res.status).to.be(200);
|
||||
done();
|
||||
@@ -812,7 +812,7 @@ describe("socket.io", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("should close a client without namespace", (done) => {
|
||||
it("should close a client without namespace (2)", (done) => {
|
||||
const srv = createServer();
|
||||
const sio = new Server(srv, {
|
||||
connectTimeout: 100,
|
||||
@@ -836,6 +836,27 @@ describe("socket.io", () => {
|
||||
});
|
||||
|
||||
it("should exclude a specific socket when emitting", (done) => {
|
||||
const srv = createServer();
|
||||
const io = new Server(srv);
|
||||
|
||||
srv.listen(() => {
|
||||
const socket1 = client(srv, "/");
|
||||
const socket2 = client(srv, "/");
|
||||
|
||||
socket2.on("a", () => {
|
||||
done(new Error("should not happen"));
|
||||
});
|
||||
socket1.on("a", () => {
|
||||
done();
|
||||
});
|
||||
|
||||
socket2.on("connect", () => {
|
||||
io.except(socket2.id).emit("a");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should exclude a specific socket when emitting (in a namespace)", (done) => {
|
||||
const srv = createServer();
|
||||
const sio = new Server(srv);
|
||||
|
||||
@@ -886,6 +907,17 @@ describe("socket.io", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("should emit an 'new_namespace' event", (done) => {
|
||||
const sio = new Server();
|
||||
|
||||
sio.on("new_namespace", (namespace) => {
|
||||
expect(namespace.name).to.eql("/nsp");
|
||||
done();
|
||||
});
|
||||
|
||||
sio.of("/nsp");
|
||||
});
|
||||
|
||||
describe("dynamic namespaces", () => {
|
||||
it("should allow connections to dynamic namespaces with a regex", (done) => {
|
||||
const srv = createServer();
|
||||
@@ -942,6 +974,24 @@ describe("socket.io", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should emit an 'new_namespace' event for a dynamic namespace", (done) => {
|
||||
const srv = createServer();
|
||||
const sio = new Server(srv);
|
||||
srv.listen(() => {
|
||||
sio.of(/^\/dynamic-\d+$/);
|
||||
|
||||
sio.on("new_namespace", (namespace) => {
|
||||
expect(namespace.name).to.be("/dynamic-101");
|
||||
|
||||
socket.disconnect();
|
||||
srv.close();
|
||||
done();
|
||||
});
|
||||
|
||||
const socket = client(srv, "/dynamic-101");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -955,7 +1005,9 @@ describe("socket.io", () => {
|
||||
clientSocket.off("connect", init);
|
||||
clientSocket.io.engine.close();
|
||||
|
||||
clientSocket.connect();
|
||||
process.nextTick(() => {
|
||||
clientSocket.connect();
|
||||
});
|
||||
clientSocket.on("connect", () => {
|
||||
done();
|
||||
});
|
||||
@@ -2385,6 +2437,28 @@ describe("socket.io", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should pre encode a broadcast packet", (done) => {
|
||||
const srv = createServer();
|
||||
const sio = new Server(srv);
|
||||
|
||||
srv.listen(() => {
|
||||
const clientSocket = client(srv, { multiplex: false });
|
||||
|
||||
sio.on("connection", (socket) => {
|
||||
socket.conn.on("packetCreate", (packet) => {
|
||||
expect(packet.data).to.eql('2["hello","world"]');
|
||||
expect(packet.options.wsPreEncoded).to.eql('42["hello","world"]');
|
||||
|
||||
clientSocket.close();
|
||||
sio.close();
|
||||
done();
|
||||
});
|
||||
|
||||
sio.emit("hello", "world");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("middleware", () => {
|
||||
|
||||
Reference in New Issue
Block a user