Socketio on https using redis - node.js

I have a webapplication on a bitnami lamp stack, the os is ubuntu and it uses Apache as a webserver.
The SSL Certificate is generated using Let's Encrypt. I can visit the site on http and https.
Furthermore I am using following stacks:
- nodejs
- socket.io
- redis
Sending notifications on my local machine work fine, the websocket works.
But on my production Server which runs on https it does not work. I Keep getting following error messages:
socket.io.js:2 GET https://mypage.com:3000/socket.io/?EIO=3&transport=polling&t=MNxGNEt
net::ERR_CONNECTION_TIMED_OUT
This is how my socket.js (Server) Looks like:
var app = require('http').createServer(handler);
var fs = require('fs');
var io = require('socket.io')(app);
var Redis = require('ioredis');
var redis = new Redis();
// class declaration
var Redis = require('ioredis');
function handler(req, res) {
res.writeHead(200);
res.end('');
}
io.on('connection', function(socket) {});
var redisUserSignedUp = new Redis();
redisUserSignedUp.subscribe('signed-up-channel');
redisUserSignedUp.on('message', function(channel, message) {
message = JSON.parse(message);
io.emit(channel + ':' + message.event, message.data);
});
// run server on port 3000
app.listen(3000, function () {
console.log('Server runs!');
});
In my production I currently am trying it like this:
var app = require('https').createServer({
key: fs.readFileSync('/opt/bitnami/apache2/conf/serverKey.pem'),
cert: fs.readFileSync('/opt/bitnami/apache2/conf/serverCrt.pem')
}, handler);
var fs = require('fs');
var io = require('socket.io')(app);
var Redis = require('ioredis');
var redis = new Redis();
// class declaration
var Redis = require('ioredis');
function handler(req, res) {
res.writeHead(200);
res.end('');
}
io.on('connection', function(socket) {});
var redisUserSignedUp = new Redis();
redisUserSignedUp.subscribe('signed-up-channel');
redisUserSignedUp.on('message', function(channel, message) {
message = JSON.parse(message);
io.emit(channel + ':' + message.event, message.data);
});
// run server on port 3000
app.listen(3000, function () {
console.log('Server runs!');
});
And I am trying to Access it like this:
var options = {
key: fs.readFileSync('/opt/bitnami/apache2/conf/serverKey.pem'),
cert: fs.readFileSync('/opt/bitnami/apache2/conf/serverCrt.pem'),
requestCert: true
}
var app = require('https').createServer(options, handler);
local:
const socket = io('http://myapp.test:3000'); // localhost dev Folder is mapped to this .test url
socket.on('signed-in-channel:App\\Events\\UserSignedIn', (data) => {
…
production:
var socket = io('mypage.com:3000', {secure: true});

You only create a http server but to connect with ssl you need a https server.
var options = {
key: fs.readFileSync('./file.pem'),
cert: fs.readFileSync('./file.crt')
};
var app = require('https').createServer(handler);

Related

Express + MQTT from POST request to publish in topic

I need a Node.js web service that accept a specific POST request that will trigger a publishing in a specific MQTT topic.
I use Express to listen for the request and this part of the script works fine.
The problem is when I it should trigger the publish in topic to perform a downlink.
The code without the Express part works fine. So It seems like Express interfere with MQTT. But the connection to the Broker works fine. Only the publish procedure doesn't work.
var express = require('express');
var bodyParser = require('body-parser');
var mqtt = require('mqtt')
var fs = require('fs')
var path = require('path')
const util = require('util')
var app = express();
var CERT = //certificate
var PORT = //port
var HOST = // host
var options = {
port: PORT,
host: HOST,
clientId: //client_id
username: //uname
password: //pswd
cert: CERT,
rejectUnauthorized: false,
protocol: 'mqtts'
}
var client;
var jsonParser = bodyParser.json();
var port = process.env.PORT || 8080;
app.use(express.static('public'));
app.get('/', function (req, res) {
res.render(__dirname + "/public/index.html");
})
client = mqtt.connect(options);
client.on("connect", () => {
console.log("MQTT connected");
})
client.on('message', function (topic, message) {
var msg = JSON.parse(message)
console.log("topic: " + topic + " msg:" + util.inspect(msg))
});
app.post('/', jsonParser, function (req, res) {
// Prepare output in JSON format
data = {
dev_id: req.body.dev_id,
pswd: req.body.password,
tx_cycle: req.body.tx_cycle
};
if (data.pswd != "password") {
console.log("Wrong password")
}
else {
console.log(data);
var topic = 'publish_topic';
var tx_cy = data.tx_cycle;
var msg = '{"port":"222","payload":"' + tx_cy + '","confirmed": false,"window":"BOTH","priority":0}';
console.log('Try to send downlink message, for ' + data.dev_id + ' set to ' + data.tx_cycle + ' min -> hex ' + tx_cy);
client.subscribe('reply/+/id/+');
client.publish(topic, msg);
res.status(200).send(msg + " sent to broker");
}
});
var server = app.listen(port, function () {
var host = server.address().address
var port = server.address().port
console.log("App listening at http://%s:%s", host, port)
})
I solve the problem. The client id was refused by the broker because was not unique. Changing it solved the issue.

How to send message to frontend in case of MongoDb connection Failed

Is there any way to send error to frontend on mongoDb connection error.I had tried in a different different way but I didnt get a solution.
var express = require('express');
var session = require('express-session');
var MongoDBStore = require('connect-mongodb-session')(session);
var store = new MongoDBStore(
{
uri: config.connectionString,
collection: 'tbl_session'
});
// Catch errors
store.on('error', function(error) {
app.get('/',function(req,res){
res.send('NOT Connected....')
});
});
You can use web sockets to push this information to the UI.
const express = require('express');
const app = express();
const path = require('path');
const server = require('http').createServer(app);
const io = require('../..')(server);
const port = process.env.PORT || 3000;
var session = require('express-session');
var MongoDBStore = require('connect-mongodb-session')(session);
var store = new MongoDBStore(
{
uri: config.connectionString,
collection: 'tbl_session'
});
// Catch errors
store.on('error', function(error) {
socket.emit('mongodb-failed', error)
});
});
server.listen(port, () => {
console.log('Server listening at port %d', port);
});
// Routing
app.use(express.static(path.join(__dirname, 'public')));
io.on('connection', (socket) => {
// when socket emits 'mongodb-connection-failed', this listens and executes
socket.on('mongodb-failed', (data) => {
// we tell the client to execute 'new message'
socket.broadcast.emit('mongodb-connection-failed', {
errorDetails: data
});
});
});
now at client side:
var socket = io();
socket.on('mongodb-connection-failed', () => {
console.log('you have been disconnected');
//do more whatever you want to.
});
This above example is using socket.io.
You can use any web socket library, see more here

