Can't get socket.io and nodejs running with OpenShift - javascript

I can't get socket.io running on OpenShift. I googled for some hours now but nothing really helped me. Locally it works fine (with different ports and localhost as host of course).
This is my server.js file:
var port = process.env.OPENSHIFT_NODEJS_PORT || 8080;
var ipadr = process.env.OPENSHIFT_NODEJS_IP || "127.0.0.1";
var http = require('http').createServer(function(request, response) {
response.writeHead(200, {"Content-Type": "text/plain"});
response.end();
}).listen(port,ipadr);
console.log(port+":"+ipadr);
var io = require('socket.io').listen(http),
fs = require('fs'),
request = require('request'),
mysql = require('mysql'),
moment = require('moment'),
connectionsArray = [],
connection = mysql.createConnection({
host: 'xxx',
user: 'xxx',
password: 'xxx',
database: 'xxx',
port: 3306
}),
POLLING_INTERVAL = 1000,
pollingTimer;
io.on('connection', function(socket){
console.log('a user connected');
});
var updateSockets = function(data) {
// adding the time of the last update
t = new Date();
t = moment().format('H:mm:ss');
console.log('(%s) Connections: %s', t, connectionsArray.length);
// sending new data to all the sockets connected
connectionsArray.forEach(function(tmpSocket) {
tmpSocket.volatile.emit('notification', data);
});
};
console.log('server.js executed\n');
When I run this on SSH OpenShift it just shows the first console.log with my port and ipadress of OpenShift and the last line of my server.js code:
server.js executed
and that's it. So I don't get the "a user connected" message like when I test it locally.
This is how I want to connect in my client-side .js-file:
var socket = io.connect('http://njs-uniqo.rhcloud.com:8080/');
Browser (Chrome) Console outputs:
> ?s=product&id=10:1 XMLHttpRequest cannot load http://xxx.rhcloud.com:8000/socket.io/?EIO=3&transport=polling&t=1430395459829-1.
> No 'Access-Control-Allow-Origin' header is present on the requested
> resource. Origin 'http://localhost' is therefore not allowed access.
> The response had HTTP status code 503.
If I change the port to 8080 on the client-side .js-file I get ERR_CONNECTION_TIMED_OUT:
GET http://xxx.rhcloud.com:8080/socket.io/?EIO=3&transport=polling&t=1430395346761-6 net::ERR_CONNECTION_TIMED_OUT

You need to use port 8000. It's what openshift forces for websockets.
var socket = io.connect('http://yourapp.rhcloud.com:8000/',{'forceNew':true });
Port 8000 is for http and 8443 is for https
Source

You must edit package.json. Add...
"socket.io": "~0.9.16"
...under dependencies. The server then automatically downloads socket.io which is not present by default.

Related

Using a single port for bittorrent-tracker server in Heroku

