4

I'm creating Chat app in Laravel 5.4 using socket.io at client side also sending APNS notification to a target user.

While doing this when user send Message to target user that Message send more than once means It depends upon number of connections connected with node socket.io server which I'm thinking it's mean's My channel ('messages') looping that message to connected number of clients so it's showing more than once at receiver side. Here My Sender Side (Laravel):

    $redis = LRedis::connection();
        $data = [
            'message' => $msg,
            'user' => $auth,
            'music'=>$music,
            'target_user'=>$target_user
            ];
 $redis->publish('message', json_encode($data));

At socket.js:

var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
var redis = require('redis');
var apn = require('apn');
var request = require('request');
var auth_user_id = null;
var mysql = require('mysql');

var con = mysql.createConnection({
  host: "localhost",
  user: "root",
  password: "",
  database: "database"
});

con.connect(function(err) {
  if (err) throw err;
  console.log("Database Connected!");
});
var options = {
    token: {
        key: "app-keys/APNsAuthKey_U3QV9H86BR.p8",
        keyId: "keyId",
        teamId: "teamid",
        cert: "app-keys/musicChatAppDevelopment.pem",
    },
    development: true,
    production: false,
};
var apnProvider = new apn.Provider(options); 
server.listen(8890);
io.on('connection', (socket) => {
    var auth_user_id = socket.handshake.query.auth_user_id; 
    console.log("client connected");
    console.log("Client Socket id--"+socket.id+"-----User Id----"+auth_user_id);
    var redisClient = redis.createClient();
    redisClient.subscribe('message');   
        if(auth_user_id>0) {
            var sql = "UPDATE users SET socket_id ='"+socket.id+"' WHERE id ="+auth_user_id;
                con.query(sql, function (err, result) {
                    if (err) throw err;
                    console.log(result.affectedRows + " record(s) updated");
                });
        }
    redisClient.on('message', (channel, data) => {
        console.log(channel);
            let data_= JSON.parse(data);
            let message_ = data_.message;
            let deviceToken = data_.target_user['ios_token'];
            if(data_.user['id']!=data_.target_user['id']) {
            console.log(data_.target_user['ios_token']);
            var note = new apn.Notification();
            note.expiry = Math.floor(Date.now() / 1000) + 3600; // Expires 1 hour from now. 
            note.badge = 0;
            note.sound = "ping.aiff";
            note.alert = {
                "title" : data_.user['first_name'],
                "body" :  message_,
                };
            note.payload =  { "aps" : {
                                "alert" : {
                                "title" : data_.user['first_name'],
                                "body" :  message_
                                } 
                             }
                    }
            note.topic = "com.charpixel.hellodemo";
            console.log(note);
            let socketId = data_.target_user['socket_id'];
                apnProvider.send(note, deviceToken).then( (result) => {
                    console.log(JSON.stringify(result)); 
                });    
                console.log("Target User Socket id "+data_.target_user['socket_id']);
                socket.broadcast(data_.target_user['socket_id']).emit(channel, data);
                io.to(socketId).emit(channel,data);

        }

    });
    socket.on('disconnect', () => {
        redisClient.quit();
    });  
});

At index.blade.php:

var ip = '<?php echo config('app.current_ip'); ?>:8890?auth_user_id='+JSON.parse(user_id)['id'];
    console.log("Curent_URL"+ip);
    var socket = io.connect(ip);
    socket.on('message', function (data) {
});

Also getting apns notification multiple times on my IOS App.

StealthTrails
  • 2,281
  • 8
  • 43
  • 67
honor_123
  • 41
  • 5

1 Answers1

3

For 1-1 chat you should create separate channel for each chat. Your code sends message on channel 'message' which is subscribed by every client. So there are multiple problems here. For example, if you have 3 clients:

  1. redisClient.on('message') will be triggered for all 3 clients.
  2. As the data remains same (which means device token remains same), no matter for which client on('message) was triggered, the notification will be sent to the same receiver and that's the reason why you are receiving multiple notifications.

The solution is that you should create a unique channel for each chat. See this stackoverflow answer as an example. Its not using redis but you can change it to work with reddis too.

Qandeel Abbassi
  • 999
  • 7
  • 31
  • This Case also create Problem in future like if I set private channel w.r.t to User ID or User Name like ('user_123') if this user chatting with ('user_456') and at same time he is chatting with another user ('user_789') so when ('user_123') emit message to ('user_456') then it will sent two times because he has connection with ('user_456') and ('user_789')... Getting my point? – honor_123 Jan 25 '18 at 12:08
  • I have another question why not Socket.id is working? – honor_123 Jan 25 '18 at 12:10
  • First thing, why would it be sent multiple times? If user_123 emits message to channel 'user_456' then only user_456 will get the message because only he has subscribed to 'user_456'. If you are doing it other way i.e: user is subscribing to other two channels rather than its own, then yes the problem you pointed out will occur. – Qandeel Abbassi Jan 25 '18 at 14:47
  • Second thing, this is not what i suggested exactly. Your channel naming convention and pub/sub logic is wrong according to your comment. The channel should be named something like this 'user_123-user_456' and both user_123 and user_456 should be subscribed to this channel for their private chat and no one else. This way every 1-1 chat would have its own unique channel and multiple notifications won't occur. – Qandeel Abbassi Jan 25 '18 at 14:52
  • and what's the problem with socket.id? is it undefined? – Qandeel Abbassi Jan 25 '18 at 14:55
  • hi Qadeel, Dynamic channels are not working. Connections established but not listening at socket.js let dynamic_channel = 'from_'+socket.handshake.query.auth_user+'_user_to_'+socket.handshake.query.target_user; console.log(dynamic_channel); var redisClient = redis.createClient(); redisClient.subscribe(dynamic_channel); redisClient.on(dynamic_channel, (channel, data) => { – honor_123 Jan 26 '18 at 14:08
  • have you checked that the channel you are publishing on is same as the one the user has subscribed? also console.log(dynamic_channel); is inside io.on('connection'), right? do you see the dynamic channel printed in console? – Qandeel Abbassi Jan 26 '18 at 16:49