How to emit an event in socket.io from the routes file? - javascript

This is my app configuration
app.js
//SERVER
var server = app.listen(3000, function(){
console.log("Express server listening on port %d in %s mode", app.get('port'),
app.settings.env);
});
//SOCKET.IO
var io = require('./socket.io').listen(server)
/socketio
var socketio = require('socket.io')
module.exports.listen = function(app)
{
io = socketio.listen(app);
io.configure('development',function()
{
//io.set('transports', ['websocket', 'xhr-polling']);
//io.enable('log');
});
io.configure('production',function()
{
io.enable('browser client minification'); // send minified client
io.enable('browser client etag'); // apply etag caching logic based on version number
io.set('log level', 1); // reduce logging
io.set('transports', [ // enable all transports (optional if you want flashsocket)
'websocket'
, 'flashsocket'
, 'htmlfile'
, 'xhr-polling'
, 'jsonp-polling'
]);
});
io.sockets.on('connection', function (socket)
{
console.log("new connection: "+socket.id);
socket.on('disconnect',function(){console.log("device "+socket.id+" disconnected");});
socket.emit('news', { hello: 'world' });
socket.on('reloadAccounts',function(data)
{
var accounts=['account1','account2']
socket.emit('news',accounts)
});
});
return io
}
/routes
exports.newAccount=function(fields,callback)//localhost:3000/newAccountForm
{
//... bla bla bla config db connection bla bla bla
db.collection('accounts').insert(fields,function(err,result)
{
if(err)
{
console.warn(err);
db.close();
return callback(err,null);
}else{
if(result)
{
db.close();
return callback(null,result);
socket.emit('new account created',result) // i want to emit a new event when any user create an account
}else{
db.close();
return callback('no se consigue resultado',null);
}
}
})
});
}
How to emit an event in socket.io from the routes file?

First you need to decide that what socket you want to send the new info. If it's all of them(to everyone connected to your app), it would be easy, just use io.sockets.emit:
In the ./socket.io file you add exports.sockets = io.sockets; somewhere after io = socketio.listen(app);. Then in the routes file, you can emit like this:
var socketio = require('./socket.io');
socketio.sockets.emit('new account created', result);
If you know the socket id that you want to send to, then you can do this:
var socketio = require('./socket.io');
socketio.sockets.sockets[socketId].emit('new account created', result);
You can also select the socket by express session id:
First you need to attach the session id to the socket on authorization:
io.set('authorization', function (data, accept) {
// check if there's a cookie header
if (data.headers.cookie) {
// if there is, parse the cookie
data.cookie = cookie.parse(data.headers.cookie);
// note that you will need to use the same key to grad the
// session id, as you specified in the Express setup.
data.sessionID = data.cookie['express.sid'];
} else {
// if there isn't, turn down the connection with a message
// and leave the function.
return accept('No cookie transmitted.', false);
}
// accept the incoming connection
accept(null, true);
});
Then you can select sockets with the session id:
var socketio = require('./socket.io');
var sockets = socketio.sockets.forEach(function (socket) {
if (socket.handshake.sessionID === req.sesssionID)
socket.emit('new account created', result);
});
You can also query your session store and using the method I described above, emit the event to sockets with sessionId that matched your query.

Related

Using passport for socket.io

