How can I call a Javascript function in python? - javascript

I'm trying to make a snake game with Electron and deep reinforcement learning. The reinforcement learning stuff I do in python and the game in Javascript. Now how can I call a function like this in python?
makeSomeThing(x) {
}
or
getValue() {
return x;
}

Please build your python script to an executable binary file. You can use pyinstaller to package your python scripts to a standalone executable file.
Then you can spawn this binary file at your Electron project like this.
import { spawn } from 'child_process';
// in my case I'm storing the file at bin directory at the root path of the application
// You can change this whatever you want
const pythonPath = const basicURL = process.env.NODE_ENV === 'development'
? path.join(__dirname, './bin/xxxx')
: path.join(process.resourcesPath, 'bin', 'xxxx');
const params = ['arg1', 'arg2']; // params that your python scripts need.
const pythonChildProcess = spawn(pythonPath, params);
pythonChildProcess.stdout.on('data', data => {
console.log(`stdout: ${data}`);
// Here is where the output goes
});
pythonChildProcess.stderr.on('data', data => {
console.log(`tderr: ${data}`);
// Here is where the error output goes
});
pythonChildProcess.on('close', code => {
console.log(`closing code: ${code}`);
// Here you can get the exit code of the script
});

Well, I don't know if it is the answer that you expect, but I would create a standalone python service that exposes some API.
Create a client in electron and use python API to send data and get processed information from the Python service
You cant call Javascript API from python. You need something in the middle anyway.

Related

python script in a typescript file

how do I use my python script in a typescript file? Like how do I link it ? I have to traverse a xml file which I have a python code which updates some details and wanted to use it in the typescript server file.
Like the server should update some details in a xml file. this update functionality is implemented in python and I wanted to use it in the typescript server code.
You can run the python script in node using exec(): https://nodejs.org/api/child_process.html#child_processexeccommand-options-callback
A minimal example assuming you have python3 installed on the machine running your node script could be:
// shell.py
print('printed in python')
// server.js
import {exec} from 'child_process'
//if you don't use module use this line instead:
// const { exec } = require('child_process')
exec('python3 shell.py', (error, stdout, stderr) => {
if (error) {
console.log(`error: ${error.message}`);
}
else if (stderr) {
console.log(`stderr: ${stderr}`);
}
else {
console.log(stdout);
}
})
// using it in the shell
% node server.js
// should output this:
printed in python
This way you could traverse your XML file, change it and output it to the js/ts file, or save it as a file and just read that via your js/ts code.

How do you call a node.js function from a HTML page?

I'm following a node.js and Azure service bus tutorial.
I'm able to run the below as a node app, however, I am struggling to call a node function from my HTML page:
Note that all the files have correctly loaded with the node http-server module, however, when I call the main function, I get the following error:
ReferenceError: ServiceBusClient is not defined
Node.js function:
const { ServiceBusClient } = require("#azure/service-bus");
// Define connection string and related Service Bus entity names here
const connectionString ="";
const queueName = "";
async function main() {
const sbClient = ServiceBusClient.createFromConnectionString(
connectionString
);
const queueClient = sbClient.createQueueClient(queueName);
const sender = queueClient.createSender();
try {
for (let i = 0; i < 1; i++) {
const message = {
body: "{}",
label: "Contact",
userProperties: {
myCustomPropertyName: "my custom property value",
},
};
console.log(`Sending message: ${message.body}`);
await sender.send(message);
}
await queueClient.close();
} finally {
await sbClient.close();
}
}
main().catch((err) => {
console.log("Error occurred: ", err);
});
Any help much appreciated.
Summarize the comments from Pogrindis for other communities reference:
Node is backend business logic, the HTML is the front end and so there is no direct communication to the methods in Node. We could implement some webserver like express to allow http calls to be made to the node server, and from there we could call the business logic. And for the error of service bus, we need to implement the ServiceBusClientOptions interface.
To use Azure SDK libraries on a website, you need to convert your code to work inside the browser. You can do this using bundler such as rollup, webpack, parcel, etc. Refer to this bundling docs to use the #azure/service-bus library in the browsers.
Moreover, the code in your sample looks like it is using version 1.
Version 7.0.0 has been recently published. Refer to the links below.
#azure/service-bus - 7.0.0
Samples for 7.0.0
Guide to migrate from #azure/service-bus v1 to v7

Passing sensitive information in the req object Node.js server

