-
Notifications
You must be signed in to change notification settings - Fork 15
Conversation
This is my attempt so far to connect the streams. Unfortunately this is more complex than a call to My attempt fails as soon as at the end of const out = new stream.PassThrough();
const err = new stream.PassThrough();
const in_ = new stream.PassThrough();
out.on('data', (chunk) => {
ctx.externs.out.write(chunk);
});
err.on('data', (chunk) => {
ctx.externs.err.write(chunk);
});
const fn_err = label => err => {
console.log(`ERR(${label})`, err);
};
out.on('error', fn_err('out'));
err.on('error', fn_err('err'));
child.stdout.on('error', fn_err('stdout'));
child.stderr.on('error', fn_err('stderr'));
child.stdin.on('error', fn_err('stdin'));
// pipe streams to child process
// out.pipe(child.stdin);
child.stdout.pipe(out);
child.stderr.pipe(err);
let rslv_sigint;
const p_int = new Promise(rslv => rslv_sigint = rslv);
ctx.externs.sig.on((signal) => {
if ( signal === signals.SIGINT ) {
rslv_sigint({ is_sigint: true });
}
});
let data, done;
const next_data = async () => {
let is_sigint = false;
({ value: data, done, is_sigint } = await Promise.race([
p_int, in_.read(),
]));
if ( is_sigint ) {
console.log('SIGINT HAPPENED HERE');
throw new Exit(130);
}
// ({ value: line, done } = await in_.read());
}
for ( await next_data() ; ! done ; await next_data() ) {
console.log('WRITING SOMETHING')
child.stdin.write(data);
}
// wait for the child to exit
console.log('WAITING');
await new Promise((resolve, reject) => {
child.on('exit', (code) => {
ctx.externs.out.write(`Exited with code ${code}`);
if (code === 0) {
resolve();
} else {
reject(new Error(`Exited with code ${code}`));
}
});
});
console.log('DONE WAITING'); |
512a389
to
9a11569
Compare
It complaining that the WritableStream is closed is a complete mystery to me. I bumped into that when I was first trying to make it work originally. What confuses me is that passing a Node.js Stream object to With some trial and error, I've found that it accepts passing in the process's streams. This isn't perfect, but it's a lot closer than what I had before. I've updated my code to do that (and to shrink the |
I'll leave the PR open in the meantime. This is worth continued investigation because passing the streams on |
Thought I was getting somewhere with this today, but I'm still a little stumped...
I tried a hack, of using Anyway, this feels promising. |
9a11569
to
67edddd
Compare
Yep, |
Spawn should have an exit event so we can resolve a Promise object when the process is done |
67edddd
to
b7e9cf1
Compare
Some progress, finally! It's still not perfect, as noted, but it's more correct than it was.
Actually testing SIGINT handling is also impossible until #65 is fixed. |
b7e9cf1
to
c2ba7e3
Compare
Another update, to make the code compatible with the upcoming |
This checks for the given command name in each directory in $PATH, and returns an object for executing the first match it finds. In situations where we don't need to redirect output, we use node-pty to spawn a new PTY for the command to run in. This works better than our own ioctl implementation for now, but but can't be used always because it doesn't allow distinguishing between stderr and stdout. So when we do need to redirect those, we use Node's process spawning. Current issues: - The unhandledRejection callback is very dubious. - We eat one chunk of stdin input after the executable stops, because we can't cancel `ctx.externs.in_.read()`. Possibly this should go via another stream that we can disconnect. - Stdin is always echoed even when the command handles it for us. This means typing in the `python` repl makes each character appear doubled. It's not actually doubled though, it's just a visual error.
c2ba7e3
to
95b23b6
Compare
Changes: We now use Long-term we'd need to properly handle terminal-related ioctls ourself, and stop needing I've un-drafted in case you do feel like this is worth merging Eric, but fair enough if you don't yet. |
This checks for the given command name in each directory in $PATH, and returns an object for executing the first match it finds.
This executing is very basic: the command is run, and the arguments are passed to it, and we wait for it to exit before continuing. But we don't connect stdin, stdout, or stderr. (Because I couldn't figure out how to make a Node stream that works. 😅)
Slight progress towards #14.