1 | 'use strict'
|
2 |
|
3 | var Transform = require('stream').Transform
|
4 | var util = require('util')
|
5 |
|
6 | exports = module.exports = function(opts) {
|
7 | return new Decoder(opts)
|
8 | }
|
9 | exports.decode = exports
|
10 |
|
11 | var Decoder = exports.Decoder = function(opts) {
|
12 | this.opts = util._extend({
|
13 | lengthSize: 4,
|
14 | maxSize: 0,
|
15 | unbuffered: false
|
16 | }, opts)
|
17 |
|
18 | this.getLength = this.opts.getLength || createGetLengthMethod(this.opts.lengthSize)
|
19 | this.buffer = null
|
20 | this.frameLength = -1
|
21 | this.framePos = 0
|
22 |
|
23 | Transform.call(this, opts)
|
24 | }
|
25 |
|
26 | util.inherits(Decoder, Transform)
|
27 |
|
28 | Decoder.prototype._transform = function(chunk, enc, cont) {
|
29 | while (chunk.length > 0) {
|
30 | var start = this.opts.lengthSize
|
31 |
|
32 | if (this.buffer) {
|
33 | chunk = Buffer.concat([this.buffer, chunk])
|
34 | this.buffer = null
|
35 | }
|
36 |
|
37 | if (this.frameLength < 0) {
|
38 | if (chunk.length < this.opts.lengthSize) {
|
39 | this.buffer = chunk
|
40 | return cont()
|
41 | }
|
42 |
|
43 | this.frameLength = this.getLength(chunk)
|
44 |
|
45 | if (this.frameLength < 0) {
|
46 | return cont(new Error('Message length is less than zero'))
|
47 | }
|
48 |
|
49 |
|
50 | if (this.opts.maxSize > 0 && this.frameLength > this.opts.maxSize) {
|
51 | return cont(new Error('Message is larger than the allowed maximum of ' + this.opts.maxSize))
|
52 | }
|
53 | } else if (this.opts.unbuffered) {
|
54 | start = 0
|
55 | }
|
56 |
|
57 | var end = start + this.frameLength - this.framePos
|
58 |
|
59 | if (this.opts.unbuffered) {
|
60 | end = Math.min(end, chunk.length)
|
61 | } else if (chunk.length < end) {
|
62 | this.buffer = chunk
|
63 | return cont()
|
64 | }
|
65 |
|
66 | var buf = chunk.slice(start, end)
|
67 |
|
68 | buf.framePos = this.framePos
|
69 | buf.frameLength = this.frameLength
|
70 |
|
71 | this.framePos += end - start
|
72 | buf.frameEnd = this.framePos === this.frameLength
|
73 |
|
74 | if (buf.frameEnd) {
|
75 | this.frameLength = -1
|
76 | this.framePos = 0
|
77 | }
|
78 |
|
79 | this.push(buf)
|
80 |
|
81 | if (chunk.length > end) {
|
82 | chunk = chunk.slice(end)
|
83 | } else {
|
84 | return cont()
|
85 | }
|
86 | }
|
87 | cont()
|
88 | }
|
89 |
|
90 | exports.encode = function(opts) {
|
91 | return new Encoder(opts)
|
92 | }
|
93 |
|
94 | var Encoder = exports.Encoder = function(opts) {
|
95 | this.opts = util._extend({ lengthSize: 4 }, opts)
|
96 |
|
97 | this.setLength = this.opts.setLength || createSetLengthMethod(this.opts.lengthSize)
|
98 |
|
99 | Transform.call(this, opts)
|
100 | }
|
101 |
|
102 | util.inherits(Encoder, Transform)
|
103 |
|
104 | Encoder.prototype._transform = function(message, enc, cont) {
|
105 | var length = Buffer.alloc(this.opts.lengthSize)
|
106 | this.setLength(length, message.length)
|
107 | this._pushFrameData([length, message])
|
108 | cont()
|
109 | }
|
110 |
|
111 | Encoder.prototype._pushFrameData = function(bufs) {
|
112 | this.push(Buffer.concat(bufs))
|
113 | }
|
114 |
|
115 |
|
116 | exports.prefix = exports.encode
|
117 | exports.FrameStream = Decoder
|
118 | exports.LengthPrefixStream = Encoder
|
119 |
|
120 | function createGetLengthMethod(lengthSize) {
|
121 | switch (lengthSize) {
|
122 | case 1:
|
123 | return function(buffer) {
|
124 | return buffer.readUInt8(0)
|
125 | }
|
126 | case 2:
|
127 | return function(buffer) {
|
128 | return buffer.readUInt16BE(0)
|
129 | }
|
130 | case 4:
|
131 | return function(buffer) {
|
132 | return buffer.readUInt32BE(0)
|
133 | }
|
134 | default:
|
135 | throw new Error('Invalid frame length size')
|
136 | }
|
137 | }
|
138 |
|
139 | function createSetLengthMethod(lengthSize) {
|
140 | switch (lengthSize) {
|
141 | case 1:
|
142 | return function(buffer, value) {
|
143 | return buffer.writeUInt8(value, 0)
|
144 | }
|
145 | case 2:
|
146 | return function(buffer, value) {
|
147 | return buffer.writeUInt16BE(value, 0)
|
148 | }
|
149 | case 4:
|
150 | return function(buffer, value) {
|
151 | return buffer.writeUInt32BE(value, 0)
|
152 | }
|
153 | default:
|
154 | throw new Error('Invalid frame length size')
|
155 | }
|
156 | }
|