I am trying to build/deploy a tracker server for use with P2P applications using the below code. It works fine locally, but when I deploy it to Heroku, the port bindings fail because only one port is allowed.
// Create a web sockets signaling server
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
//Allow all requests from all domains & localhost
app.all('/*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With, Content-Type, Accept");
res.header("Access-Control-Allow-Methods", "POST, GET");
next();
});
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
let lookup = {}
const hostname = '0.0.0.0';
const port = process.env.PORT;
var Server = require('bittorrent-tracker').Server
var server = new Server({
udp: false, // enable udp server? [default=true]
http: true, // enable http server? [default=true]
ws: true, // enable websocket server? [default=true]
stats: true, // enable web-based statistics? [default=true]
})
server.on('error', function (err) {
// fatal server error!
console.log(err.message)
})
server.on('warning', function (err) {
// client sent bad data. probably not a problem, just a buggy client.
console.log(err.message)
})
server.on('listening', function () {
// fired when all requested servers are listening
console.log('Signal server http port:' + server.http.address().port)
console.log('Signal server ws port:' + server.ws.address().port)
})
// start tracker server listening! Use 0 to listen on a random free port.
server.listen(port, hostname, 'listening')
// listen for individual tracker messages from peers:
server.on('start', function (addr) {
console.log('got start message from ' + addr)
Object.keys(server.torrents).forEach(hash => {
lookup[server.torrents[hash].infoHash] = server.torrents[hash].peers.length
console.log("peers: " + server.torrents[hash].peers.length)
})
})
server.on('complete', function (addr) {})
server.on('stop', function (addr) {})
app.get('/peers', function(req, res) {
res.send(lookup);
})
app.listen(process.env.PORT, function() {
console.log('Express server port: ' + this.address().port); //Listening on port #
})
If I use process.env.PORT for both server and app, I get the following, which is expected since Heroku only allows 1 listen port:
2021-02-13T05:35:31.016101+00:00 heroku[web.1]: State changed from starting to up
2021-02-13T05:35:30.885170+00:00 app[web.1]: Express server port: 9898
2021-02-13T05:35:30.885204+00:00 app[web.1]: listen EADDRINUSE: address already in use 0.0.0.0:9898
2021-02-13T05:35:30.885205+00:00 app[web.1]: listen EADDRINUSE: address already in use 0.0.0.0:9898
If I hard code the port for either server or app, the application launches fine, but the signaling server doesn't work. No substantial logging is generated.
2021-02-13T05:38:21.141806+00:00 heroku[web.1]: State changed from starting to up
2021-02-13T05:38:20.998054+00:00 app[web.1]: Express server port: 25702
2021-02-13T05:38:20.998550+00:00 app[web.1]: Signal server http port:31415
2021-02-13T05:38:20.998683+00:00 app[web.1]: Signal server ws port:31415
Is it possible that the bittorrent-tracker server and express server can use the same port? For instance, could I get and return the list of peers within this block of code without the need for express at all?
server.on('start', function (addr) {
console.log('got start message from ' + addr)
// Could I do something here to eliminate the need for Express?
Object.keys(server.torrents).forEach(hash => {
lookup[server.torrents[hash].infoHash] = server.torrents[hash].peers.length
console.log("peers: " + server.torrents[hash].peers.length)
})
})
The documentation states:
The http server will handle requests for the following paths:
/announce, /scrape. Requests for other paths will not be handled.
But perhaps there is some way I can shim in the requests that express is handling?
Not long after asking this question, it occurred to me that I might not need express at all. It turns out that was correct.
For anyone wanting a Heroku-ready bittorrent-tracker, here is the updated code:
// Create a web sockets signaling server
let lookup = {}
const hostname = '0.0.0.0';
const port = process.env.PORT;
var Server = require('bittorrent-tracker').Server
var server = new Server({
udp: false, // enable udp server? [default=true]
http: true, // enable http server? [default=true]
ws: true, // enable websocket server? [default=true]
stats: true, // enable web-based statistics? [default=true]
})
server.on('error', function (err) {
// fatal server error!
console.log(err.message)
})
server.on('warning', function (err) {
// client sent bad data. probably not a problem, just a buggy client.
console.log(err.message)
})
server.on('listening', function () {
// fired when all requested servers are listening
console.log('Signal server http port:' + server.http.address().port)
console.log('Signal server ws port:' + server.ws.address().port)
})
// start tracker server listening! Use 0 to listen on a random free port.
server.listen(port, hostname, 'listening')
// listen for individual tracker messages from peers:
server.on('start', function (addr) {
console.log('got start message from ' + addr)
Object.keys(server.torrents).forEach(hash => {
lookup[server.torrents[hash].infoHash] = server.torrents[hash].peers.length
console.log("peers: " + server.torrents[hash].peers.length)
})
})
server.on('complete', function (addr) {})
server.on('stop', function (addr) {})

Websocket connection error: returns 101, but does not upgrade

I am setting up some websockets using ws library. I am struggling to set up authorisation using a handshake. I have added a route to our server to upgrade to a websocket connection like so:
.get(
'/chat',
authorisationFunction,
upgradeConnection,
),
The websocket server:
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 3030 });
This is the upgradeConnection function, which will run if authorisation is successful:
const upgradeConnection = (request, socket, head) => {
return wss.handleUpgrade(request, request.socket, head, function done(ws) {
return wss.emit('connection', ws, request);
});
}
I also have a function that listens to messages:
function webSocketsServer() {
wss.on('connection', (ws, request, client) => {
ws.on('message', message => {
ws.send(message);
});
});
}
A connection gets emitted, and from my server I get this response:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: QyVvqadEcI1+ALka6j2pLKBkfNQ=
but then immediately on my client I get the error “WebSocket connection to 'ws://localhost:3000/chat’ failed: Invalid frame header”.
But when I bypass the handshake and connect directly to my websocket server, I can send messages successfully. The error is only on the client and not on the backend. What am I missing?
I am not 100% sure it is the only way but might help so I post it.
Based on this answer I would go for a server that uses the same port for http and websocket connections.
You can achieve it like this:
const { createServer } = require('http')
const ws = require('ws')
const express = require('express')
const app = express()
const server = createServer(app)
app.get('/', (req, res) => {
res.send('I am a normal http server response')
})
const wsServer = new ws.Server({
server,
path: '/websocket-path',
})
wsServer.on('connection', (connection) => {
connection.send('I am a websocket response')
})
server.listen(3030, () => {
console.log(`Server is now running on http://localhost:3030`)
console.log(`Websocket is now running on ws://localhost:3030/<websocket-path>`)
})
So your server listens on port 3030 for normal http requests. If it gets a websocket connection request on path '/websocket-path' it is passed to the the ws connection handler and from there you are good to go.

Lua HTTP request in ROBLOX is giving me a 403, but works on when testing in other places

local httpService = game:GetService("HttpService");
local s = httpService:GetAsync("https://rbxapi.herokuapp.com/api/Users/1");
print(s);
This is a simple GET request that sends to my proxy server, but it continues to give me a 403 error.
HTTP 403 (HTTP/1.1 403 Forbidden)
When testing the URL on other sites like API tester, it works completely fine and passes the test.
The proxy server is hosted on heroku, which this is the code for the server:
const _express = require("express"),
_proxy = require("express-http-proxy"),
_fs = require("fs");
_body_parser = require("body-parser")
var client = _express();
var port = process.env.PORT || 5000;
client.use("/api", _proxy("https://api.roblox.com", {
proxyReqPathResolver: function(req){
return require('url').parse(req.url).path;
},
}));
client.listen(port, (err) =>{
if(err){
console.log(`Error: ${err}`);
return;
} else {
console.log(`Server is now listenin' on port ${port}!`);
}
})
Solved, ROBLOX knows that it originated from a game server, thus rejecting it.

