mpneuried
2/14/2013 - 3:05 PM

Middleware solution to run multiple tasks

Middleware solution to run multiple tasks

class Middleware
	
	constructor: ->
		# define a shared object witch will be routed through all called methods
		shared = {}

		# run the middleware method to process all defined methods
		# If one method fails by calling error the queue will be stopped
		@middleware shared, @simpleCall, @addSomeMethods, ( err, shared )=>
			if err
				console.error( err )
				return

			console.log( "DONE", shared )
			# Predicted result in this example
			# 
			# shared = 
			#   simple: { ... }
			#   usersraw: [ { id: 1, name: "Max", ... }, { id: 2, name: "Fritz", ... }, ... ]
			#   users: 
			#     1: { id: 1, name: "Max", processed: true, ... }
			#     2: { id: 2, name: "Fritz", processed: true, ... }
			return
		return
	
	# main midddleware method to handle the queue.
	middleware: =>
		_error = false
		[ fns..., cb ] = arguments
		
		if not _.isFunction( fns[ 0 ] )
			data = fns.splice( 0 , 1 )[ 0 ]
		else
			data = {}
		
		_errorFn = ( error )->
			fns = []
			_error = true
			cb( error, data )
			return
	
		run = ->
			if not fns.length
				cb( null, data )
			else
				fn = fns.splice( 0 , 1 )[ 0 ]
				
				fn( data, ->
					run() if not _error
					return
				, _errorFn, fns )
		run()
	
		return
	
	# a simple middel ware method
	simpleCall: ( shared, next, error )=>
		
		# run the task
		root.doSomethingSimple ( err, result )=>
			if err
				# on error stop the queue
				error( err )
				return
			
			# save the result to the shared object	
			shared.simple = result

			# run the next method
			next()
			return
		return
	
	# you also can add additional methods to the queue within every middleware method
	addSomeMethods: ( shared, next, error, fns )=>
		
		# e.g. get a list of elements to process
		root.getUsers ( err, users )=>
			if err
				error( err )
				return
			
			shared.usersraw = users
			shared.users = {}
			
			# add new methods to the queue. You can also use `fns.unshift( @_curryingProcessUser( user ) )` to make shure the methods will be called directly after the current method
			for user in users
				fns.push @curryingProcessUser( user )
			
			next()
			return
		return
	
	# a example with a curried method to pass data to a middleware method
	curryingProcessUser: ( user )=>

		# just return a valid middleware method 
		return ( shared, next, error, fns )=>
			
			# e.g. process a element
			root.processUsers user, ( err, userRes )=>
				if err
					error( err )
					return

				# save the result to the shared object
				shared.users[ userRes.id ] = userRes
				next()
				return
			return