Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/jhthorsen/mojo-ioloop-readwritefork
Fork a process and read/write from it
https://github.com/jhthorsen/mojo-ioloop-readwritefork
Last synced: 3 months ago
JSON representation
Fork a process and read/write from it
- Host: GitHub
- URL: https://github.com/jhthorsen/mojo-ioloop-readwritefork
- Owner: jhthorsen
- Created: 2013-11-20T09:23:48.000Z (about 11 years ago)
- Default Branch: main
- Last Pushed: 2022-06-10T05:18:30.000Z (over 2 years ago)
- Last Synced: 2024-06-18T18:45:29.951Z (7 months ago)
- Language: Perl
- Size: 219 KB
- Stars: 13
- Watchers: 6
- Forks: 8
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: Changes
Awesome Lists containing this project
README
# NAME
Mojo::IOLoop::ReadWriteFork - Fork a process and read/write from it
# VERSION
2.02
# SYNOPSIS
use Mojo::Base -strict, -signatures;
my $rwf = Mojo::IOLoop::ReadWriteFork->new;# Emitted if something terrible happens
$rwf->on(error => sub ($rwf, $error) { warn $error });# Emitted when the child completes
$rwf->on(finish => sub ($rwf, $exit_value, $signal) { Mojo::IOLoop->stop; });# Emitted when the child prints to STDOUT or STDERR
$rwf->on(read => sub ($rwf, $buf) { print qq(Child process sent us "$buf") });# Need to set "conduit" for bash, ssh, and other programs that require a pty
$rwf->conduit({type => 'pty'});# Start the application
$rwf->run('bash', -c => q(echo $YIKES foo bar baz));# Using promises
$rwf->on(read => sub ($rwf, $buf) { ... });
$rwf->run_p('bash', -c => q(echo $YIKES foo bar baz))->wait;See also
[https://github.com/jhthorsen/mojo-ioloop-readwritefork/tree/master/examples/tail.pl](https://github.com/jhthorsen/mojo-ioloop-readwritefork/tree/master/examples/tail.pl)
for an example usage from a [Mojo::Controller](https://metacpan.org/pod/Mojo%3A%3AController).# DESCRIPTION
[Mojo::IOLoop::ReadWriteFork](https://metacpan.org/pod/Mojo%3A%3AIOLoop%3A%3AReadWriteFork) enable you to fork a child process and ["read"](#read)
and ["write"](#write) data to. You can also [send signals](#kill) to the child and see
when the process ends. The child process can be an external program (bash,
telnet, ffmpeg, ...) or a CODE block running perl.## Conduits
[Mojo::IOLoop::ReadWriteFork](https://metacpan.org/pod/Mojo%3A%3AIOLoop%3A%3AReadWriteFork) can write to STDIN or a [IO::Pty](https://metacpan.org/pod/IO%3A%3APty) object, and
read from STDOUT or STDERR, depending on the "type" given to ["conduit"](#conduit).Here is an overview of the different conduits:
- pipe
The "pipe" type will create a STDIN and a STDOUT conduit using a plain pipe.
Passing in `stderr` will also create a seperate pipe for STDERR.$rwf->conduit({type => 'pipe'});
$rwf->conduit({type => 'pipe', stderr => 1});
$rwf->write('some data'); # write to STDIN
$rwf->on(read => sub { ... }); # STDOUT and STDERR
$rwf->on(stdout => sub { ... }); # STDOUT
$rwf->on(stderr => sub { ... }); # STDERRThis is useful if you want to run a program like "cat" that simply read/write
from STDIN, STDERR or STDOUT.- pty
The "pty" type will create a STDIN and a STDOUT conduit using [IO::Pty](https://metacpan.org/pod/IO%3A%3APty).
Passing in "stderr" will also create a seperate pipe for STDERR.$rwf->conduit({type => 'pty'});
$rwf->conduit({type => 'pty', stderr => 1});
$rwf->write('some data'); # write to STDIN
$rwf->on(read => sub { ... }); # STDOUT and STDERR
$rwf->on(stdout => sub { ... }); # STDOUT
$rwf->on(stderr => sub { ... }); # STDERRThe difference between "pipe" and "pty" is that a [IO::Pty](https://metacpan.org/pod/IO%3A%3APty) object will be
used for STDIN and STDOUT instead of a plain pipe. In addition, it is possible
to pass in `clone_winsize_from` and `raw`:$rwf->conduit({type => 'pty', clone_winsize_from => \*STDOUT, raw => 1});
This is useful if you want to run "bash" or another program that requires a
pseudo terminal.- pty3
The "pty3" type will create a STDIN, a STDOUT, a STDERR and a PTY conduit.
$rwf->conduit({type => 'pty3'});
$rwf->write('some data'); # write to STDIN/PTY
$rwf->on(pty => sub { ... }); # PTY
$rwf->on(stdout => sub { ... }); # STDOUT
$rwf->on(stderr => sub { ... }); # STDERRThe difference between "pty" and "pty3" is that there will be a different
["read"](#read) event for bytes coming from the pseudo PTY. This type also supports
"clone\_winsize\_from" and "raw".$rwf->conduit({type => 'pty3', clone_winsize_from => \*STDOUT, raw => 1});
This is useful if you want to run "ssh" or another program that sends password
prompts (or other output) on the PTY channel. See
[https://github.com/jhthorsen/mojo-ioloop-readwritefork/tree/master/examples/sshpass](https://github.com/jhthorsen/mojo-ioloop-readwritefork/tree/master/examples/sshpass)
for an example application.# EVENTS
## asset
$rwf->on(asset => sub ($rwf, $asset) { ... });
Emitted at least once when calling ["run\_and\_capture\_p"](#run_and_capture_p). `$asset` can be
either a [Mojo::Asset::Memory](https://metacpan.org/pod/Mojo%3A%3AAsset%3A%3AMemory) or [Mojo::Asset::File](https://metacpan.org/pod/Mojo%3A%3AAsset%3A%3AFile) object.$rwf->on(asset => sub ($rwf, $asset) {
# $asset->auto_upgrade(1) is set by default
$asset->max_memory_size(1) if $asset->can('max_memory_size');
});## drain
$rwf->on(drain => sub ($rwf) { ... });
Emitted when the buffer has been written to the sub process.
## error
$rwf->on(error => sub ($rwf, $str) { ... });
Emitted when when the there is an issue with creating, writing or reading
from the child process.## finish
$rwf->on(finish => sub ($rwf, $exit_value, $signal) { ... });
Emitted when the child process exit.
## pty
$rwf->on(pty => sub ($rwf, $buf) { ... });
Emitted when the child has written a chunk of data to a pty and ["conduit"](#conduit) has
"type" set to "pty3".## prepare
$rwf->on(prepare => sub ($rwf, $fh) { ... });
Emitted right before the child process is forked. `$fh` can contain the
example hash below or a subset:$fh = {
stderr_read => $pipe_fh_w_or_pty_object,
stderr_read => $stderr_fh_r,
stdin_read => $pipe_fh_r,
stdin_write => $pipe_fh_r_or_pty_object,
stdin_write => $stderr_fh_w,
stdout_read => $pipe_fh_w_or_pty_object,
stdout_read => $stderr_fh_r,
stdout_write => $pipe_fh_w,
};## read
$rwf->on(read => sub ($rwf, $buf) { ... });
Emitted when the child has written a chunk of data to STDOUT or STDERR, and
neither "stderr" nor "stdout" is set in the ["conduit"](#conduit).## spawn
$rwf->on(spawn => sub ($rwf) { ... });
Emitted after `fork()` has been called. Note that the child process might not yet have
been started. The order of things is impossible to say, but it's something like this:.------.
| fork |
'------'
|
___/ \_______________
| |
| (parent) | (child)
.--------------. |
| emit "spawn" | .--------------------.
'--------------' | set up filehandles |
'--------------------'
|
.---------------.
| exec $program |
'---------------'See also ["pid"](#pid) for example usage of this event.
## stderr
$rwf->on(stderr => sub ($rwf, $buf) { ... });
Emitted when the child has written a chunk of data to STDERR and ["conduit"](#conduit)
has the "stderr" key set to a true value or "type" is set to "pty3".## stdout
$rwf->on(stdout => sub ($rwf, $buf) { ... });
Emitted when the child has written a chunk of data to STDOUT and ["conduit"](#conduit)
has the "stdout" key set to a true value or "type" is set to "pty3".# ATTRIBUTES
## conduit
$hash = $rwf->conduit;
$rwf = $rwf->conduit(\%options);Used to set the conduit options. Possible values are:
- clone\_winsize\_from
See ["clone\_winsize\_from" in IO::Pty](https://metacpan.org/pod/IO%3A%3APty#clone_winsize_from). This only makes sense if ["conduit"](#conduit) is set
to "pty". This can also be specified by using the ["conduit"](#conduit) attribute.- raw
See ["set\_raw" in IO::Pty](https://metacpan.org/pod/IO%3A%3APty#set_raw). This only makes sense if ["conduit"](#conduit) is set to "pty".
This can also be specified by using the ["conduit"](#conduit) attribute.- stderr
This will make [Mojo::IOLoop::ReadWriteFork](https://metacpan.org/pod/Mojo%3A%3AIOLoop%3A%3AReadWriteFork) emit "stderr" events, instead of
"read" events. Setting this to "0" will close STDERR in the child.- stdout
This will make [Mojo::IOLoop::ReadWriteFork](https://metacpan.org/pod/Mojo%3A%3AIOLoop%3A%3AReadWriteFork) emit "stdout" events, instead of
"read" events. Setting this to "0" will close STDOUT in the child.- type
"type" can be either "pipe", "pty" or "pty3". Default value is "pipe".
See also ["Conduits"](#conduits)
## ioloop
$ioloop = $rwf->ioloop;
$rwf = $rwf->ioloop(Mojo::IOLoop->singleton);Holds a [Mojo::IOLoop](https://metacpan.org/pod/Mojo%3A%3AIOLoop) object.
## pid
$int = $rwf->pid;
Holds the child process ID. Note that ["start"](#start) will start the process after
the IO loop is started. This means that the code below will not work:$rwf->run("bash", -c => q(echo $YIKES foo bar baz));
warn $rwf->pid; # pid() is not yet setThis will work though:
$rwf->on(fork => sub ($rwf) { warn $rwf->pid });
$rwf->run('bash', -c => q(echo $YIKES foo bar baz));# METHODS
## close
$rwf = $rwf->close('stdin');
Close STDIN stream to the child process immediately.
## run
$rwf = $rwf->run($program, @program_args);
$rwf = $rwf->run(\&Some::Perl::function, @function_args);Simpler version of ["start"](#start). Can either start an application or run a perl
function.## run\_and\_capture\_p
$p = $rwf->run_and_capture_p(...)->then(sub { my $asset = shift });
["run\_and\_capture\_p"](#run_and_capture_p) takes the same arguments as ["run\_p"](#run_p), but the
fullfillment callback will receive a [Mojo::Asset](https://metacpan.org/pod/Mojo%3A%3AAsset) object that holds the
output from the command.See also the ["asset"](#asset) event.
## run\_p
$p = $rwf->run_p($program, @program_args);
$p = $rwf->run_p(\&Some::Perl::function, @function_args);Promise based version of ["run"](#run). The [Mojo::Promise](https://metacpan.org/pod/Mojo%3A%3APromise) will be resolved on
["finish"](#finish) and rejected on ["error"](#error).## start
$rwf = $rwf->start(\%args);
Used to fork and exec a child process. `%args` can have:
- program
Either an application or a CODE ref.
- program\_args
A list of options passed on to ["program"](#program) or as input to the CODE ref.
Note that this module will start ["program"](#program) with this code:
exec $program, @$program_args;
This means that the code is subject for
[shell injection](https://en.wikipedia.org/wiki/Code_injection#Shell_injection)
unless invoked with more than one argument. This is considered a feature, but
something you should be avare of. See also ["exec" in perlfunc](https://metacpan.org/pod/perlfunc#exec) for more details.- env
Passing in `env` will override the default set of environment variables,
stored in `%ENV`.## write
$rwf = $rwf->write($chunk);
$rwf = $rwf->write($chunk, $cb);Used to write data to the child process STDIN. An optional callback will be
called once the `$chunk` is written.Example:
$rwf->write("some data\n", sub ($rwf) { $rwf->close });
## kill
$bool = $rwf->kill;
$bool = $rwf->kill(15); # defaultUsed to signal the child.
# SEE ALSO
[Mojo::IOLoop::ForkCall](https://metacpan.org/pod/Mojo%3A%3AIOLoop%3A%3AForkCall).
[https://github.com/jhthorsen/mojo-ioloop-readwritefork/tree/master/examples/tail.pl](https://github.com/jhthorsen/mojo-ioloop-readwritefork/tree/master/examples/tail.pl)
# COPYRIGHT AND LICENSE
Copyright (C) 2013-2016, Jan Henning Thorsen
This program is free software, you can redistribute it and/or modify it under
the terms of the Artistic License version 2.0.# AUTHOR
Jan Henning Thorsen - `[email protected]`