142 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			142 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 
								 | 
							
								var async = require('./async.js');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// API
							 | 
						||
| 
								 | 
							
								module.exports = {
							 | 
						||
| 
								 | 
							
								  iterator: wrapIterator,
							 | 
						||
| 
								 | 
							
								  callback: wrapCallback
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Wraps iterators with long signature
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @this    ReadableAsyncKit#
							 | 
						||
| 
								 | 
							
								 * @param   {function} iterator - function to wrap
							 | 
						||
| 
								 | 
							
								 * @returns {function} - wrapped function
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function wrapIterator(iterator)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  var stream = this;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return function(item, key, cb)
							 | 
						||
| 
								 | 
							
								  {
							 | 
						||
| 
								 | 
							
								    var aborter
							 | 
						||
| 
								 | 
							
								      , wrappedCb = async(wrapIteratorCallback.call(stream, cb, key))
							 | 
						||
| 
								 | 
							
								      ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    stream.jobs[key] = wrappedCb;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // it's either shortcut (item, cb)
							 | 
						||
| 
								 | 
							
								    if (iterator.length == 2)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      aborter = iterator(item, wrappedCb);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    // or long format (item, key, cb)
							 | 
						||
| 
								 | 
							
								    else
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      aborter = iterator(item, key, wrappedCb);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return aborter;
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Wraps provided callback function
							 | 
						||
| 
								 | 
							
								 * allowing to execute snitch function before
							 | 
						||
| 
								 | 
							
								 * real callback
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @this    ReadableAsyncKit#
							 | 
						||
| 
								 | 
							
								 * @param   {function} callback - function to wrap
							 | 
						||
| 
								 | 
							
								 * @returns {function} - wrapped function
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function wrapCallback(callback)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  var stream = this;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var wrapped = function(error, result)
							 | 
						||
| 
								 | 
							
								  {
							 | 
						||
| 
								 | 
							
								    return finisher.call(stream, error, result, callback);
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return wrapped;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Wraps provided iterator callback function
							 | 
						||
| 
								 | 
							
								 * makes sure snitch only called once,
							 | 
						||
| 
								 | 
							
								 * but passes secondary calls to the original callback
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @this    ReadableAsyncKit#
							 | 
						||
| 
								 | 
							
								 * @param   {function} callback - callback to wrap
							 | 
						||
| 
								 | 
							
								 * @param   {number|string} key - iteration key
							 | 
						||
| 
								 | 
							
								 * @returns {function} wrapped callback
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function wrapIteratorCallback(callback, key)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  var stream = this;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return function(error, output)
							 | 
						||
| 
								 | 
							
								  {
							 | 
						||
| 
								 | 
							
								    // don't repeat yourself
							 | 
						||
| 
								 | 
							
								    if (!(key in stream.jobs))
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      callback(error, output);
							 | 
						||
| 
								 | 
							
								      return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // clean up jobs
							 | 
						||
| 
								 | 
							
								    delete stream.jobs[key];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return streamer.call(stream, error, {key: key, value: output}, callback);
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Stream wrapper for iterator callback
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @this  ReadableAsyncKit#
							 | 
						||
| 
								 | 
							
								 * @param {mixed} error - error response
							 | 
						||
| 
								 | 
							
								 * @param {mixed} output - iterator output
							 | 
						||
| 
								 | 
							
								 * @param {function} callback - callback that expects iterator results
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function streamer(error, output, callback)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  if (error && !this.error)
							 | 
						||
| 
								 | 
							
								  {
							 | 
						||
| 
								 | 
							
								    this.error = error;
							 | 
						||
| 
								 | 
							
								    this.pause();
							 | 
						||
| 
								 | 
							
								    this.emit('error', error);
							 | 
						||
| 
								 | 
							
								    // send back value only, as expected
							 | 
						||
| 
								 | 
							
								    callback(error, output && output.value);
							 | 
						||
| 
								 | 
							
								    return;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // stream stuff
							 | 
						||
| 
								 | 
							
								  this.push(output);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // back to original track
							 | 
						||
| 
								 | 
							
								  // send back value only, as expected
							 | 
						||
| 
								 | 
							
								  callback(error, output && output.value);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Stream wrapper for finishing callback
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @this  ReadableAsyncKit#
							 | 
						||
| 
								 | 
							
								 * @param {mixed} error - error response
							 | 
						||
| 
								 | 
							
								 * @param {mixed} output - iterator output
							 | 
						||
| 
								 | 
							
								 * @param {function} callback - callback that expects final results
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								function finisher(error, output, callback)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  // signal end of the stream
							 | 
						||
| 
								 | 
							
								  // only for successfully finished streams
							 | 
						||
| 
								 | 
							
								  if (!error)
							 | 
						||
| 
								 | 
							
								  {
							 | 
						||
| 
								 | 
							
								    this.push(null);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // back to original track
							 | 
						||
| 
								 | 
							
								  callback(error, output);
							 | 
						||
| 
								 | 
							
								}
							 |