Я хотел бы реализовать потоки больших данных (в обоих направлениях) с помощью Snap-сервера. Чтобы изучить возможности, я создал образец программы, которая имеет две конечные точки - чтение и запись. Существует очень простой внутренний буфер, который содержит один ByteString
, и все, что написано в конечной точке записи, появляется в считывающем. (В настоящее время не существует никакого способа, как прекратить поток, но это нормально для этой цели.)Как реализовать потоковую передачу данных с помощью привязки?
{-# LANGUAGE OverloadedStrings #-}
import Control.Applicative
import Control.Concurrent.MVar.Lifted
import Control.Monad
import Data.ByteString (ByteString)
import Blaze.ByteString.Builder (Builder, fromByteString)
import Data.Enumerator
import qualified Data.Enumerator.List as E
import Data.Enumerator.Binary (enumFile, iterHandle)
import Snap.Core
import Snap.Http.Server
main :: IO()
main = do
buf <- newEmptyMVar
quickHttpServe (site buf)
site :: MVar ByteString -> Snap()
site buf =
route [ ("read", modifyResponse (setBufferingMode False
. setResponseBody (fromBuf buf)))
, ("write", runRequestBody (toBuf buf))
]
fromBuf :: MVar ByteString -> Enumerator Builder IO a
fromBuf buf = E.repeatM (liftM fromByteString $ takeMVar buf)
toBuf :: MVar ByteString -> Iteratee ByteString IO()
toBuf buf = E.mapM_ (putMVar buf)
Затем я бегу в разных терминалах
curl http://localhost:8000/read >/dev/nul
и
dd if=/dev/zero bs=1M count=100 | \
curl --data-binary @- http://localhost:8000/write
Но сбой записи с исключение, спрятанное в toplevel: Слишком много байтов, прочитанных. Это, очевидно, пример TooManyBytesReadException
, но я не мог найти, куда его бросили. Написание меньшего количества данных, таких как 1MB, работает так, как ожидалось.
Мои вопросы:
- Где/как исправить предел для чтения?
- Будет ли этот поток данных без загрузки всего запроса POST в память? Если нет, как это исправить?
Вероятно, «приложение/октет-поток» будет более подходящим типом контента. – nh2