Node.js 具有可写流的消息块

Node.js 具有可写流的消息块,node.js,stream,Node.js,Stream,我正在使用nodejs0.10和(websocketlib) 我想实现我自己的stream.Writable类来发送websocket消息。 我的限制是: 在将写入的数据发送到websocket之前,我必须将其分割成10KB的数据块,并预先向它们发送一个JSON头 最后一个区块的JSON标头必须包含“last:true” 例如,如果我打电话: myStream = new FoobarStream; myStream.write(<a buffer of 7KB>); myStr

我正在使用nodejs0.10和(websocketlib)

我想实现我自己的
stream.Writable
类来发送websocket消息。
我的限制是:

  • 在将写入的数据发送到websocket之前,我必须将其分割成10KB的数据块,并预先向它们发送一个JSON头
  • 最后一个区块的JSON标头必须包含“last:true”
例如,如果我打电话:

myStream = new FoobarStream;
myStream.write(<a buffer of 7KB>);
myStream.end(<another buffer of 7KB>);
myStream=newfoobarstream;
myStream.write();
myStream.end();
然后,我希望我的流以两条消息的形式发送此数据:第一条消息的JSON头后跟10KB的数据,第二条消息的JSON头(包含“last:true”字段)后跟4KB的数据

这意味着我必须临时发送数据,这意味着我必须找到一种方法来知道何时写入消息的最后一个数据,因为我必须将这个“last:true”字段写入JSON头中

我不知道如何只继承stream.writeable的
\u write()
方法。似乎我无法在_write()中知道是否调用了end(),因此我无法用“
last:true
”标记我的JSON头

这是否意味着我必须继承stream.writeable的
end()
方法


有什么想法吗?

可以定义自己的
end
方法并从那里开始处理。但这意味着要从原来的
end
方法重写一些代码

相反,您可以保留一个内部缓冲区,并在
prefinish
finish
事件中处理最后一块数据块。下面是一个简单的例子:

function FoobarStream(options){
    Writable.call(this, options);


    this.on('prefinish', function(){
        if(this._buffer){
            //process the last chunk
            process.stdout.write('footer: '+ this._buffer+ "\n");
        }
    });
}

FoobarStream.prototype._write = function(chunk, encoding, cb){

    if(this._buffer){
        //process other chunks here
        process.stdout.write('header: ' + this._buffer+ "\n");
        this._buffer = chunk;
    }
    else
        this._buffer = chunk;
    cb();
}

myStream = new FoobarStream;
myStream.write('first line');
myStream.write('second line');
myStream.end('last line');

/*
outputs:
header: first line
header: second line
footer: last fine
*/

您可以将对接收器(底层可写流资源)的写入延迟到
process.nextTick
,这将允许您在写入结果之前检查流上是否触发了
finish
(0.10中没有
prefinish
)事件。以下是您可以运行的示例:

var Stream = require('stream');
var Util = require('util');

// Create a readable to test our FoobarStream out

var readable = new Stream.Readable();
var finished = false;

readable._read = function () {

    if (finished) {
        this.push(new Buffer('world'));
        return this.push(null);
    }

    this.push(new Buffer('hello '));
    finished = true;
};

// Create the FoobarStream

var FoobarStream = function (options, sink) {

    Stream.Writable.call(this, options);

    this.sink = sink;
    this.finished = false;

    this.on('finish', function () {
        this.finished = true;
    });
};

Util.inherits(FoobarStream, Stream.Writable);

FoobarStream.prototype.serialize = function (chunk) {

    var header = new Buffer(JSON.stringify({some: 'header', last: this.finished}));
    return Buffer.concat([header, chunk]);
};

FoobarStream.prototype._write = function (chunk, encoding, callback) {

    var self = this;

    process.nextTick(function () {
        self.sink.write(self.serialize(chunk));
    });

    callback();
}

readable.pipe(new FoobarStream(null, process.stdout));
控制台中的输出:

$ node index.js
{"my":"header","last":false}hello
{"my":"header","last":true}world