I'm having a trouble on looking for the error can anyone point it out for me please i have been into this for 2 days and still can't figure it out.
the picture above is the error log from heroku.
and here is my server.js for the ice configuration
// Load required modules
var http = require("http"); // http server core module
var https = require('https');
var express = require("express"); // web framework external module
var serveStatic = require('serve-static'); // serve static files
var socketIo = require("socket.io"); // web socket external module
var easyrtc = require('./lib/easyrtc_server'); // EasyRTC external module
// Set process name
process.title = "node-easyrtc";
// Setup and configure Express http server. Expect a subfolder called "static" to be the web root.
var app = express();
app.use(serveStatic('public', {'index': ['index.html']}));
var port = process.env.PORT || 8080;
// Start Express http server on port 8080
var webServer = http.createServer(app).listen(port);
// Start Socket.io so it attaches itself to Express server
var socketServer = socketIo.listen(webServer, {"log level":1});
easyrtc.setOption("logLevel", "debug");
// Overriding the default easyrtcAuth listener, only so we can directly access its callback
easyrtc.events.on("easyrtcAuth", function(socket, easyrtcid, msg, socketCallback, callback) {
easyrtc.events.defaultListeners.easyrtcAuth(socket, easyrtcid, msg, socketCallback, function(err, connectionObj){
if (err || !msg.msgData || !msg.msgData.credential || !connectionObj)
{
callback(err, connectionObj);
return;
}
connectionObj.setField("credential", msg.msgData.credential, {"isShared":false});
console.log("["+easyrtcid+"] Credential saved!", connectionObj.getFieldValueSync("credential"));
callback(err, connectionObj);
});
});
// To test, lets print the credential to the console for every room join!
easyrtc.events.on("roomJoin", function(connectionObj, roomName, roomParameter, callback) {
console.log("["+connectionObj.getEasyrtcid()+"] Credential retrieved!", connectionObj.getFieldValueSync("credential"));
easyrtc.events.defaultListeners.roomJoin(connectionObj, roomName, roomParameter, callback);
});
// Start EasyRTC server
var rtc = easyrtc.listen(app, socketServer, null, function(err, rtcRef) {
console.log("Initiated");
rtcRef.events.on("roomCreate", function(appObj, creatorConnectionObj, roomName, roomOptions, callback) {
console.log("roomCreate fired! Trying to create: " + roomName);
appObj.events.defaultListeners.roomCreate(appObj, creatorConnectionObj, roomName, roomOptions, callback);
});
});
//ice config easyrtc
easyrtc.on("getIceConfig", function(connectionObj, callback) {
// This object will take in an array of XirSys STUN and TURN servers
var iceConfig = [];
http.request({
url: 'https://service.xirsys.com/ice',
qs: {
ident: "***",
secret: "****",
domain: "***",
application: "test-livestream",
room: "test-livestream-room",
secure: 1
},
function (error, response, body) {
if (!error && response.statusCode == 200) {
// body.d.iceServers is where the array of ICE servers lives
iceConfig = body.d.iceServers;
console.log(iceConfig);
callback(null, iceConfig);
}
else
{
console.log(error);
}
}
});
});
//listen on port 8080
webServer.listen(8080, function () {
console.log('listening on http://localhost:'+port);
});
By adding another module
var request = require("request");
and editting my ice server
request.post('https://service.xirsys.com/ice',{
form:{
ident: "****",
secret: "****",
domain: "****",
application: "****",
room: "****",
secure: 1
},
json:true
},
i obtain to let it work :)
Related
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.
I'd like to encrypt my Koa server with SSL. It seems simple enough with a regular httpServer, but I'm not how to do it with Koa. Could anyone help?
I stumbled upon this. Launching an https server with the node package and passing it the Koa server instance .callback() does the trick.
Koa's doc
var fs = require('fs');
var path = require('path');
var http = require('http');
var https = require('https');
var Koa = require('koa');
var server = new Koa();
// add main routes
// the following routes are for the authorisation challenges
// ... we'll come back to this shortly
var acmeRouter = require('./acme-router.js');
server
.use(acmeRouter.routes())
.use(acmeRouter.allowedMethods());
var config = {
domain: 'example.com',
http: {
port: 8989,
},
https: {
port: 7979,
options: {
key: fs.readFileSync(path.resolve(process.cwd(), 'certs/privkey.pem'), 'utf8').toString(),
cert: fs.readFileSync(path.resolve(process.cwd(), 'certs/fullchain.pem'), 'utf8').toString(),
},
},
};
let serverCallback = server.callback();
try {
var httpServer = http.createServer(serverCallback);
httpServer
.listen(config.http.port, function(err) {
if (!!err) {
console.error('HTTP server FAIL: ', err, (err && err.stack));
}
else {
console.log(`HTTP server OK: http://${config.domain}:${config.http.port}`);
}
});
}
catch (ex) {
console.error('Failed to start HTTP server\n', ex, (ex && ex.stack));
}
try {
var httpsServer = https.createServer(config.https.options, serverCallback);
httpsServer
.listen(config.https.port, function(err) {
if (!!err) {
console.error('HTTPS server FAIL: ', err, (err && err.stack));
}
else {
console.log(`HTTPS server OK: http://${config.domain}:${config.https.port}`);
}
});
}
catch (ex) {
console.error('Failed to start HTTPS server\n', ex, (ex && ex.stack));
}
module.exports = server;
Looks like there's no clear cut way to do this, but running Nginx on top of my server was an easy workaround.
I have node.js code similar to this one:
var firebase = require('firebase');
var request = require('request');
var API_KEY = "..."; // Your Firebase Cloud Server API key
firebase.initializeApp({
serviceAccount: ".json",
databaseURL: "https://.firebaseio.com/"
});
ref = firebase.database().ref();
function listenForNotificationRequests() {
var requests = ref.child('notificationRequests');
ref.on('child_added', function(requestSnapshot) {
var request = requestSnapshot.val();
sendNotificationToUser(
request.username,
request.message,
function() {
request.ref().remove();
}
);
}, function(error) {
console.error(error);
});
};
function sendNotificationToUser(username, message, onSuccess) {
request({
url: 'https://fcm.googleapis.com/fcm/send',
method: 'POST',
headers: {
'Content-Type' :' application/json',
'Authorization': 'key='+API_KEY
},
body: JSON.stringify({
notification: {
title: message
},
to : '/topics/user_'+username
})
}, function(error, response, body) {
if (error) { console.error(error); }
else if (response.statusCode >= 400) {
console.error('HTTP Error: '+response.statusCode+' - '+response.statusMessage);
}
else {
onSuccess();
}
});
}
// start listening
listenForNotificationRequests();
My question is how to run it on heroku? When I try it is giving me Error R10 (Boot timeout) -> Web process failed to bind to $PORT within 60 seconds of launch. Procfile is like this:
worker: node server.js
Here is my guess:
You probably have something similar to this in your code (just not posted):
var http = require('http');
http.createServer(server.js);
server.listen(5000);
Well, that server.listen(5000); is forcing the app to connect to port 5000 and listen.
Heroku doesn't work that way. It will automatically assign a port to your env and use that. So you need to tell your app "Hey, use the env port, or use 5000 as a backup". You can do this like this:
server.listen(process.env.PORT || 5000);
Again, this is just a guess considering you didn't post your code that refers to the port number. My example might differ from yours, but it's the same general concept.
I fixed it by this:
//add this in the begining
var express = require('express');
var app = express();
app.set('port', (process.env.PORT || 5000));
//this at the end
app.listen(app.get('port'), function() {
listenForNotificationRequests();
});
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.
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")
})