我想让 warp 运行一个进程,然后用该进程的输出响应。假设输出大于服务器的 RAM;加载整个输出然后响应不是一种选择。我以为我可以使用类似的东西来完成此任务
withProcessWait_ (setStdout createSource "cat largefile") (pure . responseSource ok200 [] . getStdout)
但responseSource
用途ConduitT i (Flush Builder) IO ()
和createSource
用途ConduitT i ByteString m ()
。我不知道如何将ByteString
管道转换为Flush Builder
管道。
所以我设计了一个似乎可行的解决方案,但遗憾的是它的定义不那么简单:
responseProcess :: Status -> ResponseHeaders -> ProcessConfig in out err -> Response
responseProcess s hs cfg = responseStream s hs $ \send flush ->
withProcessWait_ (setStdout createPipe cfg) $ \p@(getStdout -> h) ->
let loop = do
bs <- hGetSome h defaultChunkSize
unless (BS.null bs) (send (byteString bs) *> flush *> loop)
in loop *> hClose h
. 这有必要吗,即使我可以尝试通过包裹mkStreamSpec
或其他方式来美化它?还是我缺少更简单的方法?
编辑:对解决方案的评论:
intersperseC
让我Chunk
和Flush
一起使用。这解决了Flush Builder
/ByteString
转换问题。我还没有测试过它,但它看起来是正确的,我相信它已经被使用过。
然而,我发现
withProcessWait_ (setStdout createSource "cat largefile") $ \p ->
responseSource ok200 [] (getStdout p .| mapC (Chunk . byteString) .| intersperseC Flush)
过早关闭进程句柄。因此我需要自己管理管道:使用createPipe
而不是createSource
. 但这意味着我需要hClose
在最后调用,这意味着我需要一个返回的响应处理程序IO ()
;唯一能做的(除了responseRaw
)是responseStream
,它StreamingBody
用作Conduit的替代品。因此,我得出结论,需要我的原始解决方案,并且 Conduit 不能用于流式处理。如果不正确,请随时纠正。