Low hanging fruit: Don't re-create binary parsers constantly
This commit is contained in:
parent
2c9a68d0b1
commit
cd3b8d5e76
|
@ -165,6 +165,74 @@ exports.PacketHeader = PacketHeader;
|
|||
// * Writeup on differences between type 2, 2.2, and 2+:
|
||||
// http://walon.org/pub/fidonet/FTSC-nodelists-etc./pkt-types.txt
|
||||
//
|
||||
const PacketHeaderParser = new Parser()
|
||||
.uint16le('origNode')
|
||||
.uint16le('destNode')
|
||||
.uint16le('year')
|
||||
.uint16le('month')
|
||||
.uint16le('day')
|
||||
.uint16le('hour')
|
||||
.uint16le('minute')
|
||||
.uint16le('second')
|
||||
.uint16le('baud')
|
||||
.uint16le('packetType')
|
||||
.uint16le('origNet')
|
||||
.uint16le('destNet')
|
||||
.int8('prodCodeLo')
|
||||
.int8('prodRevLo') // aka serialNo
|
||||
.buffer('password', { length : 8 }) // can't use string; need CP437 - see https://github.com/keichi/binary-parser/issues/33
|
||||
.uint16le('origZone')
|
||||
.uint16le('destZone')
|
||||
//
|
||||
// The following is "filler" in FTS-0001, specifics in
|
||||
// FSC-0045 and FSC-0048
|
||||
//
|
||||
.uint16le('auxNet')
|
||||
.uint16le('capWordValidate')
|
||||
.int8('prodCodeHi')
|
||||
.int8('prodRevHi')
|
||||
.uint16le('capWord')
|
||||
.uint16le('origZone2')
|
||||
.uint16le('destZone2')
|
||||
.uint16le('origPoint')
|
||||
.uint16le('destPoint')
|
||||
.uint32le('prodData');
|
||||
|
||||
const MessageHeaderParser = new Parser()
|
||||
.uint16le('messageType')
|
||||
.uint16le('ftn_msg_orig_node')
|
||||
.uint16le('ftn_msg_dest_node')
|
||||
.uint16le('ftn_msg_orig_net')
|
||||
.uint16le('ftn_msg_dest_net')
|
||||
.uint16le('ftn_attr_flags')
|
||||
.uint16le('ftn_cost')
|
||||
//
|
||||
// It would be nice to just string() these, but we want CP437 which requires
|
||||
// iconv. Another option would be to use a formatter, but until issue 33
|
||||
// (https://github.com/keichi/binary-parser/issues/33) is fixed, this is cumbersome.
|
||||
//
|
||||
.array('modDateTime', {
|
||||
type : 'uint8',
|
||||
length : 20, // FTS-0001.016: 20 bytes
|
||||
})
|
||||
.array('toUserName', {
|
||||
type : 'uint8',
|
||||
// :TODO: array needs some soft of 'limit' field
|
||||
readUntil : b => 0x00 === b,
|
||||
})
|
||||
.array('fromUserName', {
|
||||
type : 'uint8',
|
||||
readUntil : b => 0x00 === b,
|
||||
})
|
||||
.array('subject', {
|
||||
type : 'uint8',
|
||||
readUntil : b => 0x00 === b,
|
||||
})
|
||||
.array('message', {
|
||||
type : 'uint8',
|
||||
readUntil : b => 0x00 === b,
|
||||
});
|
||||
|
||||
function Packet(options) {
|
||||
var self = this;
|
||||
|
||||
|
@ -175,39 +243,7 @@ function Packet(options) {
|
|||
|
||||
let packetHeader;
|
||||
try {
|
||||
packetHeader = new Parser()
|
||||
.uint16le('origNode')
|
||||
.uint16le('destNode')
|
||||
.uint16le('year')
|
||||
.uint16le('month')
|
||||
.uint16le('day')
|
||||
.uint16le('hour')
|
||||
.uint16le('minute')
|
||||
.uint16le('second')
|
||||
.uint16le('baud')
|
||||
.uint16le('packetType')
|
||||
.uint16le('origNet')
|
||||
.uint16le('destNet')
|
||||
.int8('prodCodeLo')
|
||||
.int8('prodRevLo') // aka serialNo
|
||||
.buffer('password', { length : 8 }) // can't use string; need CP437 - see https://github.com/keichi/binary-parser/issues/33
|
||||
.uint16le('origZone')
|
||||
.uint16le('destZone')
|
||||
//
|
||||
// The following is "filler" in FTS-0001, specifics in
|
||||
// FSC-0045 and FSC-0048
|
||||
//
|
||||
.uint16le('auxNet')
|
||||
.uint16le('capWordValidate')
|
||||
.int8('prodCodeHi')
|
||||
.int8('prodRevHi')
|
||||
.uint16le('capWord')
|
||||
.uint16le('origZone2')
|
||||
.uint16le('destZone2')
|
||||
.uint16le('origPoint')
|
||||
.uint16le('destPoint')
|
||||
.uint32le('prodData')
|
||||
.parse(packetBuffer);
|
||||
packetHeader = PacketHeaderParser.parse(packetBuffer);
|
||||
} catch(e) {
|
||||
return Errors.Invalid(`Unable to parse FTN packet header: ${e.message}`);
|
||||
}
|
||||
|
@ -544,41 +580,7 @@ function Packet(options) {
|
|||
|
||||
let msgData;
|
||||
try {
|
||||
msgData = new Parser()
|
||||
.uint16le('messageType')
|
||||
.uint16le('ftn_msg_orig_node')
|
||||
.uint16le('ftn_msg_dest_node')
|
||||
.uint16le('ftn_msg_orig_net')
|
||||
.uint16le('ftn_msg_dest_net')
|
||||
.uint16le('ftn_attr_flags')
|
||||
.uint16le('ftn_cost')
|
||||
//
|
||||
// It would be nice to just string() these, but we want CP437 which requires
|
||||
// iconv. Another option would be to use a formatter, but until issue 33
|
||||
// (https://github.com/keichi/binary-parser/issues/33) is fixed, this is cumbersome.
|
||||
//
|
||||
.array('modDateTime', {
|
||||
type : 'uint8',
|
||||
length : 20, // FTS-0001.016: 20 bytes
|
||||
})
|
||||
.array('toUserName', {
|
||||
type : 'uint8',
|
||||
// :TODO: array needs some soft of 'limit' field
|
||||
readUntil : b => 0x00 === b,
|
||||
})
|
||||
.array('fromUserName', {
|
||||
type : 'uint8',
|
||||
readUntil : b => 0x00 === b,
|
||||
})
|
||||
.array('subject', {
|
||||
type : 'uint8',
|
||||
readUntil : b => 0x00 === b,
|
||||
})
|
||||
.array('message', {
|
||||
type : 'uint8',
|
||||
readUntil : b => 0x00 === b,
|
||||
})
|
||||
.parse(packetBuffer);
|
||||
msgData = MessageHeaderParser.parse(packetBuffer);
|
||||
} catch(e) {
|
||||
return cb(Errors.Invalid(`Failed to parse FTN message header: ${e.message}`));
|
||||
}
|
||||
|
|
|
@ -26,6 +26,25 @@ exports.SAUCE_SIZE = SAUCE_SIZE;
|
|||
//
|
||||
const SAUCE_VALID_DATA_TYPES = [0, 1, 2, 3, 4, 5, 6, 7, 8 ];
|
||||
|
||||
const SAUCEParser = new Parser()
|
||||
.buffer('id', { length : 5 } )
|
||||
.buffer('version', { length : 2 } )
|
||||
.buffer('title', { length: 35 } )
|
||||
.buffer('author', { length : 20 } )
|
||||
.buffer('group', { length: 20 } )
|
||||
.buffer('date', { length: 8 } )
|
||||
.uint32le('fileSize')
|
||||
.int8('dataType')
|
||||
.int8('fileType')
|
||||
.uint16le('tinfo1')
|
||||
.uint16le('tinfo2')
|
||||
.uint16le('tinfo3')
|
||||
.uint16le('tinfo4')
|
||||
.int8('numComments')
|
||||
.int8('flags')
|
||||
// :TODO: does this need to be optional?
|
||||
.buffer('tinfos', { length: 22 } ); // SAUCE 00.5
|
||||
|
||||
function readSAUCE(data, cb) {
|
||||
if(data.length < SAUCE_SIZE) {
|
||||
return cb(Errors.DoesNotExist('No SAUCE record present'));
|
||||
|
@ -33,30 +52,11 @@ function readSAUCE(data, cb) {
|
|||
|
||||
let sauceRec;
|
||||
try {
|
||||
sauceRec = new Parser()
|
||||
.buffer('id', { length : 5 } )
|
||||
.buffer('version', { length : 2 } )
|
||||
.buffer('title', { length: 35 } )
|
||||
.buffer('author', { length : 20 } )
|
||||
.buffer('group', { length: 20 } )
|
||||
.buffer('date', { length: 8 } )
|
||||
.uint32le('fileSize')
|
||||
.int8('dataType')
|
||||
.int8('fileType')
|
||||
.uint16le('tinfo1')
|
||||
.uint16le('tinfo2')
|
||||
.uint16le('tinfo3')
|
||||
.uint16le('tinfo4')
|
||||
.int8('numComments')
|
||||
.int8('flags')
|
||||
// :TODO: does this need to be optional?
|
||||
.buffer('tinfos', { length: 22 } ) // SAUCE 00.5
|
||||
.parse(data.slice(data.length - SAUCE_SIZE));
|
||||
sauceRec = SAUCEParser.parse(data.slice(data.length - SAUCE_SIZE));
|
||||
} catch(e) {
|
||||
return cb(Errors.Invalid('Invalid SAUCE record'));
|
||||
}
|
||||
|
||||
|
||||
if(!SAUCE_ID.equals(sauceRec.id)) {
|
||||
return cb(Errors.DoesNotExist('No SAUCE record present'));
|
||||
}
|
||||
|
|
|
@ -192,6 +192,18 @@ OPTION_IMPLS[OPTIONS.SUPPRESS_GO_AHEAD] = function(bufs, i, event) {
|
|||
return event;
|
||||
};
|
||||
|
||||
const TermTypeCmdParser = new Parser()
|
||||
.uint8('iac1')
|
||||
.uint8('sb')
|
||||
.uint8('opt')
|
||||
.uint8('is')
|
||||
.array('ttype', {
|
||||
type : 'uint8',
|
||||
readUntil : b => 255 === b, // 255=COMMANDS.IAC
|
||||
})
|
||||
// note we read iac2 above
|
||||
.uint8('se');
|
||||
|
||||
OPTION_IMPLS[OPTIONS.TERMINAL_TYPE] = function(bufs, i, event) {
|
||||
if(event.commandCode !== COMMANDS.SB) {
|
||||
OPTION_IMPLS.NO_ARGS(bufs, i, event);
|
||||
|
@ -208,18 +220,7 @@ OPTION_IMPLS[OPTIONS.TERMINAL_TYPE] = function(bufs, i, event) {
|
|||
|
||||
let ttypeCmd;
|
||||
try {
|
||||
ttypeCmd = new Parser()
|
||||
.uint8('iac1')
|
||||
.uint8('sb')
|
||||
.uint8('opt')
|
||||
.uint8('is')
|
||||
.array('ttype', {
|
||||
type : 'uint8',
|
||||
readUntil : b => 255 === b, // 255=COMMANDS.IAC
|
||||
})
|
||||
// note we read iac2 above
|
||||
.uint8('se')
|
||||
.parse(bufs.toBuffer());
|
||||
ttypeCmd = TermTypeCmdParser.parse(bufs.toBuffer());
|
||||
} catch(e) {
|
||||
Log.debug( { error : e }, 'Failed parsing TTYP telnet command');
|
||||
return event;
|
||||
|
@ -242,6 +243,15 @@ OPTION_IMPLS[OPTIONS.TERMINAL_TYPE] = function(bufs, i, event) {
|
|||
return event;
|
||||
};
|
||||
|
||||
const NawsCmdParser = new Parser()
|
||||
.uint8('iac1')
|
||||
.uint8('sb')
|
||||
.uint8('opt')
|
||||
.uint16be('width')
|
||||
.uint16be('height')
|
||||
.uint8('iac2')
|
||||
.uint8('se');
|
||||
|
||||
OPTION_IMPLS[OPTIONS.WINDOW_SIZE] = function(bufs, i, event) {
|
||||
if(event.commandCode !== COMMANDS.SB) {
|
||||
OPTION_IMPLS.NO_ARGS(bufs, i, event);
|
||||
|
@ -253,15 +263,7 @@ OPTION_IMPLS[OPTIONS.WINDOW_SIZE] = function(bufs, i, event) {
|
|||
|
||||
let nawsCmd;
|
||||
try {
|
||||
nawsCmd = new Parser()
|
||||
.uint8('iac1')
|
||||
.uint8('sb')
|
||||
.uint8('opt')
|
||||
.uint16be('width')
|
||||
.uint16be('height')
|
||||
.uint8('iac2')
|
||||
.uint8('se')
|
||||
.parse(bufs.splice(0, 9).toBuffer());
|
||||
nawsCmd = NawsCmdParser.parse(bufs.splice(0, 9).toBuffer());
|
||||
} catch(e) {
|
||||
Log.debug( { error : e }, 'Failed parsing NAWS telnet command');
|
||||
return event;
|
||||
|
@ -282,6 +284,18 @@ OPTION_IMPLS[OPTIONS.WINDOW_SIZE] = function(bufs, i, event) {
|
|||
// Build an array of delimiters for parsing NEW_ENVIRONMENT[_DEP]
|
||||
//const NEW_ENVIRONMENT_DELIMITERS = _.values(NEW_ENVIRONMENT_COMMANDS);
|
||||
|
||||
const EnvCmdParser = new Parser()
|
||||
.uint8('iac1')
|
||||
.uint8('sb')
|
||||
.uint8('opt')
|
||||
.uint8('isOrInfo') // IS=initial, INFO=updates
|
||||
.array('envBlock', {
|
||||
type : 'uint8',
|
||||
readUntil : b => 255 === b, // 255=COMMANDS.IAC
|
||||
})
|
||||
// note we consume IAC above
|
||||
.uint8('se');
|
||||
|
||||
// Handle the deprecated RFC 1408 & the updated RFC 1572:
|
||||
OPTION_IMPLS[OPTIONS.NEW_ENVIRONMENT_DEP] =
|
||||
OPTION_IMPLS[OPTIONS.NEW_ENVIRONMENT] = function(bufs, i, event) {
|
||||
|
@ -306,18 +320,7 @@ OPTION_IMPLS[OPTIONS.NEW_ENVIRONMENT] = function(bufs, i, event) {
|
|||
|
||||
let envCmd;
|
||||
try {
|
||||
envCmd = new Parser()
|
||||
.uint8('iac1')
|
||||
.uint8('sb')
|
||||
.uint8('opt')
|
||||
.uint8('isOrInfo') // IS=initial, INFO=updates
|
||||
.array('envBlock', {
|
||||
type : 'uint8',
|
||||
readUntil : b => 255 === b, // 255=COMMANDS.IAC
|
||||
})
|
||||
// note we consume IAC above
|
||||
.uint8('se')
|
||||
.parse(bufs.splice(0, bufs.length).toBuffer());
|
||||
envCmd = EnvCmdParser.parse(bufs.splice(0, bufs.length).toBuffer());
|
||||
} catch(e) {
|
||||
Log.debug( { error : e }, 'Failed parsing NEW-ENVIRON telnet command');
|
||||
return event;
|
||||
|
|
Loading…
Reference in New Issue