How to make this code run in modern nodejs? - javascript

I am trying to implement a simple web interface where I can see do tail -f of my log file.
Found the below link
https://thoughtbot.com/blog/real-time-online-activity-monitor-example-with-node-js-and-websocket
It seems to be very old and not compatible with modern-day node.j.
I tried to go through node.j` documentation but was unable to fix this.
Child process creation is causing some issues.
var filename = process.argv[2];
if (!filename)
return sys.puts("Usage: node watcher.js filename");
var tail = process.createChildProcess("tail", ["-f", filename]);
console.log("start tailing");
tail.addListener("output", function (data) {
console(data);
});
var http = require("http");
http.createServer(function(req,res){
res.sendHeader(200,{"Content-Type": "text/plain"});
tail.addListener("output", function (data) {
res.sendBody(data);
});
}).listen(8000);
I want to send this tailf'd log to another server, which will be running nodejs app to read this.
Can someone help me out?

I've searched through the whole nodejs documentation, but I haven't found any version where there were process.createChildProcess().
However, you can replace it using the child-process built-in module:
const filename = process.argv[2];
if (!filename){
console.log("Usage: node watcher.js filename");
process.exit(0)
}
const child = require('child-process')
const tail = child.exec("tail", ["-f", filename],{shell:true});
console.log("start tailing");
tail.stdout.on("data", function (data) {
console.log(data);
});
const http = require("http");
http.createServer(function(req,res){
res.writeHead(200,{"Content-Type": "text/plain"});
tail.stdout.on("data", function (data) {
res.write(data);
});
}).listen(8000);

Related

Local file download is corrupted

I am trying to download a file to my windows pc using nodejs
I tried the following code. the problem is the file which i download from nodejs is 185kb and the actual original file size is 113kb(found by directly downloading from browser)
request = require('request');
function download(url, dest, cb){
request.head(url, function(err, res, body){
request(url).pipe(fs.createWriteStream(dest)).on('close', function(){
cb();
});
});
};
I also tried downloading the file using a different code
function download(url, dest, cb) {
var file = fs.createWriteStream(dest);
var request = https.get(url, function (response) {
response.pipe(file);
file.on('finish', function () {
file.close(cb);
file.end();
});
});
}
But the same bug happened
The problem is i am trying to open that file in photoshop , but it fails , saying the file is corrupted, please help
This code (using the built-in https module) should work correctly. The stream will close automatically, there's no need to close it, the autoClose parameter defaults to true when creating a write file stream.
See docs at: fs.createWriteStream.
If the file is still too large it is likely that you are not using the direct image link, try selecting "View image" / "Open image in new tab" etc. in your browser and using that link instead.
const https = require("https");
const fs = require("fs");
const url = "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e1/FullMoon2010.jpg/1024px-FullMoon2010.jpg";
const fileStream = fs.createWriteStream("test.jpg");
https.get(url, response => {
response.pipe(fileStream);
});
You can also use the request library:
const request = require("request");
const fs = require("fs");
const url = "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e1/FullMoon2010.jpg/1024px-FullMoon2010.jpg";
const fileStream = fs.createWriteStream("request-test.jpg");
const req = request(url);
req.on("response", response => {
response.pipe(fileStream);
});

Node js Error: Protocol "https:" not supported. Expected "http:"

I am using IBM Bluemix to make a web service for a school project.
My project needs to request a JSON from an API, so I can use the data it provides. I use the http get method for a data set, and I am not sure if it is working properly.
When I run my code, I get the message:
Error: Protocol "https:" not supported. Expected "http:"
What is causing it and how can I solve it?
Here is my .js file:
// Hello.
//
// This is JSHint, a tool that helps to detect errors and potential
// problems in your JavaScript code.
//
// To start, simply enter some JavaScript anywhere on this page. Your
// report will appear on the right side.
//
// Additionally, you can toggle specific options in the Configure
// menu.
function main() {
return 'Hello, World!';
}
main();/*eslint-env node*/
//------------------------------------------------------------------------------
// node.js starter application for Bluemix
//------------------------------------------------------------------------------
// HTTP request - duas alternativas
var http = require('http');
var request = require('request');
// cfenv provides access to your Cloud Foundry environment
// for more info, see: https://www.npmjs.com/package/cfenv
var cfenv = require('cfenv');
//chama o express, que abre o servidor
var express = require('express');
// create a new express server
var app = express();
// serve the files out of ./public as our main files
app.use(express.static(__dirname + '/public'));
// get the app environment from Cloud Foundry
var appEnv = cfenv.getAppEnv();
// start server on the specified port and binding host
app.listen(appEnv.port, '0.0.0.0', function() {
// print a message when the server starts listening
console.log("server starting on " + appEnv.url);
});
app.get('/home1', function (req,res) {
http.get('http://developers.agenciaideias.com.br/cotacoes/json', function (res2) {
var body = '';
res2.on('data', function (chunk) {
body += chunk;
});
res2.on('end', function () {
var json = JSON.parse(body);
var CotacaoDolar = json["dolar"]["cotacao"];
var VariacaoDolar = json["dolar"]["variacao"];
var CotacaoEuro = json["euro"]["cotacao"];
var VariacaoEuro = json["euro"]["variacao"];
var Atualizacao = json["atualizacao"];
obj=req.query;
DolarUsuario=obj['dolar'];
RealUsuario=Number(obj['dolar'])*CotacaoDolar;
EuroUsuario=obj['euro'];
RealUsuario2=Number(obj['euro'])*CotacaoEuro;
Oi=1*VariacaoDolar;
Oi2=1*VariacaoEuro;
if (VariacaoDolar<0) {
recomend= "Recomenda-se, portanto, comprar dólares.";
}
else if (VariacaoDolar=0){
recomend="";
}
else {
recomend="Recomenda-se, portanto, vender dólares.";
}
if (VariacaoEuro<0) {
recomend2= "Recomenda-se, portanto, comprar euros.";
}
else if (VariacaoEuro=0){
recomend2="";
}
else {
recomend2="Recomenda-se,portanto, vender euros.";
}
res.render('cotacao_response.jade', {
'CotacaoDolar':CotacaoDolar,
'VariacaoDolar':VariacaoDolar,
'Atualizacao':Atualizacao,
'RealUsuario':RealUsuario,
'DolarUsuario':DolarUsuario,
'CotacaoEuro':CotacaoEuro,
'VariacaoEuro':VariacaoEuro,
'RealUsuario2':RealUsuario2,
'recomend':recomend,
'recomend2':recomend2,
'Oi':Oi,
'Oi2':Oi2
});
app.get('/home2', function (req,res) {
http.get('https://www.quandl.com/api/v3/datasets/BCB/432.json?api_key=d1HxqKq2esLRKDmZSHR2', function (res3) {
var body = '';
res3.on('data', function (chunk) {
body += chunk;
});
res3.on('end', function () {
var x=json.dataset.data[0][1];
console.log("My JSON is "+x); });
});
});
});
});
});
Here is a print of the error screen I get:
When you want to request an https resource, you need to use https.get, not http.get.
https://nodejs.org/api/https.html
As a side note to anyone looking for a solution from Google... make sure you are not using an http.Agent with an https request or you will get this error.
The reason for this error is that you are trying to call a HTTPS URI from a HTTP client. The ideal solution would have been for a generic module to figure out the URI protocol and take the decision to use HTTPS or HTTP internally.
The way I overcame this problem is by using the switching logic on my own.
Below is some code which did the switching for me.
var http = require('http');
var https = require('https');
// Setting http to be the default client to retrieve the URI.
var url = new URL("https://www.google.com")
var client = http; /* default client */
// You can use url.protocol as well
/*if (url.toString().indexOf("https") === 0){
client = https;
}*/
/* Enhancement : using the URL.protocol parameter
* the URL object , provides a parameter url.protocol that gives you
* the protocol value ( determined by the protocol ID before
* the ":" in the url.
* This makes it easier to determine the protocol, and to support other
* protocols like ftp , file etc)
*/
client = (url.protocol == "https:") ? https : client;
// Now the client is loaded with the correct Client to retrieve the URI.
var req = client.get(url, function(res){
// Do what you wanted to do with the response 'res'.
console.log(res);
});
Not sure why, but the issue for me happened after updating node to version 17, i was previously using version 12.
In my setup, i have node-fetch using HttpsProxyAgent as an agent in the options object.
options['agent'] = new HttpsProxyAgent(`http://${process.env.AWS_HTTP_PROXY}`)
response = await fetch(url, options)
Switching back to node 12 fixed the problem:
nvm use 12.18.3
I got this error while deploying the code.
INFO error=> TypeError [ERR_INVALID_PROTOCOL]: Protocol "https:" not supported. Expected "http:"
at new NodeError (node:internal/errors:372:5)
To fix this issue, I have updated the "https-proxy-agent" package version to "^5.0.0"
Now the error was gone and it's working for me.

