Subscribe the requesting client socket to changes/deletions of one or more database records.
Something.subscribe(req, ids);
Argument | Type | Details | |
---|---|---|---|
1 | req | The incoming socket request (req ) containing the socket to subscribe. |
|
2 | ids | An array of record ids (primary key values). |
When a client socket is subscribed to a record, it is a member of its dynamic "record room". That means it will receive all messages broadcasted to that room by .publish()
.
On the server, in a controller action:
// On the server:
subscribeToLouies: function (req, res) {
if (!req.isSocket) {
return res.badRequest('Only a client socket can subscribe to Louies. But you look like an HTTP request to me.');
}
// Let's say our client socket has a problem with people named "louie".
// First we'll find all users named "louie" (or "louis" even-- we should be thorough)
User.find({ or: [{name: 'louie'},{name: 'louis'}] }).exec(function(err, usersNamedLouie){
if (err) {
return res.serverError(err);
}
// Now we'll subscribe our client socket to each of these records.
User.subscribe(req, _.pluck(usersNamedLouie, 'id'));
// All done! We could send down some data, but instead, we just send an empty 200 (OK) response.
//
// > Although we're ok telling this vengeful client socket when our users get
// > destroyed, it seems ill-advised to send him our Louies' sensitive user data.
// > (We don't want to help this guy to hunt them down in real life!)
return res.ok();
});//</ User.find() >
}
Then, back in our client-side code:
// On the client:
// Send a request to the "subscribeToLouies" action, subscribing this client socket
// to all future events that the server publishes about Louies.
io.socket.get('/foo/bar/subscribeToLouies', function (data, jwr){
if (jwr.error) {
console.error('Could not subscribe to Louie-related notifications: '+jwr.error);
return;
}
console.log('Successfully subscribed.');
});
From now on, as long as our requesting client socket stays connected, it will receive a notification any time our server-side code (e.g. other actions or helpers) calls User.publish()
for one of the Louies we subscribed to above.
In order for our client-side code to handle these future notifications, it must listen for the relevant event with .on()
. For example:
// Whenever a `user` event is received, say something.
io.socket.on('user', function(msg) {
console.log('Got a message about a Louie: ', msg);
});
See Concepts > Realtime for more background on the difference between rooms and events in Sails/Socket.io.
For some applications, you may run across the need to manage two different channels related to the same record. To accomplish this, you can combine .getRoomName() and sails.sockets.join():
// On the server, in your subscribe action…
var orgId = req.param('organizationId');
if (!orgId) { return res.badRequest(); }
if (!req.isSocket) { return res.badRequest('This action is designed for use with WebSockets.'); }
var me = await User.findOne({
id: req.session.userId
})
.populate('globalAdminOfOrganizations', {
where: { id: orgId },
select: ['id']
});
// Subscribe to general notifications.
Organization.subscribe(req, orgId);
// If this user is a global admin of this organization, then also subscribe them to
// an additional private room (this is used for additional notifications intended only
// for global admins):
var isGlobalAdminOfThisOrg = (globalAdminOfOrganizations.length > 0);
if (isGlobalAdminOfThisOrg) {
var privateRoom = Organization.getRoomName(req.param('organizationId')) + 'admins-only';
sails.sockets.join(req, privateRoom);
}
return res.ok();
Then later, to publish to one of these rooms, just compute the appropriate room name and use sails.sockets.broadcast() to blast out your notification.
- Be sure and check
req.isSocket === true
before passing inreq
to refer to the requesting socket. The providedreq
must be from a socket request, not just any old HTTP request..subscribe()
will only work with requests made over a socket.io connection (e.g. usingio.socket.get()
), not over an http connection (e.g. usingjQuery.get()
). See the sails.io.js socket client documentation for information on using client sockets to send WebSockets/Socket.io messages with Sails.- This function does not actually talk to the database! In fact, none of the resourceful pubsub methods do. Remember: these are just a simplified abstraction layer built on top of the lower-level
sails.sockets
methods, designed to make your app cleaner and easier to debug by using conventional names for events/rooms/namespaces etc.