NodeJS + Cluster + Socket.io + Redis - iOS not leaving rooms after disconnect - node.js

I'm writing a nodejs/socket.io application that uses cluster and Redis in AWS Elasticache as the RedisStore backend. The app works heavily around rooms, and i'm having a really hard time understanding why only Mobile Safari (iPad mini retina iOS7 ) cannot leave rooms it subscribes to after it emits a request to do so. Even closing the connection from the client side leaves the socket humming along on the server, and the subscription to the room intact, but other browsers can exit without a problem.
NodeJS v0.10.25
Socket.io v0.9.16
Redis v2.8.6 (AWS Elasticache)
Ubuntu 14.04 LTS (EC2 behind loadbalancer in TCP mode)
Now, in my code, i've been using the io.sockets.manager.roomClients object to iterate through and see what rooms are actually in service. This is because io.sockets.clients() reports completely inaccurate data once connections are opened and closed for a period of time.
My code is really too long to put here, and also fairly private, but here's essentially what i've got:
Server:
if (cluster.isMaster) {
function heartbeat(){
// io.sockets.clients() doesn't splice dropped connections off the array
// so we have to use io.sockets.manager.roomClients to see active rooms
for( var i in io.sockets.manager.roomClients ) {
console.log("Client:", i, io.sockets.manager.roomClients[i] );
}
setTimeout(heartbeat,5000);
}
heartbeat();
} else {
io.sockets.on('connection', function (socket) {
socket.on('subscribe', function (room) {
console.log("Starting:",room);
socket.join(room);
});
socket.on('unsubscribe', function (room) {
console.log("Leaving:",room);
socket.leave(room);
});
socket.on('disconnect', function () {
console.log("Close Shop");
});
});
}
The Client:
socket.emit('subscribe', 'some-room');
Server Log
Starting: some-room
And then i get a Client log with each timeout tick:
Client: lhZsH1oL2vV7BML9QkSW { '': true, '/some-room': true }
Client: lhZsH1oL2vV7BML9QkSW { '': true, '/some-room': true }
Client: lhZsH1oL2vV7BML9QkSW { '': true, '/some-room': true }
Client: lhZsH1oL2vV7BML9QkSW { '': true, '/some-room': true }
Client: lhZsH1oL2vV7BML9QkSW { '': true, '/some-room': true }
Now, the issue is here. If i unsubscribe or disconnect from a desktop browser:
socket.emit('unsubscribe', 'some-room');
Leaving: some-room
Or
socket.disconnect();
Close Shop
The ticks look like this:
Client: lhZsH1oL2vV7BML9QkSW { '': true }
Which i expect, because as we know, socket.io sucks at connection cleanup, but at least the room subscriptions are gone. However, on my tablet, after unsubscribe or disconnect, the room subscription remains in the io.sockets.manager.roomClients object:
Client: lhZsH1oL2vV7BML9QkSW { '': true, '/some-room': true }
I'm fairly new at socket programming, so I'm sure i'm missing something obvious, but has anyone had similar issues with Mobile websockets?

So I discovered that by using my own methods of reference counting, i can bypass needing socket.io to be accurate. Since i'm already using Redis to back my sockets through pubsub, i just create another client connection to redis and setex the socket.id's on an expiration. When my sockets unsubscribe or disconnect, i delete all the keys in Redis associated with the socket.id. This way, i have an instant snapshot of whos on, and if the key for some reason didn't get deleted on disconnect/unsub, it will expire based on what i set for the setex call.
I'll try and remember to come back in two days to mark my own answer as correct.

Related

Custom room Socket.io NodeJS