Socket.io No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access

I'm trying to learn nodejs with socket.io and at the moment I'm using this tutorial by GianlucaGuarini. When entering my client.html file I get the following error. I know what it means and that it´s there for preventing Cross browser scripts but I don´t know how to allow my nodejs script to access the client.html file.
XMLHttpRequest cannot load http://localhost:8000/socket.io/?EIO=3&transport=polling&t=1422653081432-10. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.
Here is a part of my code with socket.
var app = require('http').createServer(handler),
io = require('socket.io').listen(app),
fs = require('fs'),
mysql = require('mysql'),
connectionsArray = [],
connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '',
database: 'database',
port: 3306
}),
POLLING_INTERVAL = 3000,
pollingTimer;
// If there is an error connecting to the database
connection.connect(function(err) {
// connected! (unless `err` is set)
console.log(err);
});
// creating the server ( localhost:8000 )
app.listen(8000);
// on server started we can load our client.html page
function handler(req, res) {
res.writeHead(200, {
/// ...
'Access-Control-Allow-Origin' : '*'
});
fs.readFile(__dirname + '/client.html', function(err, data) {
if (err) {
console.log(err);
res.writeHead(500);
return res.end('Error loading client.html');
}
res.writeHead(200);
res.end(data);
});
}
Does anyone know how I can solve my problem?
Kind regard / H
First of all - stop use writeHead everywhere. Because it rewrite completely response headers.
If tour write like this:
res.writeHead(200,{"coolHeader":"YesIAm"});
res.writeHead(500);
then node.js will sent response just with status 500 and without header "coolHeader";
If you wanna change Status Code, then use
res.statusCode = ###;
If you wanna add new header use
res.setHeader("key", "value");
And if you wanna rewrite all headers then use writeHeader(...)
Second. Add this code
res.statusCode = 200;
//...
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
instead of your
res.writeHead(200, {
/// ...
'Access-Control-Allow-Origin' : '*'
});
and replace all writeHead(###) with res.statusCode = ###;
Try setting the `Access-Control-Allow-Origin' header on your response object in Node.
response.writeHead(200, {
/// ...
'Access-Control-Allow-Origin' : '*'
});
Looks like you are calling .listen for both the app and the socket.io (I believe that is redundant since you are extending your server with socket.io)
I have a little piece that works fine for me using socket.io 1.x
I like to use https since it kills some issues with firewalls and antiviruses, but this example is rewritten to http.
var http = require('http'),
socketio = require('socket.io'),
options={},
port=8080;
//start http
var app = http.createServer(options, handler),
io = socketio(app, {
log: false,
agent: false,
origins: '*:*'
// 'transports': ['websocket', 'htmlfile', 'xhr-polling', 'jsonp-polling']
});
app.listen(port);
console.log('listening on port ' + port);

Socket.IO can't connect through https

I have a node.js app, that uses socket.IO. It works fine on http, but when trying to connect to the socket through https - nothing happens.
Here's some part of the code:
var fs = require('fs');
var ioHttp = require('socket.io').listen(8899, {
'flash policy port': -1
});
initSocket(ioHttp);
var ioHttps = require('socket.io').listen(8895, {
key: fs.readFileSync('/path/to/file/file.key'),
cert: fs.readFileSync('/path/to/file/file.crt'),
ca: [
fs.readFileSync('/path/to/file/sub.class1.server.ca.pem'),
fs.readFileSync('/path/to/file/ca.pem')
],
'flash policy port': -1
});
initSocket(ioHttps);
and the initSocket function:
function initSocket(io) {
io.enable('browser client minification');
io.enable('browser client etag');
io.enable('browser client gzip');
io.set('transports', [
'websocket',
'htmlfile',
'flashsocket',
'jsonp-polling'
]);
io.sockets.on('connection', function (client) {
//the connnection is handled here
});
}
The client connect like this:
var secureConnection = false;
var port = 8899;
if (window.location.protocol === 'https:') {
port = 8895;
secureConnection = true;
}
var socket = io.connect('domain.org', {port: port, secure: secureConnection});
As I said everything works fine on http, but connecting on https gives me "The connection was interrupted". What am I doing wrong?
You cannot initalize socket.io server like https server. You have to start a separate https server and then attach socket.io server to it.
var https = require('https'),
fs = require('fs');
var options = {
key: fs.readFileSync('ssl/server.key'),
cert: fs.readFileSync('ssl/server.crt'),
ca: fs.readFileSync('ssl/ca.crt')
};
var app = https.createServer(options);
io = require('socket.io').listen(app); //socket.io server listens to https connections
app.listen(8895, "0.0.0.0");

Categories

Resources