The WSServerPubSub class extends WSServer to provide Publish-Subscribe (PubSub) functionality and Remote Procedure Call (RPC) capabilities for WebSocket communication. It allows clients to subscribe to channels, publish messages, and call server-side functions. Look at WSServerRoomManager for room-based management features.
Note: The PubSub implementation sends messages directly to connected clients and does not use any message queuing system.
Creates a new WebSocket PubSub server instance.
Parameters:
options(object): Server configuration options (inherits fromWSServer)port(number, optional): The port number to run the server on. Default:443maxNbOfClients(number, optional): Maximum number of allowed clients. Default:1000maxInputSize(number, optional): Maximum size of input messages in bytes. Default:100000(100KB)origins(string, optional): Allowed origins. Default:'*'pingTimeout(number, optional): The timeout in milliseconds for ping responses. Default:30000authCallback(function, optional): Authentication callback function(token, request, wsServer) => {}. Default:(token, request, wsServer) => ({})logLevel(string, optional): Log level: 'none', 'error', 'warn', 'info', 'debug'. Default:'info'logger(object, optional): External logger instance for logging. Default:null
authCallback: This function is called when a client connects. It must return an object with user metadata if authentication is successful, or false if authentication fails. The metadata will be added to the client object and can be used in RPCs and PubSub hooks. An id metadata will be automatically generated for the client if not provided.
Note: Authentication can be handled via the token parameter (sent via WebSocket subprotocol) or via HTTP cookies accessible in request.headers.cookie.
- For token-based authentication via subprotocol, see WSClient.connect() for how clients send the token.
- For cookie-based authentication (particularly useful for JWT tokens in HTTP-only cookies), cookies are automatically sent by the browser during the WebSocket handshake and can be parsed from
request.headers.cookie.
Example:
import { WSServerPubSub, WSServerError } from 'wsmini';
const wsServer = new WSServerPubSub({
port: 8887,
origins: '*',
maxNbOfClients: 500,
maxInputSize: 50000,
pingTimeout: 30000,
logLevel: 'info',
authCallback: (token, request, wsServer) => {
// Return user metadata or false if authentication fails
// Token validation is not implemented here, just an example
if (token !== 'valid-token') return false;
return { nickname: 'user123', role: 'admin' };
}
});Adds a new channel to the server. Channels allow clients to subscribe and publish messages.
Parameters:
name(string): The channel nameoptions(object, optional): Channel configuration optionsusersCanPub(boolean, optional): Whether users can publish to this channel. Default:trueusersCanSub(boolean, optional): Whether users can subscribe to this channel. Default:truehookPub(function, optional): Hook called before publishing a message. Should return the transformed message or throwWSServerErrorto reject the publication (this will cause the client's promise to be rejected). Default:(msg, client, wsServer) => msghookPubPost(function, optional): Hook called after a successful publication. Errors thrown in this hook are logged but do not affect the publication. Default:(msg, client, wsServer) => nullhookSub(function, optional): Hook called before subscribing a client. MUST returntrueto accept the subscription orfalseto reject it. Default:(client, wsServer) => truehookSubPost(function, optional): Hook called after a successful subscription. Errors thrown in this hook are logged but do not affect the subscription. Default:(client, wsServer) => nullhookUnsub(function, optional): Hook called before unsubscribing a client. Default:(client, wsServer) => nullhookUnsubPost(function, optional): Hook called after a successful unsubscription. Errors thrown in this hook are logged but do not affect the unsubscription. Default:(client, wsServer) => null
Returns: boolean - true if channel was added successfully, false if channel already exists
Example:
// Basic channel
wsServer.addChannel('chat');
// Advanced channel with hooks
wsServer.addChannel('admin-chat', {
usersCanPub: true,
usersCanSub: true,
hookPub: (msg, client, wsServer) => {
// Validate message content
if (!msg.content || msg.content.trim().length === 0) {
throw new WSServerError('Message content cannot be empty');
}
// Check user permissions
if (msg.type === 'admin' && !client.isAdmin) {
throw new WSServerError('Insufficient permissions for admin message');
}
// Transform message before broadcasting
return {
...msg,
from: client.userId,
timestamp: Date.now()
};
},
hookPubPost: (msg, client, wsServer) => {
// Called after successful publication
console.log(`User ${client.id} published to admin chat`);
},
hookSub: (client, wsServer) => {
// MUST return true to accept subscription, false to reject
return client.isAdmin; // Accept subscription for admin users
},
hookSubPost: (client, wsServer) => {
// Called after successful subscription
console.log(`User ${client.id} joined admin chat`);
},
hookUnsub: (client, wsServer) => {
console.log(`User ${client.userId} unsubscribed from admin chat`);
},
hookUnsubPost: (client, wsServer) => {
// Called after successful unsubscription
console.log(`User ${client.id} left admin chat`);
}
});Checks if a channel exists.
Parameters:
chanName(string): The channel name to check
Returns: boolean - true if channel exists, false otherwise
Example:
if (wsServer.hasChannel('chat')) {
console.log('Chat channel exists');
}Gets a channel object by name.
Parameters:
chanName(string): The channel name to retrieve
Returns: object|null - The channel object if it exists, null otherwise
The returned channel object contains:
usersCanPub(boolean): Whether users can publish to this channelusersCanSub(boolean): Whether users can subscribe to this channelhookPub(function): The publish hook functionhookPubPost(function): The post-publish hook functionhookSub(function): The subscribe hook functionhookSubPost(function): The post-subscribe hook functionhookUnsub(function): The unsubscribe hook functionhookUnsubPost(function): The post-unsubscribe hook functionclients(Set): Set of WebSocket clients subscribed to this channel
Example:
const channel = wsServer.getChannel('chat');
if (channel) {
console.log(`Channel has ${channel.clients.size} subscribers`);
console.log(`Can publish: ${channel.usersCanPub}`);
console.log(`Can subscribe: ${channel.usersCanSub}`);
}Gets an array of clients subscribed to a specific channel.
Parameters:
chanName(string): The channel name
Returns: Array|null - Array of WebSocket client objects subscribed to the channel, or null if channel doesn't exist
Example:
const clients = wsServer.getChannelClients('chat');
if (clients) {
console.log(`${clients.length} clients are subscribed to chat`);
// Iterate through all clients
for (const client of clients) {
const metadata = wsServer.clients.get(client);
console.log(`Client ${metadata.id} is subscribed`);
}
// Send a message to all subscribers
clients.forEach(client => {
wsServer.sendCmd(client, 'special-notification', {
message: 'Hello subscriber!'
});
});
}Gets an array of client metadata objects for all clients subscribed to a specific channel.
Parameters:
chanName(string): The channel name
Returns: Array|null - Array of client metadata objects, or null if channel doesn't exist
Example:
const clientsData = wsServer.getChannelClientsData('chat');
if (clientsData) {
console.log(`${clientsData.length} clients are subscribed to chat`);
for (const clientData of clientsData) {
console.log(`Client ${clientData.id} with role ${clientData.role`);
}
}Removes a channel from the server. All subscribed clients will be unsubscribed.
Parameters:
chanName(string): The channel name to remove
Returns: boolean - true if channel was removed successfully, false if channel doesn't exist
Example:
// Remove a channel
wsServer.removeChannel('old-channel');Publishes a message to all subscribers of a channel. This is a server-side publish that bypasses the hookPub function.
Parameters:
chanName(string): The channel namemsg(any): The message to publish
Returns: boolean - true if message was published successfully, false if channel doesn't exist
Example:
// Publish a server message
wsServer.pub('chat', {
user: 'System',
message: 'Server maintenance in 5 minutes',
timestamp: Date.now()
});
// Bot message example
setInterval(() => {
wsServer.pub('chat', {
user: 'Bot',
message: 'Automated message',
timestamp: Date.now()
});
}, 30000);Adds a Remote Procedure Call (RPC) endpoint that clients can invoke.
Parameters:
name(string): The RPC namecallback(function): The RPC callback function- Parameters:
(data, clientMetadata, client, wsServer) - Returns: The response to send back to the client
- Can throw
WSServerErrorto send an error response (The promise will then be rejected with the error message on the client side)
- Parameters:
Returns: boolean - true if RPC was added successfully, false if RPC already exists
Example:
import { WSServerError } from 'wsmini';
// Simple RPC
wsServer.addRpc('add', (data, clientMetadata, client, wsServer) => {
if (typeof data.a !== 'number' || typeof data.b !== 'number') {
throw new WSServerError('Both a and b must be numbers');
}
return data.a + data.b;
});
// Complex RPC with rights check
wsServer.addRpc('getUserData', (data, clientMetadata, client, wsServer) => {
if (!clientMetadata.isAdmin) {
throw new WSServerError('Authentication required');
}
// Simulate database lookup
return {
id: clientMetadata.id,
profile: { /* user profile data */ }
};
});Removes an RPC endpoint from the server.
Parameters:
name(string): The RPC name to remove
Returns: boolean - true if RPC was removed successfully, false if RPC doesn't exist
Example:
// Remove an RPC
wsServer.removeRpc('getUserData');Sends a command to a specific client.
Parameters:
client(WebSocket): The client WebSocket connectioncmd(string): The command namedata(object, optional): The command data. Default:{}
Example:
// Send command to specific client
wsServer.sendCmd(client, 'notification', {
type: 'info',
message: 'Welcome to the server!'
});Broadcasts a command to all connected clients.
Parameters:
cmd(string): The command namedata(object, optional): The command data. Default:{}
Example:
// Broadcast server announcement
wsServer.broadcastCmd('announcement', {
message: 'Server will restart in 5 minutes',
priority: 'high'
});Broadcasts a command to all clients except the specified one.
Parameters:
client(WebSocket): The client to exclude from the broadcastcmd(string): The command namedata(object, optional): The command data. Default:{}
Example:
// Notify others when a user joins
wsServer.broadcastOthersCmd(client, 'user-joined', {
id: clientMetadata.id,
timestamp: Date.now()
});Starts the WebSocket server. Inherited from WSServer.
Parameters:
options(object, optional): Additional options to pass to the underlying WebSocket server. See WSServer.start() for details.
Example:
// Basic start
wsServer.start();Stops the WebSocket server. Inherited from WSServer.
Example:
wsServer.stop();Closes the WebSocket server and cleans up all channels and RPCs.
Example:
wsServer.close();The following methods are used internally by the server and typically don't need to be called directly:
Handles PubSub actions (sub, unsub, pub, pub-simple) from clients.
Handles RPC calls from clients.
Processes incoming messages from clients.
Handles client disconnections and cleanup.
Validates if an action is supported by the server.
sendError(client, msg)sendRpcError(client, id, name, response)sendRpcSuccess(client, id, name, response)sendSubError(client, id, chan, response)sendSubSuccess(client, id, chan, response)sendPubError(client, id, chan, response)sendPubSuccess(client, id, chan, response)sendJson(client, data)