Cannot use socket.io with redis on Heroku - heroku

I am trying to use socket io on Heroku with RedisToGo. In local environment, everything is fine.
When I deploy my code to the Heroku, most of the time I am getting 400 Bad Request with following data from the browser:
{"code":1,"message":"Session ID unknown"}
My redis config is:
var url = "redis://redistogo:xxx#lab.redistogo.com:xxxx/";
var rtg = require("url").parse(url);
var pub = redis.createClient(rtg.port, rtg.hostname, {return_buffers: true});
var sub = redis.createClient(rtg.port, rtg.hostname, {return_buffers: true});
pub.auth(rtg.auth.split(":")[1]);
sub.auth(rtg.auth.split(":")[1]);
var redisOptions = {
pubClient: pub,
subClient: sub,
host: rtg.hostname,
port: rtg.port
};
io.adapter(ioredis(redisOptions));
What is the problem?

The problem was Heroku accepting only websocket transport. Setting transports to websocket both in server and clients solved the problem.

Enabling session affinity on the Heroku app should fix the Session ID unknown error, you can do this by running
heroku features:enable http-session-affinity

Related

Connect two node.js servers with websockets (ws package) (https)

I'm trying to connect two node.js servers via websocket using the ws package. Here is some code:
Client server:
var socket = new WebSocket("wss://localhost:9000");
socket.addEventListener('open', function (event) {
console.log("websocket connected");
})
socket.addEventListener('message', function (event) {
console.log("message from backend server: ", event.data);
})
Backend server:
var https = require('https');
var httpsServer = https.createServer(credentials, app);
const WebSocket = require('ws');
const wss = new WebSocket.Server({ server:httpsServer });
wss.on('connection', function (ws) {
console.log("websocket connnected");
})
httpsServer.listen(9000, function () {
console.log(`server started on port 9000 via https`);
});
When I run this code, a get an error message on the command prompt that says "Error: certificate has expired". I am using a self-signed ssl certificate, which works perfectly fine for a websocket between a node.js server and the browser so I'm not convinced there's anything wrong with the certificate. I've seen examples of how to make this work using socket.io and socket.io-client, but how can I make it work using the ws package?
This is a problem with the ssl certificate. For some reason, going from browser to node.js server using a self-signed ssl certificate is fine, but going from node.js server to node.js using a self-signed ssl certificate is not.
I created a brand new ssl certificate and then in the client server, instead of:
var socket = new WebSocket("wss://localhost:9000");
.. I now have:
var socket = new WebSocket("wss://localhost:9000", {
rejectUnauthorized: false
});
..and it works.

Local Parse Server throwing 'unauthorised' despite correct keys

I'm setting up a local Parse Server: https://github.com/ParsePlatform/parse-server
I'm setting my keys as per the link above yet still getting 'Unauthorised'. Any ideas why this is?
Here's the snippet where I create the server var:
var express = require('express');
var ParseServer = require('parse-server').ParseServer;
var app = express();
var port = process.env.PORT || 1337;
// Specify the connection string for your mongodb database
// and the location to your Parse cloud code
var api = new ParseServer({
databaseURI: 'mongodb://localhost:27017',
cloud: '/Users/jack/Desktop/dev/node_modules/parse-server/lib/cloud/main.js', // Provide an absolute path
appId: 'jack1234',
masterKey: 'jack1234',
serverURL: 'http://localhost:' + port + '/parse'
});
// Serve the Parse API on the /parse URL prefix
app.use('/parse', api);
// Hello world
app.get('/', function(req, res) {
res.status(200).send('Express is running here.');
});
app.listen(port, function() {
console.log('parse-server-example running on port ' + port + '.');
});
Here's a screenshot of the Unauthorised:
You need to wirte the value in the header without '' (Apostrophe).
like:
X-Parse-Application-Id : jack1234
I think the issue might be from the headers you are sending to the ending. this is why you get the 403 code. I'm guessing the server does not recognize requests with these headers.
// Serve the Parse API on the /parse URL prefix
app.use('/parse', api);
On this line shown above you are injecting the arguments in which the express app needs to be authenticated with. So why not just make a request to it without the Headers ?

Connecting socket.io client to https

I'm trying to build a web chat application and want to connect my client to the socket.io server with https.
Seems like everything's fine, but the client is not connecting after all..
Server Code:
var app = require('express')();
var fs = require('fs');
var options = {
key: fs.readFileSync('server.key'),
cert: fs.readFileSync('server.crt')
};
var server = require('https').createServer(options, app).listen(3000,function(){
console.log("Https server started on port 3000");
});
var io = require('socket.io').listen(server);
app.get('/', function(req, res){
res.sendFile(__dirname + '/index.html');
});
io.on('connection', function(socket){
console.log("Client connected");
/*....*/
});
Client code to connect to server:
$(function($){
var socket = io.connect('https://localhost:3000', {secure: true});
.....
});
It kind of doesn't run the code inside of $(function($)..
When I make it a http server it works just fine..
Simply
var socket = io.connect('/', {secure: true});
EDIT: By default socket.io will try to establish a connection on the same host as webserver hosts web content, so no need to specifying host/protocol/port. The / states to connect to default namespace.
I solved the problem..
So for http it was enough if you begin your script on the client with
$(function(){
....
});
But it wouldn't work with https.
I changed it to
jQuery(function($){
....
})(jQuery);
Pretty odd but it worked for me.

Autobahn 0.9.5 (AMD) - Error during WebSocket handshake