Pass Buffer to ChildProcess Node.js

Here I have on Node.Js where I want to do Image Processing in a Sub Process.
As you will see I take the file image.jpg and want to write it back to hello.jpg in a subprocess:
var node = require('child_process').spawn('node',['-i']);
var fs = require('fs');
node.stdout.on('data',function(data) {
var fs = require('fs');
var gm = require('gm').subClass({ imageMagick: true });
gm(data)
.resize(500, 500)
.toBuffer("jpg", function(err, buffer) {
if (err) {
console.log(err);
}else{
fs.writeFile("hello.jpg", buffer);
}
});
});
var buffer = fs.readFileSync(__dirname + "/image.jpg");
node.stdin.write(buffer);
However when I run this file I get this error:
[Error: Stream yields empty buffer]
For me it seems like the buffer is not passed correctly to the subprocess?
What do I wrong? What can I do to run Image Processing in a subtask. For me its important that Its not read from a file in the subprocess. Because I want to read one File again and then send the buffer to several subprocesses that do Image Transformations. Thanks!
You are not doing any work in a subprocess. It is just node -i and nothing else. All your image processing happens in the main process.
To fix it, you can actually run another Node process and give it some script to execute, say worker.js:
process.stdin.on('data',function(data) {
var fs = require('fs');
var gm = require('gm').subClass({ imageMagick: true });
gm(data)
.resize(500, 500)
.toBuffer("jpg", function(err, buffer) {
if (err) {
console.log(err);
}else{
fs.writeFile("hello.jpg", buffer);
}
});
});
Then you would create a subprocess from your main script:
var node = require('child_process').spawn('node', ['worker.js']);
var fs = require('fs');
var buffer = fs.readFileSync(__dirname + "/image.jpg");
node.stdin.end(buffer);
Note that I used node.stdin.end in the last line to terminate the worker.
Take a look at cluster module for the alternative approach.

