Hi, I’m working on the Expect.jl module to interact with external
processes under a pty (https://github.com/wavexx/Expect.jl).
For those unfamiliar with expect-like modules, the current API looks
like this:
interact(`ssh somewhere`, 10) do ssh
expect!(ssh, " password: ")
println(ssh, "supersecret")
...
end
I need to have fine-grained control on how buffering is performed at a
lower level and I think I’ve reached a limit on what I can do using the
Julia runtime and need some guidance.
I’ll start with the easiest issue:
Julia’s Base.TTY seem to be designed only as a front-end to the main
terminal interacting with the user. This seems to stem from libuv as
well. For one, libuv tracks the first tty on which the uv_tty_set_mode
has been called, just to reset it on shutdown.
https://github.com/libuv/libuv/issues/1292
This obviously doesn’t take pseudo-ttys into consideration. Julia itself
also calls uv_tty_set_mode in jl_close_uv!
This seems broken, as if we use libuv, we should only be calling
uv_tty_reset_mode before exiting (which is intended to be called from a
signal handler) and ensure the tty reset by libuv itself is the console
(again, this can only be done currently by calling uv_tty_set_mode with
a non-normal mode at start! - another issue with the libuv api design).
Getting stuff fixed in libuv takes forever, and even more to propagate
the change to julia, so this is why I’m not directly filling PRs and
issues right away.
I see the api in libuv broken in this regard: there should be a function
call to explicitly set the tty to reset on un_tty_reset_mode.
The second issue is reading. Reads from LibuvStream are throttled by
julia, however I need to ensure the input stream coming from the
coprocess is never stopped, otherwise I can incur in a stall in a
pending write. Looking at Base.wait_readnb I see no easy way to avoid
the call to stop_reading. Ideas?
I’d love to be able to re-use the code in stream.jl, but the handling of
the read timeout is also something I want to manage directly. Is there a
“recommended” way to create a new handle directly using libuv? I need to
cram the descriptor as being watched in the main uv loop and set my own
callbacks.
Thanks for any pointer.