Node Server not working with SSL - node.js

I have a node server code on named server.js
var env = require('dotenv').config({path: '../.env'});
var fs = require("fs");
var options = {
key: fs.readFileSync(env.APP_SSL_PATH + 'server.key').toString(),
cert: fs.readFileSync(env.APP_SSL_PATH + 'server.crt').toString()
};
var app = require('express')();
var http = require('https');
var server = http.createServer(options, app);
var io = require('socket.io')(server);
var redis = require('redis');
// Check if server is listening on its port
server.listen(env.APP_NODE_PORT, function() {
console.log('Listening on your port');
io.on('connection', function (socket) {
console.log("new client connected");
var redisClient = redis.createClient();
redisClient.subscribe('notification-channel', function(err, count) {
});
redisClient.on("message", function(channel, message) {
console.log( " message= "+ message + " channel = " + channel);
socket.emit(channel, message);
});
socket.on('disconnect', function() {
redisClient.quit();
});
});
});
Using http it works fine but then when I add the SSL certificate on https the code is not working already and it doesn't throw any error. I run the node server.js by
node server.js > stdout.txt 2> stderr.txt
there are no error log showing on stderr.txt file. Please help me Im new on this. On the console
Listening on your port
will logged only it does not continue and log
new client connected
This is my client side code:
<script>
var socket = io.connect('{{ env("APP_URL") }}:8890');
socket.on('notification-channel', function (data) {
var header_count_elem = $('#menubar #header-messages-count');
var count = header_count_elem.text();
if (data != 'no-sound') {
$.get('/notification/notif-alerts', function(response) {
header_count_elem.text((response.count == '0') ? '' : response.count);
if (data != 'no-sound') {
if (count != response.count) {
var sound = '<audio id="audioplayer" autoplay=true volume=1>' +
'<source src="{{ url('assets/themes/cpanel/alarms/notification_sound.mp3') }}" type="audio/mpeg">' +
'<source src="{{ url('assets/themes/cpanel/alarms/notification_sound.ogg')}}" type="audio/ogg">' +
'</audio>';
$('body').append(sound);
}
}
});
}
});

Related

Node Socketio Websocket on Subdomain

Since weeks I am trying to implement my websocket functionality on my production (ubuntu) Server (nginx). My websockets work locally, but I Keep getting Errors on production.
My socket.js Looks like this:
var fs = require('fs');
var options = {
type: "local",
key: fs.readFileSync("/etc/nginx/ssl/sub.domain.com/467605/server.key"),
cert: fs.readFileSync("/etc/nginx/ssl/sub.domain.com/467605/server.crt")
};
if (options.type == 'dev') {
var app = require('http').createServer(handler);
} else {
var app = require('http').createServer(options,handler);
}
var io = require('socket.io')(app);
var Redis = require('ioredis');
var redis = new Redis();
function handler(req, res) {
res.writeHead(200);
res.end('');
}
io.on('connection', function(socket) {});
// Redis UserSignedUp Channel, Channel if user signs up
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 3333
app.listen(3333, function () {
console.log('Server running!');
});
My Event.js Looks like this:
const socket = io('sub.domain.com:3333', {
secure: true
});
// ... works locally
socket.on('signed-in-channel:App\\Events\\UserSignedIn', (data) => {
this.signedInUsers = data.username;
this.$toasted.info('Success: ' + data.username, {
theme: "primary",
duration: 10000
});
});
If I do this in my Event.js:
const socket = io('sub.domain.com:3333', { secure: true });
I get this error:
https://sub.domain.com:3000/socket.io/?EIO=3&transport=polling&t=MdZoLnn
net::ERR_SSL_PROTOCOL_ERROR
Where as if I watch for the Server ip like this:
const socket = io('123.123.123.123:3333', { secure: true });
I get this error:
https://123.123.123.123:3333/socket.io/?EIO=3&transport=polling&t=MdZpRnE
net::ERR_CONNECTION_TIMED_OUT
The site has an let's encrypt ssl certificate, further the webserver is nginx and the os is ubuntu. On my local window (wamp) it works starting it with node socket.js.

