Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion doc/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ Create a serializer of `mainType` defined in `proto`. This is a Transform stream

### Serializer.createPacketBuffer(packet)

Returns a buffer of the `packet`.
Returns a buffer of the `packet`. If serialization fails and `packet.name` is set, the error message is prefixed with
`in packet <name>: ` unless the error's field path already contains that name.

## Parser(proto,mainType)

Expand Down
11 changes: 10 additions & 1 deletion src/serializer.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,16 @@ class Serializer extends Transform {
}

createPacketBuffer (packet) {
return this.proto.createPacketBuffer(this.mainType, packet)
try {
return this.proto.createPacketBuffer(this.mainType, packet)
} catch (e) {
// A compiled protocol reports no field path, so the packet name is the only way to say which packet failed
const name = packet?.name
if (name != null && !String(e.field ?? '').split('.').includes(String(name))) {
e.message = `in packet ${name}: ${e.message}`
}
throw e
}
}

_transform (chunk, enc, cb) {
Expand Down
31 changes: 30 additions & 1 deletion test/misc.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-env mocha */

const assert = require('assert')
const { ProtoDef } = require('../')
const { ProtoDef, Serializer } = require('../')
const { ProtoDefCompiler } = require('../').Compiler

it('example works', () => {
Expand All @@ -25,3 +25,32 @@ describe('mapper', () => {
})
}
})

describe('Serializer', () => {
const types = {
packet_position: ['container', [{ name: 'x', type: 'f64' }, { name: 'face', type: ['mapper', { type: 'varint', mappings: { 0: 'down' } }] }]],
packet: ['container', [
{ name: 'name', type: ['mapper', { type: 'varint', mappings: { 0: 'position' } }] },
{ name: 'params', type: ['switch', { compareTo: 'name', fields: { position: 'packet_position' } }] }
]]
}
const proto = new ProtoDef()
proto.addTypes(types)
const compiler = new ProtoDefCompiler()
compiler.addTypesToCompile(types)
const compiled = compiler.compileProtoDefSync()
const bad = { name: 'position', params: { x: 1, face: 'up' } }

it('names the packet when the error has no field path (compiled)', () => {
assert.throws(() => new Serializer(compiled, 'packet').createPacketBuffer(bad),
{ message: 'in packet position: SizeOf error for undefined : up is not in the mappings value' })
})
it('does not repeat a packet name already in the field path (interpreted)', () => {
assert.throws(() => new Serializer(proto, 'packet').createPacketBuffer(bad),
{ message: 'SizeOf error for params.position.face : up is not in the mappings value' })
})
it('leaves errors alone when the value has no name', () => {
assert.throws(() => new Serializer(compiled, 'packet_position').createPacketBuffer(bad.params),
{ message: 'SizeOf error for undefined : up is not in the mappings value' })
})
})
Loading