I need your help.
I want to get the public IP address of my Beaglebone via ifconfig.me.
If I have an existing internet connection it works fine. If I don't have an internet connection the request should be aborted.
Here is my code:
function publicIP_www(callback){
try{
exec('curl ifconfig.me',{timeout:3000}, function(error, stdout, stderr){
callback(stdout); });
}
catch (err){
callback("000.000.000.000");
}
}
The returned IP address is then displayed on a web site in the browser.
If there is no internet connection, the browser calculates forever. It seems as if the call exec ...... is not terminated.
I'm looking forward to your support and hope that someone can tell me what I'm doing wrong.
best regards Hans
It's difficult to predict why it is in your case not working, due to not to be able see your code. But you can try next that works fine. Of Course it's dirty, just is an example.
Next code is for index.js file of the "Node.js Express App + Jade" project that was created from template in WebStorm IDE.
const util = require('util');
const exec = util.promisify(require('child_process').exec);
....
....
router.get('/', async function(req, res, next) {
try {
const {stdout, stderr} = await exec('curl ifconfig.me');
res.render('index', { title: stdout});
}
catch (err) {
res.render('index',{ title: "000.000.000.000"});
}
});
OR use
const util = require('util');
const exec = require('child_process').exec;
function publicIP_www(callback){
exec('curl ifconfig.me',{timeout:3000}, function(error, stdout, stderr){
if (error) {
return callback("000.000.000.000");
}
callback(stdout);
});
}
router.get('/', function(req, res, next) {
publicIP_www((title) => {
res.render('index', { title });
})
});
Related
I'm new to Node and have previously just written Javascript for simple browser extensions. What I'm trying to do is run a shell script and then return the text for it on a get request (simplified version).
I've tried looking at callbacks and can't seem to get my head around it or even adapt another example to what I'm trying to do. My main problem is either that the I'm receiving the error "first argument must be one of type string or buffer. received type undefined" or "received type function" (when I tried to implement a callback, which is what I believe I need to do here?).
I've looked at a few examples of callbacks and promises and seeing them in abstraction (or other contexts) just isn't making sense to me so was hoping someone could help direct me in the right direction?
The code is very crude, but just trying to get some basic functionality before expanding it any further.
var express = require("express");
var app = express();
const { exec } = require("child_process");
var ifcfg = function(callback) {
exec("ifconfig", (error, stdout, stderr) => {
if (error) {
console.log(`error: ${error.message}`);
return error;
}
if (stderr) {
console.log(`stderr: ${stderr}`);
return err;
} else {
var output = stdout.toString();
return callback(output);
}
});
}
app.get("/ifconfig", (req, res) => res.write(ifcfg(data)));
var port = process.env.PORT || 8080;
app.listen(port, function() {
console.log("Listening on " + port);
});
In JavaScript, a callback is a function passed into another function as an argument to be executed later.
Since the command is executed asynchronously you will want to use a callback to handle the return value once the command has finished executing:
var express = require("express");
var app = express();
const { exec } = require("child_process");
function os_func() {
this.execCommand = function(cmd, callback) {
exec(cmd, (error, stdout, stderr) => {
if (error) {
console.error(`exec error: ${error}`);
return;
}
callback(stdout);
});
}
}
app.get("/", (req, res) => {
console.log("InsideGetss");
var os = new os_func();
os.execCommand('ifconfig', function (returnvalue) {
res.end(returnvalue)
});
});
Using ReactJS, Redux, Webpack, Node.js and Express with MongoDB, I am following the tutorial https://github.com/vasansr/mern-es6 and trying to integrate it into my project. First, I am trying to make a POST request to the server I created. And it gets a response with a success and no error is logged. Yet inside the server POST API, it does not log console.log('Req body', req.body);, and in terminal I checked to see if the database has been created with mongo -> show dbs but it is empty.
Could it be that something is intercepting the request from the server? What could be the issue?
This...
app.use('/', function (req, res) {
res.sendFile(path.resolve('client/index.html'));
});
comes before:
app.post('/api/users/', function(req, res) {
//...
});
Since it's app.use the POST /api/users will still hit that middleware, and res.sendFile ends the request/response. You'll probably see that your post is getting back the client HTML.
Try moving your client HTML endpoint to the end of your middleware, just before the error handlers if you have them. That way, it'll only get used if none of your API endpoints match. Or if you want just GET / to return the HTML, change use to get:
app.use(webpackDevMiddleware(compiler, {noInfo: true, publicPath: config.output.publicPath}));
app.use(webpackHotMiddleware(compiler));
app.use(express.static('dist')); //where bundle.js is
app.use(bodyParser.json());
app.post('/api/users/', function(req, res) {
console.log('Req body', req.body);
var newUser = req.body;
db.collection('users').insertOne(newUser, function(err, result) {
if(err) console.log(err);
var newId = result.insertedId;
db.collection('users').find({_id: newId}).next(function(err, doc) {
if(err) console.log(err);
res.json(doc);
});
});
});
app.get('/', function (req, res) {
res.sendFile(path.resolve('client/index.html'));
});
app.post('/api/users/', function(req, res) {
console.log('Req body', req.body);
var newUser = req.body;
db.collection('users').insertOne(newUser, function(err, result) {
if(err) console.log(err);
var newId = result.insertedId;
db.collection('users').find({_id: newId}).next(function(err, doc) {
if(err) console.log(err);
res.json(doc);
});
});
});
I have a small comments about this code, for if(err) console.log(err); i think you should change to if(err) return console.log(err);.
For error case, i think you need return, otherwise the below part will be excuted, and there will report some error.
var database = require('database');
var express = require('express');
var app = express();
var cors = require('cors');
app.use(cors());
var bodyParser = require('body-parser');
var urlencodedParser = bodyParser.urlencoded({
extended: false
});
app.post('/dosomething', urlencodedParser, function(req, res) {
if (!req.body.a) {
res.status(500).send(JSON.stringify({
error: 'a not defined'
}));
return;
}
firstAsyncFunction(req.body.a, function(err, result) {
if (err) {
res.status(500).send('firstAsyncFunction was NOT a success!');
} else {
if (result.b) {
secondAsyncFunction(result.b, function(err, data) {
if (err) {
res.status(500).send('secondAsyncFunction was NOT a success!');
return;
}
res.send('EVERYTHING WAS A SUCCESS! ' + data);
});
}
else {
res.status(500).send('result.b is not defined');
}
}
});
});
function firstAsyncFunction(param, callback) {
//Some network call:
// Return either return (callback(null,'success')); or return (callback('error'));
var query = database.createQuery(someOptionsHere);
database.runDatabaseQuery(query, function(err, entities, info) {
if (err) {
return (callback('error'));
}
return (callback(null, 'success'));
});
};
function secondAsyncFunction(param, callback) {
//Some network call:
// Return either return (callback(null,'success')); or return (callback('error'));
var query = database.createQuery(someOptionsHere);
database.runDatabaseQuery(query, function(err, entities, info) {
if (err) {
return (callback('error'));
}
return (callback(null, 'success'));
});
};
var server = app.listen(process.env.PORT || 3000, function() {
var host = server.address().address;
var port = server.address().port;
console.log('App listening at http://%s:%s', host, port);
});
module.exports = app;
I have here a basic express http server. This server has one route, dosomething, which makes two network calls and tells the user if they were a success or not.
This is my entire webserver (this is a bare bones server of my actual server for example purposes). I am now concerned with this server crashing. Reading the docs for express I see there is a default error handler which will catch errors and prevent the server from crashing (http://expressjs.com/en/guide/error-handling.html). I have added the code:
function defaultErrorHandler(err, req, res, next) {
if (res.headersSent) {
return next(err);
}
res.status(500);
res.render('error', { error: err });
}
app.use(defaultErrorHandler);
This still crashes my server though. For example. I had a problem with my database returning an improper JSON response and inside of my firstAsyncFunction (not shown in the code) I tried to parse the JSON and it caused an error telling me it was improper JSON and the server crashed and was unable to take requests anymore until I restarted it. I would like to avoid this and have the default error handler send out a generic response back to the user when this occurs. I thought if I specified the defaultErrorHandler and put it inside of app.use that it would capture and handle all errors, but this does not seem to be the case? Inside of my async function for example you can see I am looking if an error was returned and if it was I send an error back to the user, but what if some other error occurs, how can I get express to capture and handle this error for me?
The defaultErrorHandler cannot handle exceptions that are thrown inside asynchronous tasks, such as callbacks.
If you define a route like:
app.get('/a', function(req, res) {
throw new Error('Test');
});
An error will be thrown, and in this case defaultErrorHandler will successfully catch it.
If the same exception occurs in an async manner, like so:
app.get('/a', function(req, res) {
setTimeout(function () {
throw new Error('Test');
}, 1000);
});
The server will crush, because the callback is actually in another context, and exceptions thrown by it will now be caught by the original catcher. This is a very difficult issue to deal with when it comes to callback.
There is more than one solution though. A possible solution will be to wrap every function that is prone to throw error with a try catch statement. This is a bit excessive though.
For example:
app.get('/a', function(req, res) {
setTimeout(function () {
try {
var x = JSON.parse('{');
}
catch (err) {
res.send(err.message);
}
}, 1000);
});
A nicer solution:
A nicer solution, would be to use promises instead, if it's possible, then for example you can declare a single errorHandler function like so:
function errorHandler(error, res) {
res.send(error.message);
}
Then, let's say you have to following function with fetches stuff from the database (I used setTimeout to simulate async behavior):
function getStuffFromDb() {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve("{");
}, 100);
});
}
Notice that this function returns an invalid JSON string. Your route will look something like:
app.get('/a', function(req, res) {
getStuffFromDb()
.then(handleStuffFromDb)
.catch(function (error) { errorHandler(error, res) });
});
function handleStuffFromDb(str) {
return JSON.parse(str);
}
This is a very simplified example, but you can add a lot more functionality to it, and (at least theoretically) have a single catch statement which will prevent your server from crushing.
In my app.js file I had the code below and it worked as intended. I need to clean up my code, so I moved it to it's own route at routes/random and it no longer works because I get an error that states: "http://localhost:1337/random/1/1/testing 404 (Not Found)" and I am not sure why. My original code was in my app.js file when it was working was:
app.get('/random/:room/:userId/:message', function(req, res) {
fs.appendFile(room.number.toString(), req.params.message, function(err) {
if (err) {
console.log('error writing messages to file');
};
fs.readFile('./' + room.number, 'utf-8', function(err, data) {
if (err) {
if (err.fileNotFound) {
return this.sendErrorMessage('can\'t find the file, you linked it incorrectly');
}
console.log('error reading message file');
};
if (req.params.userId == 1) {
messages.user1.push(data);
} else {
messages.user2.push(data);
};
console.log(messages);
res.send(data);
fs.unlink(req.params.room, function(err) {
});
});
});
});
the new code includes the following for app.js
var express = require('express');
var app = express();
var fs = require('fs');
var random = require('./routes/random');
app.use('/random/', random);
app.use(express.static('public'));
app.use(express.static('public/js'));
app.use(express.static('public/images'));
and after I moved it, the route code is:
var express = require ('express');
var fs = require ('fs');
var random = express.Router();
random.get('/random/:room/:userId/:message', function(req, res) {
fs.appendFile(room.number.toString(), req.params.message, function(err) {
if (err) {
console.log('error writing messages to file');
};
fs.readFile('./' + room.number, 'utf-8', function(err, data) {
if (err) {
if (err.fileNotFound) {
return this.sendErrorMessage('can\'t find the file, you linked it incorrectly');
}
console.log('error reading message file');
};
if (req.params.userId == 1) {
messages.user1.push(data);
} else {
messages.user2.push(data);
};
console.log(messages);
res.send(data);
fs.unlink(req.params.room, function(err) {
});
});
});
});
module.exports = random;
Can anyone explain what I have done wrong that won't allow it to find the file?
In your code you are defining a route called random\random... in random.js, delete first random there, because middleware(app.use..) will direct all routes with /random to your router instance.
Your router is handling a url that starts with /random, and you attach this to your app under the path /random/. Remove one or the other (preferebly, the one inside the router).
I was able to fix it. Both comments above are correct, but it still was throwing errors due to my variables being undefined. I figured it out though so I am closing this question. Thank you both
I am running node + express + mongojs. Here is a sample code:
function mongoCallback(req, res) {
"use strict";
return function (err, o) {
if (err) {
res.send(500, err.message);
} else if (!o) {
res.send(404);
} else {
res.send(o);
}
};
}
var express, app, params, mongo, db;
express = require('express');
params = require('express-params');
app = express();
params.extend(app);
app.use("/", express.static('web'));
mongo = require('mongojs');
db = mongo.connect('mydb', ['inventory']);
app.get('/api/inventory', function (req, res) {
db.inventory.find(mongoCallback(req, res));
});
app.listen(8000);
console.log('Listening on port 8000');
Sometimes I forget running mongod and an attempt to talk to the database fails with "failed to connect to ..." error. The problem is that starting mongod is not enough, the already existing db object seems to remember that no connection could be made and so the server continues to fail, even if mongod is already running.
So, I have come up with the following solution:
var express, app, params, mongo, db, api;
if (!String.prototype.startsWith) {
String.prototype.startsWith = function (str) {
"use strict";
return this.lastIndexOf(str, 0) === 0;
};
}
function setDB() {
db = mongo.connect('IF', ['invoices', 'const', 'inventory']);
}
function mongoCallback(req, res, next, caller, secondTry) {
return function (err, o) {
if (err) {
if (!secondTry && err.message && err.message.startsWith("failed to connect to")) {
setDB();
caller(req, res, next, true);
} else {
res.send(500, err.message);
}
} else if (!o) {
res.send(404);
} else {
res.send(o);
}
};
}
express = require('express');
params = require('express-params');
app = express();
params.extend(app);
app.use("/", express["static"]('web'));
mongo = require('mongojs');
setDB();
api = {
getInventory: function (req, res, next, secondTry) {
db.inventory.find(mongoCallback(req, res, next, api.getInventory, secondTry));
}
};
app.get('/api/inventory', api.getInventory);
app.listen(8000);
console.log('Listening on port 8000');
Basically it recreates the db object if a request fails with the "failed to connect to" error and reruns the request. This is done only for the first failure. A subsequent failure returns the error.
I do not like my solution at all. There has to be a better way. Any suggestions?
Thanks.
What do you mean by "the already existing db object seems to remember that no connection could be made"? Do you mean that the queries on the database fail if you start the express app before running mongod? Since you are connecting to the DB at the startup of the express app, you should have the mongod running first.
If you are worried about the database going down after the initial connection and causing your CRUD operations to fail, you can check for an error in your operations
db.inventory.find(function(err, docs) {
// check err to see if there was a connection issue
});
and then reconnect if there was an error.
As far as I know the mongodb native driver allows to set { auto_reconnect:true }, have you tried to set this?
I'm not sure how this behaves if the database wasn't running at all, mongoose.js for example caches all requests until the DB is ready and issues them after a successful connection.