How do I get the IDs of connected peers?

I managed to get the number of peers connected in my console log by having the console print out "You are peer number n" for each new connected peer.
Is there a way of adding the id of each connected peer too?
I'm relatively new with socket.io and I can't seem to find a way to do this.
This is my server.js file:
var app = require("express")();
var express = require("express");
var server = require("http").Server(app);
var p2pserver = require("socket.io-p2p-server").Server;
var io = require("socket.io")(server);
var ss = require("socket.io-stream");
var path = require("path");
app.use(express.static(__dirname));
io.use(p2pserver);
var peerNum = 0;
io.on("connection", function(socket) {
console.log("Peer " + peerNum + " connected");
io.emit("peer-num", peerNum);
peerNum++;
ss(socket).on("file", function(stream, data) {
var filename = path.basename(data.name);
var parts = [];
stream.on("data", function(data) {
parts.push(data);
});
stream.on("end", function() {
socket.broadcast.emit("file", parts);
});
});
});
server.listen(8080, function () {
console.log("Listening on 8080")
});
This is my client.js file:
// Browserified
var P2P = require("socket.io-p2p");
var io = require("socket.io-client");
var ss = require("socket.io-stream");
var socket = io();
var opts = {autoUpgrade: true, peerOpts: {numClients: 10}};
var p2p = new P2P(socket, opts);
var $ = require("jquery");
p2p.on("peer-num", function(num) {
console.log("You are peer number " + num);
$(".peerNum").html( "Number " + num );
});
p2p.on("file", function(stream) {
console.log(stream);
var img = document.createElement("img");
img.src = (window.URL || window.webkitURL).createObjectURL(new Blob(stream));
document.getElementById("receivedImages").appendChild(img);
});
$(function() {
$("#file").change(function(e) {
ss.forceBase64 = true;
var file = e.target.files[0];
var stream = ss.createStream();
ss(socket).emit("file", stream, {size: file.size,name:file.name});
var blobStream = ss.createBlobReadStream(file);
var size = 0;
blobStream.on("data", function(chunk) {
size += chunk.length;
console.log(Math.floor(size / file.size * 100) + "%");
});
blobStream.pipe(stream);
});
});
If what you mean by id is the internal id that socket.io assigns to a connection (on the server), then you can access that with socket.id. So, if you want to just use socket.id instead of your peerNum, variable, then you would change this:
io.emit("peer-num", peerNum);
to this:
io.emit("peer-num", socket.id);
The socket.id value is used only on the server. It is not meant to be a human readable moniker (it contains randomly generated characters), but it can be used to reference any given connection. Since its a string, it can be easily sent to other clients who can then use it when sending messages back to the server to reference particular client connections.

How to run socketio server properly on multiple cores using cluster module of NodeJS?