I'm trying to implement autobahn 0.9.5 on my SPA project using DurandalJS.
var ab = require('autobahn');
live = new ab.Connection(
{
url: 'ws://localhost:8080',
realm: 'realm1'
});
live.onopen = function(session, details)
{
console.log('Autobahn open successfully!', session);
};
live.onclose = function(reason, details)
{
console.log('Autobahn connection lost', reason + ' - ' + details);
};
live.open();
i received an error on firefox and chrome browser
Firefox:
InvalidAccessError: A parameter or an operation is not supported by the underlying object
websocket.close(code, reason);
Chrome:
WebSocket connection to 'ws://localhost:8080/' failed: Error during WebSocket handshake: Sent non-empty 'Sec-WebSocket-Protocol' header but no response was received
I have no idea what happened..
BEFORE I STARTED WITH - autobahn 0.9.5
I have write simple test on test.html to see if everything setup in backend is correct.
But on this test i currently used autobahn 0.8.2
test.html
<script src="http://autobahn.s3.amazonaws.com/js/autobahn.min.js"></script>
<script>
var conn = new ab.Session(
// Websocket host
'ws://localhost:8080',
// Callback on connection established
function() {
// Once connect, subscribe to channel
conn.subscribe('3', function(topic, data) {
console.log(topic, data);
});
},
// Callback on connection close
function() {
console.warn('WebSocket connection closed');
},
// Additional AB parameters
{'skipSubprotocolCheck': true}
);
</script>
This test working perfectly as what i need, but after I try to implement it inside real project, I can't make autobahn 0.8.2 loaded using requireJS, It keep give me an error ab not defined.
I don't really understand what is happening, according of autobahn getting started, it should work.
and here is how I define it on main.js (requirejs paths and shim config)
requirejs.config({
paths: {
'autobahn' : 'https://autobahn.s3.amazonaws.com/autobahnjs/latest/autobahn.min',
'when' : 'https://cdnjs.cloudflare.com/ajax/libs/when/2.7.1/when'
},
shim: {
'autobahn': {
deps: ['when']
}
}
});
Hopefully somebody can help me, I really love to make it working !
Any help will be greatly appreciated!
Thanks
Probably late, but for further reference.
This is probably not a complete answer to SO question.
First of all, everything should be written either for AutobahnJS v0.8.2 (which supports WAMPv1) or for AutobahnJS v0.9.5 (WAMPv2).
Check API documentation.
WAMP v1
AutobahnJS v0.8.2 API - http://autobahn.ws/js/reference_wampv1.html
it loads from http://autobahn.s3.amazonaws.com/js/autobahn.js
global variable for autobahn is ab
connecting with var conn = new ab.Session(wuri, onOpenCallback, onCloseCallback, options);
WAMP v2
AutobahnJS v0.9.5 API - http://autobahn.ws/js/reference.html
it loads from https://autobahn.s3.amazonaws.com/autobahnjs/latest/autobahn.min.jgz
global variable for autobahn is autobahn
connecting with new autobahn.Connection({url: wuri, realm: yourRealm});

Socket.io connection url?

I have the current setup:
Nodejs Proxy (running http-reverse-proxy) running on port 80.
Rails server running on port 3000
Nodejs web server running on port 8888
So any request starting with /nodejs/ will be redirected to nodejs web server on 8888.
Anything else will be redirected to the rails server on port 3000.
Currently Socket.io requires a connection url for io.connect.
Note that /nodejs/socket.io/socket.io.js is valid and returns the required socket.io client js library.
However, I am not able to specify connection_url to /nodejs/ on my server.
I have tried http://myapp.com/nodejs and other variants but I am still getting a 404 error with the following url http://myapp/socket.io/1/?t=1331851089106
Is it possible to tell io.connect to prefix each connection url with /nodejs/ ?
As of Socket.io version 1, resource has been replaced by path. Use :
var socket = io('http://localhost', {path: '/nodejs/socket.io'});
See: http://blog.seafuj.com/migrating-to-socketio-1-0
you can specify resource like this:
var socket = io.connect('http://localhost', {resource: 'nodejs'});
by default resource = "socket.io"
If you are using express with nodejs:
Server side:
var io = require('socket.io')(server, {path: '/octagon/socket.io'});
then
io.on('connection', function(socket) {
console.log('a user connected, id ' + socket.id);
socket.on('disconnect', function() {
console.log('a user disconnected, id ' + socket.id);
})
})
socket.on('publish message ' + clientId, function(msg) {
console.log('got message')
})
Client side:
var socket = io('https://dev.octagon.com:8443', {path: '/octagon/socket.io'})
then
socket.emit('publish message ' + clientId, msg)
I use below approach to achieve this goal:
client side:
var socket = io.connect('http://localhost:8183/?clientId='+clientId,{"force new connection":true});
server side:
var io = require('socket.io').listen(server);
io.sockets.on('connection', function(socket) {
console.log("url"+socket.handshake.url);
clientId=socket.handshake.query.clientId;
console.log("connected clientId:"+clientId);
});
reference:https://github.com/LearnBoost/socket.io/wiki/Authorizing#global-authorization
If you are serving your app with express, then maybe you can check this out. Remember express uses http to serve your application.
const express = require('express'),
http = require('http'),
socketIo = require('socket.io'),
app = express()
var server = http.createServer(app);
var io = socketIo(server);
io.on('connection', (socket)=>{
// run your code here
})
server.listen(process.env.PORT, ()=> {
console.log('chat-app inintated succesfully')
})

Resources