Execute Python script with Node.js - javascript

I am trying to execute Python Script when I click on HTML button. Both files are on a Node.js Server. When I press the button I get this message in the browser console:
app.js:5 Uncaught ReferenceError: runPython is not defined
I am not sure how to write my AJAX script to call the runPython() function on my Node web server file. Below is my code:
index.html
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.3/jquery.js"> </script>
</head>
<body>
<button id="myButton">Run Python Script</button>
<script src="app.js"></script>
</body>
</html>
app.js
$('#myButton').click(function() {
$.ajax({
url: "",
success: function(data) {
runPython();
},
});
});
webserver.js (node.js)
'use strict';
const http = require('http');
const url = require('url');
const fs = require('fs');
const path = require('path');
let mimes = {
'.htm': 'text/html',
'.css': 'text/css',
'.js': 'text/javascript'
}
//Have ajax call it to execute Python Script
function runPython(){
let exec = require('child_process').exec;
exec('python myscript.py', (error, stdout, stderr) => {
console.log(stdout);
});
}
function fileAccess(filepath) {
return new Promise((resolve, reject) => {
fs.access(filepath, fs.F_OK, error => {
if(!error) {
resolve(filepath);
} else {
reject(error);
}
});
});
}
function streamFile(filepath) {
return new Promise((resolve, reject) => {
let fileStream = fs.createReadStream(filepath);
fileStream.on('open', () => {
resolve(fileStream);
});
fileStream.on('error', error => {
reject(error);
});
});
}
function webserver(req, res) {
// if the route requested is '/', then load 'index.htm' or else
// load the requested file(s)
let baseURI = url.parse(req.url);
let filepath = __dirname + (baseURI.pathname === '/' ? '/index.htm' : baseURI.pathname);
let contentType = mimes[path.extname(filepath)];
fileAccess(filepath)
.then(streamFile)
.then(fileStream => {
res.writeHead(200, {'Content-type': contentType});
//res.end(content, 'utf-8');
fileStream.pipe(res);
})
.catch(error => {
res.writeHead(404);
res.end(JSON.stringify(error));
});
}
http.createServer(webserver).listen(3000, () => {
console.log('Webserver running on port 3000');
});
How should I write the AJAX code so that the function in webserver.js will run?

The browser is loading the script at that url. This is treated as either data or text. Browsers don't generally run Python so Working As Intended.

