fix: finish
may not emit until all chunks are read
This commit is contained in:
parent
f3ea830379
commit
a8702f4849
@ -13,7 +13,6 @@ workspace:
|
|||||||
- lists: ">=7.0.0 <8.0.0"
|
- lists: ">=7.0.0 <8.0.0"
|
||||||
- maybe: ">=6.0.0 <7.0.0"
|
- maybe: ">=6.0.0 <7.0.0"
|
||||||
- mmorph: ">=7.0.0 <8.0.0"
|
- mmorph: ">=7.0.0 <8.0.0"
|
||||||
- newtype: ">=5.0.0 <6.0.0"
|
|
||||||
- node-buffer: ">=9.0.0 <10.0.0"
|
- node-buffer: ">=9.0.0 <10.0.0"
|
||||||
- node-event-emitter: ">=3.0.0 <4.0.0"
|
- node-event-emitter: ">=3.0.0 <4.0.0"
|
||||||
- node-fs: ">=9.1.0 <10.0.0"
|
- node-fs: ">=9.1.0 <10.0.0"
|
||||||
|
@ -20,7 +20,6 @@ package:
|
|||||||
- lists: ">=7.0.0 <8.0.0"
|
- lists: ">=7.0.0 <8.0.0"
|
||||||
- maybe: ">=6.0.0 <7.0.0"
|
- maybe: ">=6.0.0 <7.0.0"
|
||||||
- mmorph: ">=7.0.0 <8.0.0"
|
- mmorph: ">=7.0.0 <8.0.0"
|
||||||
- newtype: ">=5.0.0 <6.0.0"
|
|
||||||
- node-buffer: ">=9.0.0 <10.0.0"
|
- node-buffer: ">=9.0.0 <10.0.0"
|
||||||
- node-event-emitter: ">=3.0.0 <4.0.0"
|
- node-event-emitter: ">=3.0.0 <4.0.0"
|
||||||
- node-fs: ">=9.1.0 <10.0.0"
|
- node-fs: ">=9.1.0 <10.0.0"
|
||||||
|
@ -21,6 +21,9 @@ export const isReadableEndedImpl = (s) => () => s.readableEnded;
|
|||||||
/** @type {(s: Stream.Writable | Stream.Transform) => () => boolean} */
|
/** @type {(s: Stream.Writable | Stream.Transform) => () => boolean} */
|
||||||
export const isWritableEndedImpl = (s) => () => s.writableEnded;
|
export const isWritableEndedImpl = (s) => () => s.writableEnded;
|
||||||
|
|
||||||
|
/** @type {(s: Stream.Writable | Stream.Transform) => () => boolean} */
|
||||||
|
export const isWritableFinishedImpl = (s) => () => s.writableFinished;
|
||||||
|
|
||||||
/** @type {(s: Stream.Writable | Stream.Transform) => () => void} */
|
/** @type {(s: Stream.Writable | Stream.Transform) => () => void} */
|
||||||
export const endImpl = (s) => () => s.end();
|
export const endImpl = (s) => () => s.end();
|
||||||
|
|
||||||
|
@ -14,8 +14,9 @@ import Data.Maybe (Maybe(..))
|
|||||||
import Data.Show.Generic (genericShow)
|
import Data.Show.Generic (genericShow)
|
||||||
import Effect (Effect)
|
import Effect (Effect)
|
||||||
import Effect.Aff (Aff, effectCanceler, makeAff)
|
import Effect.Aff (Aff, effectCanceler, makeAff)
|
||||||
|
import Effect.Aff as Aff
|
||||||
import Effect.Class (liftEffect)
|
import Effect.Class (liftEffect)
|
||||||
import Effect.Exception (Error)
|
import Effect.Exception (Error, error)
|
||||||
import Effect.Uncurried (mkEffectFn1)
|
import Effect.Uncurried (mkEffectFn1)
|
||||||
import Node.Buffer (Buffer)
|
import Node.Buffer (Buffer)
|
||||||
import Node.EventEmitter (EventHandle(..))
|
import Node.EventEmitter (EventHandle(..))
|
||||||
@ -61,6 +62,7 @@ foreign import isReadableImpl :: forall s. s -> Effect Boolean
|
|||||||
foreign import isWritableImpl :: forall s. s -> Effect Boolean
|
foreign import isWritableImpl :: forall s. s -> Effect Boolean
|
||||||
foreign import isReadableEndedImpl :: forall s. s -> Effect Boolean
|
foreign import isReadableEndedImpl :: forall s. s -> Effect Boolean
|
||||||
foreign import isWritableEndedImpl :: forall s. s -> Effect Boolean
|
foreign import isWritableEndedImpl :: forall s. s -> Effect Boolean
|
||||||
|
foreign import isWritableFinishedImpl :: forall s. s -> Effect Boolean
|
||||||
foreign import isClosedImpl :: forall s. s -> Effect Boolean
|
foreign import isClosedImpl :: forall s. s -> Effect Boolean
|
||||||
foreign import needsDrainImpl :: forall s. s -> Effect Boolean
|
foreign import needsDrainImpl :: forall s. s -> Effect Boolean
|
||||||
foreign import readableLengthImpl :: forall s. s -> Effect Int
|
foreign import readableLengthImpl :: forall s. s -> Effect Int
|
||||||
@ -94,6 +96,7 @@ class Stream s <= Write s a | s -> a where
|
|||||||
isWritable :: s -> Effect Boolean
|
isWritable :: s -> Effect Boolean
|
||||||
needsDrain :: s -> Effect Boolean
|
needsDrain :: s -> Effect Boolean
|
||||||
isWritableEnded :: s -> Effect Boolean
|
isWritableEnded :: s -> Effect Boolean
|
||||||
|
isWritableFinished :: s -> Effect Boolean
|
||||||
write :: s -> a -> Effect WriteResult
|
write :: s -> a -> Effect WriteResult
|
||||||
end :: s -> Effect Unit
|
end :: s -> Effect Unit
|
||||||
|
|
||||||
@ -116,18 +119,21 @@ else instance (Read s a) => Read s a where
|
|||||||
instance Write (Writable a) a where
|
instance Write (Writable a) a where
|
||||||
isWritable = isWritableImpl
|
isWritable = isWritableImpl
|
||||||
isWritableEnded = isWritableEndedImpl
|
isWritableEnded = isWritableEndedImpl
|
||||||
|
isWritableFinished = isWritableFinishedImpl
|
||||||
write s = writeImpl writeResultFFI s
|
write s = writeImpl writeResultFFI s
|
||||||
end = endImpl
|
end = endImpl
|
||||||
needsDrain = needsDrainImpl
|
needsDrain = needsDrainImpl
|
||||||
else instance Write (Transform a b) a where
|
else instance Write (Transform a b) a where
|
||||||
isWritable = isWritableImpl
|
isWritable = isWritableImpl
|
||||||
isWritableEnded = isWritableEndedImpl
|
isWritableEnded = isWritableEndedImpl
|
||||||
|
isWritableFinished = isWritableFinishedImpl
|
||||||
write s = writeImpl writeResultFFI s
|
write s = writeImpl writeResultFFI s
|
||||||
end = endImpl
|
end = endImpl
|
||||||
needsDrain = needsDrainImpl
|
needsDrain = needsDrainImpl
|
||||||
else instance (Write s a) => Write s a where
|
else instance (Write s a) => Write s a where
|
||||||
isWritable = isWritableImpl
|
isWritable = isWritableImpl
|
||||||
isWritableEnded = isWritableEndedImpl
|
isWritableEnded = isWritableEndedImpl
|
||||||
|
isWritableFinished = isWritableFinishedImpl
|
||||||
write s a = write s a
|
write s a = write s a
|
||||||
end s = end s
|
end s = end s
|
||||||
needsDrain = needsDrainImpl
|
needsDrain = needsDrainImpl
|
||||||
@ -167,25 +173,38 @@ unsafeFromStringWritable = unsafeCoerce
|
|||||||
|
|
||||||
awaitReadableOrClosed :: forall s a. Read s a => s -> Aff Unit
|
awaitReadableOrClosed :: forall s a. Read s a => s -> Aff Unit
|
||||||
awaitReadableOrClosed s = do
|
awaitReadableOrClosed s = do
|
||||||
readable <- liftEffect $ isReadable s
|
fiber <-
|
||||||
length <- liftEffect $ readableLength s
|
Aff.forkAff $ parOneOf
|
||||||
when (readable && length == 0)
|
|
||||||
$ liftEither
|
|
||||||
=<< parOneOf
|
|
||||||
[ onceAff0 readableH s $> Right unit
|
[ onceAff0 readableH s $> Right unit
|
||||||
, onceAff0 closeH s $> Right unit
|
, onceAff0 closeH s $> Right unit
|
||||||
, Left <$> onceAff1 errorH s
|
, Left <$> onceAff1 errorH s
|
||||||
]
|
]
|
||||||
|
closed <- liftEffect $ isClosed s
|
||||||
|
readEnded <- liftEffect $ isReadableEnded s
|
||||||
|
readable <- liftEffect $ isReadable s
|
||||||
|
length <- liftEffect $ readableLength s
|
||||||
|
if (not closed && not readEnded && readable && length == 0) then
|
||||||
|
liftEither =<< Aff.joinFiber fiber
|
||||||
|
else
|
||||||
|
Aff.killFiber (error "") fiber
|
||||||
|
|
||||||
awaitFinished :: forall s a. Write s a => s -> Aff Unit
|
awaitFinished :: forall s a. Write s a => s -> Aff Unit
|
||||||
awaitFinished s = onceAff0 finishH s
|
awaitFinished s = do
|
||||||
|
fiber <- Aff.forkAff $ onceAff0 finishH s
|
||||||
|
finished <- liftEffect $ isWritableFinished s
|
||||||
|
if not finished then Aff.joinFiber fiber else Aff.killFiber (error "") fiber
|
||||||
|
|
||||||
awaitWritableOrClosed :: forall s a. Write s a => s -> Aff Unit
|
awaitWritableOrClosed :: forall s a. Write s a => s -> Aff Unit
|
||||||
awaitWritableOrClosed s = do
|
awaitWritableOrClosed s = do
|
||||||
|
fiber <- Aff.forkAff $ parOneOf [ onceAff0 drainH s $> Right unit, onceAff0 closeH s $> Right unit, Left <$> onceAff1 errorH s ]
|
||||||
|
closed <- liftEffect $ isClosed s
|
||||||
|
writeEnded <- liftEffect $ isWritableEnded s
|
||||||
writable <- liftEffect $ isWritable s
|
writable <- liftEffect $ isWritable s
|
||||||
needsDrain <- liftEffect $ needsDrain s
|
needsDrain <- liftEffect $ needsDrain s
|
||||||
when (writable && needsDrain)
|
if not closed && not writeEnded && writable && needsDrain then
|
||||||
$ liftEither =<< parOneOf [ onceAff0 drainH s $> Right unit, onceAff0 closeH s $> Right unit, Left <$> onceAff1 errorH s ]
|
liftEither =<< Aff.joinFiber fiber
|
||||||
|
else
|
||||||
|
Aff.killFiber (error "") fiber
|
||||||
|
|
||||||
onceAff0 :: forall e. EventHandle0 e -> e -> Aff Unit
|
onceAff0 :: forall e. EventHandle0 e -> e -> Aff Unit
|
||||||
onceAff0 h emitter = makeAff \res -> do
|
onceAff0 h emitter = makeAff \res -> do
|
||||||
|
@ -8,10 +8,8 @@ import Control.Monad.ST.Class (liftST)
|
|||||||
import Control.Monad.ST.Ref as STRef
|
import Control.Monad.ST.Ref as STRef
|
||||||
import Control.Monad.Trans.Class (lift)
|
import Control.Monad.Trans.Class (lift)
|
||||||
import Data.Maybe (Maybe(..), maybe)
|
import Data.Maybe (Maybe(..), maybe)
|
||||||
import Data.Newtype (wrap)
|
|
||||||
import Data.Traversable (for_, traverse, traverse_)
|
import Data.Traversable (for_, traverse, traverse_)
|
||||||
import Data.Tuple.Nested ((/\))
|
import Data.Tuple.Nested ((/\))
|
||||||
import Effect.Aff (delay)
|
|
||||||
import Effect.Aff.Class (class MonadAff, liftAff)
|
import Effect.Aff.Class (class MonadAff, liftAff)
|
||||||
import Effect.Class (liftEffect)
|
import Effect.Class (liftEffect)
|
||||||
import Effect.Exception (Error)
|
import Effect.Exception (Error)
|
||||||
@ -19,7 +17,6 @@ import Node.Stream.Object as O
|
|||||||
import Pipes (await, yield)
|
import Pipes (await, yield)
|
||||||
import Pipes (for) as P
|
import Pipes (for) as P
|
||||||
import Pipes.Core (Consumer, Pipe, Producer, Producer_)
|
import Pipes.Core (Consumer, Pipe, Producer, Producer_)
|
||||||
import Pipes.Prelude (mapFoldable) as P
|
|
||||||
import Pipes.Util (InvokeResult(..), invoke)
|
import Pipes.Util (InvokeResult(..), invoke)
|
||||||
|
|
||||||
-- | Convert a `Readable` stream to a `Pipe`.
|
-- | Convert a `Readable` stream to a `Pipe`.
|
||||||
@ -97,28 +94,32 @@ fromTransform t = do
|
|||||||
maybeThrow = traverse_ throwError =<< liftEffect (liftST $ STRef.read errorST)
|
maybeThrow = traverse_ throwError =<< liftEffect (liftST $ STRef.read errorST)
|
||||||
|
|
||||||
cleanup = do
|
cleanup = do
|
||||||
|
flip tailRecM unit $ const do
|
||||||
|
liftAff $ O.awaitReadableOrClosed t
|
||||||
|
readEnded <- liftEffect $ O.isReadableEnded t
|
||||||
|
yieldWhileReadable
|
||||||
|
pure $ (if readEnded then Done else Loop) unit
|
||||||
|
|
||||||
liftAff $ O.awaitFinished t
|
liftAff $ O.awaitFinished t
|
||||||
fromReadable t
|
|
||||||
maybeThrow
|
maybeThrow
|
||||||
liftEffect $ removeErrorListener
|
liftEffect $ removeErrorListener
|
||||||
|
yield Nothing
|
||||||
|
|
||||||
yieldWhileReadable = void $ whileJust $ maybeYield1
|
yieldWhileReadable = void $ whileJust $ maybeYield1
|
||||||
|
|
||||||
maybeYield1 = traverse (\a -> yield (Just a) $> Just unit) =<< O.maybeReadResult <$> liftEffect (O.read t)
|
maybeYield1 = traverse (\a -> yield (Just a) $> Just unit) =<< O.maybeReadResult <$> liftEffect (O.read t)
|
||||||
|
|
||||||
onEOS = liftEffect (O.end t) *> cleanup $> Done unit
|
onEOS = liftEffect (O.end t) *> cleanup $> Done unit
|
||||||
onChunk a =
|
onChunk a = liftEffect (O.write t a) $> Loop unit
|
||||||
liftEffect (O.write t a)
|
|
||||||
>>= case _ of
|
|
||||||
O.WriteOk -> maybeYield1 $> Loop unit
|
|
||||||
O.WriteWouldBlock -> yieldWhileReadable $> Loop unit
|
|
||||||
|
|
||||||
go _ = do
|
go _ = do
|
||||||
maybeThrow
|
maybeThrow
|
||||||
needsDrain <- liftEffect $ O.needsDrain t
|
needsDrain <- liftEffect $ O.needsDrain t
|
||||||
ended <- liftEffect $ O.isWritableEnded t
|
ended <- liftEffect $ O.isWritableEnded t
|
||||||
if needsDrain then
|
if needsDrain then do
|
||||||
liftAff (delay $ wrap 0.0) *> yieldWhileReadable $> Loop unit
|
yieldWhileReadable
|
||||||
|
liftAff $ O.awaitWritableOrClosed t
|
||||||
|
pure $ Loop unit
|
||||||
else if ended then
|
else if ended then
|
||||||
cleanup $> Done unit
|
cleanup $> Done unit
|
||||||
else
|
else
|
||||||
@ -136,7 +137,7 @@ withEOS a = do
|
|||||||
|
|
||||||
-- | Strip a pipeline of the EOS signal
|
-- | Strip a pipeline of the EOS signal
|
||||||
unEOS :: forall a m. Monad m => Pipe (Maybe a) a m Unit
|
unEOS :: forall a m. Monad m => Pipe (Maybe a) a m Unit
|
||||||
unEOS = P.mapFoldable identity
|
unEOS = tailRecM (const $ maybe (pure $ Done unit) (\a -> yield a $> Loop unit) =<< await) unit
|
||||||
|
|
||||||
-- | Lift a `Pipe a a` to `Pipe (Maybe a) (Maybe a)`.
|
-- | Lift a `Pipe a a` to `Pipe (Maybe a) (Maybe a)`.
|
||||||
-- |
|
-- |
|
||||||
|
@ -86,9 +86,14 @@ chunked size = do
|
|||||||
a <- MaybeT await
|
a <- MaybeT await
|
||||||
chunkPut a
|
chunkPut a
|
||||||
len <- lift chunkLength
|
len <- lift chunkLength
|
||||||
when (len >= size) $ lift $ yield =<< Just <$> chunkTake
|
when (len >= size) do
|
||||||
|
chunk <- lift chunkTake
|
||||||
|
lift $ yield $ Just chunk
|
||||||
len <- chunkLength
|
len <- chunkLength
|
||||||
when (len > 0) $ yield =<< Just <$> chunkTake
|
when (len > 0) do
|
||||||
|
chunk <- chunkTake
|
||||||
|
yield $ Just chunk
|
||||||
|
|
||||||
yield Nothing
|
yield Nothing
|
||||||
|
|
||||||
-- | Equivalent of unix `uniq`, filtering out duplicate values passed to it.
|
-- | Equivalent of unix `uniq`, filtering out duplicate values passed to it.
|
||||||
|
Loading…
Reference in New Issue
Block a user