让我们说我们有一个这样的JSON对象(使用base64编码的字节串):
TaggedImage = TaggedImage { id :: Text, image :: ByteString }
现在,我们希望从来源收到image
,并使用id
标记中的信息将其存储在某个位置。因此,这意味着必须提前解析id
(以确定图像的位置),同时以流方式解析image
。这是直截了当的吗?
我打算使用pipes-aeson
,aws
(用于S3
存储)和pipes
从Websocket
制作人处使用{{1}进行流解码作为消费者的桶(在我们解析S3
以确定id
桶的位置之前,无法创建)。看看decoded
方法,我无法弄清楚我是否确实可以做我上面提到的问题。这是我第一次尝试使用JSON和管道进行流式处理。所以,非常感谢帮助。
对文件系统进行读写操作的简单示例也可以作为S3
和Websocket producer
的替代。
附录
由于在排序数组时,根据RFC JSON键值对是无序的,S3 consumer
数据可能会出现在image
之前,对于我在上面定义的数据类型。因此,它也可能有助于将其更改为JSON数组(Haskell中的一个元组id
TH派生似乎转换为有序数组)。如果需要,请随意更改数据类型定义,以强加解码顺序。例如,数据类型可能更改为:
aeson
答案 0 :(得分:1)
我相信你将无法重用pipes-aeson
库,因为它没有提供一种流式传输已解码的JSON记录的嵌套字段的方法,也没有任何支持类似光标的导航结构。这意味着您需要手动解析JSON记录的骨架。
此外,还需要完成一些工作,将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
请注意,如果解码成功完成,结果将为字节字符串的其余部分(即base64编码的字节后的所有内容)返回Producer
。这使您可以继续解析图像字节结束的位置。
但是,假设您有一个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
将以Producer
作为输入,从JSON记录的第一个字符开始,它将流式传输从该记录中提取的解码图像字节。如果解码成功,那么它将在JSON记录之后立即返回字节流的剩余部分。