Skip to content

Commit bcaa839

Browse files
Migrate to eventH-style event API (#43)
* Add dep on event-emitter; update node deps * Migrate event handlers * Update tests * Add changelog entry * Add entry for 'spawn' event
1 parent f3a0594 commit bcaa839

File tree

5 files changed

+72
-124
lines changed

5 files changed

+72
-124
lines changed

CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,24 @@ Notable changes to this project are documented in this file. The format is based
55
## [Unreleased]
66

77
Breaking changes:
8+
- Migrate `onEvent`-style event handlers to `eventH`-style (#43 by @JordanMartinez)
9+
10+
```purs
11+
-- Before
12+
onExit cp case _ of
13+
Normally exitCode -> ...
14+
BySignal signal -> ...
15+
16+
-- After
17+
cp # on_ exitH case _ of
18+
Normally exitCode -> ...
19+
BySignal signal -> ...
20+
```
21+
See https://pursuit.purescript.org/packages/purescript-node-event-emitter/3.0.0/docs/Node.EventEmitter for more details.
22+
823

924
New features:
25+
- Added event handler for `spawn` event (#43 by @JordanMartinez)
1026

1127
Bugfixes:
1228

bower.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@
1717
],
1818
"dependencies": {
1919
"purescript-exceptions": "^6.0.0",
20+
"purescript-node-event-emitter": "https://github.com/purescript-node/purescript-node-event-emitter.git#^3.0.0",
2021
"purescript-foreign": "^7.0.0",
2122
"purescript-foreign-object": "^4.0.0",
2223
"purescript-functions": "^6.0.0",
23-
"purescript-node-fs": "^8.0.0",
24-
"purescript-node-streams": "^7.0.0",
24+
"purescript-node-fs": "^9.0.0",
25+
"purescript-node-streams": "^8.0.0",
2526
"purescript-nullable": "^6.0.0",
2627
"purescript-posix-types": "^6.0.0",
2728
"purescript-unsafe-coerce": "^6.0.0"

src/Node/ChildProcess.js

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -46,50 +46,6 @@ export function fork(cmd) {
4646
return args => () => cp_fork(cmd, args);
4747
}
4848

49-
export function mkOnExit(mkChildExit) {
50-
return function onExit(cp) {
51-
return cb => () => {
52-
cp.on("exit", (code, signal) => {
53-
cb(mkChildExit(code)(signal))();
54-
});
55-
};
56-
};
57-
}
58-
59-
export function mkOnClose(mkChildExit) {
60-
return function onClose(cp) {
61-
return cb => () => {
62-
cp.on("close", (code, signal) => {
63-
cb(mkChildExit(code)(signal))();
64-
});
65-
};
66-
};
67-
}
68-
69-
export function onDisconnect(cp) {
70-
return cb => () => {
71-
cp.on("disconnect", cb);
72-
};
73-
}
74-
75-
export function mkOnMessage(nothing) {
76-
return just => (function onMessage(cp) {
77-
return cb => () => {
78-
cp.on("message", (mess, sendHandle) => {
79-
cb(mess, sendHandle ? just(sendHandle) : nothing)();
80-
});
81-
};
82-
});
83-
}
84-
85-
export function onError(cp) {
86-
return cb => () => {
87-
cp.on("error", err => {
88-
cb(err)();
89-
});
90-
};
91-
}
92-
9349
const _undefined = undefined;
9450
export { _undefined as undefined };
9551
import process from "process";

src/Node/ChildProcess.purs

Lines changed: 44 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@
1414
module Node.ChildProcess
1515
( Handle
1616
, ChildProcess
17+
, toEventEmitter
18+
, closeH
19+
, disconnectH
20+
, errorH
21+
, exitH
22+
, messageH
23+
, spawnH
1724
, stdin
1825
, stdout
1926
, stderr
@@ -25,11 +32,6 @@ module Node.ChildProcess
2532
, Error
2633
, toStandardError
2734
, Exit(..)
28-
, onExit
29-
, onClose
30-
, onDisconnect
31-
, onMessage
32-
, onError
3335
, spawn
3436
, SpawnOptions
3537
, defaultSpawnOptions
@@ -51,31 +53,64 @@ module Node.ChildProcess
5153

5254
import Prelude
5355

54-
import Control.Alt ((<|>))
5556
import Data.Function.Uncurried (Fn2, runFn2)
5657
import Data.Maybe (Maybe(..), fromMaybe, maybe)
57-
import Data.Nullable (Nullable, toNullable, toMaybe)
58+
import Data.Nullable (Nullable, toMaybe, toNullable)
5859
import Data.Posix (Pid, Gid, Uid)
5960
import Data.Posix.Signal (Signal)
6061
import Data.Posix.Signal as Signal
6162
import Effect (Effect)
6263
import Effect.Exception as Exception
63-
import Effect.Exception.Unsafe (unsafeThrow)
64+
import Effect.Uncurried (EffectFn2, mkEffectFn1, mkEffectFn2)
6465
import Foreign (Foreign)
6566
import Foreign.Object (Object)
6667
import Node.Buffer (Buffer)
6768
import Node.Encoding (Encoding, encodingToNode)
69+
import Node.EventEmitter (EventEmitter, EventHandle(..))
70+
import Node.EventEmitter.UtilTypes (EventHandle0, EventHandle1)
6871
import Node.FS as FS
69-
import Node.Stream (Readable, Writable, Stream)
72+
import Node.Stream (Readable, Stream, Writable)
73+
import Partial.Unsafe (unsafeCrashWith)
7074
import Unsafe.Coerce (unsafeCoerce)
7175

7276
-- | A handle for inter-process communication (IPC).
7377
foreign import data Handle :: Type
7478

7579
-- | Opaque type returned by `spawn`, `fork` and `exec`.
7680
-- | Needed as input for most methods in this module.
81+
-- |
82+
-- | `ChildProcess` extends `EventEmitter`
7783
newtype ChildProcess = ChildProcess ChildProcessRec
7884

85+
toEventEmitter :: ChildProcess -> EventEmitter
86+
toEventEmitter = unsafeCoerce
87+
88+
closeH :: EventHandle ChildProcess (Exit -> Effect Unit) (EffectFn2 (Nullable Int) (Nullable String) Unit)
89+
closeH = EventHandle "close" \cb -> mkEffectFn2 \code signal ->
90+
case toMaybe code, toMaybe signal >>= Signal.fromString of
91+
Just c, _ -> cb $ Normally c
92+
_, Just s -> cb $ BySignal s
93+
_, _ -> unsafeCrashWith $ "Impossible. 'close' event did not get an exit code or kill signal: " <> show code <> "; " <> show signal
94+
95+
disconnectH :: EventHandle0 ChildProcess
96+
disconnectH = EventHandle "disconnect" identity
97+
98+
errorH :: EventHandle1 ChildProcess Error
99+
errorH = EventHandle "error" mkEffectFn1
100+
101+
exitH :: EventHandle ChildProcess (Exit -> Effect Unit) (EffectFn2 (Nullable Int) (Nullable String) Unit)
102+
exitH = EventHandle "exitH" \cb -> mkEffectFn2 \code signal ->
103+
case toMaybe code, toMaybe signal >>= Signal.fromString of
104+
Just c, _ -> cb $ Normally c
105+
_, Just s -> cb $ BySignal s
106+
_, _ -> unsafeCrashWith $ "Impossible. 'exit' event did not get an exit code or kill signal: " <> show code <> "; " <> show signal
107+
108+
messageH :: EventHandle ChildProcess (Foreign -> Maybe Handle -> Effect Unit) (EffectFn2 Foreign (Nullable Handle) Unit)
109+
messageH = EventHandle "message" \cb -> mkEffectFn2 \a b -> cb a $ toMaybe b
110+
111+
spawnH :: EventHandle0 ChildProcess
112+
spawnH = EventHandle "spawn" identity
113+
79114
runChildProcess :: ChildProcess -> ChildProcessRec
80115
runChildProcess (ChildProcess r) = r
81116

@@ -165,68 +200,6 @@ instance showExit :: Show Exit where
165200
show (Normally x) = "Normally " <> show x
166201
show (BySignal sig) = "BySignal " <> show sig
167202

168-
mkExit :: Nullable Int -> Nullable String -> Exit
169-
mkExit code signal =
170-
case fromCode code <|> fromSignal signal of
171-
Just e -> e
172-
Nothing -> unsafeThrow "Node.ChildProcess.mkExit: Invalid arguments"
173-
where
174-
fromCode = toMaybe >>> map Normally
175-
fromSignal = toMaybe >=> Signal.fromString >>> map BySignal
176-
177-
-- | Handle the `"exit"` signal.
178-
onExit
179-
:: ChildProcess
180-
-> (Exit -> Effect Unit)
181-
-> Effect Unit
182-
onExit = mkOnExit mkExit
183-
184-
foreign import mkOnExit
185-
:: (Nullable Int -> Nullable String -> Exit)
186-
-> ChildProcess
187-
-> (Exit -> Effect Unit)
188-
-> Effect Unit
189-
190-
-- | Handle the `"close"` signal.
191-
onClose
192-
:: ChildProcess
193-
-> (Exit -> Effect Unit)
194-
-> Effect Unit
195-
onClose = mkOnClose mkExit
196-
197-
foreign import mkOnClose
198-
:: (Nullable Int -> Nullable String -> Exit)
199-
-> ChildProcess
200-
-> (Exit -> Effect Unit)
201-
-> Effect Unit
202-
203-
-- | Handle the `"message"` signal.
204-
onMessage
205-
:: ChildProcess
206-
-> (Foreign -> Maybe Handle -> Effect Unit)
207-
-> Effect Unit
208-
onMessage = mkOnMessage Nothing Just
209-
210-
foreign import mkOnMessage
211-
:: forall a
212-
. Maybe a
213-
-> (a -> Maybe a)
214-
-> ChildProcess
215-
-> (Foreign -> Maybe Handle -> Effect Unit)
216-
-> Effect Unit
217-
218-
-- | Handle the `"disconnect"` signal.
219-
foreign import onDisconnect
220-
:: ChildProcess
221-
-> Effect Unit
222-
-> Effect Unit
223-
224-
-- | Handle the `"error"` signal.
225-
foreign import onError
226-
:: ChildProcess
227-
-> (Error -> Effect Unit)
228-
-> Effect Unit
229-
230203
-- | Spawn a child process. Note that, in the event that a child process could
231204
-- | not be spawned (for example, if the executable was not found) this will
232205
-- | not throw an error. Instead, the `ChildProcess` will be created anyway,

test/Main.purs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ import Data.Posix.Signal (Signal(..))
77
import Effect (Effect)
88
import Effect.Console (log)
99
import Node.Buffer as Buffer
10-
import Node.ChildProcess (Exit(..), defaultExecOptions, exec, defaultExecSyncOptions, execSync, onError, defaultSpawnOptions, spawn, stdout, onExit, kill)
10+
import Node.ChildProcess (Exit(..), defaultExecOptions, defaultExecSyncOptions, defaultSpawnOptions, errorH, exec, execSync, exitH, kill, spawn, stdout)
1111
import Node.Encoding (Encoding(UTF8))
1212
import Node.Encoding as NE
13-
import Node.Stream (onData)
13+
import Node.EventEmitter (on_)
14+
import Node.Stream (dataH)
1415

1516
main :: Effect Unit
1617
main = do
@@ -24,7 +25,7 @@ main = do
2425
log "doesn't perform effects too early"
2526
spawn "ls" [ "-la" ] defaultSpawnOptions >>= \ls -> do
2627
let _ = kill SIGTERM ls
27-
onExit ls \exit ->
28+
ls # on_ exitH \exit ->
2829
case exit of
2930
Normally 0 ->
3031
log "All good!"
@@ -34,7 +35,7 @@ main = do
3435
log "kills processes"
3536
spawn "ls" [ "-la" ] defaultSpawnOptions >>= \ls -> do
3637
_ <- kill SIGTERM ls
37-
onExit ls \exit ->
38+
ls # on_ exitH \exit ->
3839
case exit of
3940
BySignal SIGTERM ->
4041
log "All good!"
@@ -47,14 +48,15 @@ main = do
4748
spawnLs :: Effect Unit
4849
spawnLs = do
4950
ls <- spawn "ls" [ "-la" ] defaultSpawnOptions
50-
onExit ls \exit ->
51+
ls # on_ exitH \exit ->
5152
log $ "ls exited: " <> show exit
52-
onData (stdout ls) (Buffer.toString UTF8 >=> log)
53+
(stdout ls) # on_ dataH (Buffer.toString UTF8 >=> log)
5354

5455
nonExistentExecutable :: Effect Unit -> Effect Unit
5556
nonExistentExecutable done = do
5657
ch <- spawn "this-does-not-exist" [] defaultSpawnOptions
57-
onError ch (\err -> log err.code *> done)
58+
ch # on_ errorH \err ->
59+
log err.code *> done
5860

5961
execLs :: Effect Unit
6062
execLs = do

0 commit comments

Comments
 (0)