Hi im trying to use passport for authencication, But im not sure what to do on the client side. I think the server side is fine, but it gives me this error:failed: WebSocket is closed before the connection is established. So it seems like it cant get the connection. what do i need to send from the client side, and do i need to change something on server side??
please heeeelp thanks:)
server.js
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require("socket.io")(server, {
cors: {
origin: "*",
methods: ["GET", "POST"]
}
});
var port = process.env.PORT || 4000;
const passportSocketIo = require('passport.socketio')
const cookieParser = require('cookie-parser')
const session = require("express-session")
const passport = require('passport')
io.use(passportSocketIo.authorize({
cookieParser: cookieParser,
key: 'express.sid',
secret: 'session_secret',
store: session,
success: onAuthorizeSuccess,
fail: onAuthorizeFail,
}));
function onAuthorizeSuccess(data, accept){
console.log('successful connection to socket.io');
// The accept-callback still allows us to decide whether to
// accept the connection or not.
accept(null, true);
// OR
// If you use socket.io#1.X the callback looks different
accept();
}
function onAuthorizeFail(data, message, error, accept){
if(error)
throw new Error(message);
console.log('failed connection to socket.io:', message);
// We use this callback to log all of our failed connections.
accept(null, false);
// OR
// If you use socket.io#1.X the callback looks different
// If you don't want to accept the connection
if(error)
accept(new Error(message));
// this error will be sent to the user as a special error-package
// see: http://socket.io/docs/client-api/#socket > error-object
}
io.on('connection', function (socket) {
console.log("connection")
var addedUser = false;
// when the client emits 'new message', this listens and executes
socket.on('new message', function (data) {
var data = validator.escape(data);
// we tell the client to execute 'new message'
socket.broadcast.emit('new message', {
username: socket.username,
message: data
});
db.serialize(function() {
// console.log('inserting message to database');
var insertMessageStr = "INSERT INTO messages (username, content, posted) VALUES ('" + socket.username + "','" + data.toString() + "'," + Date.now() + ");"
// console.log(insertMessageStr)
db.run(insertMessageStr);
});
});
client.js
const socket = io({
key: 'express.sid',
secret: 'session_secret',
});

SO_REUSEADDR in NodeJs using net package

I have two backends. Backend A and Backend B.
Backend B sends and receives info using a socket server running at port 4243.
Then, with Backend A, I need to catch that info and save it. But I have to also have a socket server on Backend A running at port 4243.
The problem is that, when I run Backend A after running Backend B I receive the error "EADDRINUSE", because I'm using the same host:port on both apps.
If, for Backend A I use Python, the problem dissapear because I have a configuration for sockets that's called SO_REUSEADDR.
Here we have some examples:
https://www.programcreek.com/python/example/410/socket.SO_REUSEADDR
https://subscription.packtpub.com/book/networking-and-servers/9781849513463/1/ch01lvl1sec18/reusing-socket-addresses
But, I want to use JavaScript for coding my Backend A, so I was using the net package for coding the sockets, and I can't get it to work, because of the "EADDRINUSE" error.
The NodeJS documentation says that "All sockets in Node set SO_REUSEADDR already", but it doesn't seem to work for me...
This is my code so far:
// Step 0: Create the netServer and the netClient
console.log(`[DEBUG] Server will listen to: ${HOST}:${PORT}`);
console.log(`[DEBUG] Server will register with: ${AGENT_ID}`);
const netServer = net.createServer((c) => {
console.log('[netServer] Client connected');
c.on('message', (msg) => {
console.log('[netServer] Received `message`, MSG:', msg.toString());
});
c.on('*', (event, msg) => {
console.log('[netServer] Received `*`, EVENT:', event);
console.log('[netServer] Received `*`, MSG:', msg);
});
}).listen({
host: HOST, // 'localhost',
port: PORT, // 4243,
family: 4, // ipv4, same as socket.AF_INET for python
});
// Code copied from nodejs documentation page (doesn't make any difference)
netServer.on('error', function (e) {
if (e.code == 'EADDRINUSE') {
console.log('Address in use, retrying...');
setTimeout(function () {
netServer.close();
netServer.listen(PORT, HOST);
}, 1000);
}
});
const netClient = net.createConnection(PORT, HOST, () => {
console.log('[netClient] Connected');
});
// Step 1: Register to instance B of DTN with agent ID 'bundlesink'
netClient.write(serializeMessage({
messageType: AAPMessageTypes.REGISTER,
eid: AGENT_ID,
}));
With this code, I get the following output in the terminal:
But, with the Python code, the socket connects successfully:
I don't know what to do :(
I hope I get some help here.
Edit 1
By the way, the lsof command, throws me this output for the JavaScript backend:
And this other output for the Python backend:
Edit 2
It really seems to be a problem with JavaScript. I also found this snippet:
var net = require('net');
function startServer(port, host, callback) {
var server = net.createServer();
server.listen(port, host, function() {
callback(undefined, server);
});
server.on('error', function(error) {
console.error('Ah damn!', error);
callback(error);
});
}
startServer(4000, '0.0.0.0', function(error, wildcardServer) {
if (error) return;
startServer(4000, '127.0.0.1', function(error, localhostServer) {
if (error) return;
console.log('Started both servers!');
});
});
From this post:
https://medium.com/#eplawless/node-js-is-a-liar-sometimes-8a28196d56b6
As the author says:
Well, that prints “Started both servers!” which is exactly what we don’t want.
But for me, instead of printing that, I get an error:
Ah damn! Error: listen EADDRINUSE: address already in use 127.0.0.1:4000
at Server.setupListenHandle [as _listen2] (node:net:1319:16)
at listenInCluster (node:net:1367:12)
at doListen (node:net:1505:7)
at processTicksAndRejections (node:internal/process/task_queues:84:21) {
code: 'EADDRINUSE',
errno: -98,
syscall: 'listen',
address: '127.0.0.1',
port: 4000
}
I really cannot make it to run and print "Started both servers!".
Because that's what I want my code to do.
Edit 3
This is the Python server socket: https://gitlab.com/d3tn/ud3tn/-/blob/master/tools/aap/aap_receive.py
This is the important part:
addr = (args.tcp[0], int(args.tcp[1])) # args.tcp[0] = "localhost", args.tcp[1] = "4243"
with AAPTCPClient(address=addr) as aap_client:
aap_client.register(args.agentid) # args.agentid = "bundlesink"
run_aap_recv(aap_client, args.count, args.verify_pl)
It creates an AAPTCPClient, and the only thing that AAPTCPClient does, is the following:
def __init__(self, socket, address):
self.socket = socket
self.address = address
self.node_eid = None
self.agent_id = None
def register(self, agent_id=None):
"""Attempt to register the specified agent identifier.
Args:
agent_id: The agent identifier to be registered. If None,
uuid.uuid4() is called to generate one.
"""
self.agent_id = agent_id or str(uuid.uuid4())
logger.info(f"Sending REGISTER message for '{agent_id}'...")
msg_ack = self.send(
AAPMessage(AAPMessageType.REGISTER, self.agent_id)
)
assert msg_ack.msg_type == AAPMessageType.ACK
logger.info("ACK message received!")
def send(self, aap_msg):
"""Serialize and send the provided `AAPMessage` to the AAP endpoint.
Args:
aap_msg: The `AAPMessage` to be sent.
"""
self.socket.send(aap_msg.serialize())
return self.receive()
def receive(self):
"""Receive and return the next `AAPMessage`."""
buf = bytearray()
msg = None
while msg is None:
data = self.socket.recv(1)
if not data:
logger.info("Disconnected")
return None
buf += data
try:
msg = AAPMessage.parse(buf)
except InsufficientAAPDataError:
continue
return msg
I don't see any bind, and I don't understand why the python code can call "socket.recv", but in my JavaScript code I can't do "netServer.listen". I think it should be the same.
There are things to clarify.
1.) The client uses the bind syscall where the kernel selects the source port automatically.
It does so by checking sys local_portrange sysctl settings.
1.) If you want to bind the client to a static source port, be sure to select a TCP port outside the local_portrange range !
2.) You cannot subscribe to event "*", instead you've to subscribe to the event "data" to receive messages.
For best practice you should also subscribe to the "error" event in case of errors !
These links will get you started right away:
How do SO_REUSEADDR and SO_REUSEPORT differ?
https://idea.popcount.org/2014-04-03-bind-before-connect/
So, for all beginners, who want to dig deeper into networking using node.js…
A working server example:
// Step 0: Create the netServer and the netClient
//
var HOST = 'localhost';
var PORT = 4243;
var AGENT_ID = 'SO_REUSEADDR DEMO';
var net = require('net');
console.log(`[DEBUG] Server will listen to: ${HOST}:${PORT}`);
console.log(`[DEBUG] Server will register with: ${AGENT_ID}`);
const netServer = net.createServer((c) => {
console.log('[netServer] Client connected');
c.on('data', (msg) => {
console.log('[netServer] Received `message`, MSG:', msg.toString());
});
c.on('end', () => {
console.log('client disconnected');
});
c.on('error', function (e) {
console.log('Error: ' + e.code);
});
c.write('hello\r\n');
c.pipe(c);
}).listen({
host: HOST,
port: PORT,
family: 4, // ipv4, same as socket.AF_INET for python
});
// Code copied from nodejs documentation page (doesn't make any difference)
netServer.on('error', function (e) {
console.log('Error: ' + e.code);
if (e.code == 'EADDRINUSE') {
console.log('Address in use, retrying...');
setTimeout(function () {
netServer.close();
netServer.listen(HOST, PORT);
}, 1000);
}
if ( e.code = 'ECONNRESET' ){
console.log('Connection reset by peer...');
setTimeout(function () {
netServer.close();
netServer.listen(HOST, PORT);
}, 1000);
}
});
The Client:
/* Or use this example tcp client written in node.js. (Originated with
example code from
http://www.hacksparrow.com/tcp-socket-programming-in-node-js.html.) */
var net = require('net');
var HOST = 'localhost';
var PORT = 4243;
var client = new net.Socket();
client.setTimeout(3000);
client.connect(PORT, HOST, function() {
console.log("Connected to " + client.address().address + " Source Port: " + client.address().port + " Family: " + client.address().family);
client.write('Hello, server! Love, Client.');
});
client.on('data', function(data) {
console.log('Received: ' + data);
client.end();
});
client.on('error', function(e) {
console.log('Error: ' + e.code);
});
client.on('timeout', () => {
console.log('socket timeout');
client.end();
});
client.on('close', function() {
console.log('Connection closed');
});
Best Hannes
Steffen Ullrich was completely right.
In my JavaScript code, I was trying to create a server to listen to the port 4243.
But you don't need to have a server in order to listen to some port, you can listen with a client too! (At least that's what I understood)
You can create a client connection as following:
const netClient = net.createConnection(PORT, HOST, () => {
console.log('[netClient] Connected');
});
netClient.on('data', (data) => {
console.log('[netClient] Received data:', data.toString('utf8'));
});
And with "client.on", then you can receive messages as well, as if it were a server.
I hope this is useful to someone else.

