如何使用laravel 5.4中的LRedis和nodejs中的socket.io将apns通知或消息发送到同一通道中的特定用户?

时间:2018-01-23 19:09:39

标签: node.js sockets redis laravel-5.4

我在Laravel 5.4中使用socket.io在客户端创建聊天应用程序,同时向目标用户发送APNS通知。

当用户向目标用户发送消息时,消息发送多次意味着这取决于与节点socket.io服务器连接的连接数量,我认为它的意思是我的频道('messages')循环该消息连接数量的客户端,因此它在接收方显示不止一次。 在这里我的发送方(Laravel):

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

在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();
    });  
});

在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) {
});

还在我的IOS应用程序上多次获取apns通知。

1 个答案:

答案 0 :(得分:3)

对于1-1聊天,您应该为每个聊天创建单独的频道。您的代码会在频道&#39;消息&#39;上发送消息。这是每个客户订阅的。所以这里有很多问题。例如,如果您有3个客户端:

    将为所有3个客户启动
  1. redisClient.on('message')
  2. 由于数据保持不变(这意味着设备令牌保持不变),无论触发了哪个客户端(&#39;消息),通知都将被发送到同一个接收器,原因是什么你收到多个通知的原因。
  3. 解决方案是您应该为每个聊天创建一个唯一的频道。请参阅this stackoverflow答案作为示例。它不使用redis,但你可以改变它以使用reddis。