Socket IO server is running fine on single instance of NodeJs. But when I'm using cluster module of NodeJS to run the servers on multiple cores I'm getting the error, "Connection closed before receiving a handshake response". I've googled the reason and found out that,
Essence of the problem is, when you run multiple Node app threads (workers) on a server, or multiple servers, socket.io clients connections are routed by cluster in a random round-robin manner, and handshaken / authorized io client requests get handed to workers where they are not handshaken / authorized, where the mess begins. Source Link
I've tried a couple of things to make it work but no success so far. Here's the code
'use strict';
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
var express = require('express');
var config = require('./config/environment');
var session = require('express-session');
var redisStore = require('connect-redis')(session);
var cluster = require('cluster');
var domain = require('domain');
var socketIo = require('./config/socketio');
var REDIS = require('redis')
var store = REDIS.createClient();
var pub = REDIS.createClient();
var sub = REDIS.createClient();
if(cluster.isMaster) {
var numWorkers = require('os').cpus().length;
for(var i = 0; i < numWorkers; i++) {
cluster.fork();
}
} else {
var d = domain.create ();
d.on ("error", function (error){
// start new server
});
// Setup server
var app = express();
var server = require('http');
d.run (function (){
server = server.createServer(app);
});
require('./config/express')(app);
require('./config/redis')();
require('./routes')(app);
server.listen(config.port, config.ip, function () {
console.log('Express server listening on %d, in %s mode', config.port, app.get('env'));
});
var redis = require('socket.io-redis');
var socketIO = require('socket.io')(server, {
serveClient: (config.env === 'production') ? false : true,
path: '/socket.io-client'
});
sub.subscribe('chat');
socketIO.adapter(redis( {host: 'localhost', port: 6379}));
socketIo.createSocketConnection('/dummy', socketIO, sub, pub, store);
exports = module.exports = app;
}
File: ./config/socketio
'use strict';
function addNamespaceForId (socketio, namespace, sub, pub, store){
socketio.of(namespace).on('connection', function(socket) {
onConnect(socketio, socket, namespace, sub, pub, store);
console.info('[%s] CONNECTED', socket.address);
sub.on('message', function(pattern, key){
store.hgetall(key, function(e, obj){
socket.send(obj.uid + ": " + obj.text)
})
})
socket.on('disconnect', function() {
console.info('[%s] DISCONNECTED', socket.address);
});
});
}
}
function onConnect(io, socket, namespace, sub, pub, store) {
socket.on('message', function(from, msg) {
store.incr("messageNextId", function(e, id){
store.hmset("messages:" + id, { uid: socket.sessionId, text: 'text;' }, function(e, r){
pub.publish("chat", "messages:" + id)
})
})
io.emit('broadcast', {
payload : from['message'],
source : from
});
io.of(namespace).emit('broadcast', {
payload : from['message'],
source : from
});
});
// When the client emits 'info', this listens and executes
socket.on('info', function(data) {
console.info('[%s] %s', socket.address, JSON.stringify(data, null, 2));
});
// Insert sockets below
require('../api/thing/thing.socket').register(socket);
}
module.exports = {
createSocketConnection : function (namespace, socketio, sub, pub, store){
addNamespaceForId(socketio, namespace, sub, pub, store);
}
};
I've also tried using adapter for redis as suggested in the documentation.
This setup works sometimes but not always. I'm unable to figure out the missing point.

How to set RedisStore -- Node, Express, Socket.io, Heroku

