带有流式存档的Websockets

时间:2013-10-15 08:16:13

标签: node.js websocket zip gzip archive

所以这就是我正在使用的设置:

  1. 我在快速服务器上,必须将存档的二进制有效负载流式传输到浏览器(无论是ziptar还是tar.gz都无关紧要 - 尽管zip会很好的。)
  2. 在这台服务器上,我打开了一个websocket,它连接到另一台服务器,该服务器向我发送目录中单个文件的二进制有效负载。我将这些有效负载作为缓冲区逐个流式传输,并且我按顺序执行此操作(即逐个文件 - 一次不打开多个websockets,每个文件有一个websocket )。这是我正在使用的websocket库:https://github.com/einaros/ws
  3. 我想浏览每个文件,打开一个websocket,然后在缓冲区通过websockets时将缓冲区附加到存档器中。当数据附加到归档器时,如果我可以将归档器的输出流式传输到浏览器(通过带有response的{​​{1}}对象),那将是很好的。所以,基本上,当我从websocket获取有效负载时,我希望有效负载通过归档器流传输到响应。 : - )

    我调查了一些事情:

    1. node-zipstream - 这很好,因为它为我提供了一个输出流,我可以直接管道到response.write。但是,它似乎不支持嵌套文件/文件夹,更重要的是,它只接受输入流。我查看了源代码(非常简洁和可读),似乎如果我能够访问response.write中的update函数,我可以调用每个我从websocket获取二进制缓冲区时ZipStream.prototype.addFile事件的时间。这是非常混乱/ hacky,并且,鉴于这个库似乎不支持嵌套文件/文件夹,我不确定我会不会用它。
    2. node-archiver - 这会遇到与node-zipstream相同的问题(可能是因为它受到它的启发),它允许我管道输出,但我不能为归档中的同一文件追加多个缓冲区(然后在为给定文件追加最后一个缓冲区时手动发出信号)。但是,它 允许我拥有嵌套文件夹,这明显胜过node-zipstream。
    3. 有什么我不知道的,或者这只是我想要做的一件非常疯狂的事情?

      我在这一点上看到的唯一选择是等待整个有效负载通过websocket进行流式处理,然后使用node-archiver附加,但我真的希望获得真正的流式传输/存档的好处。飞。

      我还考虑过创建一个读取流的可能性,只是作为一个代理对象,我可以将其传递给node-archiver,然后将我从websocket获取的缓冲区附加到此读取流。看看各种读取流,我不知道如何做到这一点。我能想到的唯一方法是创建一个写入流,向其传递缓冲区,并从该写入流中读取读取流。我在这里正确的思考过程吗?

      与往常一样,感谢您为SO社区提供的任何帮助/指导。

      修改

      由于我刚刚开启了这个问题,而且我是节点的新手,可能会有比我提供的答案更好的答案。如果一个人在几天内出现,我会保持这个问题的开放并接受更好的答案。一如往常,我会赞成任何其他答案,即使它们是荒谬的,只要它们是正确的,并允许我像我的那样即时流动。

1 个答案:

答案 0 :(得分:0)

我找到了一种方法来使用node-archiver。 : - )

这是基于我的预感,创造了一个临时的“代理流”,受到这个SO问题的启发:How to create streams from string in Node.Js?

基本要点是(coffeescript语法):

archive = archiver 'zip'
archive.pipe response // where response is the http response

// and then for each file...
fileName = ... // known file name
fileSize = ... // known file size
ws = .... // create websocket
proxyStream = new Stream()
numBytesStreamed = 0

archive.append proxyStream, name: fileName

ws.on 'message', (dataBuffer) ->
    numBytesStreamed += dataBuffer.length
    proxyStream.emit 'data', dataBuffer

    if numBytesStreamed is fileSize
        proxyStream.emit 'end'
        // function/indicator to do this for the next file in the folder

// and then when you're completely done...
archive.finalize (err, bytesOfArchive) ->
    if err?
        // do whatever
    else
        // unless you somehow knew this ahead of time
        res.addTrailers
            'Content-Length': bytesOfArchive
        res.end()

请注意,这不是我实施的完整解决方案。获取文件,路径等仍然有很多逻辑。更不用说错误处理了。

<强> 修改

由于我刚刚开启了这个问题,而且我是节点的新手,可能会有更好的答案。如果一个人在几天内出现,我会保持这个问题的开放并接受更好的答案。一如往常,我会赞成任何其他答案,即使它们是荒谬的,只要它们是正确的,并允许我像我的那样即时流动。