Emit Events To Socket.IO Not Working From Server - javascript

i am trying to get a chat program to work using socket.io but it doesnt seem to work properly.
i am using a Node.js server and it seems to be running properly. i think this may have something to do with emitting to rooms.
the code i have on the client browser is:
<script>
var socket = io("https://localhost:3000/userChat");
socket.on('connect', function(){
socket.emit('initialiseConnection', "user1");
});
socket.on('messageIn', function(msg){
console.log(msg);
$('#messages').append($('<li>').text(msg.message));
});
</script>
so when the page loads, socket.io it connects to the server and emits the "initialiseConnection" event on the server with "user1". which is a new room specifically for that user.
on the server, the code i have handling "initialiseConnection" is:
socket.on("initialiseConnection", function(username){
socket.join(username);
console.log(username + " has joined.");
Message.find({recipient:username}, function (err, message){
console.log("messages for "+username+": "+message.length);
for (var x = 0; x < message.length; x++){
console.log(username+"'s message "+x);
console.log(message[x]);
socket.to(username).emit("messageIn", {"message":message[x]});
}
});
});
this code as you can see, creates and joins a room with the same name as the username. the looks in the database for any messages, and tries to emit those messages to the user. i log the message. there is definately a message and the username in the "socket.to()" method is also correctly shown in the logs. but the "socket.on('messageIn')" on the client browser doesnt seem to be picking up the event.
i have also tried putting:
setTimeout(function() {
socket.to(username).emit("messageIn", {"message":"test message"});
}, 5000);
immediately after the socket.join(), in case this was related to some backbround processing that needed to complete
can anyone see where i may have gone wrong on this?
Thanks.
--EDIT 1--------------------------------------
var https = require('https');
var express = require('express');
var app = express();
var server = https.createServer(https_options, app).listen(3000);
var io = require('socket.io')(server);
var userChat = io.of("/userChat");
userChat.on('connection', function(socket){
console.log('a user connected');
socket.on("initialiseConnection", function(username){
...
});
socket.on('disconnect', function(){
socket.leave(socket.room);
});
});

You need to change this:
socket.to(username).emit("messageIn", {"message":message[x]});
to this:
socket.emit("messageIn", {"message":message[x]});
A socket is the endpoint. When sending, you just send directly to the socket. You don't send to a user in a room? You just send to a socket. Since you already have the socket in your socket variable, that's what you send to.

Related

return client socket.io to variable

