我相信您将无法重用该pipes-aeson
库,因为它不提供在解码的 JSON 记录的嵌套字段上流式传输的方法,也不支持结构的类似光标的导航。这意味着您将需要手动解析 JSON 记录的骨架。
此外,还需要做一些工作来将这种类型的 API 包装base64-bytestring
在类似pipes
的 API 中:
-- Convert a base64-encoded stream to a raw byte stream
decodeBase64
:: Producer ByteString m r
-- ^ Base64-encoded bytes
-> Producer ByteString m (Either SomeException (Producer ByteString m r))
-- ^ Raw bytes
请注意,Producer
如果解码成功完成,则结果将返回字节字符串的其余部分(即 base64 编码字节之后的所有内容)。这使您可以继续解析图像字节结束的位置。
但是,假设您有一个decodeBase64
函数,那么代码如何工作的大致轮廓是您将具有三个部分:
binary
使用适用于的解析器在图像字节之前解析记录的前缀pipes
- 使用该
decodeBase64
函数流式传输解码的图像字节
- 在图像字节之后解析记录的后缀,也使用
binary
适用于的解析器pipes
换句话说,类型和实现大致如下所示:
-- This would match the "{ 'id' : 'foo', 'image' : '" prefix of the JSON record
skipPrefix :: Data.Binary.Get ()
skipPrefix’ :: Monad m => Producer ByteString m r -> m (Either DecodingError (Producer ByteString m r))
skipPrefix’ = execStateT (Pipes.Binary.decodeGet skipPrefix)
— This would match the "' }" suffix of the JSON record
skipSuffix :: Data.Binary.Get ()
skipSuffix’ :: Monad m => Producer ByteString m r -> m (Either DecodingError (Producer ByteString m r))
skipSuffix’ = execStateT (Pipes.Binary.decodeGet skipSuffix)
streamImage
:: Monad m
=> Producer ByteString m r
-> Producer ByteString m (Either SomeException (Producer ByteString m r))
streamImage p0 = do
e0 <- lift (skipPrefix’ p0)
case e0 of
Left exc -> return (Left (toException exc))
Right p1 -> do
e1 <- decodeBase64 p1
case e1 of
Left exc -> return (Left exc)
Right p2 -> do
e2 <- lift (skipSuffix’ p2)
case e2 of
Left exc -> return (Left (toException exc))
Right p3 -> return (Right p3)
换句话说,streamImage
它将 aProducer
作为输入,从 JSON 记录的第一个字符开始,它将流式传输从该记录中提取的解码图像字节。如果解码成功,那么它将在 JSON 记录之后立即返回字节流的剩余部分。