I'm using Node & Express 4.0 deployed on Heroku, and I'm trying to implement Socket.io with Redis as aa session store. So I have this as my current code:
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);
var RedisStore = io.RedisStore;
if (process.env.REDISTOGO_URL) {
// inside if statement
var rtg = require("url").parse(process.env.REDISTOGO_URL);
var redis = require("redis").createClient(rtg.port, rtg.hostname);
redis.auth(rtg.auth.split(":")[1]);
} else {
var redis = require("redis").createClient();
}
/** Initialize RedisStore for socket.io **/
io.set('store', new RedisStore({
redis : redis
}));
But I get the following error:
14:25:03 web.1 | io.set('store', new RedisStore({
14:25:03 web.1 | ^
14:25:03 web.1 | TypeError: undefined is not a function
I've also seen this way of defining a RedisStore:
var redis = require('socket.io/node_modules/redis');
var RedisStore = require('socket.io/lib/stores/redis');
However, my installed version of socket.io, installed using npm install --save socket.io, doesn't include stores in the lib directory:
EDIT
I saw this on the socket.io page in regards to their 1.0 release:
// 2. Implement the socket.io-redis adapter
var io = require('socket.io')(3000);
var redis = require('socket.io-redis');
io.adapter(redis({ host: 'localhost', port: 6379 }));
But there's no other documentation I could find regarding this new module, and since I'm new to this whole stack, I don't think I could figure it out on my own.
The trend among node.js modules is to remove functionality that isn't truly core to the module.
Which is why socket.io 1.0 no longer supports redis out of the box.
So step one is to track down the functionality you need.
http://socket.io/docs/server-api/
https://github.com/Automattic/socket.io-adapter
https://github.com/Automattic/socket.io-redis
Then you need to install the other module npm install socket.io-redis --save
And finally configure your app.
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);
var redis = require('socket.io-redis');
io.adapter(redis(process.env.REDISTOGO_URL));
The nice part is the socket.io-redis adapter accepts redis urls and defaults to localhost:6379 so you (should) be able to simple pass in the REDISTOGO_URL
I had to parse libraries above to get this example, so I figured I would post a full blown example, but I must admit there are a couple of things off, this uses REDISCLOUD, it is on Heroku, it does work. I'll post this elsewhere and maybe put it in a doc too.
var redis = require('redis');
var ioredis = require('socket.io-redis'); //Adapter
var url = require('url');
var redisURL = url.parse(process.env.REDISCLOUD_URL );
var pub = redis.createClient(redisURL.port, redisURL.hostname, {return_buffers: true});
var sub = redis.createClient(redisURL.port, redisURL.hostname, {return_buffers: true});
pub.auth(redisURL.auth.split(":")[1]);
sub.auth(redisURL.auth.split(":")[1]);
var redisOptions = {
pubClient: pub,
subClient: sub,
host: redisURL.hostname,
port: redisURL.port
};
io.adapter(ioredis(redisOptions));
Following code works for me with Heroku Redis, hope this helps.
var app = express();
var server = require('http').Server(app);
var io = require('socket.io')(server);
var redis = require('redis');
var redisAdapter = require('socket.io-redis');
io.adapter(redisAdapter({
pubClient: redis.createClient(process.env.REDIS_URL, {return_buffers: true}),
subClient: redis.createClient(process.env.REDIS_URL, {return_buffers: true})
}));
For the ones interested,
this is my prototype chat server running on newest socket.io with express, multiple cores and redis as an intermediate.
Broadcasted messages are send to all room users no matter if they are connected to a different node and port instance.
Just run
node server.js
and on other machines
node client.js
or for testing node client.js 7001, 7002, 7003 ......
server.js
var options = {
//workers: 2, // total workers (default: cpu cores count).
first_port: 7000, // 8000, 8001 are worker's ports (default: 8000).
proxy_port: 5000, // default (5000).
session_hash: function (req, res) { return req.connection.remoteAddress; },
no_sockets: false // allow socket.io proxy (default: false).
};
require('sticky-socket-cluster')(options, start);
function start(port) {
// requirements
var express = require('express');
var http = require('http');
var socketio = require('socket.io');
var path = require('path');
var sticky = require('sticky-session');
var app = express();
var server = http.createServer(app);
var io = socketio.listen(server);
var redis = require('socket.io-redis');
io.adapter(redis({ host: 'localhost', port: 6379 }));
server.listen(port, function() {
console.log(' - listening on ' + port+ ' ' + __dirname);
});
// require our chatserver
var ChatServer = require('./chatserver');
// initialize a new chat server.
new ChatServer({io: io, port: port}).init();
}
chatserver.js
RoomUtil = (function(){
roomMessages = {};
return {
getMessages : function(room_id,limit,cb){
//TODO
cb(roomMessages[room_id] || []);
},
postMessage : function(message,room_id,cb){
if (!roomMessages[room_id]) roomMessages[room_id] = [];
roomMessages[room_id].push(message);
cb();
}
}
})();
var Server = function(options) {
var self = this;
self.io = options.io;
// users array
self.users = [];
// initialize function
self.init = function() {
console.log("init");
// Fired upon a connection
self.io.on('connection', function(socket) {
console.log("incoming connection");
// var ru = new RoomUser();
self.handleConnection(socket,options.port);
});
}
// socket handler for an incoming socket
self.handleConnection = function(socket,port) {
// wait for a login message
socket.emit("incoming connection",{});
socket.on("joinroom",function(data,joinroom_callback){
console.log("attempt to join room ",data.room_id," on port ",port);
if (!data.room_id){
console.log("cannon join room -> no room id given");
return socket.disconnect();
}
else{
var room_id = data.room_id;
socket.join(room_id,function(){
console.log(socket.rooms);
RoomUtil.getMessages(data.room_id,50,function(messages){
console.log("client succesfully joined room ",data.room_id);
joinroom_callback(null,{'messages':messages});
});
socket.on("login",function(data,login_callback){
if (!data.username){
login_callback("invalid userdata",null);
}
else{
login_callback(null,1);
socket.on("post_message",function(data,message_callback){
if (!data.message || data.message == ""){
console.log("empty message posted. ignore");
message_callback("invalid_message",null);
}
else{
console.log("received message on port ",port,data.message);
message_callback(null,1);
RoomUtil.postMessage(data.message,room_id,function(){
RoomUtil.getMessages(room_id,50,function(messages){
console.log("emit messages to room id ",room_id);
//socket.to(room_id).emit('update_messages', messages);
//socket.broadcast.to(room_id).emit('update_messages', messages);
//socket.broadcast.to(room_id).emit('update_messages', messages);
//self.io.to(room_id).emit('update_messages', messages);
self.io.in(room_id).emit('update_messages', messages);
});
})
}
});
}
});
});
}
});
}
}
module.exports = Server;
client.js
var servercon = 'http://localhost:'+(process.argv[2] || 5000);
console.log("going to connect to "+servercon)
var socket = require('socket.io-client')(servercon);
var readline = require('readline');
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
socket.on('connect', function(){
console.log("connected, going to login");
socket.emit("joinroom",{"room_id":123123}, function(error,data){
if (error){
console.log("cannot join room ",error);
}
else{
console.log("succesfully joined room -> going to login now");
console.log("received messages count",data.messages.length);
socket.emit("login",{username:"John Mckain"}, function(error, message){
if (error){
console.log("error logging in ",error);
}
else{
console.log("logged in succesfully -> post message now");
var readline = function(){
rl.question("type in a message -> ", function(message) {
socket.emit("post_message",{'message':message}, function(error, message){
if (error){
console.log("error posting message");
readline();
}
else{
console.log("succesfully posted message");
readline();
}
});
});
}
readline();
}
});
socket.on("update_messages",function(data){
console.log("received new messages count ",data.length,data);
});
}
});
});
socket.on('event', function(data){
console.log("event send",data);
});
socket.on('disconnect', function(e){
console.log("disconnected",e);
});
socket.on("welcome",function(data){
console.log("on welcome ",data)
})
socket.on("pong",function(e){
console.log("pong")
})

Why does the Socket Server stops working?

I am creating a WebSocket for an online game. I have some code that works perfectly, but after a time the server stops the Socket. I don't know what can be wrong and I don't have an error or something. It just stops running.
Does anyone know what can be wrong with this code?
var mysql = require('mysql');
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var cookies;
var db = mysql.createConnection({
host: 'hostname',
user: 'username',
password: 'password',
database: 'database',
port: 3306
});
db.connect(function(err){
if (err) console.log(err)
});
function createCookie(name,value,days, socket) {
if (days) {
var date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
}
else var expires = "";
socket.handshake.headers['cookie'] = name+"="+value+expires+"; path=/";
}
function readCookie(name, socket) {
var nameEQ = name + "=";
var ca = socket.handshake.headers['cookie'].split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
}
function eraseCookie(name, socket) {
createCookie(name,"",-1, socket);
}
io.on('connection', function(socket){
console.log('a user connected');
socket.on('disconnect', function(){
console.log('user disconnected');
});
socket.on('chat message', function(msg){
if(readCookie('uid', socket) != null) {
db.query('SELECT * FROM ww_user_settings WHERE usr_set_id = '+readCookie('uid', socket)+' AND usr_set_setting_id = 23').on('result', function(data){console.log('Message from '+data.usr_set_value+': '+msg);io.emit('chat message', data.usr_set_value+": "+msg);});
}
else {
console.log('Unauthorized message sent.');
socket.disconnect('unauthorized');
}
});
});
http.listen(44444, function(){
console.log('listening on *:44444');
});
As I said, the Socket works. But after a time, even when nothing special happens, the Socket stops running on my Windows 2012 Server.
The problem here was that the server lost the connection with the MySQL Server. By losing it, it will stop working.

Resources