Redis publish and subscription not working on dynamic keys - php

my requirement is to publish message for specific user.
Controller
$messageQueueKey=(string)$receiver; (receiver_id)
$redis->publish($messageQueueKey, json_encode($data));
Server.js //Node js
var handshakeData = socket.request;
var messageQueueKey=handshakeData._query['userid'];
clients[socket.id] = socket;
var redisClient = redis.createClient();
redisClient.subscribe(messageQueueKey);
// redisClient.subscribe('message');
redisClient.on('message', function(channel, message)
{
var data = JSON.parse(message);
if(typeof connectedClients[data['receiver']] === 'undefined'){}
else
{
connectedClients[data['receiver']].socket.emit(channel, message);
}
});
However my code works for hard coded key 'message' but receivers receives multiple messages that is why i want to publish and subscribe each user on different keys based on their auth id

That's fine! if the user is receiving multiple message you can ignore the one :P

Related

Send FCM notification to multiple tokens using Plokko Firebase

I am using the Plokko FCM v1 library: https://github.com/plokko/php-fcm-v1
so far i am using a loop to send to multiple tokens, and it is becoming too slow as each loop is waiting for the notification to be sent, how to send to multiple tokens at once like we used to do it in legacy HTTP code.
i tried making it an array, a comma seperated value both times i am getting
The registration token is not a valid FCM registration token
any help would be appriciated
thank you
You must use registration_ids instead of to in creating an object and make an array of devices token and assign it to registration_ids as follow
const id = deviceIds;
const Title = "Title";
const message = "This is testing notification";
const messaged = {
registration_ids: id, //// multiple devices
// to: id, //// use for single device
collapse_key: 'appName',
notification: {
title:Title,
body: message
}
};
await fcm.send(messaged, function(err, response){
if (err) {
console.log(err)
// result(null,{success:false,message:"Some Error", data:err});
} else {
console.log(response)
}
});

Private Chat Messaging using Node.js, Socket.io, Redis in PHP

