I'm writing a backend, and I need to execute certain command with text passed via stdin, then read the result from stdout. Such utilities provided by Node.ChildProcess
module, except I don't see any way to wait till child exits. Which is odd, because there's no point in reading from stdout if the app didn't write anything there yet.
In terms of a minimal example I'm using cat
. cat
reads text from stdin and writes to stdout.
module Main where
import Prelude
import Data.Maybe (Maybe(..))
import Effect (Effect)
import Effect.Console (log)
import Node.ChildProcess as Proc
import Node.Encoding (Encoding(UTF8))
import Node.Stream as Stream
main :: Effect Unit
main = do
child :: Proc.ChildProcess <- Proc.spawn "cat" []
let
stdin' :: Stream.Writable ()
stdin' = Proc.stdin child
_ <- Stream.writeString stdin' UTF8 "hello"
_ <- Stream.end stdin'
-- wait for child ?? How?
let
stdout' :: Stream.Readable ()
stdout' = Proc.stdout child
output :: Maybe String <- Stream.readString stdout' UTF8
case output of
Just s -> log s
_ -> log "nothing"
I want this to print hello
, because that's what cat
writes to its stdout. Instead unsurprisingly I get "nothing", because by the time Stream.readString
is executed cat
didn't write anything to stdout yet.
How do I wait for cat
to exit?
When the process exits, Node will fire an "exit"
event, which is mapped to PureScript as exitH
, and you can attach a listener to it with the on_
function from Node.EventEmitter
.
Since your program is all synchronous (runs in Effect
), you should put everything that should happen after the child's exit inside the "exit"
event handler:
main :: Effect Unit
main = do
child :: Proc.ChildProcess <- Proc.spawn "cat" []
let
stdin' :: Stream.Writable ()
stdin' = Proc.stdin child
_ <- Stream.writeString stdin' UTF8 "hello"
_ <- Stream.end stdin'
child # on_ Proc.exitH \_ -> do
let
stdout' :: Stream.Readable ()
stdout' = Proc.stdout child
output :: Maybe String <- Stream.readString stdout' UTF8
case output of
Just s -> log s
_ -> log "nothing"