Waiting for a Python's spawn when executing a Javascript file - javascript

I was making a Discord bot with 'discord.js' but I need to work with Python's Pandas module.
I need to execute a Python function inside a Javascript one that updates a '.csv' file and then the Javascript command continues and send that updated '.csv' file.
For this, I need that the Javascript's command waits for the Python's spawn to finish executing and then proceed with the rest of the command, but I can't get it to work.
To explain my problem further, I created a simple example:
Inside the Javascript's code I have this written
async function main() {
console.log("J: Hey...")
console.log("J: I can't count to 5...")
console.log("J: Can you help me, Mr. Python?")
var spawn = require('child_process').spawn,
py = spawn('python', [`main.py`]),
data = [],
dataString = ''; // python's console
py.stdout.on('data', function(data){
dataString += data.toString();
});
py.stdout.on('end', function(){
console.log(dataString)
});
py.stdin.write(JSON.stringify(data));
py.stdin.end();
console.log("J: Thank you, mister!")
}
main()
And inside the Python's code I have this:
def main():
print("P: Of course!")
print("P: It's like this:")
for i in range(5): print(f"P: {i + 1}")
print("P: Hope that it helps!")
if __name__ == "__main__":
main()
This is what I need after the code is executed:
J: Hey...
J: I can't count to 5...
J: Can you help me, Mr. Python?
P: Of course!
P: It's like this:
P: 1
P: 2
P: 3
P: 4
P: 5
P: Hope that it helps!
J: Thank you, mister!
But this is what I receive:
J: Hey...
J: I can't count to 5...
J: Can you help me, Mr. Python?
J: Thank you, mister!
P: Of course!
P: It's like this:
P: 1
P: 2
P: 3
P: 4
P: 5
P: Hope that it helps!
I'm not expert in asynchronous programming, so I don't know much about how to get to the correct solution.
I tried to explore new forms to execute Python's code inside Javascript, but I couldn't get so far.
Thank you in advance!

Node’s child_process.spawn method returns a ChildProcess object. You can set handlers for the child process’s events, to get a signal when the process closes, and continue with your local code in that. You would probably want to listen for other events, like error, exit, etc. too, just in case. There are some pretty good examples in the Node documentation: https://nodejs.org/api/child_process.html#child_processspawncommand-args-options

Related

Exported File Scope Variables of ES6 Javascript

Following up on What is file scope in javascript, from which I know that there might or might not be a so-called File Scope Variables, however, I do remember reading such term somewhere but couldn't find it any more, except the Q&A of What is file scope in javascript. Anyway,
I want to know what's exact behavior definition for such exported file scope variables.
Because I was trying to toggle my bot dynamically but wasn't able to, eliminating factors one by one, and it finally came down on me it is because of such "exported file scope variables", and me not understanding their behavior. Take a look at the following extremely simplified bot application:
VarTestFileA.js
function nextBot() {
BotC = !BotC
return BotA[BotC]
}
function logBot() {
console.log("I:", bot)
}
const BotA = {true: {"token": 2}, false: {"token":3}}
let BotC = true
var bot = BotA[BotC]
module.exports = {
bot,
nextBot,
logBot,
}
VarTestFileB.js
const bt = require('./VarTestFileA')
console.log(bt.bot)
bt.bot = bt.nextBot()
bt.logBot()
console.log("O:", bt.bot)
bt.bot = bt.nextBot()
bt.logBot()
console.log("O:", bt.bot)
bt.bot = bt.nextBot()
bt.logBot()
console.log("O:", bt.bot)
You may know (even without running it) that no matter how I did, the bt.bot cannot be toggled. Here is the output:
$ node VarTestFileB.js
{ token: 2 }
I: { token: 2 }
O: { token: 3 }
I: { token: 2 }
O: { token: 2 }
I: { token: 2 }
O: { token: 3 }
Also, I tried to toggle bot from within VarTestFileA.js, it works within it, but console.log("O:", bt.bot.token) never shows the updated value. All and all,
It all comes down to exact behavior definition of such exported file scope variables, because if putting them in the same file, it runs perfectly fine. Hence the question.
The behavior is quite straight forward, and quite interesting at the same time. The statement const bt = require('./VarTestFileA') creates an object copy of the exported object, and where we used variables (e.g bot) - values are passed instead of reference, but where we passed a Function then a reference is passed because functions are objects in JS.
From VarTestFileA.js we exported { bot, nextBot, logBot } so dt in essence is actually equal to:
dt = {
bot : bot, //copy of old bot = BotA[BotC] which equals {"token": 2}
nextBot: nextBot, //reference to nextBot() which has access to bot in file A
nextBot: logBot , //reference to logBot () which has access to bot in file A
}
Now coming to VarTestFileB.js where we print and try to understand the behavior, let's look at how each statement behaves:
First Statement:
console.log(bt.bot) will print {"token": 2} because bot was passed by value and not reference.
Second Statement:
bt.bot = bt.nextBot() this actually changes value of dt.bot and not the true bot in file A. So bt.bot will have the toggled value, but the actual bot declared in file A is still the same because it hasn't been changed. That now takes us to the third statement:
Third Statement:
bt.logBot(), this prints the initial value of bot in file A. Because it hasn't been changed.
So the real answer here is, based on this behavior we can declare that if we hold references of the variables in File A, then we can change them from another file. But can I really provide evidence for this? Well! yes, let's see how below
To test this, let's create another method in File A;
function getBot(){
return bot;
}
And then modify the nextBot as follows:
function nextBot() {
BotC = !BotC
bot = BotA[BotC]
}
and then export references to these methods;
module.exports = {
getBot,
nextBot,
logBot,
}
So we can now perform the same experiments and try to print out the old test from the question:
const bt = require('./VarTestFileA')
console.log(bt.getBot())
bt.nextBot()
bt.logBot()
console.log("O:", bt.getBot())
bt.nextBot()
bt.logBot()
console.log("O:", bt.getBot())
bt.nextBot()
bt.logBot()
console.log("O:", bt.getBot())
And the output is as follows:
{ token: 2 }
I: { token: 3 }
O: { token: 3 }
I: { token: 2 }
O: { token: 2 }
I: { token: 3 }
O: { token: 3 }
The results are interesting because now the bot from File A seems to be toggling as expected.
In Conclusion, the issue is passing properties either by reference or value. bot from your initial code is passed as by value, it's not a complex item or it's not declared as type Object but holds a simple object as value. So there's no way to pass bot by reference. I stand to be corrected but I don't think variables that holds a primitive value like a Boolean in JavaScript or simple objects as values can be passed by reference. But functions are complex types, meaning they are Objects, hence they are passed by reference.
I hope you find this in order.

