admin管理员组

文章数量:1431466

I want to make a notifications system based on events triggered by a user and gets delivered to another user ('X wrote on your wall). I understand the logic of broadcasting event, but if I broadcast, the message will be sent to everyone on the channel.

I am using Laravel 5 and I used Jeffrey Way's Nodejs, Redis, Socket.io tutorial. Very helpful.

For broadcasting and catching the messages,

  • Server.js

    var server = require('http').Server();
    var io = require('socket.io')(server);
    
    var Redis = require('ioredis');
    var redis = new Redis();
    
    redis.subscribe('globalNotificationChannel');
    
    redis.on('message', function(channel, message) {
        message = JSON.parse(message);
    
        io.emit(channel + ':' + message.event, message.data);
    });
    
    server.listen(3000);
    
    • Client

      <script>
         var socket = io('http://localhost:3000');
      
         socket.on('globalNotificationChannel:WroteOnWall', function(data) {
              //     (Notification Received)
             //      console.log(data.message)
           }.bind(this));
         }
      <script>
      
    • Triggering Action

      $data = [
        'event' => 'WroteOnWall',
        'data' => [
            'message' => $username + ' wrote on your wall.'
        ]
      ];
      
      Redis::publish('globalNotificationChannel', json_encode($data));
      

Until here everything is clear however at this point I got lost. I have couple of questions.

  • First, how do I deliver the triggered event to a specific user's channel if everyone gets subscribed on the same channel.

  • Or is there a way of making unique channels? If so, how can I store the unique_channel_ids to prevent any bug?

  • And secondly, I have seen people are using cluster. Is it a good use for my case? Will it give me any benefits to me?

  • Note that on the Client side, I inserted it in master page as I need to run in every page, but now, I need to call 'connection' and 'listening' in every page. When re-run the connection scripts won't I end up with differing socketids?

Edit: I found this SO answer, and I believe it solves my problem, but I couldn't adapt it on redis instance.

I want to make a notifications system based on events triggered by a user and gets delivered to another user ('X wrote on your wall). I understand the logic of broadcasting event, but if I broadcast, the message will be sent to everyone on the channel.

I am using Laravel 5 and I used Jeffrey Way's Nodejs, Redis, Socket.io tutorial. Very helpful.

For broadcasting and catching the messages,

  • Server.js

    var server = require('http').Server();
    var io = require('socket.io')(server);
    
    var Redis = require('ioredis');
    var redis = new Redis();
    
    redis.subscribe('globalNotificationChannel');
    
    redis.on('message', function(channel, message) {
        message = JSON.parse(message);
    
        io.emit(channel + ':' + message.event, message.data);
    });
    
    server.listen(3000);
    
    • Client

      <script>
         var socket = io('http://localhost:3000');
      
         socket.on('globalNotificationChannel:WroteOnWall', function(data) {
              //     (Notification Received)
             //      console.log(data.message)
           }.bind(this));
         }
      <script>
      
    • Triggering Action

      $data = [
        'event' => 'WroteOnWall',
        'data' => [
            'message' => $username + ' wrote on your wall.'
        ]
      ];
      
      Redis::publish('globalNotificationChannel', json_encode($data));
      

Until here everything is clear however at this point I got lost. I have couple of questions.

  • First, how do I deliver the triggered event to a specific user's channel if everyone gets subscribed on the same channel.

  • Or is there a way of making unique channels? If so, how can I store the unique_channel_ids to prevent any bug?

  • And secondly, I have seen people are using cluster. Is it a good use for my case? Will it give me any benefits to me?

  • Note that on the Client side, I inserted it in master page as I need to run in every page, but now, I need to call 'connection' and 'listening' in every page. When re-run the connection scripts won't I end up with differing socketids?

Edit: I found this SO answer, and I believe it solves my problem, but I couldn't adapt it on redis instance.

Share Improve this question edited May 23, 2017 at 12:09 CommunityBot 11 silver badge asked Oct 6, 2015 at 1:54 sentysenty 12.9k30 gold badges141 silver badges267 bronze badges 4
  • Here are two ways I've seen it done: 1. Keep reference to the user's sockets on the server. OR 2. Have the users join a unique room generated from their id and use that room to reach them. I prefer 2. – Dave Thomas Commented Oct 6, 2015 at 2:16
  • If 2 is better, I'd go for 2. But, as far as I understand, there are 3 dimensions: channel - event - event data. What do you mean by rooms? Channels? Is there something I am missing? – senty Commented Oct 6, 2015 at 2:19
  • Rooms as specified here: socket.io/docs/rooms-and-namespaces – Dave Thomas Commented Oct 6, 2015 at 2:26
  • So, it's just in the server side, I just use io.connected[socketid].emit(channel + ':' + message.event, message.data); instead of io.emit(channel + ':' + message.event, message.data); ? – senty Commented Oct 6, 2015 at 2:35
Add a ment  | 

1 Answer 1

Reset to default 7

Alright here it is as per #2 in my ment above. Forgive me for not including Redis into the mix here.

Your server probably has some sort of authentication login endpoint. I'm going to use json web token in this example. You may use something else. But you will need a way identify your users in your socket connections. https://auth0./blog/2014/01/15/auth-with-socket-io/

A client authenticates in some way perhaps a RESTful API call and gets a json web token:

//Server

var jwt = require('jsonwebtoken');
var returnedToken = jwt.sign(user, app.get('superSecret'), {
            expiresInMinutes: 1440 // expires in 24 hours
        });

Then they connect to your socket.io server passing that token in the query as ?token="fasfsadfsaf"

//Client

var socket = io('http://localhost:3000', { query: 'token='+token });

On your sever you handle decoding the token into a user

//Server

//This adds the jwt session token to handshake when connecting to the socket
var socketioJwt = require('socketio-jwt');
io.use(socketioJwt.authorize({
    secret:'superSecret',
    handshake:true
}));

//When a user connects throw them in their own unique room

io.on('connection', function (socket) {
    //This will get the encoded user object in the JWT token
    var user = socket.decoded_token;

    //This puts them into their unique room
    socket.join('user_room_'+user._id);
});

The user can now be reached by broadcasting to that room

io.to('user_room_'+referenceToSameUserId).emit('Your message');

For your other questions:

  • Cluster will help you scale across multiple processes/servers. Redis helps with this as well. Add this when you got the basic frame down.

  • If your users are reconnecting at every page perhaps the pages should be loaded with ajax? You don't have to worry about different socket ids if you are identifying the users by some sort of authentication method rather than by the socket id.

Sorry if this answer isn't a plete answer, I'm new to this stuff too as well. But hopefully this is some direction that you can work with. Just helping some more since I started off in the ments.

本文标签: javascriptEvent Broadcasting to a Specific User (socketioredisnode)Stack Overflow