I am an ex-PHP Laravel developer and I am trying to explore other options right now, currently using Node.js, Sequelize, Koa and Next.js to build a small app.
When sequelize is initialized, a models folder gets created automatically and it has along the lines the following code.
...
fs
.readdirSync(__dirname)
.filter(file => {
console.log('Filer file: ', file)
return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js');
})
...
Which is working fine when imported in the main server.js file.
I am trying to figure out what is the best way to include this in any of the other files, in my case I need to have access to it via the newly release API routes from Next.js /api/{endpoint} (https://nextjs.org/docs/api-routes/introduction).
If I import the file there __dirname (from the main sequelize models file) is the root directory of my machine which makes me think that if this code is automatically generated code by their CLI tool I am probably doing something wrong.
One way I found to make this work is by passing the db object via the req object in the server.js file.
router.get('/api/*', async (ctx) => {
/**
* There has to be a better way
*/
ctx.req.db = db
await handle(ctx.req, ctx.res);
ctx.respond = false;
ctx.res.statusCode = 200;
});
Is there better way to handle all of this?

Read environment variables and then replace them in client-side JS when using gulp for building prod or dev code

So lets say I have some code in js
const myApiKey = 'id_0001'
But instead of harcoding it I want to put it in some bash script with other env vars and read from it and then replace it in the JS
So lets say for prod I would read from prod-env.sh or for dev I would read them from dev-env.sh and then gulp or some other tool does the magic and replaces MY_API_KEY based on whatever is established inside of prod-env.sh or dev-env.sh.
const myApiKey = MY_API_KEY
Update: I want to add I only care about unix OS, not concerned about windows. In golang there is way to read for example envVars.get('MY_API_KEY'), I'm looking for something similar but for JS in the client side.
If you're using gulp, it sounds like you could use any gulp string replacer, like gulp-replace.
As for writing the gulp task(s). If you are willing to import the environment into your shell first, before running node, you can access the environment via process.env
gulp.task('build', function(){
gulp.src(['example.js'])
.pipe(replace('MY_API_KEY', process.env.MY_API_KEY))
.pipe(gulp.dest('build/'));
});
If you don't want to import the environment files before running node, you can use a library like env2 to read shell environment files.
Another option would be to use js/json to define those environment files, and load them with require.
prod-env.js
{
"MY_API_KEY": "api_key"
}
gulpfile.js
const myEnv = require('./prod-env')
gulp.task('build', function(){
gulp.src(['example.js'])
.pipe(replace('MY_API_KEY', myEnv.MY_API_KEY))
.pipe(gulp.dest('build/'));
});
Also, for a more generic, loopy version of the replace you can do:
gulp.task('build', function () {
stream = gulp.src(['example.js']);
for (const key in process.env) {
stream.pipe('${' + key + '}', process.env[key]);
}
stream.pipe(gulp.dest('build/'));
});
In that last example I added ${} around the environment variable name to make it less prone to accidents. So the source file becomes:
const myApiKey = ${MY_API_KEY}
This answer is an easy way to do this for someone who doesn't want to touch the code they are managing. For example you are on the ops team but not the dev team and need to do what you are describing.
The environment variable NODE_OPTIONS can control many things about the node.js runtime - see https://nodejs.org/api/cli.html#cli_node_options_options
One such option we can set is --require which allows us to run code before anything else is even loaded.
So using this you can create a overwrite.js file to perform this replacement on any non-node_modules script files:
const fs = require('fs');
const original = fs.readFileSync;
// set some custom env variables
// API_KEY_ENV_VAR - the value to set
// API_KEY_TEMPLATE_TOKEN - the token to replace with the value
if (!process.env.API_KEY_TEMPLATE_TOKEN) {
console.error('Please set API_KEY_TEMPLATE_TOKEN');
process.exit(1);
}
if (!process.env.API_KEY_ENV_VAR) {
console.error('Please set API_KEY_ENV_VAR');
process.exit(1);
}
fs.readFileSync = (file, ...args) => {
if (file.includes('node_modules')) {
return original(file, ...args);
}
const fileContents = original(file, ...args).toString(
/* set encoding here, or let it default to utf-8 */
);
return fileContents
.split(process.env.API_KEY_TEMPLATE_TOKEN)
.join(process.env.API_KEY_ENV_VAR);
};
Then use it with a command like this:
export API_KEY_ENV_VAR=123;
export API_KEY_TEMPLATE_TOKEN=TOKEN;
NODE_OPTIONS="--require ./overwrite.js" node target.js
Supposing you had a script target.js
console.log('TOKEN');
It would log 123. You can use this pretty much universally with node, so it should work fine with gulp, grunt, or any others.

Execute a JS file (with logs, etc...) inside another NodeJS process

Here is my problem, I want to create a CLI that automatically runs a test. Without the CLI, I'm able to run everything perfectly with the node command:
node test.js
Basically, I want to do the exact same thing as the command before, so I googled for a technique that does this. I found this:
#!/usr/bin/env node
'use strict';
const options = process.argv;
const { execFile } = require('child_process');
const child = execFile('node', ['../dist/test.js'], (error, stdout, stderr) => {
if (error) {
throw error;
}
console.log(stdout);
});
This method doesn't work for me because, in the test.js file, I'm using the ora package. And because this package is making real-time animations, it doesn't come in stdout.
Is there any way of executing in real time (without subprocess) my test.js using Node? I'm open to other methods, but I want to publish the CLI on NPM, so keep in mind that it has to be in JavaScript 😊.
You can find every file that I've talked here on GitHub. Normally, you wouldn't need this link, but I'm giving it to you if you need to have a closer look.
You should simply call your test() function from your CLI code, after requiring the module that defines it. Have a look at mocha and jasmine: you will see that while both tools provide a CLI, they also provide instructions for invoking the test frameworks from arbitrary JS code.
I can't think of a way without a sub-process. but this may help.
The child process exec will not work with the continuous output commands as it buffers the output the process will halt when that buffer is full.
The suitable solution is spwan :
var spwan = require('child_process').spwan
var child = spwan('node', ['../dist/test.js'])
child.stdout.on('data', function(data) {
console.log(data)
})
child.stderr.on('data', function(data) {
console.log(data)
})
Here is my solution, you can use the fs library to get the code of the file, and then, you simply use eval to execute in the same process.
const fs = require("fs");
function run(file) {
fs.readFile(file, (err, data) => {
eval(data.toString('utf8'))
})
}

Categories