var stream = require('stream') , util = require('util') // // This stream is used to read tarballs from repository // function ReadTarball(options) { stream.PassThrough.call(this, options) // called when data is not needed anymore add_abstract_method(this, 'abort') } util.inherits(ReadTarball, stream.PassThrough) module.exports.ReadTarballStream = ReadTarball // // This stream is used to upload tarballs to a repository // function UploadTarball(options) { stream.PassThrough.call(this, options) // called when user closes connection before upload finishes add_abstract_method(this, 'abort') // called when upload finishes successfully add_abstract_method(this, 'done') } util.inherits(UploadTarball, stream.PassThrough) module.exports.UploadTarballStream = UploadTarball // // This function intercepts abstract calls and replays them allowing // us to attach those functions after we are ready to do so // function add_abstract_method(self, name) { self._called_methods = self._called_methods || {} self.__defineGetter__(name, function() { return function() { self._called_methods[name] = true } }) self.__defineSetter__(name, function(fn) { delete self[name] self[name] = fn if (self._called_methods && self._called_methods[name]) { delete self._called_methods[name] self[name]() } }) } function __test() { var test = new ReadTarball() test.abort() setTimeout(function() { test.abort = function() { console.log('ok') } test.abort = function() { throw 'fail' } }, 100) }