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();
});
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'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 :)
I'm trying to create a Facebook chatbot using NodeJS, Express, and a Heroku server.
I created my webhook on Heroku and had it verified and saved by Facebook. I then ran this code to connect my webhook to Facebook.
curl -ik -X POST "https://graph.facebook.com/v2.6/me/subscribed_apps?access_token=<token>"
this returned {success:true}.
So then I started adding code that would reply to incoming messages but I can't seem to get it to receive the sent information. Whenever I send a message I get no reply.
Everything is connected and running but this error I am getting "TypeError: Cannot read property '0' of undefined" is because I'm not getting the message information sent to my webhook from facebook. This is the line of code that is empty:
messaging_events = req.body.entry[0].messaging;
Here is my full code:
var express = require('express');
var bodyParser = require('body-parser');
var request = require("request")
var app = express();
var port = process.env.PORT || 3000;
// body parser middleware
app.use(bodyParser.urlencoded({ extended: true }));
app.get('/', function (req, res) {
if (req.query['hub.verify_token'] === '8FKU9XWeSjnZN4ae') {
res.send(req.query['hub.challenge']);
console.log("app.get ran")
res.sendStatus(200)
}
console.log("Error: wrong validation token")
})
app.post('/', function (req, res) {
messaging_events = req.body.entry[0].messaging;
console.log("app.post ran")
for (i = 0; i < messaging_events.length; i++) {
event = req.body.entry[0].messaging[i];
sender = event.sender.id;
if (event.message && event.message.text) {
text = event.message.text;
sendTextMessage(sender, "Text received, echo: "+ text.substring(0, 200));
}
}
res.sendStatus(200);
});
app.listen(port, function () {
console.log('Listening on port ' + port);
});
var token = "<myToken>";
function sendTextMessage(sender, text) {
messageData = {
text:text
}
request({
url: 'https://graph.facebook.com/v2.6/me/messages',
qs: {access_token:token},
method: 'POST',
json: {
recipient: {id:sender},
message: messageData,
}
}, function(error, response, body) {
if (error) {
console.log('Error sending message: ', error);
} else if (response.body.error) {
console.log('Error: ', response.body.error);
}
});
}
Here are my Heroku Logs:
So I'm confused as to why I'm not getting the message data when my webhook is connected to Facebook and they are communicating. I also made sure I had all the subscription fields necessary checked.
Anyone see the problem? Any help is appreciated. Thanks!
Edit: I'm following this guide by the way - https://developers.facebook.com/docs/messenger-platform/quickstart
I had the same problem. Can you add app.use(bodyParser.json()) before bodyParser.urlencoded() ) ?
Trying to Connect to a local server from Xcode. I have imported an Alamofire Pod into my Xcode project and run the following command in xcode
Alamofire.request(.GET, "http://localhost:3000" , parameters: ["code": "123"]).responseJSON {
response in
print ("Hello", response)
}
I recieve the following error in Xcode when running on iOS device.
FAILURE: Error Domain=NSURLErrorDomain Code=-1004 "Could not connect to the server." UserInfo={NSUnderlyingError=0x13d84f7f0 {Error Domain=kCFErrorDomainCFNetwork Code=-1004 "(null)" UserInfo={_kCFStreamErrorCodeKey=61, _kCFStreamErrorDomainKey=1}}, NSErrorFailingURLStringKey=http://localhost:3000/, NSErrorFailingURLKey=http://localhost:3000/, _kCFStreamErrorDomainKey=1, _kCFStreamErrorCodeKey=61, NSLocalizedDescription=Could not connect to the server.}
I know the local is serving is running. When I call the following function on the command line:
$ node index.js
Running at http://localhost:3000
In the browser the following is shown:
Cannot GET /
My .js file is the following:
var buffer = require('buffer');
var bodyParser = require('body-parser');
var crypto = require('crypto');
var express = require('express');
var request = require('request');
var url = require('url');
var app = express();
var config = {
clientId: '',
clientSecret: '',
callbackUrl: '',
encryptionSecret: '',
endpoint: 'https://accounts.spotify.com',
};
var secretString = config.clientId + ':' + config.clientSecret;
var authHeader = 'Basic ' + new buffer.Buffer(secretString).toString('base64');
// app.use(bodyParser.urlencoded({ extended: false })); // TODO - Figure out why this should be here
app.use(bodyParser.json()); // TODO - Figure out why this should be here
var server = app.listen(3000, function() {
var address = server.address();
console.log('Running at http://localhost:%s', address.port);
});
app.post('/swap', function(req, res) {
console.log(req.body);
if (!req.body || !req.body.hasOwnProperty('code')) {
console.log('Swap: missing auth code');
res.status(550).send('Permission Denied');
return;
}
formData = {
grant_type: 'authorization_code',
redirect_uri: config.callbackUrl,
code: req.body.code
};
console.log('Swap: POST to %s', url.resolve(config.endpoint, '/api/token'), formData);
request.post({
url: url.resolve(config.endpoint, '/api/token'),
headers: {
'Authorization': authHeader,
'Content-Type': 'application/x-www-form-urlencoded',
},
form: formData,
}, function(error, response, body) {
if (error) {
console.log('Swap: Error - ', error);
res.status(500).send('Internal Server Error');
return;
}
if (res.statusCode != 200) {
debug('Swap: response: ', response.statusCode);
res.status(550).send('Permission Denied');
return;
}
var tokenData = JSON.parse(body);
console.log('Swap: tokenData - ', tokenData);
res.status(200).set({
'Content-Type': 'application/json',
}).send(tokenData);
});
});
Here is the summary of the discussion from comments:
1) Initially the node.js application only had a route for POST requests. This makes debugging more complex. Add a route for GET requests, so you can check http://localhost:3000 from the browser. Now check if it works in the desktop browser and in the simulator browser to confirm the general node application availability.
2) Address like http://localhost:3000 or http://127.0.0.1:3000 only works on the same machine where the node.js application is running. This includes the iOS simulator, but will not work with such address on the device.
3) To test on the device - replace the localhost address with your local network IP address. The local network address usually looks like 192.168.xxx.xxx and can be found in network settings.
To actually run this setup in production, you will need a server, where you run the node.js application, to have a public real IP address or domain name and you will connect to it using something like http://my.app.domain.or.ip:3000.