Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to parse multiple objects #38

Open
lmammino opened this issue Jan 19, 2018 · 5 comments
Open

How to parse multiple objects #38

lmammino opened this issue Jan 19, 2018 · 5 comments

Comments

@lmammino
Copy link

Is it possible to parse a buffer that contains multiple objects?

After a 30-minutes investigation, I couldn't figure out a way to do it.

@lmammino
Copy link
Author

lmammino commented Jan 23, 2018

I found a solution eventually. Not sure it's the ideal one, but it seems to be working.

The idea is that I keep iterating over the data buffer until:

buffer.length > capnp.expectedSizeFromPrefix(buffer)

For every iteration, the buffer is slice with the expectedSizeFromPrefix size removed from to beginning.

This is a streaming implementation of this approach.

const { Transform } = require('stream')
const capnp = require('capnp')

class CapnpReaderStream extends Transform {
  constructor (schema, options = {}) {
    options.objectMode = true
    super(options)
    this.schema = schema
    this.buffer = null

  }

  _transform (chunk, encoding, callback) {
    if (!this.buffer) {
      this.buffer = chunk
    } else {
      this.buffer = Buffer.concat([this.buffer, chunk])
    }

    let expectedSize = capnp.expectedSizeFromPrefix(this.buffer)
    let data = null
    while (this.buffer.length >= expectedSize) {
      data = capnp.parse(this.schema, this.buffer)
      this.buffer = this.buffer.slice(expectedSize)
      expectedSize = capnp.expectedSizeFromPrefix(this.buffer)
      this.push(data)
    }

    callback()
  }
}

module.exports = CapnpReaderStream

Please @kentonv, let me know if this approach makes sense of if there are better approaches.

@lmammino
Copy link
Author

Turned this into an npm module https://github.com/lmammino/capnp-stream/

I will probably add a writable equivalent

Looking forward for @kentonv feedback

@kentonv
Copy link
Member

kentonv commented Jan 24, 2018

Hmm, I guess that's probably the best way to do it given the current interface.

In C++ you would read a stream by constructing a new InputStreamMessageReader or StreamFdMessageReader for each message. Or, FlatArrayMessageReader has a method to get the rest of the buffer after the message end. But these aren't exposed in node-capnp as far as I recall.

I'd be happy to accept a PR implementing a new variant of parse() that also returns the endpoint of the message, or returns the slice of the buffer after the message end.

@lmammino
Copy link
Author

Thanks, @kentonv. This approach doesn't seem to work when using the packed option. The expectedSizeFromPrefix seems to hang forever. Any advice on how to solve this?

Regarding the PR, unfortunately, I don't have experience in porting c/c++ modules to Node.js

@kentonv
Copy link
Member

kentonv commented Jan 24, 2018

expectedSizeFromPrefix should never hang -- that seems like a bug. However, it definitely won't work on packed messages. Making a version of this that works for packed messages would require new C++ code that unfortunately will be a bit hairy to implement. Feel free to file an issue but I'm not sure when I'll be able to work on it... :/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants