-
Consider using latest version of uWebSockets if you don't need ws compatibility.
-
This repository is a fork of ClusterWS/cWS
-
This repository is a fork of uWebSockets v0.14 therefore has two licence MIT and ZLIB
-
Due to a change in libuv, if you're running cWS on Linux and using these versions of Node (>= 18.18, >= 20.3 && < 20.11.1), set the environment variable
UV_USE_IO_URING=0
before starting the application.
This table is true if you run ssl directly with cws
(Node.js
). In case if you use proxy for example nginx
, cws
can be run on bigger coverage.
CWS Version | Node 12 | Node 13 | Node 14 | Node 16 | Node 18 | Node 19 | Node 20 | Node 21 | Node 22 |
---|---|---|---|---|---|---|---|---|---|
4.7.0 | X | X | X | X | >=18.20 | X | >=20.12 | >=21.7 | >=22.0 |
4.6.0 | X | X | X | >=16.20 | >=18.18 | X | >=20.9 | >=21.1 | X |
4.5.0 | X | X | >=14.21 | >=16.20 | >=18.18 | X | >=20.7 | X | X |
4.4.0 | X | X | >=14.20 | >=16.18 | >=18.13 | X | >=20.0 | X | X |
4.3.0 | >=12.18 | X | >=14.5 | >=16.18 | >=18.13 | >=19.2 | X | X | X |
4.2.0 | >=12.18 | X | >=14.5 | >=16.0 & <16.18 | >=18.0 & <18.13 | >=19.0 | X | X | X |
4.1.0 | >=12.18 | X | >=14.5 | >=16.0 & <16.18 | >=18.0 & <18.13 | X | X | X | X |
4.0.0 | >=12.18 | X | >=14.5 | >=16.0 & <16.18 | X | X | X | X | X |
- Installation
- Websocket Client
- Websocket Server
- Secure WebSocket
- Handle App Level Ping In Browser (example)
npm i @clusterws/cws
Typings: dist/client.d.ts
Import cws WebSocket:
const { WebSocket } = require('@clusterws/cws');
Connect to WebSocket server:
const socket = new WebSocket(/* ws server endpoint **/);
Event on open
is triggered when server accepts connection and this connection is ready to perform other actions:
socket.on('open', () => { });
// or like browser interface
socket.onopen = () => { };
Event on error
is triggered if there is an error with the connection:
socket.on('error', (err) => { });
// or like browser interface
socket.onerror = (err) => { };
Event on close
is triggered when connection has been closed:
// code: number and reason: string are optional
socket.on('close', (code, reason) => { });
// or like browser interface
socket.onclose = (code, reason) => { };
Event on message
is triggered when client receives message(s):
// receives string or binary
socket.on('message', (message) => { });
// or like browser interface
socket.onmessage = (message) => { };
Event ping
is triggered when other side sends ping to check if connection still active:
socket.on('ping', () => { });
Event pong
is triggered after ping
has been sent and it received back conformation:
socket.on('pong', () => { })
To send message use send
function:
// send accepts string or binary
// will automatically identify type
socket.send(msg);
// will overwrite/specify message type to string (does not transform data to specified type)
socket.send(msg, { binary: false });
// will overwrite/specify message type to binary (does not transform data to specified type)
socket.send(msg, { binary: true });
// will call callback after message sent or errored
socket.send(msg, null, (err) => { });
To close connection you can use close
or terminate
methods:
// clean close code and reason are optional
socket.close(code, reason);
// destroy socket
socket.terminate()
Use ping
function to manually send ping:
socket.ping();
// now just wait for `pong` event
To get current socket ready state can use readyState
getter:
socket.readyState; // -> OPEN (1) or CLOSED (3)
// check if socket open can be done by
if(socket.readyState === socket.OPEN) {}
// check if socket closed can be done by
if(socket.readyState === socket.CLOSED) {}
To get addresses use _socket
getter:
socket._socket;
// Returns some thing like (all fields could be undefined):
// {
// remotePort,
// remoteAddress,
// remoteFamily
// }
For more information check typings (*.d.ts
) files in dist folder
Typings: dist/server.d.ts
Import cws WebSocket:
const { WebSocket } = require('@clusterws/cws');
Create WebSocket server:
const wsServer = new WebSocket.Server({
/**
* port?: number (creates server and listens on provided port)
* host?: string (provide host if necessary with port)
* path?: string (url at which accept ws connections)
* server?: server (provide already existing server)
* noDelay?: boolean (set socket no delay)
* noServer?: boolean (use this when upgrade done outside of cws)
* maxPayload?: number
* perMessageDeflate?: boolean | { serverNoContextTakeover: boolean;}
* verifyClient?: (info: ConnectionInfo, next: VerifyClientNext) => void (use to allow or decline connections)
**/
}, () => {
// callback called when server is ready
// is not called when `noServer: true` or `server` is provided
// from outside
});
Event on connection
is triggered when new client is connected to the server:
// `ws` is websocket client all available options
// can be found in `Websocket Client` section above
// `req` is http upgrade request
wsServer.on('connection', (ws, req) => {})
Event on error
is triggered when server has some issues and noServer
is false:
// on error event will NOT include httpServer errors IF
// server was passed under server parameter { server: httpServer },
// you can register on 'error' listener directly on passed server
wsServer.on('error', (err) => { })
Event on close
is triggered after you call wsServer.close()
function, if cb
is provided both cb
and on close
listener will be triggered:
wsServer.on('close', () => { })
To get all connected clients use clients
getter:
wsServer.clients;
// loop thought all clients:
wsServer.clients.forEach((ws) => { });
// get number of clients:
wsServer.clients.length;
To send message to all connected clients use broadcast
method:
// broadcast string
wsServer.broadcast(message);
// broadcast binary
wsServer.broadcast(message, { binary: true });
cWS supports auto ping with startAutoPing
function:
wsServer.startAutoPing(interval, appLevel);
// send ping to each client every 10s and destroy client if no pong received
wsServer.startAutoPing(10000);
// pass true as second parameter to run app level ping
// this is mainly used for browser to track pings at client level
// as they do not expose on ping listener
// look for browser client side implementation at the bottom
// `Handle App Level Ping In Browser (example)`
wsServer.startAutoPing(10000, true);
To stop server use close
function:
wsServer.close(() => {
// triggered after server has been stopped
})
handleUpgrade
is function which is commonly used together with noServer
(same as ws
module)
const wss = new WebSocket.Server({ noServer: true });
const server = http.createServer();
wss.on('connection', (ws, req) => { })
server.on('upgrade', (request, socket, head) => {
wss.handleUpgrade(request, socket, head, (ws) => {
wss.emit('connection', ws, request);
});
});
For more information check typings (*.d.ts
) files in dist folder
You can use wss://
with cws
by providing https
server to cws
and setting secureProtocol
on https options:
const { readFileSync } = require('fs');
const { createServer } = require('https');
const { WebSocket, secureProtocol } = require('@clusterws/cws');
const options = {
key: readFileSync(/** path to key */),
cert: readFileSync(/** path to certificate */),
secureProtocol
// ...other Node HTTPS options
};
const server = createServer(options);
const wsServer = new WebSocket.Server({ server });
// your secure ws is ready (do your usual things)
server.listen(port, () => {
console.log('Server is running');
})
For more detail example check examples folder
Handling custom App level ping
, pong
from the client side which does not have onping
and onpong
listeners available such as browsers.
Note if all your clients have onping
and onpong
listeners do not send appLevelPing
ping from the server. If you enable appLevelPing you will need to implement similar handler for every client library which connects to the server.
const PING = 57;
const PONG = new Uint8Array(['A'.charCodeAt()]);
socket.binaryType = 'arraybuffer';
socket.onmessage = function (message) {
// note actually sent message in
// browser default WebSocket is under `message.data`
// check if message is not string
if (typeof message.data !== 'string') {
// transform it to Uint8Array
let buffer = new Uint8Array(message.data);
// Check if it is actually ping from the server
if (buffer.length === 1 && buffer[0] === PING) {
// this is definitely `ping` event you can call custom on ping handler
// also must send back immediately pong to the server
// otherwise server will disconnect this client
return socket.send(PONG);
}
}
// process with your logic
}