I spawn a python child process in javascript (for coding a Bot with Microsoft Botframework) like this:
async function searchForRelevantDoc (context) {
var msg = context.activity.text;
var spawn = require('child_process').spawn,
py = spawn('python', ['../path/to/file.py', msg]),
output = '';
py.stdin.setEncoding = 'utf-8';
py.stdout.on('data',
(data) => {
output += data.toString();
console.log('output was generated: ' + output);
});
// Handle error output
py.stderr.on('data', (data) => {
// As said before, convert the Uint8Array to a readable string.
console.log('error:' + data);
});
py.stdout.on('end', async function(code){
console.log('output: ' + output);
console.log(`Exit code is: ${code}`);
// "return" is probably wrong, what should be done instead?
return output;
}
});
}
I want output
to be returned as the value of the function searchForRelevanceDoc()
. How can this be done? I am not able to use
await context.sendActivity(output)
instead of the return statement. Error message:
TypeError: Cannot perform 'get' on a proxy that has been revoked
Function searchForRelevanceDoc
is called like so:
//in bot.js
const pysearch = require('../bboti/python-search');
class MyBot {
// constructor...
async onTurn(context) {
// ...
var search_engine_answer = pysearch.searchForRelevantDoc(context);
context.sendActivity(search_engine_answer)
// ...
}
}
I spawn a python child process in javascript (for coding a Bot with Microsoft Botframework) like this:
async function searchForRelevantDoc (context) {
var msg = context.activity.text;
var spawn = require('child_process').spawn,
py = spawn('python', ['../path/to/file.py', msg]),
output = '';
py.stdin.setEncoding = 'utf-8';
py.stdout.on('data',
(data) => {
output += data.toString();
console.log('output was generated: ' + output);
});
// Handle error output
py.stderr.on('data', (data) => {
// As said before, convert the Uint8Array to a readable string.
console.log('error:' + data);
});
py.stdout.on('end', async function(code){
console.log('output: ' + output);
console.log(`Exit code is: ${code}`);
// "return" is probably wrong, what should be done instead?
return output;
}
});
}
I want output
to be returned as the value of the function searchForRelevanceDoc()
. How can this be done? I am not able to use
await context.sendActivity(output)
instead of the return statement. Error message:
TypeError: Cannot perform 'get' on a proxy that has been revoked
Function searchForRelevanceDoc
is called like so:
//in bot.js
const pysearch = require('../bboti/python-search');
class MyBot {
// constructor...
async onTurn(context) {
// ...
var search_engine_answer = pysearch.searchForRelevantDoc(context);
context.sendActivity(search_engine_answer)
// ...
}
}
Share
Improve this question
edited Nov 30, 2019 at 13:26
Lady_Hangaku
asked Nov 29, 2019 at 14:59
Lady_HangakuLady_Hangaku
1191 silver badge11 bronze badges
1
- show stacktrace. – Marios Nikolaou Commented Nov 29, 2019 at 15:24
3 Answers
Reset to default 7The easiest way to return/resolve output
from searchForRelevantDoc
, using async/await
is to use events.once
which was added in Node 11.13.0, and wait for close
event of py
const { once } = require('events'); // Added in Node 11.13.0
async function searchForRelevantDoc (context) {
var msg = context.activity.text;
var spawn = require('child_process').spawn,
py = spawn('python', ['../path/to/file.py', msg]),
output = '';
py.stdin.setEncoding = 'utf-8';
py.stdout.on('data', (data) => {
output += data.toString();
console.log('output was generated: ' + output);
});
// Handle error output
py.stderr.on('data', (data) => {
// As said before, convert the Uint8Array to a readable string.
console.log('error:' + data);
});
py.stdout.on('end', async function(code){
console.log('output: ' + output);
console.log(`Exit code is: ${code}`);
});
await once(py, 'close')
return output;
}
If you're using an older version of Node, you can wrap it in a new Promise
async function searchForRelevantDoc (context) {
// ...
// You can also check for `code` and reject if a non zero code is returned
await new Promise(resolve => py.on('close', resolve));
return output;
}
Then when calling searchForRelevantDoc
you need to use await
or .then
class MyBot {
// constructor...
async onTurn(context) {
// ...
var search_engine_answer = await pysearch.searchForRelevantDoc(context);
context.sendActivity(search_engine_answer)
// ...
}
}
@Marcos Casagrande's answer is more beautiful, I just wanted to add the promise solution as well.
You can just return a new Promise
and wrap the stdout.on
inside the promise.
async function searchForRelevantDoc (context) {
...
return new Promise((res, rej) => {
py.stdout.on('end', async function(code){
console.log('output: ' + output);
console.log(`Exit code is: ${code}`);
// "return" is probably wrong, what should be done instead?
res(output);
})
});
}
Promises hot-load
so whenever you declare a promise the function will start to run. So basically the event will be attached.
Make your function
return new Promise((resovle, reject) => ...)
and resolve needed value