I am making an application with sockets and the need arises to broadcast information, but only to people who are inside a room.
This is my code from the server.ts
// Dependencies
import express from 'express'
import http from 'http'
import socket from 'socket.io';
import {connect, disconnect, orderChanged} from './sockets/socket';
import {config} from 'dotenv';
config ();
// Main class
export default class server {
_private static instance: server
public app: express.Application
public port: number
http: http.Server private
public io: socket.Server
// Initialize variables and methods
// Singleton pattern implementation
private constructor () {
this.app = express ()
this.port = Number (process.env.SRV_PORT)
this.http = new http.Server (this.app)
this.io = new socket.Server (this.http, {
cors: {
origin: true,
credentials: true
}
})
this.listenSockets ();
}
// Return the instance running Singleton pattern
public static get instance () {
returns this._instance || (this._instance = new Server ())
}
// Method to start the server
start (callback: any) {
this.http.listen (this.port, callback)
}
private listenSockets (): void {
console.log ('Listening Sockets');
this.io.on ('connection', client => {
console.log ('Connected to room', client.rooms, '-', client.id);
// User disconnected
disconnect (client);
connect (client);
});
}
}
Since node starts, an instance is created in DP Singleton and the socket listener is launched
When an operation happens in the database, anywhere in the app, I send it to call and send information to the front-end which is correctly received by the front-end and does what it has to do. Example url / edit-products
import server from '../core/server';
// Socket broadcast, new information
const __id = String (req.headers.id);
const updatedData = await getNewData (__id);
Server.instance.io.emit ('data changed', updatedData);
The problem is that this information is sent indiscriminately to all users connected to the socket. Now, I have a unique ID that brings multiple users together in a MongoDB model. You could use that ID to broadcast only to users with that ID. There is a logic that implies that if the user connects from Mexico, add it to an Array of people in MongoDB, otherwise it will add it to another MongoDB document, then they are two different IDs.
I would love the room to be that ID.
I saw that I could use the socket's join () method, but that function derives from the connected client, not from the server itself. I try to issue the information like this
// Socket broadcast, new information
const __id = String (req.headers.id);
const updatedData = await getNewData (__id);
Server.instance.io.in (updatedData._id) .emit ('data changed', updatedData);
But at no point did I set up that "ROOM". When the user login, he could add it but I don't know how to create a custom room, he tried something like this
const user = await UserModel.find (_data);
Server.instance.io.join (user.channel._id);
But that function within io does not exist.
It exists this way, but it doesn't work for me
Server.instance.io.on ('user-join', (socket: Socket) => {
console.log (plug);
socket.join (uuid);
});
Server.instance.io.emit ('user join');
What could I do?
.join() is a method on an individual socket. That's how you use it as socket.join(roomName). When the first user joins a room, the room is created automatically and other users can also join it. When the last user leaves the room, the room is removed automatically from the server. So, you join a user's socket to a room - you don't join something to the server.
Similarly, when you tried this:
Server.instance.io.on ('user-join', (socket: Socket) => {
console.log (plug);
socket.join (uuid);
});
That doesn't work because you don't listen for incoming messages from a socket on the server (except for the connection message - which introduces the socket object). You listen for incoming client messages on a socket itself:
Server.instance.io.on ('connection', (socket: Socket) => {
socket.on('user-join', () => {
// you will have to find the room name that goes with this socket
socket.join(someRoomName);
});
});
Also, note that this code:
private listenSockets (): void {
console.log ('Listening Sockets');
this.io.on ('connection', client => {
console.log ('Connected to room', client.rooms, '-', client.id);
// User disconnected
disconnect (client);
connect (client);
});
}
looks problematic. Why would you disconnect a client when they connect? You don't show those functions disconnect() and connect() so it's unclear what they actually do - I would guess they keep track of connected clients somehow. If you're just trying to clean up any state that might have been previously left hanging, then you should be doing something like this:
private listenSockets (): void {
console.log ('Listening Sockets');
this.io.on ('connection', client => {
console.log ('Connected to room', client.rooms, '-', client.id);
client.on('disconnect', () => {
// User disconnected
disconnect(client);
});
// user connected now
connect(client);
});
}
You don't have to worry about inaccurate housekeeping on whether a socket is connected or not. You will always get a disconnect event for a socket when it disconnects. This is for two reasons. For a browser window that closes or a page that the user navigates away from, the browser cleans up all objects associated with that page, including the open socket.io connection. This will always close the socket and cause a disconnect event. Second, socket.io uses ping and pong messages to regularly check if an existing connection is still working. If it's not, it will get disconnected. The client may or may not retry to open a new connection depending upon the circumstance. But, any disfunctional connection (one that isn't respond to ping messages) will get closed by the server and a disconnect event will occur for that too. So, those two circumstances make sure that a disconnect event always happens.
Server.instance.io.emit ('data changed', updatedData); The problem is that this information is sent indiscriminately to all users connected to the socket.
This sends to all users connected to your server and is how it was designed.
To send to a single socket, you would use:
socket.emit(...);
where socket is what you're code calls client, the object you get from the connection event.
To send to all sockets who have joined a room, you would use:
io.in(roomName).emit(...)
where io is the socket.io server instance.
And, there are many, many more variations of .emit() depending upon exactly what you're trying to send to.
Now, I have a unique ID that brings multiple users together in a MongoDB model. You could use that ID to broadcast only to users with that ID. There is a logic that implies that if the user connects from Mexico, add it to an Array of people in MongoDB, otherwise it will add it to another MongoDB document, then they are two different IDs. I would love the room to be that ID.
I don't completely follow what you're trying to do, but it seems like inside your connect(client) function, you could just call client.join(uniqueIDForMultipleUsers) and that would create a room with this uniqueID and add this client to that room. In the future, you can send to everyone in that room with io.in(uniqueIDForMultipleUsers).emit(...).
But at no point did I set up that "ROOM". When the user login, he could add it but I don't know how to create a custom room, he tried something like this
You don't create rooms manually. You just use socket.join(roomName) and the socket.io infrastructure automatically creates the room if it doesn't already exist. Similarly when the last socket in a room either leaves the room or disconnects, the room is automatically removed. So you just don't have to manage the room creation or deletion yourself. In fact, a room object is not something you ever deal with directly - it's a housekeeping item inside of the socket.io server that contains a list of sockets that are currently in the room. A socket can be in as many rooms as it wants to be. You use these on the server:
socket.join(roomName); // add a client's socket to a room
socket.leave(roomName); // remove a client's socket from a room
io.in(roomName).emit(...); // broadcast a message to every socket in a room
What is sometimes a bit confusing about the above logic is that socket.join() and socket.leave() are socket methods, but they actually modify a data structure in the server (where the list of rooms/sockets are kept). For whatever reason, that's just how they chose to originally design the API. Logically, it's more like io.join(socket, roomName) since it's modifying something on the server. But, since the socket knows the server object it's part of, they can leave that off and just do socket.join(roomName).

Socket.io + Redis - clients are joining each others' "private" rooms

I've just started working with Socket.io and Redis for pub/sub messaging and it's pretty great. One important feature of my application is that the server needs to be able to broadcast messages to all subscribers of a room, and also choose 1 subscriber in that room and narrowcast a message just to them. For now, that subscriber is chosen at random. Based on reading socket.io's documentation, I think I can accomplish this.
However, I've come across something I don't understand. In Socket.io's Default Room documentation (https://socket.io/docs/rooms-and-namespaces/#default-room), they say that each socket automatically joins a room named after its socket ID. This looks like it would solve my narrowcast requirement -- look at the list of client IDs connected to my "big" room, choose one at random, and then send a message to the room with the same name as the chosen ID.
However, it doesn't work because for some reason all clients are joining each others' default rooms. I'm not seeing any exceptions in my code, but my "narrowcast" messages are going to all clients.
Here's my server-side code:
var io = require('socket.io');
var redisAdapter = require('socket.io-redis');
var server = io();
server.adapter(redisAdapter({ host: 'localhost', port: 6379 }))
server.on('connect', (socket) => {
console.log(`${socket.id} connected!`);
socket.join('new');
server.emit('welcome', `Please give a warm welcome to ${socket.id}!`);
server.to(socket.id).emit('private', 'Just between you and me, I think you are going to like it here');
});
server.listen(3000);
setInterval(whisperAtRandom, 2000);
function whisperAtRandom() {
server.in('new').adapter.clients((err, clients) => {
if (err) throw err;
console.log('Clients on channel "new": ', clients);
chosenOne = clients[Math.floor(Math.random()*clients.length)];
console.log(`Whispering to ${chosenOne}`);
server.to(chosenOne).emit('private', { message: `Psssst... hey there ${chosenOne}`});
server.in(chosenOne).adapter.clients((err, clients) => {
console.log(`Clients in ${chosenOne}: ${clients}`)
})
});
}
It stands up the server, listens on port 3000, and then every 2 seconds sends a message to a random client in the "new" room. It also logs out the list of clients who are connected to the "new" room and the "" room.
Here's the client-side code:
var sock = require('socket.io-client')('http://localhost:3000');
sock.connect();
sock.on('update', (data) => {
console.log('Updating...');
console.log(data);
});
sock.on('new', (data) => {
console.log(`${sock.id} accepting request for new`);
console.log(data.message);
});
sock.on('welcome', (data) => {
console.log('A new challenger enters the ring');
console.log(data);
});
sock.on('private', (data) => {
console.log(`A private message for me, ${sock.id}???`);
console.log(data);
});
My problem is that all my clients are connected to each others' "" room. Here's a sample from my logs:
0|socket-s | Clients on channel "new": [ 'dJaoZd6amTfdQy5NAAAA', 'bwG1yTT46dr5R_G6AAAB' ]
0|socket-s | Whispering to bwG1yTT46dr5R_G6AAAB
2|socket-c | A private message for me, dJaoZd6amTfdQy5NAAAA???
2|socket-c | Psssst... hey there bwG1yTT46dr5R_G6AAAB
1|socket-c | A private message for me, bwG1yTT46dr5R_G6AAAB???
1|socket-c | Psssst... hey there bwG1yTT46dr5R_G6AAAB
0|socket-s | Clients in bwG1yTT46dr5R_G6AAAB: dJaoZd6amTfdQy5NAAAA,bwG1yTT46dr5R_G6AAAB
You can see that the "private" message is received by both clients, dJaoZ... and bwG1y..., and that both clients are connected to the default room for bwG1y....
Why is this? Does it have something to do with the fact that both of my clients are running on the same machine (with different Node processes)? Am I missing something in Socket.io's documentation? Any help is appreciated!
PS -- to add even more confusion, the private messaging that occurs in server.on('connect', ... works! Each clients receives the "Just between you and me ..." message exactly once, right after they connect to the server.
Your main problem could caused by server.to in whisperAtRandom function, use socket instead of server for the private message:
socket.to(chosenOne).emit('private', { message: `Psssst... hey there ${chosenOne}`});
To answer your other problems, try to change these:
server.emit('welcome', `Please give a warm welcome to ${socket.id}!`);
server.to(socket.id).emit('private', 'Just between you and me, I think you are going to like it here');
To:
socket.broadcast.emit('welcome', `Please give a warm welcome to ${socket.id}!`);
socket.emit('private', 'Just between you and me, I think you are going to like it here');
Check out my Socket.IO Cheatsheet:
// Socket.IO Cheatsheet
// Add socket to room
socket.join('some room');
// Remove socket from room
socket.leave('some room');
// Send to current client
socket.emit('message', 'this is a test');
// Send to all clients include sender
io.sockets.emit('message', 'this is a test');
// Send to all clients except sender
socket.broadcast.emit('message', 'this is a test');
// Send to all clients in 'game' room(channel) except sender
socket.broadcast.to('game').emit('message', 'this is a test');
// Send to all clients in 'game' room(channel) include sender
io.sockets.in('game').emit('message', 'this is a test');
// sending to individual socket id
socket.to(socketId).emit('hey', 'I just met you');

Why use redis in a chat application? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
I just recently built a chat, it's working pretty well, but I think I need to hook it up to redis.
From what I understand I need redis for scaling and holding some data if a client refreshes or a server goes down.
A core component of the 1on1 chat is that I store the users, and associate a socket.id to those users
var users = {};
io.sockets.on('connection', function (socket) {
// store the users & socket.id into objects
users[socket.handshake.headers.user.username] = socket.id;
});
Now on the client side I can say hey I want to chat with "Jack", as long as that is a valid user then I can pass that data to the server, i.e the user name and message just to jack like so.
var chattingWith = data.nickname; // this is Jack passed from the client side
io.to(users[chattingWith]).emit();
My question is, why should I use redis? What should I store in redis? How should I interact with that data?
I am using an io.adapter
io.adapter(redisIo({
host: 'localhost',
port: 6379,
pubClient: pub,
subClient: sub
}));
Also reading code from an example app I see when a socket connects they save the socket data into redis like so.
// store stuff in redis
redisClientPublish.sadd('sockets:for:' + userKey + ':at:' + room_id, socket.id, function(err, socketAdded) {
if(socketAdded) {
redisClientPublish.sadd('socketio:sockets', socket.id);
redisClientPublish.sadd('rooms:' + room_id + ':online', userKey, function(err, userAdded) {
if(userAdded) {
redisClientPublish.hincrby('rooms:' + room_id + ':info', 'online', 1);
redisClientPublish.get('users:' + userKey + ':status', function(err, status) {
io.sockets.in(room_id).emit('new user', {
nickname: nickname,
provider: provider,
status: status || 'available'
});
});
}
});
}
});
They use it when entering a room, to get information about the room.
app.get('/:id', utils.restrict, function(req, res) {
console.log(redisClientPublish);
utils.getRoomInfo(req, res, redisClientPublish, function(room) {
console.log('Room Info: ' + room);
utils.getUsersInRoom(req, res, redisClientPublish, room, function(users) {
utils.getPublicRoomsInfo(redisClientPublish, function(rooms) {
utils.getUserStatus(req.user, redisClientPublish, function(status) {
utils.enterRoom(req, res, room, users, rooms, status);
});
});
});
});
});
So again, I am asking because I am kind of confused if I need to store anything inside redis/why I need to, for instance we may have a few hundred thousand users and the node.js server "Jack" and "Mike" are chatting on goes down, it then changes to point to a new node.js instance.
Obviously I want the chat to still remember "Jack's" socket id is "12333" and "Mike's" socket id is "09278" so whenever "Jack" says hey I want to send "Mike/09278" a message the server side socket will direct it properly.
Would storing the username as a key and socket ID as a value be a wise use case for redis, would that socket.id still work?
Redis is a pretty good choice as a database for a chat as it provides a couple of data structures that are not only very handy for various chat use cases but also processed in a really performant way. It also comes along with a PubSub messaging functionality that allows you to scale your backend by spawning multiple server instances.
Scaling socket.io with the socket.io-redis adapter
When you want to run multiple instances of your server - be it because of one server not being able to handle increasing users any more or for setting up a high availablility cluster - then your server instances must communicate with each other in order to be able to deliver messages between users who are connected to different servers. The socket.io-redis adapter solves this by using the redis PubSub feature as a middleware. This won't help you if you are using only a single server instance (in fact I assume it will be slightly less performant) but as soon as you spawn a second server this will work out just fine without any headaches.
Want to get a feeling and some insight on how it's working? Monitor your dev redis while using it and you'll see the internal socket.io messages that are pushed through redis.
redis-cli
monitor
Use cases and their according redis data types
Save active conversations in a SET
A redis set is a collection of unique strings. I don't think storing socket.io id's would work out well as you can't assume that a user will get the same id on a reconnect. Better store his rooms and rejoin him on connect. You add every chat room (btw. direct messages can be defined as a room with two participiants so the handling is the same in both cases) that a user enters to their room set. On a server restart, a client reconnect or second client instance you can retrieve the whole set and rejoin users to their rooms.
/* note: untested pseudo code just for illustration */
io.sockets.on('connection', function (socket) {
rooms = await redis.smembers("rooms:userA");
rooms.foreach (function(room) {
socket.join(room);
}
socket.on('leave', room) {
socket.leave(room);
redis.srem("rooms:userA", room);
}
socket.on('join', room) {
socket.join(room);
redis.sadd("rooms:userA", room);
}
}
Save the last 10 messages of a conversation using a redis LIST
A redis list is somewhat of an persistent array of strings. You push a new message into a list and pop the oldest when the list size reaches your threshold. Conveniently the push command returns the size right away.
socket.on('chatmessage', room, message) {
if (redis.lpush("conversation:userA:userB", "Hello World") > 10) {
redis.rpop("conversation:userA:userB");
}
io.to(room).emit(message);
}
To get the message history use lrange:
msgHistory = redis.lrange("conversation:userA:userB", 0, 10)
Save some basic user details in a HASH
A hash is a key/value collection. Use it to store the online status along with avatar urls or whatever.
io.sockets.on('connection', function (socket) {
redis.hset("userdata:userA", "status", "online");
socket.on('disconnect', function () {
redis.hset("userdata:userA", "status", "offline");
}
}
Maintain a "recent conversations" list in a SORTED LIST
Sorted sets are similar to SETs but you can assign a score value to every element and retrieve the set ordered by this value. Simply use a timestamp as score whenever there is an interaction between two users and that's it.
socket.on('chatmessage', room, message) {
io.to(room).emit(message);
redis.zadd("conversations:userA", new Date().getTime(), room);
}
async function getTheTenLatestConversations() {
return await redis.zrange("conversations:userA", 0, 10);
}
References
socket.io-redis: https://github.com/socketio/socket.io-redis
redis PubSub docs: https://redis.io/topics/pubsub
redis data types: https://redis.io/topics/data-types-intro

node.js only one client is receiving the messages

As far as I know, unless told otherwise, if the server sends a message, all clients should receive it. But in my case only one client is getting the messages.
client :
(function () {
window.Network = {
socket : null,
initialize : function(socketURL) {
this.socket = io.connect(socketURL);
this.socket.on('new move', this.add);
},
add : function(data) {
var msg = $('<div class="msg"></div>')
.append('<span class="text">' + data.x+'/'+data.y + '</span>');
$('#messages')
.append(msg)
.animate({scrollTop: $('#messages').prop('scrollHeight')}, 0);
},
send : function(data) {
this.socket.emit("move",data);
return false;
}
};
}());
server:
io.sockets.on('connection', function (socket) {
socket.on('move', function (data) {
console.log(data);
socket.emit("new move",data);
});
});
If I open several clients and use "send" function, only the client that sent it receives the emit from the server.
Any idea what I am doing wrong?
Thanks
To emit globally on the server side use this :
io.sockets.emit('new move', 'data1');
To emit to the current socket :
socket.emit('function', 'data1', 'data2');
To broadcast to everyone but the client :
socket.broadcast.emit('function', 'data1', 'data2');
Source
When you are using socket, you are talking directly to the connected client.
You can use rooms however, un this snippet i add the socket to room1
// Add the player socket, to the room.
socket.join('room1');
Then you can emit to all client in a room by
io.sockets.in('room1').emit('startGame', true);
The code is working just as it is supposed to. You are doing socket.emit("new move",data);, which will emit a new move event back to that specific socket, which in your case is the same socket that connected.
If you also want it to be sent to other clients that are connected, then you need to explicitly emit the event to other clients.
socket.emit("new move",data);
socket.broadcast.emit("new move",data);

How to disable Multiplexing with Socket.io

I am using Socket.io to stream live tweets to my users using Twitter's Streaming API (my implementation is more or less based on this tutorial).
The problem is that every time a connection event is fired by Socket.io the newly connected client causes every other client connected to the server to cease updating. While it would take too long to go through all the hacks that I tried, I will say that I played with it enough that I believe the problem is caused by Socket.io's multiplexing of the connections from multiple clients (enabled by default) as a performance boost to allow multiple clients or connections to share the same underlying socket. In short, I believe this to be the case because I don't think it would be possible for new connections to affect older connections in this manner if not for the connection multiplexing. In other words, if a new, independent connection with its own underlying (TCP) socket were created every time a client connected it would be impossible for this to occur since one connection would know nothing about the other and therefore couldn't affect any other client's state as is currently happening. This also leads me to believe that simply disabling the multiplexing functionality would be the simplest way to get around this problem since I am not concerned about scaling because Node.js already handles all the concurrency I'm likely to need to handle very adequately.
I have gone through Socket.io's documentation but could not see where the ability to "demultiplex" the connections is exposed via the API, so if anyone knows how to do this I'd create appreciate your response.
My code below is pretty standard and simple. But just to be clear, the issue is that whenever a new client connects to Socket.io every other client stops receiving new tweets and updates are no longer pushed to the older client unless I refresh the browser in which case the newly refreshed client will begin to update and receive fresh tweets again, but the other still connected clients will then stop updating.
Server-side Code:
// Code also uses ntwitter (https://github.com/AvianFlu/ntwitter) as an abstraction over Twitter's Streaming API
io.sockets.on('connection', function (socket) {
tweet.stream('statuses/filter', { track : 'new orleans' }, function (stream) {
stream.on('data', function (data) {
// The following lines simply pre-process data sent from Twitter so junk isn't
// unnecessarily sent to the client.
if (data.user) {
tweets = {
text : data.text,
image : data.user.profile_image_url,
user : data.user.name
};
var t = JSON.stringify(tweets);
console.log(t);
socket.send(t);
}
});
});
});
Client-Side Code
// Notice the option that I passed in as the second argument. This supposedly forces every
// new client to create a new connection with the server but it either doesn't work or I'm
// implementing it incorrectly. It is the very last configuration option listed in the
// documentation linked to above.
var socket = io.connect('http://' + location.host, {'force new connection' : true });
socket.on('message', function (tweet) {
var t = JSON.parse(tweet);
if (t.image) {
$('.hero-unit').prepend('<div class="media"><a class="pull-left" href="#"><img class="media-object" alt="64x64" style="width: 64px; height: 64px;" src="' + t.image + '"></a><div class="media-body"><h4 class="media-heading">' + t.user + '</h4>' + t.text + '</div></div>');
}
});
If I am thinking of this incorrectly or if there's something wrong with my code I am definitely open to any suggestions. I'd also be happy to reply with any additional details.
I would try something like this
Serverside:
io.sockets.on('connection', function (socket) {
//Other Connectiony goodness here.
});
});
tweet.stream('statuses/filter', { track : 'new orleans' }, function (stream) {
stream.on('data', function (data) {
// The following lines simply pre-process data sent from Twitter so junk isn't
// unnecessarily sent to the client.
if (data.user) {
tweets = {
text : data.text,
image : data.user.profile_image_url,
user : data.user.name
};
var t = JSON.stringify(tweets);
console.log(t);
io.sockets.emit("tweet", t);
}
});
Client-side:
var socket = io.connect('http://' + location.host, {'force new connection' : true });
socket.on('tweet', function (tweet) {
var t = JSON.parse(tweet);
if (t.image) {
$('.hero-unit').prepend('<div class="media"><a class="pull-left" href="#"><img class="media-object" alt="64x64" style="width: 64px; height: 64px;" src="' + t.image + '"></a><div class="media-body"><h4 class="media-heading">' + t.user + '</h4>' + t.text + '</div></div>');
}
});
Basically have the stream from twitter outside your socket, and then on a new tweet emit a message to all connected.

Resources