I want to be able to load these 4 functions: returnAvailable, processMessage, removeUser and joinRoom from an external file, but i get reference errors where it says that socket and nicknames are undefined. How do I modularize my app with respect to dependencies I use?
Here's my code:
server.js
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);
// mongoDB init
var mongoose = require('mongoose');
mongoose.connect("mongodb://localhost:27017/chat");
var Message = require('./server/datasets/message');
//include these 4 functions
var util = require('./server/util/util');
//object which contains all users and chatrooms
var nicknames = {
'Music': [],
'Videogames': [],
'Sports': [],
'TV': [],
'Politics': []
};
// middleware
// serves static files
app.use('/client', express.static(__dirname + '/client'));
app.use('/node_modules', express.static(__dirname + '/node_modules'));
// routes
app.get('/', function(req, res){
res.sendFile(__dirname + '/index.html')
});
app.get('/api/rooms/get', function(req, res){
res.json(nicknames);
});
server.listen(2000);
// socket functionality
io.sockets.on('connection', function(socket){
socket.on('new user', util.returnAvailable);
// do when 'send message' data is received from client
socket.on('send message', function(data){
util.processMessage(data);
});
// do when 'disconnect' data is received from the client
socket.on('disconnect', function(data){
util.removeUser();
});
socket.on('leave room', function(){
util.removeUser();
});
});
util.js
module.exports.returnAvailable = function (data, callback){
console.log(data);
if(nicknames[data.room].indexOf(data.username) != -1){
callback({ bool: false });
}else {
socket.nickname = data.username;
joinRoom(socket, data.room);
nicknames[data.room].push(socket.nickname);
console.log(nicknames[data.room]);
io.sockets.to(data.room).emit('usernames', nicknames[data.room]);
callback({ bool: true, nickname: socket.nickname});
}
}
module.exports.removeUser = function(){
//console.log(socket.nickname + " disconnected. Bool value: " + socket.nickname==true);
if(socket.nickname==false) return;
// socket.room has to be defined, otherwise crashes if user reloads while not in a roomn
if(socket.room)
{
nicknames[socket.room].splice(nicknames[socket.room].indexOf(socket.nickname), 1);
socket.leave(socket.room);
}
io.sockets.to(socket.room).emit('usernames', nicknames[socket.room]);
}
module.exports.joinRoom = function (data){
socket.join(data);
socket.room = data;
console.log(socket.room);
var query = Message.find({room: socket.room});
query.sort({created:-1}).limit(5).exec(function(err, results){
if(err) { console.log(err); }
else if(results){
io.sockets.to(socket.room).emit('old messages', results);
}
});
}
module.exports.processMessage = function(data){
io.sockets.to(socket.room).emit('new message', {msg : data, nick : socket.nickname});
var message = new Message({
created: new Date,
user: socket.nickname,
message: data,
room: socket.room
});
message.save(function(err){
if(err){
console.log(err);
}else{
console.log('Successfully saved.');
}
});
}
I'm using Express 4.13.4
The socket variable is only available within io.sockets.on('connection', callback function so you can't use it in other files this easily. But you can pass the socket variable to the function where you are trying to use it like this
util.removeUser(socket);
and change the definition of removeUser to accept the socket as an argument
module.exports.removeUser = function(socket){
// your code here
}
The same goes for nicknames variable, use it like this
socket.on('new user', function(data) {
util.returnAvailable(io, socket, nicknames, data);
});
and change the function to accept those arguments
module.exports.returnAvailable = function (io, socket, nicknames, data){
// your code here
}
Related
Hello I'm trying to create a chat application, I googled around and I got some issues on this step. Would appreciate some help...
Server.js
var express = require("express");
var app = express();
var http = require("http").createServer(app);
var io = require("socket.io")(http);
var users = [];
io.on("connection", function (socket) {
console.log("User connected", socket.id);
socket.on("user_connected", function (username) {
users[username] = socket.id;
io.emit("user_connected", username);
});
socket.on("send_message", function (data) {
var socketId = users[data];
io.to(socketId).emit("new_message", data);
console.log(data);
});
});
http.listen(3000, function () {
console.log("Server Started");
});
chat.php
function sendMessage(){
var message = document.getElementById("message").value;
io.emit("send_message", {
sender: sender,
message: message
});
return false;
}
io.on("new_message", function (data) {
console.log(data);
//var html = "";
//html += "<li>" + data.sender + " says: " + data.message + "</li>";
//document.getElementById("messages").innerHTML += html;
});
So my problem is happening in chat.php where my console.log(data) isn't shown, however the data is shown in server.js. Why is this currently not working?
From what you said earlier it's possible that you make it more complicated than it actually is. No need to change anything in chat.php, however instead of creating the variable socketId you could just emit the data immediately like this:
io.on("connection", function (socket) {
console.log("User connected", socket.id);
socket.on("user_connected", function (username) {
users[username] = socket.id;
io.emit("user_connected", username);
});
socket.on("send_message", function (data) {
io.emit("new_message", data);
});
});
I'm working on chat, where facebook friends can talk only with each other. I'm using redis so save relation: fb_user_id - user_socket_id. This is how my implementation looks like:
getting friends from facebook;
selecting socket ids of my friends from redis, creating local friends-sockets list in my node client;
connecting to node server. Server saving my socket id to redis and notifying all my friends about new friend login (about me);
all my friends updating local friends-sockets list;
when someone sending chat message to server, this message comes with friends-sockets list, so server knows where need to send message (only for my friends).
Question: it's better solution to send friends-sockets every time to server, or it's better to get this relation on server from redis (or create array of sockets in server). How to adapt my task for high availability?
Any comments and suggestions are welcomed, thanks.
Here is my code (socket.io 1.2.0)
server.js
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var redis = require("redis"), client = redis.createClient();
var parts;
client.select(2, function() {});
client.on("error", function (err) {
console.log("Error " + err);
});
process.on('uncaughtException', function (err) {
console.log(err);
});
app.get('/', function (req, res) {
res.sendFile(__dirname + '/index.html');
});
io.on('connection', function (socket) {
// on connect
socket.on("join", function (data)
{
if (data) {
// notify all friedns about new friend login
if (data.to) {
if (data.to.length > 0) {
for (x in data.to) {
io.to(data.to[x]['socket_id']).emit('new friend response', {uid: data.uid, sid: socket.id});
}
}
}
// save or update user socket id to redis
parts = split_id(data.uid);
client.hset(parts[1], parts[0], socket.id);
}
});
// disconnect
socket.on('disconnect', function () {
console.log("user disconnected");
});
// send message by friends-sockets list
socket.on('chat message', function (data) {
if (data.to.length > 0) {
for (x in data.to) {
var message = data.msg;
io.to(data.to[x]['socket_id']).emit('chat message response', {msg: message, uid: data.uid});
}
}
});
});
http.listen(3000, function () {
console.log('listening on *:3000');
});
// split facebook uid in 2 parts (for redis saving)
function split_id(str)
{
var n = str.length;
var res1 = str.substr(n - 2, 2);
var res2 = str.substr(0, n - 2);
return [res1, res2];
}
client.js
// friends socket list
var friends_sockets = [];
// my data from facebook
var my_data;
// my facebook uid
var my_uid;
function client() {
socket = io('http://server.com:3000');
// connect
socket.on('connect', function () {
// notify server about login
socket.emit('join', {uid: my_uid, to: friends_sockets, from: my_data, type: 'web'});
});
// send chat message to my friends
$('.enter_form button').click(function () {
if (friends_sockets.length > 0) {
socket.emit('chat message', {msg: $('#m').val(), to: friends_sockets, from: my_data, uid: my_uid});
}
// add message to my chat
$('#messages').append($('<li>').text(my_data.first_name + ' ' + my_data.last_name + ': ' + $('#m').val()));
$('#m').val('');
return false;
});
// new message listner (waiting for chat messages)
socket.on('chat message response', function (data) {
$('#messages').append($('<li>').text(data.msg));
});
// new friends lister (update list on friends login)
socket.on('new friend response', function (data) {
var found = false;
if (friends_sockets.length > 0) {
for (x in friends_sockets) {
if (friends_sockets[x]['uid'] == data.uid) {
friends_sockets[x]['socket_id'] = data.sid;
found = true;
}
}
}
if (found === false) {
friends_sockets.push(data);
}
});
}
Concerning your question regarding high availablity, have a look at
http://socket.io/docs/using-multiple-nodes/
for a configuration example using nginx, multiple Node processes and Redis as session store.
I am using node.js with socket.io to push real time notifications to users. However, currently I am just sending back a query result done in my socket.io code and sending it back to the client but I need to let socket know about the changes that occur and to either update with the changes or re-query the db to check for the new number and send that to the client.
For example if a user gets a friend request then the notification count will change and I want socket.io to push the new notification count number to the user.
here is my socket.io code in my app.js file:
io.on('connection', function(socket) {
var sessionID = socket.handshake.sessionID,
session = new connect.middleware.session.Session({ sessionStore: sessionStore }, socket.handshake.session)
console.log('socket: new ' + sessionID)
socket.broadcast.emit('arpNewConn', session.passport.user)
var intervalID = setInterval(function() {
socket.handshake.session.reload(function() {
socket.handshake.session.touch().save()
})
socket.emit('pulse', { heartbeat: new Date().toString(), timestamp: new Date().getTime() })
}, 300 * 1000)
socket.on('disconnect', function() {
console.log('socket: dump ' + sessionID)
socket.broadcast.emit('arpLostConn', session.passport.user)
clearInterval(intervalID)
})
socket.emit('entrance', {message: 'Message works'});
dbnotif.findOne(userID, function (err, user) {
if(err) throw err;
notify = user.notifications;
socket.emit('notify', {notific: notify});
});
});
Here is the client side:
div#CheckSocket
script(src='http://localhost:3000/socket.io/socket.io.js')
script.
$(document).ready(function () {
console.log('socket');
var socket = io.connect('http://localhost:3000/');
console.log('entered1');
socket.on('entrance', function (data) {
console.log('entered');
console.log(data.message);
});
socket.on('notify', function (data) {
console.log('noting');
console.log(data.notific);
if(data.notific !== 0)
$('.notifications').html(data.notific);
});
socket.on('reconnecting', function(data) {
setStatus('reconnecting');
console.log('entered2');
});
function setStatus(msg) {
console.log('connection status: ' + msg);
console.log('entered5');
}
});
Here is the example of adding a friend in the route file:
exports.addContactPost = function(req, res, err) {
async.waterfall([
function(callback) {
var success;
var newFriend = new Friend ({
userId: req.signedCookies.userid,
friend_id: mongoose.Types.ObjectId(req.body.otherUser),
friend_status: 1
});
newFriend.save(function(err){
if(err) {
console.log(err);
} else {
console.log("saved it");
success = true;
}
});
callback(null, success)
},
function(success, callback) {
//if(success === true) {
var success2;
var newFriend2 = new Friend ({
userId: mongoose.Types.ObjectId(req.body.otherUser),
friend_id: req.signedCookies.userid,
friend_status: 2
});
newFriend2.save(function(err){
if(err) {
res.send("request not received");
} else {
success2 = true;
}
});
callback(null, success2);
//} else {
// res.send("error with request sent");
//}
},
function(success2, callback) {
console.log('callback3');
//if(success2 === true) {
var success3;
Notification.findOneAndUpdate({userId: mongoose.Types.ObjectId(req.body.otherUser)}, {
$inc: {notifications: 1}
}, function(err, notify) {
if(err) {
res.send(err);
} else {
console.log(notify);
if(notify.added_notifications === true) {
// enable mail and include general u have got a new request... do not include name because not storing it
}
}
success3 = true;
callback(null, success3);
}],
function(err, results) {
res.json({response: true});
console.log("Add successful");
});
};
Notes: dbnotif is a model being called by mongoose,
userID is a global variable available to the file
I helped him solve this question offline, but we ended up using an EventEmitter as a proxy.
// main.js
var EventEmitter = require('events').EventEmitter;
var emitter = new EventEmitter();
Then add it to each request as middleware:
// elsewhere in main.js
app.use(function(req, res, next) {
req.emitter = emitter;
next();
});
Then in external routes file:
// routes.js
exports.addContactPost = function(req, res, err) {
req.emitter.emit( 'some-key', whatever, data, you, want );
};
I would like to:
retrieve data entered from input forms.
send the data through socket.io and send console log saying done
receive the data on express app.js
insert the data into a mongodb database using mongoose.
I understand emit messages but not sure how to post data through. thank you in advance
my app.js is set up like this:
//app.js config ...
var socket = io.listen(server);
socket.on('connection', function(socket) {
console.log('socket.io connected');
});
app.post('/go', function(req, res) {
socket.on('data', function(data) {
new Order({
routeFrom : data.routeFrom,
routeTo : data.routeTo,
leaving: data.leaving
}).save(function(err, docs) {
if(err) { console.log("error"); }
res.json(data);
});
socket.emit('callback', {done: 'Done'});
});
});
my index.ejs file:
<script src="/socket.io/socket.io.js"></script>
var socket = io.connect('http://localhost:3000');
$('#send').on('click', function() {
$.post('/go', {
socket.emit('data', {
routeFrom: $('#rf').val(),
routeTo: $('#rt').val(),
leaving: $('#l').val()
});
});
socket.on('callback', function(data) {
console.log(data);
});
});
You don't need POST at all.
I would do on the client side:
var socket = io.connect('http://localhost:3000');
$('#send').on('click', function(event) {
event.preventDefault();
socket.emit('data', {
routeFrom: $('#rf').val(),
routeTo: $('#rt').val(),
leaving: $('#l').val()
});
});
socket.on('callback', function(data) {
console.log(data.done);
// Print the data.data somewhere...
});
And on the server side:
//app.js config ...
var socket = io.listen(server);
socket.on('connection', function(socket) {
console.log('socket.io connected');
});
socket.on('data', function(data) {
new Order({
routeFrom : data.routeFrom,
routeTo : data.routeTo,
leaving: data.leaving
}).save(function(err, docs) {
if(err) { return console.log("error"); }
socket.emit('callback', {done: 'Done', data: data});
});
});
i made an app with socket.io.my problem is when i close node and open again server response count is up.first time 1 resutlset sending but second time 2 and third time 3 and so on? what is the problem
client code is
<script>
var socket = io.connect('http://10.0.0.192:8888');
socket.on('connecting', function () {
console.log('connecting');
});
socket.on('connect', function(s){
console.log('connect');
socket.emit('Baglan');
console.log('emit-Baglan');
socket.on('guncelle',function(data){
console.log(new Date().getMilliseconds());
console.dir(data);
});
});
socket.on('reconnecting', function () {
console.log('reconnecting');
});
socket.on('reconnect', function () {
console.log('reconnect');
});
socket.on('reconnect_failed', function () {
console.log('reconnect_failed');
});
</script>
and server
function getDataForClients() {
var d = new Array();
d.push({records:res});
//console.log(d);
return d;}
function onRequest(request, response) {
var pathname = url.parse(request.url).pathname;
//console.log("Request for " + pathname + " received.");
route(handle, pathname, response, request);
}
server = http.createServer(onRequest);
io = require('socket.io').listen(server);
io.set('log level', 1);
io.sockets.on('connection', function (client) {
//console.log(client);
client.on("Baglan",function(){
//console.log("user connected");
__sockets.push(client);
client.room="weather";
client.records=[];
client.join(client.room);
if(!res)
guncelle(false,client);
else
client.emit("guncelle",getDataForClients());
});
client.on('disconnect', function(){
var i = __sockets.indexOf(client);
__sockets.splice(i,1);
client.leave(client.room);
//console.log("user leave");
});
});
server.listen(8888);
function guncelle(v,c) {
//console.log("update");
var db = mysql.createClient({
user: 'user',
password: '***',
});
db.query('USE '+TEST_DATABASE);
db.query(
"select * from table",
function selectCb(err, results, fields) {
if (err) {
throw err;
}
res = results;
var _data = getDataForClients();
if(v)
io.sockets.emit("guncelle",_data);
else
c.emit("guncelle",_data);
db.end();
}
);
}
there are 5 result between 15 ms.
sorry i cant post image.