我想编写一个代理,它会收到一个标题,指示目标IP,端口等。
所以我有这样的事情:
getHeader = do
Just x <- await
let (a, rest) = splitAt headerLen x
return $ parseHeader a
-- how to send the rest data downstream ??
(resume, header) <- clientSource $$+ getHeader
-- do something according to the header
问题在于,有时会将标头和后续数据一起发送,因此getHeader
会消耗后续数据,这些数据应该被后来的管道消耗。那么如何发送rest
下游?
答案 0 :(得分:1)
您还可以考虑使用包含在管道中的解析器,例如 conduit-extra 中的Data.Conduit.Attoparsec
。包装器负责根据需要请求尽可能多的输入部分(在您的情况下,可能会发生第一部分短于headerLen
),以及处理剩余物:
import Control.Monad.Catch
import qualified Data.Attoparsec.ByteString as P
import Data.Attoparsec.Types
import qualified Data.ByteString as BS
import Data.Conduit
import Data.Conduit.Attoparsec
parseHeader :: Parser BS.ByteString BS.ByteString
parseHeader = P.take headerLen -- do whatever parsing you need to get the header
where
headerLen = 42
consumerHeader :: (MonadThrow m) => Consumer BS.ByteString m BS.ByteString
consumerHeader = sinkParser parseHeader
Consumer
定义为
type Consumer i m r = forall o. ConduitM i o m r
所以consumerHeader
将ByteString
作为输入,在输出和monad中是多态的,并返回已解析的ByteString
。