Basic usage
API overview
[Server] Create a server
Similar logic should already be inside server.js
if using the default boilerplate:
// --- in server.js ---
const http = require('http');
const socketClusterServer = require('socketcluster-server');
let options = {
// ...
};
let httpServer = http.createServer();
let agServer = socketClusterServer.attach(httpServer, options);
// port 8000
httpServer.listen(8000);
The httpServer
argument must be an instance of a Node.js HTTP server.
The list of possible options
which can be passed to the SocketCluster server instance can be found here.
Note that you can also use the ECMAScript import
syntax.
[Server] Listen for inbound socket connections
Inside server.js
, you can find the for-await-of
loop which is handling inbound connections. It should look like this:
// --- in server.js ---
// SocketCluster/WebSocket connection handling loop.
(async () => {
for await (let {socket} of agServer.listener('connection')) {
// Handle socket connection.
}
})();
[Client] Connect to the server
Inside public/index.html
, a client connects to the server like this:
// --- in public/index.html ---
let socket = socketClusterClient.create();
^ If the connection succeeds, this will cause the connection
loop on the server side to iterate once.
!! You can pass an options
object to the socketClusterClient.create(...)
function.
[Server] Listen for inbound messages on a socket
You can use a socket.receiver(...)
within a for-await-of
loop to handle messages on a socket:
// --- in server.js ---
// SocketCluster/WebSocket connection handling loop.
(async () => {
for await (let {socket} of agServer.listener('connection')) {
(async () => {
// Set up a loop to handle remote transmitted events.
for await (let data of socket.receiver('customRemoteEvent')) {
// ...
}
})();
}
})();
!! You can also iterate over a socket.receiver(receiverName)
stream on a client socket using the same syntax.
[Client] transmit messages through a socket
// --- in public/index.html ---
// ... After the socket is created.
socket.transmit('customRemoteEvent', 123);
^ If the message reaches the server, this will cause the customRemoteEvent
loop on the server side to iterate once; data
will be 123
.
!! You can also use the same syntax to transmit from the server socket. Transmit can never fail, so you don’t need to wrap it in a try-catch
block.
[Server] Listen for inbound RPCs on a socket
Unlike messages, RPCs expect a response from the other side.
You can use a socket.procedure(...)
within a for-await-of
loop to handle RPCs on a socket:
// --- in server.js ---
// SocketCluster/WebSocket connection handling loop.
(async () => {
for await (let {socket} of agServer.listener('connection')) {
(async () => {
// Set up a loop to handle and respond to RPCs.
for await (let request of socket.procedure('customProc')) {
if (request.data && request.data.bad) {
let badCustomError = new Error('Server failed to execute the procedure');
badCustomError.name = 'BadCustomError';
request.error(badCustomError);
continue;
}
request.end('Success');
}
})();
}
})();
!! You can also iterate over a socket.procedure(procedureName)
stream on a client socket using the same syntax.
[Client] Invoke RPCs through a socket
// --- in public/index.html ---
// ... After the socket is created.
(async () => {
let result = await socket.invoke('customProc', {foo: 'bar'});
// result will be 'Success'
})();
!! You should always add a try-catch
block around the socket.invoke(...)
call to capture async errors:
// --- in public/index.html ---
// ... After the socket is created.
(async () => {
let result;
try {
result = await socket.invoke('customProc', {bad: true});
} catch (error) {
// error will throw.
// error.name will be 'BadCustomError'.
}
})();
!! You can also use the same syntax on server sockets.
[Client] Subscribe to a channel and watch for messages
(async () => {
let channel = socket.subscribe('foo');
for await (let data of channel) {
// ... Handle channel data.
}
})();
[Client] Publish to a channel without waiting for acknowledgement
// Publish data; do not wait for an acknowledgement from the server.
socket.transmitPublish('foo', 'This is some data');
!! You can also call transmitPublish
on an AGChannel
object; in this case, you should omit the first argument, for example:
let fooChannel = socket.channel('foo');
fooChannel.transmitPublish('This is some data');
[Client] Publish to a channel and wait for acknowledgement
(async () => {
try {
// Publish data; wait for an acknowledgement from the server.
await socket.invokePublish('foo', 'This is some more data');
} catch (error) {
// ... Handle potential error if server does not acknowledge before timeout.
}
})();
!! You can also call invokePublish
on an AGChannel
object; in this case, you should omit the first argument, for example:
(async () => {
let fooChannel = socket.channel('foo');
try {
// Publish data; wait for an acknowledgement from the server.
await fooChannel.invokePublish('This is some more data');
} catch (error) {
// ... Handle potential error if server does not acknowledge before timeout.
}
})();
[Server] Publish to a channel without waiting for acknowledgement
// Publish data; do not wait for an acknowledgement from the back end broker.
agServer.exchange.transmitPublish('foo', 'This is some data');
[Server] Publish to a channel and wait for acknowledgement
(async () => {
try {
// Publish data; wait for an acknowledgement from the back end broker (if it exists).
await agServer.exchange.invokePublish('foo', 'This is some more data');
} catch (error) {
// ... Handle potential error if broker does not acknowledge before timeout.
}
})();