ng-websocket and ws: client sends successfully but doesn't receive

My angularjs client websocketserver can properly send to the server, but when sending from server to client, the client doesn't register the event.
I'm using angular-websockets at the client side and ws at my express.js server
Here's my code.
server
var port = process.env.PORT || 3002;
var server = http.createServer(app); // app = express
server.listen(port);
var socketComs = require('./lib/socketcoms').connect(server);
var connect = function(server) {
var wss = new WebSocketServer({
server: server
});
wss.on('connection', function(ws) {
console.log("websocket connection open");
ws.on('message', function incoming(message) {
console.log('received', message); // THIS WORKS FINE
});
var id = setInterval(function() {
ws.send('pong', 'data 123', function(err) {
console.log('sent pong', err); // THIS IS NEVER CAUGHT BY CLIENT, err = clean
});
}, 2000); // Pong is never received
});
};
client
var connect = function() {
ws.$on('$open', function() {
console.log('wow its working');
ws.$emit('message', 'some message');
});
ws.$on('pong', function(data) {
console.log('yes', data);
});
ws.$on('$close', function(data) {
console.log('wss closed');
});
};
Can anyone see what's going wrong?
I'm using ng-websocket with PHP socket, and I have the same issue.
I just opened the ng-websocket.js and..guess what? the "ping" and "pong" events don't exist!
The "incoming" event is called "$message"...
This is how to get data from server:
ws.$on('$message', function (response) {
console.log("DATA FROM SERVER", response);

Nodejs accessing nested variable in global scope

How would I access socket in the global scope based on my following NodeJS code
io.on('connection', function (socket) {
console.log('connection '+socket)
socket.on("data",function(d){console.log('data from flash: ',d);});
socket.emit("message","wtfwtwftwftwf hello from server");
socket.on('disconnect', function (socket) {
console.log("disconnect");
});
});
I need to access socket from within the following app.post method
var express = require('express'),
multer = require('multer');
var app = express();
//auto save file to uploads folder
app.use(multer({ dest: './uploads/'}))
app.post('/', function (req, res) {
console.log(req.body); //contains the variables
console.log(req.files); //contains the file references
res.send('Thank you for uploading!');
});
app.listen(8080);
Haven't tested yet but going to try a simple getter function first
io.on('connection', function (socket) {
console.log('connection '+socket)
socket.on("data",function(d){console.log('data from flash: ',d);});
socket.emit("message","wtfwtwftwftwf hello from server");
return{
getSocket: function(){
return socket;
}
};
socket.on('disconnect', function (socket) {
console.log("disconnect");
});
});
io.getSocket() ??
Express's app and Socket.io have nothing to do with one another.
So fundamentally, you can't use socket inside app.post.
You need to identify the client. You can use Passport which has a Socket.io plugin that essentially bridges the app.post/get's req.user to socket.request.user.
Note: It doesn't have to be an authenticated client with user that's fetched from database, just a client with a temporary user stored in memory would do. Something like this:
app.use(function(req, res, next) {
if (!req.user) { // if a user doesn't exist, create one
var id = crypto.randomBytes(10).toString('hex');
var user = { id: id };
req.logIn(user);
res.redirect(req.lastpage || '/');
return;
}
next();
});
var Users = {};
passport.serialize(function(user) {
Users[user.id] = user;
done(null, user);
});
passport.deserialize(function(id) {
var user = Users[id];
done(null, user);
});
Then you can attach the client's socket ID to its user session.
io.on('connection', function (socket) {
socket.request.user.socketid = socket.id
});
And then instead of socket.emit use io.emit in app.post using the socketid
app.post('/', function (req, res) {
io.to(req.user.socketid).emit('whatever');
});
Note: io.to() is used to emit to a room, but every socket is by default joined to the same room named as its socket.id, so it'll work.
Javascript and socketIO experts > please tell me why this simple solution shouldn't work. It seems to...
1 Define a global pointer
var _this=this;
2 In my socketIO handler make a reference to the socket object
_this.socket=socket;
3 And finally within app.post, access the socket like thus
_this.socket.emit(....

Nodejs server unable to detect connection with Pubnub+SocketIO

My nodejs server is unable to detect when a new browser connects ('connection' event) and I dont know why. I narrowed down a problem working on it for a few days and suspect that is has to due with the addition of the pubnub socket connection implemented on the browser.
The following is my server.js
var http = require('http')
, connect = require('connect')
, io = require('socket.io')
, fs = require('fs')
, uuid = require('node-uuid')
, _ = require('lodash');
// pubnub!!! (how to initialize it for use on server)
var pubnub = require('pubnub').init({
channel: "my_channel",
publish_key: "pub-key",
subscribe_key: "sub-c-key",
uuid: "Server",
origin : 'pubsub.pubnub.com'
});
pubnub.subscribe({
channel: 'my_channel',
callback: function(message) {
console.log("Message received: ", message);
},
message: 'Server ready',
presence: function(data) {
console.log("Presense: ", data);
},
connect: publish
});
// various socket.on() events omitted
var app = connect().use(connect.static(__dirname)).use(connect.directory(__dirname));
var server = http.createServer(app);
server.listen(8888);
io = io.listen(server);
io.sockets.on('connection', handleNewPeer);
Upon arriving on the html page, the doConnect(isBroadcaster) function is ran from script tag
The doConnect function (In peer.js):
var doConnect = function(isBroadcaster) {
console.log("doConnect");
// broadcaster or normal peer
var user;
if (isBroadcaster)
user = "Broadcaster";
else
user = "Viewer";
(function() {
var pubnub_setup = {
channel: "my_channel",
publish_key: "pub-c-key",
subscribe_key: "sub-c-key",
user: user
};
// Note removed the var
socket = io.connect( 'http://pubsub.pubnub.com', pubnub_setup);
// various socket.on() omitted
})();
Here is what how it was before with just socketIO & it was working:
var doConnect = function(isBroadcaster) {
socket = io.connect();
// various socket.on() omitted
}
My p2p video website is implemented with WebRTC running on a Nodejs + SocketIO server.
I have been trying to incorporate pubnub into it & thought it would be easy since pubnub supports SocketIO (or at least client side?). Really did not think it would be this difficult to set up server side.
Any input at all on this? I think it's something simple that I just cannot put my finger on
Socket.IO on the Server using Node.JS
Socket.IO with PubNub does not provide a Node.JS Socket.IO backend option. However you can use the PubNub SDK directly for on-connect events.
NPM Package
npm install pubnub
After you install the PubNub NPM you can use the node.js server backend:
Node.js Backend Code
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// PubNub!!! (how to initialize it for use on server)
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
var pubnub = require('pubnub').init({
publish_key : "pub-key",
subscribe_key : "sub-c-key",
uuid : "Server-ID"
});
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// On user Connect
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
function on_user_connect(data) {
console.log( "User Connected: ", data.uuid );
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// On user Leave
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
function on_user_leave(data) {
console.log( "User Left: ", data.uuid );
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// Open Socket Connection for User Join Events
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
pubnub.subscribe({
channel : 'my_channel',
connect : connected
message : function(message) {
console.log("Message received: ", message);
},
presence : function(data) {
if (data.action == "leave") on_user_leave(data);
if (data.action == "timeout") on_user_leave(data);
if (data.action == "join") on_user_connect(data);
}
});
function connected() {
console.log('connected!');
}
What version of socket.io are you using?
This might not fix it. I am using version 1.+ Have you tried:
io.on('connection', function(socket){
console.log('user connected');
});

Categories