Node Http Proxy Web Socket Balance

I need to able to balance websocket on application level. Lets say forward websocket request on the basis of message I received, decode it on proxy and then using that data send to another socket server using some logic.
But I am unable to do this. This is the initial code I wrote and trying to do that. This is the server
var http = require('http');
var httpProxy = require('http-proxy');
var WebSocket = require('ws');
var WebSocketServer = require('ws').Server;
var wss = new WebSocketServer({ port: 8080 });
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(message) {
console.log('received: %s', message);
});
ws.send('something');
});
var proxy = httpProxy.createServer({target: 'ws://localhost:8080', ws:true});
var server = httpProxy.createServer(function(req, res) {
//SOME LOGIC HERE TO PARSE WS DATA AND SEND TO WS SERVER
proxy.ws(req, res, { target: 'ws://localhost:8080'});
}).listen(8014);
CLIENT
var http = require('http');
var httpProxy = require('http-proxy');
var WebSocket = require('ws');
var ws = new WebSocket('ws://localhost:8014/');
ws.on('open', function () {
ws.send("CLIENT");
});
ws.on('message', function (msg) {
console.log(msg);
});
Here's an example. In this case the client connects directly to outer.js which then forwards connections to upstream servers (inner.js).
outer.js
var http = require('http');
var httpProxy = require('http-proxy');
var proxies = {
foo: new httpProxy.createProxyServer({
target: {
host: "foo.com",
port: 8080
}
}),
bar: new httpProxy.createProxyServer({
target: {
host: "bar.com",
port: 8080
}
})
// extend this...
};
var findUpstream = function(req){
// TODO return key for lookup in #proxies
};
var proxyServer = http.createServer(function (req, res){
var upstream = findUpstream(req);
proxies[upstream].web(req, res);
});
proxyServer.on('upgrade', function (req, socket, head) {
var upstream = findUpstream(req);
proxies[upstream].ws(req, socket, head);
});
proxyServer.listen(8014);
inner.js
var WebSocketServer = require('ws').Server;
var wss = new WebSocketServer({ port: 8080 });
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(message) {
console.log('received: %s', message);
});
ws.send('something');
});
In this example you'll need to fill in the findUpstream to return the key such as foo or bar based on data in the request. It'd also be worth putting some error handling in for when the proper upstream server isn't found, but this should illustrate the general idea.