Send message between two independent running processes in Node.js

I've got an Adobe AIR Application on the local machine that communicates with an remote node.js server script (socket-script.js) via socket connection.
Furthermore i start a new node.js process through command line and send some additional arguments to a second server script (terminal-script.js).
Question: How can i send the arguments from the terminal-script.js to socket-script.js? Afterwards the socket-script.js should broadcast the
args to the AIR Application. Anyone an idea how to connect the two independent running processes in Node.js? Thanks.
Illustration link
Use the server to communicate between processes:
socket-script.js
var net = require('net');
var app = null;
var server = net.createServer(function(socket) {
socket.on('data', function(data){
if(data.indexOf('terminal:') >-1){
if(app){
app.write(data);
}
} else if(data.indexOf('app:') >-1){
app = socket;
}
});
});
terminal-script.js:
var net = require('net');
var client = net.connect({port: 9001}, function() {
client.write('terminal:' + process.argv[2]);
});
app:
var net = require('net');
var client = net.connect({port: 9001}, function() {
client.write('app:connect');
});
client.on('data', function(data){
if(data.indexOf('terminal:') >-1){
// got terminal data
}
});
The only way that I conceive of to make this work is something like this:
1) You'll need to have terminal-script.js be listening on a socket. Like so:
var arguments = process.args.splice(2);
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(arguments[0]);
}).listen(8000, '127.0.0.1');
2) Just make a request from socket-script to the terminal script:
//somewhere in socket-script use this to grab the value from the terminal script.
var http = require('http');
var options = {
host: 'terminal-script-host.com',
port: '8000',
path: '/'
};
var req = http.get(options, function(res) {
res.on('data', function (data) {
console.log('socket-script got the data from terminal-script: ' + data);
});
});
Not sure if this helps. But I can tell you that it would be nearly impossible to "inject" something into the socket-script from the terminal-script, not in a way that would work with the same request anyways.

Require in nodejs

The argument of require(...) in node.js is a filename. If I had a module source code in a string code, could I somehow call require(code) and load functions from that string?
I put this into a function for reuse. It creates a file in the os temp directory based on a random hash, requires it and then deletes it.
var fs = require('fs'),
os = require('os'),
crypto = require('crypto');
function requireString(moduleString) {
var token = crypto.randomBytes(20).toString('hex'),
filename = os.tmpdir() + '/' + token + '.js',
requiredModule = false;
// write, require, delete
fs.writeFileSync(filename, moduleString);
requiredModule = require(filename);
fs.unlinkSync(filename);
return requiredModule;
}
Then you can do:
var carString = "exports.start = function(){ console.log('start'); };",
car = requireString(carString);
console.log("Car:", car);
This is still more of a workaround, but more convenient to use, I think.
A work around could be to write the module source code to a temporary file ./tmp-file.js and then require('./tmp-file'), and then remove the file.
This is probably not optimal because you would either have to block and write the file synchronously, or put everything requiring that module in the callback to the async write.
A working example for async file write (gist - also includes sync file write):
var http = require('http');
var fs = require('fs');
var helloModuleString = "exports.world = function() { return 'Hello World\\n'; }";
fs.writeFile('./hello.js', helloModuleString, function (err) {
if (err) return console.log(err);
var hello = require('./hello');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(hello.world());
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');
});
Results in:
$ curl 127.0.0.1:1337
> Hello World

Categories