itns-sidechain/lib/workers/parser.js

203 lines
4.6 KiB
JavaScript
Raw Normal View History

2016-10-02 01:01:16 -07:00
/*!
2018-08-01 20:00:09 -07:00
* parser.js - worker parser for hsd
2018-02-01 13:40:45 -08:00
* Copyright (c) 2017-2018, Christopher Jeffrey (MIT License).
2018-08-01 20:00:09 -07:00
* https://github.com/handshake-org/hsd
2016-10-02 01:01:16 -07:00
*/
'use strict';
2018-07-19 05:40:48 -07:00
const assert = require('bsert');
const EventEmitter = require('events');
2017-06-29 20:54:07 -07:00
const packets = require('./packets');
2016-10-02 01:01:16 -07:00
/**
* Parser
2017-02-03 22:47:26 -08:00
* @alias module:workers.Parser
2017-11-16 20:26:28 -08:00
* @extends EventEmitter
2016-10-02 01:01:16 -07:00
*/
2017-11-16 20:26:28 -08:00
class Parser extends EventEmitter {
/**
* Create a parser.
* @constructor
*/
2016-10-02 01:01:16 -07:00
2017-11-16 20:26:28 -08:00
constructor() {
super();
2016-10-02 01:01:16 -07:00
2017-11-16 20:26:28 -08:00
this.waiting = 9;
this.header = null;
this.pending = [];
this.total = 0;
}
2016-10-02 01:01:16 -07:00
2017-11-16 20:26:28 -08:00
feed(data) {
this.total += data.length;
this.pending.push(data);
2016-10-02 01:01:16 -07:00
2017-11-16 20:26:28 -08:00
while (this.total >= this.waiting) {
const chunk = this.read(this.waiting);
this.parse(chunk);
}
2016-10-02 01:01:16 -07:00
}
2017-11-16 20:26:28 -08:00
read(size) {
assert(this.total >= size, 'Reading too much.');
2016-10-02 01:01:16 -07:00
2017-11-16 20:26:28 -08:00
if (size === 0)
return Buffer.alloc(0);
2016-10-02 01:01:16 -07:00
2017-11-16 20:26:28 -08:00
const pending = this.pending[0];
2016-10-02 01:01:16 -07:00
2017-11-16 20:26:28 -08:00
if (pending.length > size) {
const chunk = pending.slice(0, size);
this.pending[0] = pending.slice(size);
this.total -= chunk.length;
return chunk;
}
if (pending.length === size) {
const chunk = this.pending.shift();
this.total -= chunk.length;
return chunk;
}
const chunk = Buffer.allocUnsafe(size);
let off = 0;
while (off < chunk.length) {
const pending = this.pending[0];
const len = pending.copy(chunk, off);
if (len === pending.length)
this.pending.shift();
else
this.pending[0] = pending.slice(len);
off += len;
}
assert.strictEqual(off, chunk.length);
2016-10-02 01:01:16 -07:00
this.total -= chunk.length;
2017-11-16 20:26:28 -08:00
2016-10-02 01:01:16 -07:00
return chunk;
}
2017-11-16 20:26:28 -08:00
parse(data) {
let header = this.header;
2016-10-02 01:01:16 -07:00
2017-11-16 20:26:28 -08:00
if (!header) {
try {
header = this.parseHeader(data);
} catch (e) {
this.emit('error', e);
return;
}
2016-10-02 01:01:16 -07:00
2017-11-16 20:26:28 -08:00
this.header = header;
this.waiting = header.size + 1;
2016-10-02 01:01:16 -07:00
2017-11-16 20:26:28 -08:00
return;
}
2016-10-02 01:01:16 -07:00
2017-11-16 20:26:28 -08:00
this.waiting = 9;
this.header = null;
2016-10-02 01:01:16 -07:00
2017-11-16 20:26:28 -08:00
let packet;
2016-10-02 01:01:16 -07:00
try {
2017-11-16 20:26:28 -08:00
packet = this.parsePacket(header, data);
2016-10-02 01:01:16 -07:00
} catch (e) {
this.emit('error', e);
return;
}
2017-11-16 20:26:28 -08:00
if (data[data.length - 1] !== 0x0a) {
this.emit('error', new Error('No trailing newline.'));
return;
}
2016-10-02 01:01:16 -07:00
2017-11-16 20:26:28 -08:00
packet.id = header.id;
2016-10-02 01:01:16 -07:00
2017-11-16 20:26:28 -08:00
this.emit('packet', packet);
2016-10-02 01:01:16 -07:00
}
2017-11-16 20:26:28 -08:00
parseHeader(data) {
const id = data.readUInt32LE(0, true);
const cmd = data.readUInt8(4, true);
const size = data.readUInt32LE(5, true);
return new Header(id, cmd, size);
2016-10-02 01:01:16 -07:00
}
2017-11-16 20:26:28 -08:00
parsePacket(header, data) {
switch (header.cmd) {
case packets.types.ENV:
return packets.EnvPacket.decode(data);
2017-11-16 20:26:28 -08:00
case packets.types.EVENT:
return packets.EventPacket.decode(data);
2017-11-16 20:26:28 -08:00
case packets.types.LOG:
return packets.LogPacket.decode(data);
2017-11-16 20:26:28 -08:00
case packets.types.ERROR:
return packets.ErrorPacket.decode(data);
2017-11-16 20:26:28 -08:00
case packets.types.ERRORRESULT:
return packets.ErrorResultPacket.decode(data);
2017-11-16 20:26:28 -08:00
case packets.types.CHECK:
return packets.CheckPacket.decode(data);
2017-11-16 20:26:28 -08:00
case packets.types.CHECKRESULT:
return packets.CheckResultPacket.decode(data);
2017-11-16 20:26:28 -08:00
case packets.types.SIGN:
return packets.SignPacket.decode(data);
2017-11-16 20:26:28 -08:00
case packets.types.SIGNRESULT:
return packets.SignResultPacket.decode(data);
2017-11-16 20:26:28 -08:00
case packets.types.CHECKINPUT:
return packets.CheckInputPacket.decode(data);
2017-11-16 20:26:28 -08:00
case packets.types.CHECKINPUTRESULT:
return packets.CheckInputResultPacket.decode(data);
2017-11-16 20:26:28 -08:00
case packets.types.SIGNINPUT:
return packets.SignInputPacket.decode(data);
2017-11-16 20:26:28 -08:00
case packets.types.SIGNINPUTRESULT:
return packets.SignInputResultPacket.decode(data);
2017-11-16 20:26:28 -08:00
case packets.types.ECVERIFY:
return packets.ECVerifyPacket.decode(data);
2017-11-16 20:26:28 -08:00
case packets.types.ECVERIFYRESULT:
return packets.ECVerifyResultPacket.decode(data);
2017-11-16 20:26:28 -08:00
case packets.types.ECSIGN:
return packets.ECSignPacket.decode(data);
2017-11-16 20:26:28 -08:00
case packets.types.ECSIGNRESULT:
return packets.ECSignResultPacket.decode(data);
2017-11-16 20:26:28 -08:00
case packets.types.MINE:
return packets.MinePacket.decode(data);
2017-11-16 20:26:28 -08:00
case packets.types.MINERESULT:
return packets.MineResultPacket.decode(data);
2017-11-16 20:26:28 -08:00
case packets.types.SCRYPT:
return packets.ScryptPacket.decode(data);
2017-11-16 20:26:28 -08:00
case packets.types.SCRYPTRESULT:
return packets.ScryptResultPacket.decode(data);
2017-11-16 20:26:28 -08:00
default:
throw new Error('Unknown packet.');
}
2016-10-02 01:01:16 -07:00
}
2017-11-16 20:26:28 -08:00
}
2016-10-02 01:01:16 -07:00
/**
2016-12-02 11:06:01 -08:00
* Header
2017-02-03 22:47:26 -08:00
* @ignore
2016-10-02 01:01:16 -07:00
*/
2017-11-16 20:26:28 -08:00
class Header {
/**
* Create a header.
* @constructor
*/
constructor(id, cmd, size) {
this.id = id;
this.cmd = cmd;
this.size = size;
}
2016-10-02 01:01:16 -07:00
}
/*
* Expose
*/
module.exports = Parser;