Difficulty setting up Letsencrypt SSL for node.js socket.io application. What am I doing wrong?

I have a node.js application running on a Ubuntu 14.04 server, I also depend on apache because my application uses MySQL on the backend. I have apache running on port 8080 and the node app listening on port 80. (Just some preliminary information) So I got a ssl cert from letsencrpyt but It doesn't seem to be working with socket.io.
Here is my code
app.js
var favicon = require('serve-favicon');
var crypto = require("crypto");
var mysql = require('mysql');
var http = require('http');
var fs = require('fs');
var _favicon = favicon(__dirname + '/favicon.ico');
var connection = mysql.createConnection({
host: 'localhost',
user: 'root',
port: '3306',
password: 'password',
database : 'database'
});
connection.connect(function(err){
if(!err) {
console.log("mysql connected");
} else {
console.log(err);
}
});
var https = require('https');
var options = {
key: fs.readFileSync('../privkey.pem'),
cert: fs.readFileSync('../cert.pem')
};
var server = https.createServer(options,
function(req, response){
fs.readFile(__dirname + '/index.html',
function(err, data){
if(err){
response.writeHead(500);
return response.end('error');
} else {
_favicon(req, response, function onNext(err){
if(err){
response.writeHead(200);
response.end(data);
} else {
response.writeHead(200);
response.end(data);
}
});
}
})
});
var io = require('socket.io').listen(server);
server.listen(80, "0.0.0.0");
and then on the client side I do this
<script src="https://cdn.socket.io/socket.io-1.4.5.js"></script>
var socket = io.connect('https://localhost', {secure: true, port: 80});
this is probably all wrong and also how do I make it so that if people type my domain "oncampus.ws" they get redirected to the https location "https://www.oncampus.ws" ?

Nodejs websocket communication with external system

I'm new to nodejs and I'm trying to solve communication issue with external system.
There is a gateway to external system which can handle websocket requests on port 5000. In the example below, when you request homepage, the nodejs opens websocket connection, then on websocket open event it sends request and waits for response which is used for the HTTP response.
Do you know how to open websocket to external system only once and handle requests based on request id?
var ws = require('ws');
var express = require('express');
var async = require('async');
var uuid = require('node-uuid');
app = express();
app.get('/', function (req, res) {
var webSocket = new ws('ws://localhost:5000/');
async.series([
function (callback) {
webSocket.on('open', function () {
webSocket.send(JSON.stringify({query:'data query', requestid: uuid.v4()}));
callback(null, 'data query');
});
},
function (callback) {
webSocket.on('message', function (data, flags) {
callback(null, data);
})
}
], function (err, results) {
res.setHeader('content-type', 'text/javascript');
res.send(results[1]);
webSocket.terminate();
});
});
var server = app.listen(3000, function () {
var port = server.address().port
console.log('Listening at %s', port)
});
Thanks for the hints. I ended with the following solution which does what I expect:
var ws = require('ws');
var express = require('express');
var uuid = require('node-uuid');
var requests = {};
app = express();
var webSocket = new ws('ws://localhost:5000/');
webSocket.on('open', function () {
console.log('Connected!');
});
webSocket.on('message', function (data, flags) {
var json = JSON.parse(data);
console.log(json.requestId);
var res = requests[json.requestId];
res.setHeader('content-type', 'text/javascript');
res.send(json.data);
delete requests[json.requestId];
});
app.get('/', function (req, res) {
var rid = uuid.v4();
requests[rid] = res;
webSocket.send(JSON.stringify({query:'data query', requestId: rid}));
});
var server = app.listen(3000, function () {
var port = server.address().port
console.log('Listening at %s', port)
});

Resources