In my express server, I am using socket.io and Redis pubsub.
The server subscribes a Redis message channel, and forwards Redis message to a specific websocket client when someone publishes new message via Redis.
From what i read from socket.io and Redis documentation, I can send message to a specific client by using the varible socket and call socket.broadcast.to(mySocketID).emit.
But in the following code, what should I do if I wanna emit message to mySocketID inside the redis subscriber, which is out of the scope of io.on('connection')?
var redis = require('redis');
var server = require('http').createServer(app);
var io = require("socket.io")(server);
io.on('connection', function (socket) {
socket.on('whatever_event', function() {
socket.broadcast.to(mySocketID).emit('TEST', 'hello ' + mySocketID);
}
}
var subscriber = redis.createClient();
subscriber.on('message', function (channel, redisMessage) {
// I want to send redisMessage to the websocket client
// Can I access to "socket" in io.on('connection' ...) ?
});
I did something similar with WebSockets a while back (If I understand what you're trying to do). Effectively, I had to create a in-process event proxy layer between the Redis Pub/Sub (plain ol' EventEmitter) and the websocket. Without this layer you're going to have a lot of unneeded connection overhead, by using it you can limit the number of open connections to Redis.
So, the subscriber.on section sends a EventEmitter event (yourEventsObject.emit(/*...*/)). Then inside your socket.io connection callback you respond to these events with listeners (yourEventsObject.on(/*...*/)). When your socket.io connection closes, you need to make sure and clean up these EventEmitter listeners so you don't get errors with closed sockets.
Here is the full file on full source on and the article describing the problem/solution with websockets.
Related
I am trying to use Socket.io and Sequelize to create a chat app. Socket.io will handle the socket to allow for instant messaging. Sequelize will handle storing the messages so when you refresh the screen you still have your messages.
What is happening is that on localhost my socket works, but it does not send the messages to the database. When I put it onto Heroku, my database worked, but it does not use the sockets.
My socket is located in app.js and my database route is located in routes/messages.js.
I have been working on this bug for a while now and I have been trying to get help with it. I think the best way to share this is with my markdown I created detailing my efforts to fix my bug that can be found at here. My repo for this can be found here.
There are a few different parts that you need to distinguish:
the HTTP server, in your code represented by the variable http
the Express app, represented by app
the Socket.IO server, represented by io
a Socket.IO (client) connection (see below)
The HTTP server directs "normal" HTTP requests to the Express app, which will handle them according to the middleware and routes that are set up. A router handler gets called with (at least) two arguments, generally called req and res, to represent the (incoming) HTTP request and the (outgoing) HTTP response.
The Socket.IO server gets to handle specific Socket.IO requests, which get sent to the server by the Socket.IO client (running in the browser). When such a client sets up a connection with the server, the connection event gets triggered on the server. Any handlers for this event will get passed an argument, generally called socket, that represents the (bidirectional) connection with that client.
That Socket.IO connection can receive messages (sent from the client running in the browser), which trigger events on the socket. You can install a handler to listen for particular messages (like "chat message"), which will receive, as argument, the data that was sent to it by the client.
The issue in your code seems to be with setting up everything to handle those chat messages. The correct setup order would be:
listen on the Socket.IO server for connection events
when such an event is received, add a listener for the chat message event on the connection
when such an event is received, write the data to the database.
In code:
// Listen for new client connections.
io.on('connection', function(socket) {
// Listen for the client to send a _"chat message"_ message.
socket.on('chat message', function(data) {
// Store the data in the database.
models.Messages.create({
message : data.message,
username : data.username
});
});
});
As you can see, req and res aren't available inside of those Socket.IO event handlers, because those are only used for normal HTTP requests.
Also, as opposed to HTTP, you don't necessarily have to send anything back to the client when you have received a message, so I left that part out. The handler above only writes the message data to the database (it also doesn't check for, or handle, errors, which eventually you should add).
I want to create an Event Publisher that connect via Websocket. When I try to connect it with my simple socket io server, the url is
ws://localhost:3000/socket.io/
It didn't receive the stream..
I've set the inline format for the stream like this :
42["input-message",{"LAT":{{latitude}},"LON":{{longitude}}}]
If I understand your question correctly,
you do not get any errors when the event is published from the CEP
server
but the socket io server does not show any indication that it
received the event either.
CEP server showing no error logs means:
CEP server is successfully connected to the socket io server. (if the connection is dropped, then you should see an error log, and CEP will try to reconnect)
Probably the event was sent to socket io server by Websocket publisher (or the Websocket publisher did not recieve any event at all to be sent to socket io server)
(When you send an event, if the CEP server cannot parse the event, then also you should see an error log.)
Here are some points which might help you to troubleshoot the issue:
Enable tracing in your websocket publisher (You may refer to this 'Event Tracer' doc). Then send an event and check the traces. This will allow you to verify whether the Websocket publisher recieved the event.
If there are traces shown for the publisher, but still no event received at the socket io server, then it could be that some error occurs at socket io server, and the exception is not logged (might have being swallowed).
Hope this will help.
Because I cannot directly connect to the socket.io, thus I created a simple websocket that act as a middleware that sending the input from WSO2CEP into the socket.io
var io = require('socket.io').listen(server);
io.set('origins', '*:*');
var WebSocketServer = require('ws').Server,
wss = new WebSocketServer({ port: 8087 })
//wss sending every message that it received to the socket.io
wss.on('connection', function connection(ws) {
console.log('a WSO2CEP-PUBLISHER is connected');
ws.on('message', function incoming(message) {
console.log('received: %s', message);
io.emit('input-message', JSON.parse(message));
});
});
notice that, the data that come from event publisher is string formatted, so if needed to send it as a JSON object, than use JSON.parse() function.
I have a single Node.js server - I would like for the process to listen to messages sent from itself - this is for testing only. The problem I am having is that when publishing a message to the same process, the subscriber doesn't seem to receive it at all.
I have this setup:
var redis = require('redis');
var rcPub = redis.createClient();
var rcSub = redis.createClient();
var message = String('testing123');
rcSub.subscribe('redis_channel#test_overall_health');
rcSub.on('message', function (channel, msgs) {
console.log(channel,msgs);
});
rcPub.publish('redis_channel#test_overall_health', message);
I have one redis client that acts as a subscriber and one as a publisher, which is the way you must do it, but for some reason the messages aren't being received. Is there some limitation that a process can't listen to the messages it publishes? It doesn't seem to make sense. I can verify this code is more or less right because other processes listening to the same channel received the message.
Apparently, the SUBSCRIBE command is being sent after the PUBLISH command.
Node's Redis client queues commands until a connection is established to the Redis server and flushes the queued commands to the server when a connect event is received on the socket. The client that initiated the connection first (publisher), will most likely receive the connect event first, at which point it will send its queued commands (publish). Because Redis processes commands in a single thread, the subscriber SUBSCRIBEs only after the PUBLISH command is complete. The other processes are able to receive the messages since they've already subscribed to this channel.
Creating the subscriber client first should work in most cases, albeit a safer approach will be to wait for the subscription to complete before publishing any messages:
var redis = require('redis');
var publisher = redis.createClient(),
subscriber = redis.createClient(),
message = 'testing123';
subscriber.subscribe('redis_channel#test_overall_health');
subscriber.on('message', function (channel, message) {
console.log(channel, message);
});
subscriber.on('subscribe', function (channel, count) {
publisher.publish('redis_channel#test_overall_health', message);
});
I have a problem with understanding how socket.io and node.js works.
I tried few examples with emitting messages and it worked. What I don't understand is emitting from clients.
I use emit in client, for example: socket.emit('custom_event');, but it doesn't work in other clients unless I add something like this in my server:
var io = require('socket.io').listen(app);
io.sockets.on('connection', function(socket) {
socket.on('custom_event', function() {
socket.emit('custom_event');
});
});
Am I doing something wrong or do I need to always add definition on server side for something that client should be emitting to other clients?
this is not possible, socketio need the server logic between your clients.
You can do:
socket.broadcast.emit
Broadcasting means sending a message to everyone else except for the socket that starts it.
io.sockets.emit
Emits to all, (inc the socket that starts the action.)
But allways from the server
Can you connect client to client via web sockets without touching the server?
I'm building a simple system like a realtime news feed, using node.js + socket.io.
Since this is a "read-only" system, clients connect and receive data, but clients never actually send any data of their own. The server generates the messages that needs to be sent to all clients, no client generates any messages; yet I do need to broadcast.
The documentation for socket.io's broadcast (end of page) says
To broadcast, simply add a broadcast flag to emit and send method calls. Broadcasting means sending a message to everyone else except for the socket that starts it.
So I currently capture the most recent client to connect, into a variable, then emit() to that socket and broadcast.emit() to that socket, such that this new client gets the new data and all the other clients. But it feels like the client's role here is nothing more than a workaround for what I thought socket.io already supported.
Is there a way to send data to all clients based on an event initiated by the server?
My current approach is roughly:
var socket;
io.sockets.on("connection", function (s) {
socket = s;
});
/* bunch of real logic, yadda yadda ... */
myServerSideNewsFeed.onNewEntry(function (msg) {
socket.emit("msg", { "msg" : msg });
socket.broadcast.emit("msg", { "msg" : msg });
});
Basically the events that cause data to require sending to the client are all server-side, not client-side.
Why not just do like below?
io.sockets.emit('hello',{msg:'abc'});
Since you are emitting events only server side, you should create a custom EventEmitter for your server.
var io = require('socket.io').listen(80);
events = require('events'),
serverEmitter = new events.EventEmitter();
io.sockets.on('connection', function (socket) {
// here you handle what happens on the 'newFeed' event
// which will be triggered by the server later on
serverEmitter.on('newFeed', function (data) {
// this message will be sent to all connected users
socket.emit(data);
});
});
// sometime in the future the server will emit one or more newFeed events
serverEmitter.emit('newFeed', data);
Note: newFeed is just an event example, you can have as many events as you like.
Important
The solution above is better also because in the future you might need to emit certain messages only to some clients, not all (thus need conditions). For something simpler (just emit a message to all clients no matter what), io.sockets.broadcast.emit() is a better fit indeed.