I am working for a real time private messaging system into my php application. My codes are working for all users together. But I need private messaging system as one-to-one message.
After setup node and redis I can get the message data what I need : here is the code ::
Front-end ::
1. I use a form for - username , message and send button
and Notification JS:
$( document ).ready(function() {
var socket = io.connect('http://192.168.2.111:8890');
socket.on('notification', function (data) {
var message = JSON.parse(data);
$( "#notifications" ).prepend("<p> <strong> " + message.user_name + "</strong>: " + message.message + "</p>" );
});
});
Server Side js:
var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
var redis = require('redis');
server.listen(8890);
var users = {};
var sockets = {};
io.on('connection', function (socket) {
console.log(" New User Connected ");
// instance of Redis Client
var redisClient = redis.createClient();
redisClient.subscribe('notification');
socket.on('set nickname', function (name) {
socket.set('nickname', name, function () {
socket.emit('ready');
});
});
socket.on('msg', function () {
socket.get('nickname', function (err, name) {
console.log('Chat message by ', name);
});
});
redisClient.on("message", function(channel, message)
{
// to view into terminal for monitoring
console.log("Message from: " + message + ". In channel: " + channel + ". Socket ID "+ socket.id );
//send to socket
socket.emit(channel, message);
});
redisClient.on('update_chatter_count', function(data)
{
socket.emit('count_chatters', data);
});
//close redis
socket.on('disconnect', function()
{
redisClient.quit();
});
});
HTML::
<script src="https://cdn.socket.io/socket.io-1.3.5.js"></script>
<form .....>
<input ....... >
</form>
<div id="notifications" ></div>
Over-all output:
John : Hello
Kate : Hi
Others: .....
Above codes are working nicely in my php application. Now I want to set-up private or one-to-one messaging system.
The way I need to add username or email or unique socketID for user. I do not have any more ideas for private messaging. I tried to figure on online but failed.
**How do I setup private message into my php application ? **
Basic initialization of variables:-
First, make a MAP of mapOfSocketIdToSocket and then send the userid of the specific user to whom you want to sent the message from the front-end. In the server, find the socket obeject mapped with the userid and emit your message in that socket. Here is a sample of the idea (not the full code)
var io = socketio.listen(server);
var connectedCount = 0;
var clients = [];
var socketList = [];
var socketInfo = {};
var mapOfSocketIdToSocket={};
socket.on('connectionInitiation', function (user) {
io.sockets.sockets['socketID'] = socket.id;
socketInfo = {};
socketInfo['userId']=user.userId;
socketInfo['connectTime'] = new Date();
socketInfo['socketId'] = socket.id;
socketList.push(socketInfo);
socket.nickname = user.name;
socket.userId= user.userId;
loggjs.debug("<"+ user.name + "> is just connected!!");
clients.push(user.userId);
mapOfSocketIdToSocket[socket.id]=socket;
}
socket.on('messageFromClient', function (cMessageObj, callback) {
for(var i=0; i<socketList.length;i++){
if(socketList[i]['userId']==cMessageObj['messageToUserID']){ // if user is online
mapOfSocketIdToSocket[socketList[i]['socketId']].emit('clientToClientMessage', {sMessageObj: cMessageObj});
loggjs.debug(cMessageObj);
}
}
})
Either you may want to go for private one-to-many chat room or you can go for one-to-one channel communication (if there are only two members communicating) http://williammora.com/nodejs-tutorial-building-chatroom-with/
I would suggest you to use socketIO namespaces, it allow you to send / emit event from / to specific communication "channels".
Here is the link to socketIO documentation regarding rooms & namespaces
http://socket.io/docs/rooms-and-namespaces/
Cheers
One solution could be sending messages to person with the particular socket id. As you are already using redis you can store the user's detail and socket id in redis when user joins and then to send messages to user by getting the socket id from the redis whenever you want to send him a message. Call events like
socket.emit('send private') from front end
and on backend handle the
socket.on('send private'){
// do redis stuff inside this }
Use Pusher. It offers channel usage to make private chats possible without any additional code

PHP + SockJS + Redis: Unicast

My application stack:
On my server runs a Redis server. The PHP backend communicates with Predis library with the Redis server. It will publish messages. These messages will be fetched by my Redis client (node.js) and pushed to the connected websocket clients (with SockJS).
My problem:
It runs well. At least for broadcast messages. Now I came to the point I need to send a unicast message and I'm stuck... How to connect the user on the backend side (sender of messages) with the connected client of the websocket?
Code snippets:
PHP
$redis = new Client();
$redis->publish('updates', Random::getUniqueString());
Redis client on node.js server
redis.subscribe('updates');
redis.on('message', function(channel, data) {
for (var id in sockets) {
if (sockets.hasOwnProperty(id)) {
sockets[id].write(data);
}
}
});
SockJS client
mySocketFactory.setHandler('message', function(event) {
console.log(event.data);
});
Like I said. Working well but the id used for the socket connection is not known by the PHP backend.
Edit: One idea I got in mind is to use cookies.
I found a way to solve my problem. When the socket connection is established I sent a request to my PHP backend and ask for the user id. This is stored on the node.js server. When messages are incoming there is a check if they are for specific user and handle them only for them.
So, what do I store exactly on my node server?
var sockets = {}; // {connection_id: socket_connection}
var connIdToUser = {}; // {connection_id: user_id}
var connIdsForUser = {}; // {user_id: [connection_id_1, connection_id_2 ,...]}
socketServer.on('connection', function(conn) {
sockets[conn.id] = conn;
var options = {
host: os.hostname(),
port: 80,
path: '/user/id',
method: 'GET'
};
var req = http.request(options, function(res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
var userId = JSON.parse(chunk).id;
connIdToUser[conn.id] = userId;
if (!connIdsForUser.hasOwnProperty(userId)) {
connIdsForUser[userId] = [];
}
connIdsForUser[userId].push(conn.id);
console.log('connection id ' + conn.id + ' related to user id ' + userId);
});
});
req.end();
conn.on('close', function() {
console.log('connection lost ' + conn.id);
// remove connection id from stack for user
var connections = connIdsForUser[connIdToUser[conn.id]];
var index = connections.indexOf(conn.id);
if (index > -1) {
connections.splice(index, 1);
}
// remove connection at all
delete sockets[conn.id];
// remove relation between connection id and user
delete connIdToUser[conn.id];
});
});
The reason for storing the relation between user id an connection id twice is the different use case I need either for sending a message or deleting the connection for the close event. Otherwise I would have to use a nested loop.
As you can see deleting a socket is fairly easy. Although deleting the connection from the connection stack of an user is a little bit complicated.
Let's continue with the sending of a message. Here I defined a structure of the message I get from the Redis server:
{
targets: [], // array of unit ids (can be empty)
data: <mixed> // the real data
}
Sending the data to the sockets looks like:
redis.on('message', function(channel, message) {
message = JSON.parse(message);
// unicast/multicast
if (message.targets.length > 0) {
message.targets.forEach(function(userId) {
if (connIdsForUser[userId] !== undefined) {
connIdsForUser[userId].forEach(function(connId) {
sockets[connId].write(message.data);
});
}
});
// broadcast
} else {
for (var id in sockets) {
if (sockets.hasOwnProperty(id)) {
sockets[id].write(message.data);
}
}
}
});
Since I store the connection stack per user it is quite easy to send the data to all sockets related to a specific user. So what I can do now is unicast (array with one user id), multicast (array with more than one user id) and broadcast (empty array).
It's working well for my use case.

