nehalist
nehalist

Reputation: 1496

Filter notifications within policy

Whenever a model is created (or deleted/modified) every connected socket is notified through Sails autowatch setting. That's fine to some extent, but I'd like to filter these notifications at some point.

My application has its own "Notifications" which should be sent to their respective receiver. So their anatomy is somewhat like: id, message, receiver, sender.

Authentication is a local passport implementation.

Listening for notification events result in getting notified every time a notification is created.

// client: app.js
io.socket.on('notification', function(evt) { console.log(evt); });

What I try to achieve now is to filter these notifications to match the user id. I've written a policy which gets applied to the /notification events.

// Policy: forUser
module.exports = function(req, res, next) {
  // ... whatever ... //

  return next();
}

Within the policies

  'notification': {
    'create': ['passport', 'forUser']
  }

My problem now is: how to implement this policy? I thought of just checking for notification.receiver == req.user.id, but how to get the notification model within the policy (if this is the right way at all)?

Thanks.

Edit: Tried implementing the room solution, but I don't get any notifications on the client.

I've altered my subscribe function within my NotificationController:

subscribe: function(req, res) {
        sails.log.info('Your user id: ' + req.user.id);
        sails.sockets.join(req.socket, 'user_notifications_' + req.user.id);
        res.json({
            room: 'user_notifications_' + req.user.id
        });
    },

And added a afterCreate method to my model:

afterCreate: function(model, next) {
    sails.sockets.broadcast('user_notifications_' + model.receiver, { test: 'hello' });
    next();
  }

Code on client is now:

  io.socket.get("/notification/subscribe", function(data, jwr) {
    io.socket.on(data.room, function(obj) {
      console.log(obj);
    });
  });

The subscription method is called and returns the right room name. But I don't get any messages when calling /notification/create?message=test&receiver=1. The afterCreate method is called, all user ids are right (since there's only one user), but nothing happens.

Edit2: It seems like joining the rooms fails.

sails.sockets.join(req.socket, 'testroom');
// For testing
sails.log.debug(sails.sockets.socketRooms(req.socket));

The room gets created, but the socket is not subscribed to it.

Edit3: Found the solution. I'll post the GitHub link as soon as the interface is done.

Upvotes: 1

Views: 126

Answers (1)

Alexis N-o
Alexis N-o

Reputation: 3993

Are you using sails.sockets.blast() to send your notifications?

To send custom events, you could use sails.sockets.emit()

// Controller action
actionSendingNotification: function(req, res) {
  // Retrieve the user socket ID and the data to send
  // ...
  sails.sockets.emit(userSocketId, 'notification', data);
}

You have to be able to know if the user has an active websocket connection and retrieve his socket ID. He could have several tabs opened in his browser and several websocket connections ...

A probably better solution would be to use sails.sockets.join() and sails.sockets.broadcast(). You would then create the association between the connected user and the observed event within socket.io.

// When the user creates a websocket connection, subscribe him to the model room
// This action MUST be called by a websocket request
// Here I assume your event is related to a model
subscribeToModelRoom: function(req, res) {
  var roomName = 'myModelRoom' + req.param('model_id');
  sails.sockets.join(req.socket, roomName);
  res.json({
    message: 'Subscribed to a room called '+roomName+'!'
  });
}

Then every time you send a message to the room, the subscribed user will receive it.

// When the model has to send a notification, use broadcast() to send it to the room associated to the model.
sails.sockets.broadcast('myModelRoom' + modelInstance.id, 'notification', data);

Edit Reading your question again, I will add some explanations.

It seems that you try to send your notification to a user, based on his user.id. You cannot assume that this user will be connected via websocket when you send this notification. You don't send events to a user, but to a opened websocket connection (that may be authenticated).

If the user must not miss the notification, you have to store it in a database. You will then show it to the user when he will be connected.

If you want the user to be informed in real time while he is connected, you could subscribe him to a room "user_notifications_" + user.id when you initialize his authenticated websocket connection. Then emit an event to this room when you create a new notification.

You could add the logic to manage seen / not seen notifications and delete the obsolete records.

This way, you can send information to your users in real time and you will not lose the information if nobody is here to receive it.

Upvotes: 2

Related Questions