On the docs page they say that i need to use like this.
io.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
});
there is any way to expose the client to a variable?
var socket = io.on('connection');
socket.emit('news', { hello: 'world' });
On the help page they say that Server#onconnection(socket:engine#Socket):Server expose a client, but i can't figure out how to use it. doc
this way i can use socket inside my other functions.
Right now on every function that i emiting stuff i do the io.on('connection', function (socket) all over again
Another question:
There is a way to different files emit event to each other
app.js
var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
file1.html emit
<script src="socket.io/socket.io.js"></script>
<script>
var socket = io('http://localhost');
socket.emit('event15', function(x){
});
</script>
file2.html receive
<script src="socket.io/socket.io.js"></script>
<script>
var socket = io('http://localhost');
socket.on('event15', function(x){
});
</script>
On the server you have to deal with multiple sockets, one for each client. That's why on the server, you write an event handler that sets up the socket for each new client that connects. The basic idea is this:
Server:
io.on('connection', function(socket) {
socket.on('chat message', function(msg) {
io.emit('chat message', msg);
});
});
All of your message handling is supposed to be setup in the outer function. If you want to use the socket elsewhere however, you can pass it on like this:
io.on('connection', function(socket) {
socket.on('login', function(data) {
myServer.attemptLogin(socket, data.user, data.hash);
});
});
The attemptLogin(socket, user, hash) function can now process the parameters, then reply to the client by calling socket.emit()
If you want to store each user's socket in a variable, you need to create a data structure to do that. Here's an example:
var users = {}; // empty object
io.on('connection', function(socket) {
users[socket.id] = socket; // store socket for later use
// ...
});
This is only useful though if a connected user can somehow resume their previous session after a disconnect. Otherwise this is just a question of properly organizing your functions and variables.
As for the second question, you cannot send data from one HTML document to another. As soon as the user clicks a link leading to file2.html, a new socket will be opened and socket.io won't even realize that this is still the same user. As far as socket.io is concerned, some random dude just opened file2.html elsewhere in the world.
There are two ways around this: you can create a single-page app, where the user never actually navigates to another site. However they will still lose the connection if they accidentally close the tab, or navigate back, or refresh the page.
The other way is to use some kind of session information. If the user logs in, you can simply store their username and password hash in localStorage. On each page, check localStorage for the stored credentials, then send a "login" message to the server.

Can't send message to only one specific room through node.js and socket.io

I have a problem that i don't seems to be able to solve it. I'm doing some kind of integration with remote system and my code is in iframe but that can't be important for this one i hope :).
I'm trying to send a message from server to specific room/client to begin session. First thing I do is when user log in, I emit message from client side with username.
CLIENT.JS
conn.on('connect', function () {
conn.emit('session', { username: 'some_username' });
}, false);
And on server side i get message and join socket to the room.
SERVER.JS
socket.on('session', function(session) {
socket.join(session.username);
});
I have another module that communicates with this server.js script through redis. So i have two more events in server.js
SERVER.JS
var userCreate = redis.createClient();
userCreate.subscribe("userCreate", "userCreate");
var userDestroy = redis.createClient();
userDestroy.subscribe("userDestroy", "userDestroy");
userCreate.on("message", function(channel, data) {
socket.to(JSON.parse(data).username).emit('beginSession', data);
});
userDestroy.on("message", function(channel, data) {
socket.to(JSON.parse(data).username).emit('endSession', data);
socket.leave(JSON.parse(data).username);
});
But when ever i try to emit message from server to client i broadcast message to everyone. What am I doing wrong?
Well, from the syntax point of view you are doing everything correct.
Didn't you forget to specify the userId property in the endSession?
userDestroy.on("message", function(channel, data) {
socket.to(JSON.parse(data).userId).emit('endSession', data);
socket.leave(JSON.parse(data).userId);
});
If that doesn't work - you should provide the contents of a data object

Socket IO Server to Server

Is it possible for a server to connect to another using Socket.IO and be treated like a client?
And have it join rooms, recieve io.sockets.in('lobby').emit(). And more?
The first server is also listening for connections/messages as well.
Hey Brad, here's my full .js app below for reference:
var io = require("socket.io").listen(8099);
io.set('log level', 1);
io.sockets.on("connection", function (socket) {
console.log('A Client has Connected to this Server');
//Let Everyone Know I just Joined
socket.broadcast.to('lobby').emit("message",'UC,' + socket.id); // Send to everyone in Room but NOT me
socket.on("message", function (data) {
//Missing code
socket2.send('message,' + data); //Forward Message to Second Server
});
socket.on("disconnect", function (data) {
//Send Notification to Second Server
//Need to figure out later
//Send Notification to Everyone
socket.broadcast.emit("message",'UD,' + socket.id ); //Send to Everyone but NOT me
//Remove user from Session ID
arSessionIDs.removeByValue(socket.id);
//Send Notification to Console
console.log("disconnecting " + arRoster[socket.id][1]);
});
});
var io_client = require( 'socket.io-client' );
var socket2 = io_client.connect('http://192.168.0.104:8090');
socket2.on('connect', function () {
socket2.emit('C3434M,Test');
});
Yes, absolutely. Just use the Socket.IO client in your server application directly.
https://github.com/LearnBoost/socket.io-client
You can install it with npm install socket.io-client. Then to use:
var socket = io.connect('http://example.com');
socket.on('connect', function () {
// socket connected
socket.emit('server custom event', { my: 'data' });
});
I realize this is an old post, but I was working on something similar and decided to come back and contribute something as it got me thinking.
Here's a basic Client -> Server 1 -> Server 2 setup
Server #1
// Server 1
var io = require("socket.io").listen(8099); // This is the Server for SERVER 1
var other_server = require("socket.io-client")('http://example.com:8100'); // This is a client connecting to the SERVER 2
other_server.on("connect",function(){
other_server.on('message',function(data){
// We received a message from Server 2
// We are going to forward/broadcast that message to the "Lobby" room
io.to('lobby').emit('message',data);
});
});
io.sockets.on("connection",function(socket){
// Display a connected message
console.log("User-Client Connected!");
// Lets force this connection into the lobby room.
socket.join('lobby');
// Some roster/user management logic to track them
// This would be upto you to add :)
// When we receive a message...
socket.on("message",function(data){
// We need to just forward this message to our other guy
// We are literally just forwarding the whole data packet
other_server.emit("message",data);
});
socket.on("disconnect",function(data){
// We need to notify Server 2 that the client has disconnected
other_server.emit("message","UD,"+socket.id);
// Other logic you may or may not want
// Your other disconnect code here
});
});
And here's Server #2
// Server 2
var io = require("socket.io").listen(8100);
io.sockets.on("connection",function(socket){
// Display a connected message
console.log("Server-Client Connected!");
// When we receive a message...
socket.on("message",function(data){
// We got a message. I don't know, what we should do with this
});
});
This is our Client, who sends the original message.
// Client
var socket = io('http://localhost');
socket.on('connect', function(){
socket.emit("message","This is my message");
socket.on('message',function(data){
console.log("We got a message: ",data);
});
});
I am making this post a Community Wiki so that someone can improve this if they feel like it.
The code has not been tested, use at your own risk.
I had the same problem, but instead to use socket.io-client I decided to use a more simple approach (at least for me) using redis pub/sub, the result is pretty simple.
You can take a look at my solution here: https://github.com/alissonperez/scalable-socket-io-server
With this solution you can have how much process/servers you want (using auto-scaling solution), you just use redis as a way to forward your messages between your servers.

Disconnect from Redis cleanly when Node exits?

Currently I have the following code, working with Node.js, socket.io and Redis:
var io = require('socket.io'), redis = require("redis"), client = redis.createClient();
io.sockets.on('connection', function (socket) {
var socket_id = socket.id;
socket.on('chat', function(data) {
client.set('user:' + socket_id, data['colour']);
// The user left the page. Remove them from Redis.
socket.on('disconnect', function () {
client.del('user:' + socket_id);
client.quit();
});
});
});
This works fine for normal socket connections and disconnections, but there seems to be a problem if Node goes down, or if I just restart Node as part of normal development.
The key is never deleted from Redis. So the number of entries stored in the Redis database gradually grows and grows. I'm also not sure whether the Redis client exists cleanly.
How can I clean up Redis entries and quit the Redis client when Node exits, as well as when the socket disconnects?
You could handle this when node exits, but e.g. in case the power goes down, there's no way you can clean it up at shutdown time. I'd wipe old stuff from the DB at startup time instead.
I've run in to this problem too. My solution was to just use a specific Redis database on the server for Socket.io data. A simple FLUSHDB to that database on start up will clean out stuck keys.
var socketIoDatabase = 4;
var client = redis.createClient();
client.select(socketIoDatabase);
client.flushdb();
Of course if you have multiple node processes using this same database clearing it will cause problems. In this case you can do it during a maintenance window or something while all node processes are terminated.
check this out:
http://nodejs.org/docs/v0.4.12/api/process.html#event_uncaughtException_
var io = require('socket.io'), redis = require("redis"), client = redis.createClient();
io.sockets.on('connection', function (socket) {
var socket_id = socket.id;
socket.on('chat', function(data) {
client.set('user:' + socket_id, data['colour']);
// The user left the page. Remove them from Redis.
socket.on('disconnect', function () {
client.del('user:' + socket_id);
client.quit();
});
});
});
// this will be activated on any error without try catch :)
process.on('uncaughtException', function (err) {
console.log('Caught exception: ' + err);
});

Is it possible to update a single part of a page using Nodejs and Socket.io?

I'm trying to create a basic Node application, every time a client connects I want to update the counter which is displayed on the page. (My goal is to create this application in its most simple, and learnable form to demonstrate node to my lecturer).
Server side application snippets:
Making the connection
var clients = 0;
io.sockets.on('connection', function (socket) {
socket.on('connect', function () { clients += 1 });
socket.on('disconnect', function(){ clients -= 1 });
});
Rendering the page
app.get(navigation.chat.page, function(req, res){
res.render('chat', {
title: navigation.chat.title,
connected: clients
});
});
Chat page jade template snippet:
span#client_count #{connected}
| connected clients
Client side jQuery, Socket.io and JavaScript
var socket = io.connect('http://localhost');
$(document).ready(function(){
socket.on('connect', socket.emit('connect'));
});
Problem:
The number of connected clients only updates upon page refresh. I would like the number to be updated asynchronously. I'm quite new to node, socket.io and express so i'm unsure how to tackle the problem!
rather than incrementing on client side, better keep counter value on server side, increment on connection and decrement on disconnect io events. Then, you can send updated counter (in the same event handlers where value was changed). On client side, listen for event with counter and when received, replace value in html.
server :
var users_count = 0;
io.sockets.on('connection', function (socket) {
//on connection, update users count
++users_count;
//send it to every opened socket
io.sockets.emit('users_count', users_count);
//when this socket is closed
socket.on('disconnect', function () {
//user disconnected
--users_count;
//emit to every opened socket, so everyone has up to date data
io.sockets.emit('users_count', users_count);
});
});
client :
jQuery(function($){
//connect to localhost
var socket = io.connect('http://localhost');
//handle users_count event, by updating our html
socket.on('users_count', function(data){
$('#client_count').text(data);
});
});

Categories

Resources