memcache + socket.io + php application to read sessions and chat with each other

i used multi room chat application example for node.js writed by mike in this article.and changed it to use session data which grabed from php session handler until now
this is the part of code which i wrote until now
var express = require('express'),
app = express(),
memcache = require("memcache"),
http = require('http'),
server = http.createServer(app),
io = require('socket.io').listen(server),
co = require("./cookie.js"),
php = require('phpjs'),
codein = require("node-codein");
//check if user loggedin
// routing
app.get('/', function (req, res) {
res.sendfile(__dirname + '/index.html');
var cookieManager = new co.cookie(req.headers.cookie);
var client = new memcache.Client(11211, "localhost");
client.connect();
user = client.get("sessions/"+cookieManager.get("sec_session_id"), function(error, result){
var session = JSON.parse(result);
user = JSON.parse(session.name);
user = user.username;
storeUsername(user);
});
});
function storeUsername(user){
// usernames which are currently connected to the chat
var usernames = {};
io.of('/private').authorization(function (handshakeData, callback) {
console.dir(handshakeData);
handshakeData.foo = 'baz';
callback(null, true);
}).io.sockets.on('connection', function (socket) {
usernames[socket.id] = socket;
// when the client emits 'sendchat', this listens and executes
socket.on('sendchat', function (data) {
// we tell the client to execute 'updatechat' with 2 parameters
io.sockets.emit('updatechat', socket.username, data);
});
// when the client emits 'adduser', this listens and executes
socket.on('adduser', function(username){
// we store the username in the socket session for this client
socket.username = user;
// add the client's username to the global list
// echo to client they've connected
if(php.in_array(socket.username,usernames)){
delete usernames[socket.username];
}else{
usernames[user] = user;
console.log('not exist');
socket.emit('updatechat', 'SERVER', 'you have connected');
// echo globally (all clients) that a person has connected
socket.broadcast.emit('updatechat', 'SERVER', username + ' has connected');
// update the list of users in chat, client-side
io.sockets.emit('updateusers', usernames);
}
});
// when the user disconnects.. perform this
socket.on('disconnect', function(){
// remove the username from global usernames list
delete usernames[socket.username];
// update list of users in chat, client-side
io.sockets.emit('updateusers', usernames);
// echo globally that this client has left
socket.broadcast.emit('updatechat', 'SERVER', socket.username + ' has disconnected');
});
});
}
server.listen(3000);
for example user master will connect to our chatroom and he will have his username which stored from php based application.but where is the problem now?when user master connect from 2 or 3 tab of our browser he will connect to socket server 3 or 4 times and if he post some data we have this result
master : hello
master : hello
master : hello
i want users to connect to my application just once and can post data just once.now how should i achieve that?
how should i access this users in case of private message to each other
i am so new in node.js.my bad.sorry
thanks for help in advance.+1 for all teachers
1) You could you (seems to), var app = require('express').express();
2) On first app.get, you don't need to put 2 times JSON.parse, maybe the second JSON.parse is not what you want (are you trying to retrieve user threw that field ?)
3) MOST IMPORTANT : to make usage of room, you must use socket.join to join a room, if you don't
do it, the socket.broadcast will have no special effect...
To remove a user from a room, use socket.leave

notification system with php and socket.io

Im trying to build an notification system with php and socket.io. The idea is, the clients connect to socket.io and are waiting for notification. A PHP script connects to socket.io via curl on another port and posts the update even, which gets passed to the connected clients. The clients are identified via an id they send in a message after the connection event. I Store the socket variable associated to the user_id. Everything works fine, but after some time the script stops working. It seems that after some time the socket variable which is stored in an array. However my server-code is posted below
var notification_port = 8001;
var oak_port = 8002;
var io = require('socket.io').listen(notification_port);
var clients = new Array();
io.sockets.on("connection", function(socket){
socket.on("__identification", function(message){
if (message.id){
console.log("user with session id " + message.id + " connected!");
var sockets = clients[message.id];
if (!sockets){
sockets = new Array();
}
sockets.push(socket);
clients[message.id] = sockets;
}
});
});
var url = require('url');
var oakListener = require('http').createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
var url_parts = url.parse(req.url, true);
var query = url_parts.query;
var sockets = clients[query.id];
if (sockets){
for (var i = 0; i < sockets.length; i++){
sockets[i].emit("notification", query);
}
res.end('ok');
} else {
res.end('failed');
}
}).listen(oak_port);
you have to add a handler for disconnect like explained below:
socket.on('disconnect', function () {
//delete socket from sockets;
});
The problem was, that the connection gets lost about every minute. You have to gargabe collect in the "disconnect" function and re initializing the connection in the "connection" function

Categories