You need to make an ajax request to the server that will run some code that will invoke your python script. You're missing the middle part of that process, and simply requesting the contents of myscript.py as text.
Something like:
$('#myButton').click(function() {
$.ajax({
url: "/invoke-script"
});
});
I am not familiar with Node, but I imagine you have some sort of controller and the ability to execute commands (maybe using https://www.npmjs.com/package/exec-sync). In that controller you then invoke your python script and do what you need with the output.

Think about this script like an executable. If your URL points to some *.exe file, clicking on the URL tells the web browser to download the resource. The same happens to Python script.
If you want to run some python code, try to handle HTTP request instead with simple HTTP server. This is the most common way to execute some actions on HTTP request. Check documentation for SimpleHTTPServer and BaseHTTPServer.
Here and here you can find some code snippet for simple server implementation.

Related

ffmpeg app using node occasionally crashes as file doesn't appear to be read correctly

I have an simple Node application that allows me to pass an AWS S3 URL link to a file (in this case video files). It uses the FFMPEG library to read the video file and return data like codecs, duration, bitrate etc..
The script is called from PHP script which in turn send the data to the Node endpoint and passes the Amazon S3 URL to node. Sometimes for no obvious reasons the video file fails to return the expected values regarding container, codec, duration etc... and just returns '0'. But when I try the exact same file/request again it returns this data correctly e.g container:mp4
I'm not sure but I think the script somehow needs the createWriteStream to be closed but I cannot be sure, the problem is the issue I have found doesn't happen all the time but sporadically so its hard to get to the issue when its difficult to replicate it.
Any ideas?
router.post('/', async function(req, res) {
const fileURL = new URL(req.body.file);
var path = fileURL.pathname;
path = 'tmp/'+path.substring(1); // removes the initial / from the path
let file = fs.createWriteStream(path); // create the file locally
const request = https.get(fileURL, function(response) {
response.pipe(file);
});
// after file has saved
file.on('finish', function () {
var process = new ffmpeg(path);
process.then(function (video) {
let metadata = formatMetadata(video.metadata);
res.send ({
status: '200',
data: metadata,
errors: errors,
response: 'success'
});
}, function (err) {
console.warn('Error: ' + err);
res.send ({
status: '400',
data: 'Something went wrong processing this video',
response: 'fail',
});
});
});
file.on('error', function (err) {
console.warn(err);
});
});
function formatMetadata(metadata) {
const data = {
'video' : metadata.video,
'audio' : metadata.audio,
'duration' : metadata.duration
};
return data;
}
// Expected output
{"data":{"video":{"container":"mov","bitrate":400,"stream":0,"codec":"h264","resolution":{"w":1280,"h":720},"resolutionSquare":{"w":1280,"h":720},"aspect":{"x":16,"y":9,"string":"16:9","value":1.7777777777777777},"rotate":0,"fps":25,"pixelString":"1:1","pixel":1},"audio":{"codec":"aac","bitrate":"127","sample_rate":44100,"stream":0,"channels":{"raw":"stereo","value":2}},"duration":{"raw":"00:00:25.68","seconds":25}}
// Actual output
{"data":{"video":{"container":"","bitrate":0,"stream":0,"codec":"","resolution":{"w":0,"h":0},"resolutionSquare":{"w":0,"h":null},"aspect":{},"rotate":0,"fps":0,"pixelString":"","pixel":0},"audio":{"codec":"","bitrate":"","sample_rate":0,"stream":0,"channels":{"raw":"","value":""}},"duration":{"raw":"","seconds":0}}
Note - this happens sporadically
You are not accounting for a failed fetch from AWS. You should check the status code of the response before you move on to your pipe.
const request = https.get(fileURL, function(response) {
if(response.statusCode == 200)
response.pipe(file);
else
// Handle error case
});

How to download a file with Node.js from google drive api

How to download a file with Node.js from google drive api
I don't need anything special. I only want to download a file from a GoogleDrive, and then save it to a given directory of client.
app.get("/download",function(req,res){
const p38290token = new google.auth.OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI);
p38290token.setCredentials({ refresh_token: token.acc });
const p38290Id = google.drive({
version: "v3",
auth: p38290token,
});
var dest = fs.createWriteStream("./test.png");
try {
p38290Id.files.get({
fileId: "1daaxy0ymKbMro-e-JnexmGvM4WzW-3Hn",
alt: "media"
}, { responseType: "stream" },
(err, res) => {
res.data
.on("end", () => {
console.log("Done");
})
.on("error", err => {
console.log("Error", err);
})
.pipe(dest); // i want to sent this file to client who request to "/download"
}
)
} catch (error) {
}
})
I want to do that just someone come to www.xyz.com/download and file will be download automatically
The issue seems to be with this line:
var dest = fs.createWriteStream("./test.png");
You are using a file system command which is meant to interact with files on the server. Your question makes it clear that you wish for express to deliver the contents of the file over to the client making the HTTP request.
For that you can just use the res parameter of the route callback function. You declare it on this line:
app.get("/download",function(req,res){
In your case I'd remove the dest variable completely and simply pipe the file to res like so:
.pipe(dest);
Have a look at this answer as well.

How can I integrate python with nodejs

I want to use python scripts with my Node.JS server, but whenever I run the node server, the python script doesn't run. It starts the server but no python runs. I think it's in this part of the code but I'm not exactly sure.
My index.js:
app.post("/readPython", (request, response) => {
var dataToSend;
const python = spawn('python', ['python/cookie.py'], "Kevin");
python.stdout.on('data', function (data) {
dataToSend = data.toString();
});
python.stderr.on('data', data => {
console.error(`stderr: ${data}`);
});
python.on('exit', (code) => {
console.log(`child process exited with code ${code}, ${dataToSend}`);
response.sendFile(`${__dirname}/html/result.html`);
});
});
My python script:
import sys
print("Hello World!")
sys.stdout.flush()
I don't know exactly what I should expect but whatever it is, the script isn't running. Any help?
the 3rd argument (options) in spawn() should be an object. I am assuming you are trying to send Kevin as argument.
It should be like
const python = spawn('python', ['helloworld.py',"Kevin"]);
python.stdout.on('data', (data)=> {
console.log(data.toString());
});

Can I response.end() inside request.on(end)?

I'm learning node.js. I have a client form, from which I send to my server some data and refactor it somehow in a module makeRequest. The module returns a promise, which I want to resolve with response to the client.
So I might think that I could do something like this:
let post = '';
const server = http.createServer(function (req, res) {
const readHtml = fs.createReadStream(__dirname + '/view/form.html', 'utf8');
readHtml.pipe(res);
});
server.on('request', processPost);
function processPost(request, response) {
let body = '';
if (request.method === 'POST') {
request.on('data', function (data) {
body += data;
if (body.length > 1e6) {
request.connection.destroy();
}
});
request.on('end', function () {
post = JSON.parse(body);
makeRequest(post.text)
.then(data => {
response.end(data);
})
.catch(err => {
console.log(err);
});
});
}
}
server.listen(3000, 'localhost');
This for me means that as soon as I retreive the refactored data I immediately send it back to client with response.end(data).
But suddenly the data does not return to the client if I do like this. It does, if I write response.end(data) after request.on('end'). But this is synchronous way and therefore when I run such code, there will be no data anyhow.
What can I do to make it work as I want to?
If, as said in a discussion below the question, you just want a default page accessed in a browser, make it conditional
const server = http.createServer(function(req, res) {
if ( req.method == "GET" ) {
const readHtml = fs.createReadStream(__dirname + '/view/form.html', 'utf8');
readHtml.pipe(res);
}
});
This way both GETs and POSTs are handled correctly.
My advice would be to use a more organized approach using any framework, Express should do fine. This way you could be a more clean approach to define different routes and request types.

How would i get code from an external URL and execute it in NodeJS

I need to create a NodeJS script that will auto-update from a script hosted on my VPS. To do this, i need to get code from my VPS and send it to the client, where the client will execute the code as if it was in the client. I don't know how to achieve this...
what i have:
client:
WebSocket = require('ws')
ws = new WebSocket('ws://localhost:8720');
var getinit_init_key = "jN*&gbhh*&G8ihae8rwgh78g&*G&*G&GFUibg&GB*&GVBWG";
var getINITKey = JSON.stringify({ init: getinit_init_key, userip: 'server', reason: 'getUpdate' });
ws.on('open', function open() {
ws.send(getINITKey);
});
ws.on('message', function(data, flags) {
d = JSON.parse(data)
d.x();
});
server:
update1 = require('./socks.js') //socks.js is my code
update2 = update1.init
update = JSON.stringify({ x: update2.toString() });
var ws = require("nodejs-websocket");
var server = ws.createServer(function(conn) {
console.log("Got new connection!");
conn.on("text", function(data) {
try {
conn.sendText(update)
console.log(JSON.parse(update).x);
}
catch (error) {
console.log("RECOVERED FROM ERROR: " +error)
}
});
conn.on("close", function(code, reason) {
console.log('Sent Update to User');
});
conn.on("error", function(error) {
console.log("Recovered from Error");
});
}).listen(8720);
You can actually put your code as a js file on the external source and in your client side code using the <script> tag you can import the code, like how jquery.js can be used from cdn.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
After you import it you can directly use the methods in that js file.

Categories