when users online and don't close our clients such as browser tab or android application, i can send message to each specific user by
socket.broadcast.to(socketId)
.emit('new message', {
username: data.fromUsername,
money : 'Hurrraaa'
});
when users close clients as mobile application this event don't trigger but i can send any message to broadcast as:
socket.broadcast.emit('new message', "hooooorrrrraaaaa");
my users don't use client application any time, but i need to send message to some specific user and notify user until opening application and see message, users should be on'time in my application to get every message which i want to send from server like with Chat messengers which don't need users currently are using application such as WhatsApp, how can i resolve this problem?
then problem is send message to some specific users when they are istalled application and logged ti sever, but not using now and application waiting to receive message such as broadcast or special message to himself
this code is my simplified server:
var socket = require('socket.io'),
express = require('express'),
app = express(),
server = require('http').createServer(app),
io = socket.listen(server),
port = process.env.PORT || 3000,
mysql = require('mysql'),
uuid = require('node-uuid'),
datetime = require('node-datetime'),
moment = require('moment'),
bcrypt = require('bcrypt'),
async = require('async'),
request = require('request'),
redis = require("redis"),
redisClient = redis.createClient(),
forever = require('forever'),
log = require('log4node');
var io_redis = require('socket.io-redis');
io.adapter(io_redis({host: 'localhost', port: 6379}));
require('sticky-socket-cluster/replace-console')();
var options = {
workers : require('os').cpus().length,
first_port : 8000,
proxy_port : 3000,
session_hash: function (req, res) {
return req.connection.remoteAddress;
},
no_sockets: false
};
require('sticky-socket-cluster')(options, start);
function start(port) {
io.sockets.on('connection', function (socket) {
socket.on('new message', function (data) {
socket.broadcast.emit('new message', "hooooorrrrraaaaa");
});
socket.on('login', function (data) {
log.info(JSON.stringify(data))
login(data.username, data.password, function (success, value) {
if (success) {
redisClient.exists(data.username, function (err, doesExist) {
if (err) return;
if (!doesExist) {
redisClient.set(data.username, socket.id, function (err, res) {
redisClient.set(data.username, socket.id);
});
}
else {
redisClient.del(data.username);
redisClient.set(data.username, socket.id, function (err, res) {
redisClient.set(data.username, socket.id);
});
}
});
socket.emit('login', {
result : true,
id : value.id,
registeredMobileNumber: value.registeredMobileNumber
});
} else {
socket.emit('login', {result: false});
}
});
});
socket.on('userConnected', function (username) {
redisClient.exists(username, function (err, doesExist) {
if (err) return;
if (!doesExist) {
redisClient.set(username, socket.id, function (err, res) {
redisClient.set(username, socket.id);
});
}
else {
redisClient.del(username);
redisClient.set(username, socket.id, function (err, res) {
redisClient.set(username, socket.id);
});
}
});
});
socket.on('disconnectUser', function (data) {
redisClient.exists(data.username, function (err, doesExist) {
if (err) return;
if (doesExist) {
redisClient.del(data.username);
}
});
});
server.listen(port, function () {
console.log('Express and socket.io listening on port ' + port);
});
}
You can use socket.on('disconnect', function() {});
When a User disconnects , save the users user_id.
Subsequent message on the user_id would be saved in the server.
When the client reconnects again get the time of the latest message and then push the message after that time (saved in the server) to the client.
Related
I am trying to build socket connections between React client-side and Node.js server-side. But the server will host two sockets. Here is the server-side code
var app = express();
var server = http.createServer(app);
var io = require('socket.io')(2893, {
path: "/ws",
resource: "/ws",
transports: ['websocket'],
pingTimeout: 5000
});
var redis = require('redis');
const subscriber = redis.createClient();
require('./server/route')(app, io);
require('./server/lib/subscriber')(require('socket.io').listen(server), subscriber);
The first socket connection is ok, but I wonder why the second one is not working (which is attached with listen(server). Here is subscriber module I wrote:
module.exports = (io, subscriber) => {
io.sockets.on('connection', (socket) => {
console.log(socket);
socket.on('room', (room) => {
socket.join(room);
});
});
subscriber.on('pmessage', (pattern, channel, message) => {
const msg = JSON.parse(message);
const idCallcenter = msg.idCallcenter;
return io.to(idCallcenter).emit('message', { type: channel, message: msg });
});
subscriber.psubscribe('*');
};
And the client-side React module
var socketOption = { path: "/ws", transports: ['websocket'] };
var socket = io("http://localhost:2893", socketOption);
var socket2 = io.connect("http://localhost:4004");
export default function (user) {
debugger
socket.user = user;
contact(socket);
notify(socket);
socket.on('connect', function () {
debug('socket connect', socket.id);
store.dispatch(connectNetworkSuccess());
socket.emit('user-online', {
idUser: user._id,
idCallcenter: user.idCallcenter,
email: user.email
});
});
socket2.on('connect', () => {
debug('Socket connected');
socket2.emit('room', user.idCallcenter);
});
socket2.on('message', (data) => {
debugger
debug('Socket message');
debug(data);
const type = data.type;
const message = data.message;
if (type === 'recordFetched') {
}
});
socket.emit('user-online', {
idUser: user._id,
idCallcenter: user.idCallcenter,
email: user.email
});
socket.on('disconnect', function (reason) {
debug('socket disconnect', reason);
store.dispatch(connectNetworkFailed());
});
}
The first socket (in port 2893) runs normally. Meanwhile, socket2 (in port 4004) does not connect. It does not jump into connection callback of both server and client sides. What did I do wrong here?
I solved the case myself. The working code on client side is:
export default function (user) {
debugger
var socketOption = { path: "/ws", transports: ['websocket'] };
var socket = env === "local" ? io("http://localhost:2893", socketOption) : io(window.location.origin, socketOption);
var socket2 = io.connect();
socket.user = user;
contact(socket);
notify(socket);
socket.on('connect', function () {
debug('socket connect', socket.id);
store.dispatch(connectNetworkSuccess());
socket.emit('user-online', {
idUser: user._id,
idCallcenter: user.idCallcenter,
email: user.email
});
});
socket2.on('connect', () => {
console.log('Socket connected');
socket2.emit('room', user.idCallcenter);
});
socket2.on('message', (data) => {
debugger
console.log('Socket message', data);
const type = data.type;
const message = data.message;
if (type === 'recordFetched') {
}
});
socket.emit('user-online', {
idUser: user._id,
idCallcenter: user.idCallcenter,
email: user.email
});
socket.on('disconnect', function (reason) {
debug('socket disconnect', reason);
store.dispatch(connectNetworkFailed());
});
}
The server did jump into connection callback, but not room callback. I suppose it is because the connect callback of client side was defined after the connection is made, so that it couldn't jump into it. This is my possibility. Am I right?
Yes, I have gone through the documentation, which is very well written:
Socket IO Cheatsheet
Here is the problem: I want to notify the user of a logout when his session from the Express App is being destroyed. Now this is what is happening: When I log out from the session, all other clients (including those who have or have not even logged in) get a message saying they're logged out. Yes, my express app is working fine - they are not getting logged off, but I believe SOCKET IO is sending them the message regardless. I ran the debugger and it turns out that both the clients are distinguishable, too.
Here is my code:
server.js:
var app = express();
var server = require('http').Server(app);
var io = require('socket.io')(server);
app.set('socketio', io);
io.on('connection', function (socket) {
app.set('current_socket', socket);
console.log('No of clients:', io.engine.clientsCount);
});
userController.js:
exports.userLogout = function(req, res, next) {
const sessionID = req.session.id;
const io = req.app.get('socketio');
const this_socket = req.app.get('current_socket');
req.session.destroy(function (err){
if(err) {
console.error("userLogout failed with error:", err);
return next(err);
}
else {
console.log("this_socket:", this_socket);
console.log("io:", io);
this_socket.emit('userAction', { action: 'logout' });
//other logic to remove old sessions from DB Session Store
//and finally:
res.status(200)
.json({
status: 'success',
api_data: {'loggedIn':false},
message: 'Logout successful.'
});
}
}
}
I even tried this instead:
io.emit('userAction', { action: 'logout' });
but turns out it still emits to all the clients. I am pretty sure there is a mismatch somewhere, just can't figure out where.
You need create room for each session id if you want to send emits to spesific user
io.on('connection', function (socket) {
app.set('current_socket', socket);
var sessionId = socker.request.session.id
//join room
socket.join(sessionId);
});
userController.js:
exports.userLogout = function(req, res, next) {
const sessionID = req.session.id;
const io = req.app.get('socketio');
const this_socket = req.app.get('current_socket');
req.session.destroy(function (err){
if(err) {
console.error("userLogout failed with error:", err);
return next(err);
}
else {
console.log("this_socket:", this_socket);
console.log("io:", io);
this_socket.sockets.in(sessionID).emit('userAction', { action: 'logout' });
//other logic to remove old sessions from DB Session Store
//and finally:
res.status(200)
.json({
status: 'success',
api_data: {'loggedIn':false},
message: 'Logout successful.'
});
}
}
}
You have to define unique socket object for each user. We have many ways to do that.
In simple way, we use user id (unique) as a key to store socket object (Map way: key(userId) - vaule(socketObj)).
Follow the rabbit:
When a user loggedin, client side emits a event (login) to server side, the event include the user id.
Client Side:
// login success
socket.emit('userLoggedIn', {userId: THE_USER_ID})
Server Side:
io.on('connection', function (socket) {
// app.set('current_socket', socket);
console.log('No of clients:', io.engine.clientsCount);
socket.on('userLoggedIn', function(data) => {
app.set(data.userId, socket); // save socket object
})
});
userController.js:
exports.userLogout = function(req, res, next) {
const sessionID = req.session.id;
const userId = MAGIC_GET_USER_ID_FROM_SESSION_ID(sessionID) // who want to logout
const io = req.app.get('socketio');
const this_socket = req.app.get(userId); // get "user socket"
req.session.destroy(function (err){
if(err) {
console.error("userLogout failed with error:", err);
return next(err);
}
else {
console.log("this_socket:", this_socket);
console.log("io:", io);
this_socket.emit('userAction', { action: 'logout' });
//other logic to remove old sessions from DB Session Store
//and finally:
res.status(200)
.json({
status: 'success',
api_data: {'loggedIn':false},
message: 'Logout successful.'
});
}
}
}
I have implemented a nodejs xmpp server. As a client i have pidgin. I can't send messages from pidgin to server. Why? I can connect and authentication works.
This is my server code:
'use strict'
var xmpp = require('../index')
, server = null
, Client = require('node-xmpp-client')
var startServer = function(done) {
// Sets up the server.
server = new xmpp.C2S.TCPServer({
port: 5222,
domain: 'localhost'
})
// On connection event. When a client connects.
server.on('connection', function(client) {
// That's the way you add mods to a given server.
// Allows the developer to register the jid against anything they want
client.on('register', function(opts, cb) {
console.log('REGISTER')
cb({code: 'foo', type: 'bar'})
})
// Allows the developer to authenticate users against anything they want.
client.on('authenticate', function(opts, cb) {
console.log('server:', opts.username, opts.password, 'AUTHENTICATING')
if (opts.password === 'secret') {
console.log('server:', opts.username, 'AUTH OK')
cb(null, opts)
}
else {
console.log('server:', opts.username, 'AUTH FAIL')
cb(false)
}
})
client.on('online', function() {
console.log('server:', client.jid.local, 'ONLINE')
client.send(new xmpp.Element('iq', { type: 'chat', 'xml:lang': 'ko' }).c('body').t('Welcome to server!'))
})
// Stanza handling
client.on('stanza', function(stanza) {
console.log('server:', client.jid.local, 'stanza', stanza.toString())
//var from = stanza.attrs.from
//stanza.attrs.from = stanza.attrs.to
//stanza.attrs.to = from
console.log(stanza.toString());
client.send(stanza.toString())
//console.log('Stanza sent is :'+stanza);
})
// On Disconnect event. When a client disconnects
client.on('disconnect', function() {
console.log('server:', client.jid.local, 'DISCONNECT')
})
})
server.on('listening', done)
}
startServer(function() {
})
Here's the server code:
io.set('authorization', socketioJwt.authorize({
secret: jwtSecret,
handshake: true
}));
app.post('/login', function (req, res)
{
if((req.body.username === "test") && (req.body.password === "test"))
{
var token = jwt.sign({ username: req.body.username, password: req.body.password}, jwtSecret, { expiresInMinutes: 60*24*7 });
res.json({ token: token });
console.log(req.body.username + " logged in");
}
else
{
res.status(401).send('Wrong user or password');
}
});
io.on('connection', function(socket)
{
// test event
socket.on('ping', function (data)
{
io.emit("pong", data)
});
});
And here the client:
var server = $("#server-input").val();
var obj = { username: $("#login-input").val(), password: $("#password-input").val() };
$.post(server + "/login", obj)
.done( function(response)
{
connect_socket(response.token);
});
function connect_socket(token)
{
socket = io(server, {query: 'token=' + token});
socket.on("connect", function()
{
socket.emit("ping", {hi:"there"});
socket.on("pong", function(data)
{
console.log(data);
});
});
}
Now, when one user connects, the ping gets send and is received. When the same user connects a second time, the pong will be received on both instances, but when another user connects the pong will only be reveiced by that user. User a and b don't see eachother.
How can I fix this? Could this be a problem with the authentication?
I have a simple client server web app that is using web sockets to send / receive information. The client can connect and receives properly the config file but then when I try to send a "test' message from the client using "socket.emit('message', {my: 'data'});" it doesn't display on the server. I did check with wireshark and the packets are arriving at the server.
var sIoPort = 8181;
var host = '192.168.4.111';
var fs = require('fs');
var iniMsg = fs.readFileSync('data.json','utf8');
var http = require("http").createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(index);
});
http.listen(sIoPort,host);
var browserServer = require('socket.io').listen(http);
browserServer.on('connection', function (socket) {
console.log('Client websocket connected');
// send the config file if available
browserServer.sockets.emit('msg',iniMsg.toString());
});
browserServer.on('message', function (message) {
console.log('received message: ' + message);
});
client side
///////////////////////////////////////////////////////////////////////////////
socket = io.connect("192.168.4.111",{"port":8181});
socket.on('connect',function() {if(DEBUG) console.log('Socket Connected');});
socket.emit('message', {my: 'data'}); // test if server receives message
socket.on('msg',function(data) {
var json = JSON.parse(data);
// add the maps to the the GUI
switch(json.type) {
case 'maps': add_maps_from_json(json, null);
break;
}
});
socket.on('disconnect',function() {if(DEBUG) console.log('Socket Disconnected');});
/////////////////////////////////////////////////////////////////////////////////
Modify the serverside listener so it's paying attention to events on a socket:
browserServer.on('connection', function (socket) {
console.log('Client websocket connected');
// send the config file if available
browserServer.sockets.emit('msg',iniMsg.toString());
socket.on('message', function (message) {
console.log('received message: ' + message);
});
});