General overview of the code:
I'm trying to merge Express and Socket.IO session management using Redis. Seems to work thus far, but I'm having trouble trapping errors using domains as seen in the test below.
Server code:
"use strict";
var domain = require("domain");
var redis = require("redis");
var express = require("express");
var app = express();
var server = require("http").createServer(app);
var socketio = require("socket.io");
var redisSio = require("socket.io-redis");
// Configure Express:
app.use(require("compression")());
app.use(require("body-parser").json());
var expressSession = require("express-session");
// Configure Socket.IO:
app.io = socketio(server, {
transports: ["websocket", "polling"],
// Same name as Express cookie:
cookie: "test.sid"
});
// Manage Socket.IO sessions using Redis:
app.io.adapter(redisSio({socket: "/tmp/redis.sock"}));
// Manage Express sessions using Redis:
app.use(expressSession({
// Same name as Socket.IO cookie:
name: "test.sid",
resave: false,
saveUninitialized: false,
secret: "secret",
store: redis.createClient("/tmp/redis.sock", {
return_buffers: true
})
}));
var d = domain.create();
d.on("error", function(err) { console.log("Error"); });
d.run(function() {
// Configure listener for Socket.IO connections:
app.io.on("connection", d.bind(function(socket) {
// Configure listener for specific event:
socket.on("channel", d.bind(function(data, callback) {
// "data" is general data incoming from client.
// "callback" is a client function meant for acknowledgments.
// Generate an error:
null.test();
}));
}));
});
// Start the server:
server.listen(8080);
Client code:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Test</title>
<script language="javascript" type="text/javascript" src="/socket.io/socket.io.js"></script>
<script type="text/javascript">
var sock = io.connect();
if(sock) {
sock.emit("channel", null, function(data) {
$("#tester").text(JSON.stringify(data));
});
}
if(sock) {
sock.disconnect();
sock = null;
}
</script>
</head>
<body>
<p id="tester"></p>
</body>
</html>
When receiving the event from the client (triggering the error), the following is printed to the console:
Missing error handler on `socket`.
TypeError: Cannot call method 'test' of null
at Socket.<anonymous> (/home/debian/test.js:46:12)
at Socket.b (domain.js:183:18)
at Socket.emit (events.js:98:17)
at Socket.onevent (/home/debian/node_modules/socket.io/lib/socket.js:330:8)
at Socket.onpacket (/home/debian/node_modules/socket.io/lib/socket.js:290:12)
at Client.ondecoded (/home/debian/node_modules/socket.io/lib/client.js:193:14)
at Decoder.Emitter.emit (/home/debian/node_modules/socket.io/node_modules/socket.io-parser/node_modules/component-emitter/index.js:134:20)
at Decoder.add (/home/debian/node_modules/socket.io/node_modules/socket.io-parser/index.js:247:12)
at Client.ondata (/home/debian/node_modules/socket.io/lib/client.js:175:18)
at Socket.emit (events.js:95:17)
Why isn't the domain catching the error? And why is it complaining about a missing error handler on socket?
Relevant package versions:
Node.js (v0.10.38) and also io.js (v2.5.0)
Express (4.13.3)
Socket.IO (1.3.6)
Related
I am writing server client application in node js.
Unfortunately Socket io connection is not being established.
My server side code is like this.
filename : MyServer.js
function MyServer(selectClient)
{
var express = require('express');
var bodyParser = require("body-parser");
this.app = express();
this.app.use(bodyParser.urlencoded({ extended: false }));
this.app.use(bodyParser.json());
var cookieParser = require('cookie-parser')
this.app.use(cookieParser())
if (undefined == selectClient)
{
selectClient = "default";
}
this.setStaticRoute("client/" + selectClient);
this.client = selectClient;
};
MyServer.prototype.setStaticRoute = function (staticPath)
{
var express = require('express');
var path = require('path');
this.app.use(express.static(staticPath));
};
MyServer.prototype.listen = function (portNumber)
{
this.server = this.app.listen(portNumber, '127.0.0.1', function ()
{
var MyServerSocketIo = require('MyServerSocketIo');
this.socketLink = new MyServerSocketIo(this.server,this.onDisconnect.bind(this),
this.onError.bind(this),this.onConnection.bind(this));
console.log("Inside listen function");
}.bind(this));
};
MyServer.prototype.onDisconnect = function()
{
console.log('On Socket IO Disconnect for MyServer');
};
MyServer.prototype.onError = function()
{
console.log('On Error');
};
MyServer.prototype.onConnection = function()
{
console.log('On Connection');
};
and MyServerSocketIo.js is like below
function MyServerSocketIo(server,onDisconnectCB,onErrorCB,onConnectionCB)
{
var SocketIo = require('socket.io');
this.onDisconnectCB = onDisconnectCB;
this.onErrorCB = onErrorCB;
this.onConnectionCB = onConnectionCB;
this.socket = null;
this.socketio = SocketIo(server);
this.socketio.on('connection',this.onConnection.bind(this));
};
MyServerSocketIo.prototype.onDisconnect = function ()
{
console.log('MyServer SocketIO Client Disconnected');
this.onDisconnectCB();
};
MyServerSocketIo.prototype.onError = function (error)
{
console.log('MyServer SocketIO Connection error' + error);
this.onErrorCB();
};
MyServerSocketIo.prototype.onConnection = function (socket)
{
console.log('MyServer SocketIO Connection with Client ID '+ socket.id + ' Established');
this.socket = socket;
socket.on('disconnect', this.onDisconnect.bind(this));
socket.on('error',this.onError.bind(this));
this.onConnectionCB();
};
Below is my client side code
filename: index.html
<!DOCTYPE html>
<html><head><meta charset="UTF-8">
<title>visual Display</title>
<link rel="preload" href="css/visual.css" as="style">
<link rel="stylesheet" href="css/visual.css">
<script type="text/javascript" src="/socket.io/socket.io.js"></script>
<script type="text/javascript" src="js/jquery-3.3.1.js"></script>
<script type="text/javascript" src="js/MyClientSocketIo.js"></script>
<script type="text/javascript" src="js/display.js"></script>
<script type="text/javascript" charset="utf-8">
display = new Display();
function OnDisconnect()
{
display.showError();
}
function OnError()
{
display.showError();
}
clientSocket = io.connect('http://localhost:39198', {
transports: ['websocket'],
'forceNew': true,
rejectUnauthorized: false,
reconnection: true,
reconnectionDelay: 1000,
reconnectionDelayMax : 1000,
reconnectionAttempts: 99999
});
var socketClient = new MyClientSocketIo(clientSocket,OnDisconnect,OnError);
</script>
</head>
<body>
</body>
</html>
MyClientSocketIo.js file code is like below
function MyClientSocketIo(client,onDisconnectCB,onErrorCB)
{
this.onDisconnectCB = onDisconnectCB;
this.onErrorCB = onErrorCB;
this.client = client;
this.client.on('connect',this.onConnection.bind(this));
};
MyClientSocketIo.prototype.onDisconnect = function ()
{
console.log('MyClient Disconnected');
this.onDisconnectCB();
};
MyClientSocketIo.prototype.onError = function (error)
{
console.log('MyClient ' + this.client.id + ' encountered Error ' + error);
this.onErrorCB();
};
MyClientSocketIo.prototype.onConnection = function ()
{
console.log('MyClient ' + this.client.id + ' connected to MyServer over SocketIO !!');
this.client.on('disconnect', this.onDisconnect.bind(this));
this.client.on('error',this.onError.bind(this));
};
I could able to see server and client are getting started and below console log "Inside listen function" getting printed as well which is MyServer.prototype.listen function.
But socketIO connection b/w server and client is not getting established.
I could not see console log lines which are there inside MyServerSocketIo.prototype.onConnection function.
I am waiting 30seconds for socketio connection. If not established restarting the server and client and after restarting also socketio connection is not getting established.
This is my personal script of working chat. I have done code with nodejs, axios and socket.
You can do with this script also.
Backend Server
require("dotenv").config();
const port = process.env.SOCKET_PORT || 3000;
const main_server_url = process.env.SERVER_URL;
var express = require("express");
var app = express();
var server = app.listen(port);
var connectionOptions = {
"force new connection": true,
"reconnection": true,
"reconnectionDelay": 2000, //starts with 2 secs delay, then 4, 6, 8, until 60 where it stays forever until it reconnects
"reconnectionDelayMax": 60000, //1 minute maximum delay between connections
"reconnectionAttempts": "Infinity", //to prevent dead clients, having the user to having to manually reconnect after a server restart.
"timeout": 10000, //before connect_error and connect_timeout are emitted.
"transports": ["websocket"] //forces the transport to be only websocket. Server needs to be setup as well/
}
var io = require("socket.io").listen(server, connectionOptions);
var axios = require("axios");
var users = [];
var connections = [];
console.log("Server connected done");
io.sockets.on("connection", function (socket) {
var server_url = main_server_url;
console.log(server_url);
console.log(people);
connections.push(socket);
console.log("Connected : total connections are " + connections.length);
// rest of events of socket
});
Front End JS for load IO for client
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.0/socket.io.js"></script>
<script type="text/javascript">
var base_url = YOUR_BASE_URL;
var port = YOUR_SOCKET_PORT;
var socket_port_url = base_url + ":" + port;
var socket = io(socket_port_url);
socket.on('done', (data) => {
console.log(data);
});
</script>
I have tried setting up a namespace on the backend,
const server = require("http").createServer(app);
const connectedUsers = {};
const io = require("socket.io")(server, {
path: "/socket",
serveClient: false,
// below are engine.IO options
pingInterval: 10000,
pingTimeout: 5000,
cookie: false
});
const singularConnection = io.of("/singular-socket");
singularConnection.on("connection", socket => {
console.log("unique user connected with socket ID " + socket);
}
And on my client, I try connecting with,
const socket = io(GATEWAY, {
path: "/socket/singular-socket",
transports: ["websocket"],
jsonp: false
});
socket.connect();
socket.on("connect", () => {
console.log("connected to socket server");
});
I've tried different variation of the URL, getting rid of /socket and moving other stuff around, but I can't seem to get it working. What am I doing wrong here?
I don't have any experience in using socket.io, but from the docs...
To connect to a namespace, the client code would look like.
const socket = io('http://localhost/admin', {
path: '/mypath'
});
Here, the socket connects to the admin namespace, with the custom path
mypath.
The request URLs will look like:
localhost/mypath/?EIO=3&transport=polling&sid= (the namespace is
sent as part of the payload).
Following the above lines, your code should look like..
const socket = io("http://localhost/singular-socket", {
path: "/socket",
transports: ["websocket"],
jsonp: false
})
Where /singular-socket is the namespace and /socket is the path.
Try this repl
I'm new to node.js and XMPP but not Javascript or GCM. I'm unable to receive upstream messages using node-xmpp and none of the callbacks are called, not even error. I've looked through the other SO threads but none of the solutions have worked. Here is my entire route:
var express = require('express');
var router = express.Router();
var xmpp = require('node-xmpp');
router.get('/', function(req, res, next) {
var options = {
type: 'client',
jid: 'project-12345#gcm.googleapis.com',
password: 'apiKey12345',
port: 5235,
host: 'gcm.googleapis.com',
legacySSL: true,
preferredSaslMechanism : 'PLAIN'
};
// this prints correctly
console.log('Creating xmpp app');
var cl = new xmpp.Client(options);
cl.connection.socket.setTimeout(0);
cl.connection.socket.setKeepAlive(true, 10000);
// None of these callbacks are called
cl.on('online', function() {
console.log('online');
});
cl.on('connection', function() {
console.log('online');
});
cl.on('authenticate', function(opts, cb) {
console.log('authenticated');
});
cl.on('error',function(e) {
console.error(e);
});
cl.on('stanza', function(stanza) {
console.log(stanza);
});
res.render('index', { title: 'GCM upstream test' });
});
module.exports = router;
Thanks
OP here: The issue was because the route was terminating the XMPP action upon reaching res.render. Upon removing the XMPP code from the route, I get an XMPP authentication failure, which is most likely due to an incorrect jid/password. The project requirements have changed and I no longer need upstream messaging, so I will not attempt to fix the auth failure.
Thanks for the responses
I am trying to create a chat application using node js and mongodb. I am looking on a tutorial for this. I couldn't solve a error that states socket is not defined while running my file server.js. The code in server Js is
var mongo = require('mongodb').MongoClient,
client = require('socket.io').listen(8080).sockets;
console.log(mongo);
mongo.connect('mongodb://#127.0.0.1/chat',function(err,db) {
if(err) throw err;
client.on('connection',function() {
//Wait for Input
socket.on('input',function(data) {
console.log(data);
});
});
});
The error is created when i wanted to listen socket on input.When i try to define socket as
socket =io.connect('http://127.0.0.1:8080'); It again gives error stating io not defined. Isn't io global on nodejs?
Please enlighten me on this.
Try as below if you are using express.
var express = require('express'),
, app = express()
, server = require('http').Server(app)
, mongo = require('mongodb').MongoClient,
, io = require('socket.io')(server);
server.listen(3000, function() {
console.log("Server Running on port 3000");
});
mongo.connect('mongodb://#127.0.0.1/chat',function(err,db) {
io.sockets.once('connection', function(socket) {
io.sockets.emit('new-data', {
channel: 'stdout',
value: "My Data"
});
});
});
In you view.html
<html>
<head>
<script src="https://cdn.socket.io/socket.io-1.0.6.js"></script>
var socket = io.connect('http://localhost');
var streamer = $('#streamer');
socket.on('new-data', function(data) {
streamer.val(data.value);
});
</head>
<body>
<div id="streamer"> </div>
</body>
</html>
I am learning Node.Js, I would like to understand how to interact between front-end / backend.
I would do backend --> Front End interaction by sendig data using app.get(), but now, I'd like to understand how can I get variable from Front End to Backend.
Front-ENd. (I want to pass varGetFromFrontend to backend)
<html>
<script>
var varGetFromFrontend = 2; // This is variable I want to pass to backend
</script>
<head>
<title>Home Page</title>
</head>
<body>
<h1> This is a test</h1>
</body>
</html>
On Node.Js (backend)
var express = require('express');
var app = new express();
app.use(express.json());
app.use(express.static(__dirname + '/public'));
var entries = [
{"id":1, "title":"Hello World!"},
{"id":2, "title":"Hello World!"}
{"id":3, "title":"Hello World!"}
{"id":4, "title":"Hello World!"}
];
if(entries.id == varGetFromFrontend){
console.log("This is to print a variable by choosing it from Front End")
console.log(varGetFromFrontend)
}
var port = Number(process.env.PORT || 5000);
app.listen(port);
I would like to know how can I print "varGetFromFrontend" on server side
Make an HTTP request to the server. Include the variable in the request.
There are lots of ways to do this:
Put it in a hidden input in a form, then submit the form.
or
Set location.href to a new value and include the variable in it (e.g. in a query string)
or
Use the XMLHttpRequest object to make an HTTP request
or
Create a script element and include the variable in the URL for the src attribute
(This is a non-exhaustive list)
You can interact with the nodejs server from the browser with socket.io
First, install socket.io:
npm install socket.io
and write these code to their respective filenames.
app.js:
var express = require("express");
var http = require("http");
var socketIO = require("socket.io");
var app = express();
app.get("/", function(req, res){
res.sendfile("./index.html");
});
var server = http.createServer(app);
var io = socketIO.listen(server, {log: false});
io.sockets.on("connection", function(socket){
socket.on("sendVar", function(value){
console.log("The value of the variable is " + value);
});
});
server.listen(5000);
index.html:
<html>
<head>
<title>Index Page</title>
</head>
<script type="text/javascript" src="/socket.io/socket.io.js"></script>
<script type="text/javascript">
var variableFromFrontEnd = 2;
var socket = io.connect("/");
socket.on("connect", function(){
console.log("connected!")
socket.emit("sendVar", variableFromFrontEnd);
});
</script>
</html>
and run it.
Check out the MEAN framework I built: http://mean.wolframcreative.com/
This uses Node as the back-end server utilizing Express as the API router. The front-end uses angular and is purely an api consumption tool.
Short answer is this:
in angular:
$http
.get('/api/users/bobsaget')
.success(function (response) {
console.log(response);
});
in node(with express):
app.get('/api/users/:username', function (req, res) {
var variable = req.params.username;
//do logic here with the database(mongo) to get user info:
db.users.findOne({username: username}, function (error, response) {
if (!error) {
res.send(200, response);
} else {
res.send(500, {success: false, message: error.message});
}
});
)};
Long answer is to play around with my framework and get your hands dirty.
I'm currently working on a restful framework for node call snooze. I'm writing an api along side it and it's going very well. The framework is written to be modular and easy to use. Everything is built around modules, routes, controllers, services, and validators.
https://github.com/iamchairs/snooze
snooze.module('myServer', ['snooze-stdlib']) // inject the snooze-stdlib module
.route('get', '/users/:username', { // define the route
controller: 'UserCtrl', // what controller should handle this route
action: 'getUserByUsername', // what action to perform on this route
validator: 'GetUsername' // before processing this action what validation should occur
})
.controller('UserCtrl', function(User) { // inject the User service
return {
getUserByUsername: function(res, options) {
User.getUserByUsername(options.query.username).then(function(username) {
res.send(200, username);
}).fail(function(err) {
res.send(500, err);
});
}
};
})
.service('User', function($q) { // inject the $q service
return {
getUserByUsername: function() {
var deferred = $q.defer();
deferred.resolve('iamchairs');
return deferred.promise;
}
};
})
.validator('GetUsername', function($validator) { // inject the validator service
return function(deferred, req) {
if($validator.isLength(req.query.username, 2, 32)) {
deferred.resolve(); // resolve (valid request)
} else {
deferred.reject([400, 'Username must be between 2 and 32 characters']); // reject (invalid request)
}
}
});