How to call pre-existing WebAssembly code from Emscripten

I've made a compiler from my programming language (called AEC) targeting WebAssembly. However, that compiler only produces WebAssembly Binary Toolkit (WABT) compatible code, as I couldn't find sufficient documentation for the assembly compatible with Emscripten. So, how can I call the functions in that language from Emscripten-compatible C or C++?
Previously, I made a compiler for that language targeting x86, and it was rather easy to use C++ to interact with code written in that language. The same, however, doesn't seem to be true when using WebAssembly.
Let's say I have this code in AEC:
Function plusOne(Integer32 integer) Which Returns Integer32 Does
Return integer + 1;
EndFunction
I compile it as follows:
[teo.samarzija#teos-acer-laptop debug]$ ../AECforWebAssembly/aec *.aec
Running the tests...
All the tests passed.
Reading the file...
All characters read!
Tokenizing the program...
Finished tokenizing the program!
Parsing the program...
Finished parsing the program!
Compiling the program...
Compilation finished!
Saving the assembly in file "plusOne.wat"...
Assembly successfully saved, quitting now.
[teo.samarzija#teos-acer-laptop debug]$ wat2wasm plusOne.wat
Now, let's say I want to call it from a C code such as this one:
#include <stdio.h>
extern int plusOne(int);
int main() {
printf("plusOne(4)=%d\n",plusOne(4));
return 0;
}
How do I compile the C program to be able to do that? If I try it in an analogous way I could do it with my AEC compiler targeting x86 assembly, I get this error:
[teo.samarzija#teos-acer-laptop debug]$ emcc -o test.html test.c plusOne.wasm
emcc: error: plusOne.wasm: Input file has an unknown suffix, don't know what to do with it!
So, what should I do?
The following NodeJS code accomplishes what I want:
const FileSystem = require('fs');
const wasmFileContent = FileSystem.readFileSync("plusOne.wasm");
let stack_pointer = new WebAssembly.Global({value : 'i32', mutable : true}, 0);
let memory = new WebAssembly.Memory({initial : 1, maximum : 1});
let importObject = {
JavaScript : {stack_pointer : stack_pointer, memory : memory}
};
WebAssembly.instantiate(wasmFileContent, importObject).then((results) => {
const exports = results.instance.exports;
let plusOne = exports.plusOne;
console.log("plusOne(4)=", plusOne(4));
});
So, how can I do that in C or C++ using Emscripten?

problems on learnyounode exercise 5

Hi guys im trying to solve the exercises from nodeschool, i started with learnyounode, people recomende it a lot for beginners, the exercise question is this:
# LEARN YOU THE NODE.JS FOR MUCH WIN!
## FILTERED LS (Exercise 5 of 13)
Create a program that prints a list of files in a given directory,
filtered by the extension of the files. You will be provided a directory
name as the first argument to your program (e.g. '/path/to/dir/') and a
file extension to filter by as the second argument.
For example, if you get 'txt' as the second argument then you will need to
filter the list to only files that end with .txt. Note that the second
argument will not come prefixed with a '.'.
Keep in mind that the first arguments of your program are not the first
values of the process.argv array, as the first two values are reserved for
system info by Node.
The list of files should be printed to the console, one file per line. You
must use asynchronous I/O.
─────────────────────────────────────────────────────────────────────────────
## HINTS
The fs.readdir() method takes a pathname as its first argument and a
callback as its second. The callback signature is:
function callback (err, list) { /* ... */ }
where list is an array of filename strings.
Documentation on the fs module can be found by pointing your browser here:
file://C:\Users\Filipe\AppData\Roaming\npm\node_modules\learnyounode\node_
apidoc\fs.html
You may also find node's path module helpful, particularly the extname
method.
Documentation on the path module can be found by pointing your browser
here:
file://C:\Users\Filipe\AppData\Roaming\npm\node_modules\learnyounode\node_
apidoc\path.html
─────────────────────────────────────────────────────────────────────────────
» To print these instructions again, run: learnyounode print
» To execute your program in a test environment, run: learnyounode run
program.js
» To verify your program, run: learnyounode verify program.js
» For help run: learnyounode help
i tried to solve the exercise doing this:
var fs = require('fs');
fs.readdir(process.argv[2],process.argv[3],function(err,list){
for(var i = 0;i<list.length;i++)
{
var fileParts = list[i].split(".");
if(fileParts[1] == process.argv[3]){
console.log(list[i] + "\n");
}
}
});
why it doesnt work, i dont know what i am doing wrong, if someone can give me a tip to solve this i appreciate a lot, since the solutions on web are quite bit strange.
Hm, I just tested your code and it actually runs fine for me. Verify returns with solved. Not sure what you are experiencing. Btw.: put in at least some error handling. Below my solution:
const fs = require('fs');
const test = '.' + process.argv[3]
fs.readdir(process.argv[2], (err, data) => {
if (err) {
console.error(err);
} else {
data.filter(file => {
if (file.substring(file.length - test.length) === test) {
console.log(file)
}
})
}
});

Where is a way to run javascript code remotely?

I want to be able to run live code remotely. Therefor, I want to be able to run some arbitrary code on machine A and then, transfer some of that code to machine B and continue running it from machine B.
I find out that I can get the source code of any function via fn.toString().
Example:
var foo = function(a, b) { return a + b; }
console.log(foo.toString()); // prints "function (a, b) { return a + b; }"
So far so good, but what happens in this case?
var bar = (function() {
var x = 5;
return function(a) { return a + x; }
})();
console.log(bar.toString()); // prints "function (a) { return a + x; }"
In this case there is no way to get the variable x, so I can't run it on a remote machine.
Any suggestions?
The reason your second function returns the following as a string
function(a) { return a + x; }
is because you have an anonymous function that returns the function above. "bar" is then defined as that function, and not the anonymous one. Also, given that your returned function is localized, then you cannot run it verbatim. Instead, you can use the variable that holds it, "bar()", and once it runs, it will know the value of x.
What you do need is a js runner, but AFAIK there is none yet(?)
What it should be:
You would have a computer called "a runner" which is a slave and only waiting for code to be pushed on it. Another master computer/process would have access to this slave runner and push a block of code to be executed.
Right now, to what I know, there is no way to easily split your code and just run it remotely but one way I would see to achieve this would be to set up an RPC server which would get the source code as an argument and execute that one using exec(). You could, for instance, do this using a JSON-RPC server. The JSON-RPC client would then post the block of code and the client return the result as a JSON object.
But this would only give you back a JSON object and you still have to serialize your function or code to be run remotely. It should, however, be good enough for most of the use. I bet there should be serverless lambda-like services doing this even with a regular POST i.e. you would post source code to this service and get the result in the response.
I hope there will be "one day" a kind of remote worker where instead of running the code in another thread "locally" that one would be run "remotely". Please comment if you ever saw such a "remote worker".

Native function [.sort()] not recognized inside event handler

Environment: SeaMonkey (FireFox 20.0)
I'm trying to do a simple sort: Either inside a worker itself OR inside its postMessage handler.
(All code samples from inside the top level (.html) file).
works:
function a() {
var xyzzy = [40, 1, 5, 200];
xyzzy.sort();
};
fails: (Error: TypeError: xyzzy.sort is not a function)
var lrw0 = new Worker('lrw0.js');
lrw0.onmessage = function (event) {
var xyzzy = [40, 1, 5, 200];
xyzzy.sort();
};
After the postMessage event the handler has the same context and scope as did the worker. Fair enough. Needless to say the sort fails inside the worker itself. Seems as if a utility library cannot be accessed?
Utterly defeated. I have spent days on this - no doubt reading the solution somewhere without having understood it. Any contributions (including 'rude but informative') gratefully accepted. I fully appreciate the necessity of mercilessly punishing newbies.
Neither of those examples will work until you fix the call to the Array.sort method
Syntax
array.sort([compareFunction])
Javascript
function a() {
var xyzzy = [40, 1, 5, 200];
xyzzy.sort(); // notice the difference
console.log(xyzzy);
};
a();
On jsfiddle

Categories

Resources