You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					250 lines
				
				5.1 KiB
			
		
		
			
		
	
	
					250 lines
				
				5.1 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								'use strict'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const applicationHooks = [
							 | 
						||
| 
								 | 
							
								  'onRoute',
							 | 
						||
| 
								 | 
							
								  'onRegister',
							 | 
						||
| 
								 | 
							
								  'onReady',
							 | 
						||
| 
								 | 
							
								  'onClose'
							 | 
						||
| 
								 | 
							
								]
							 | 
						||
| 
								 | 
							
								const lifecycleHooks = [
							 | 
						||
| 
								 | 
							
								  'onTimeout',
							 | 
						||
| 
								 | 
							
								  'onRequest',
							 | 
						||
| 
								 | 
							
								  'preParsing',
							 | 
						||
| 
								 | 
							
								  'preValidation',
							 | 
						||
| 
								 | 
							
								  'preSerialization',
							 | 
						||
| 
								 | 
							
								  'preHandler',
							 | 
						||
| 
								 | 
							
								  'onSend',
							 | 
						||
| 
								 | 
							
								  'onResponse',
							 | 
						||
| 
								 | 
							
								  'onError'
							 | 
						||
| 
								 | 
							
								]
							 | 
						||
| 
								 | 
							
								const supportedHooks = lifecycleHooks.concat(applicationHooks)
							 | 
						||
| 
								 | 
							
								const {
							 | 
						||
| 
								 | 
							
								  FST_ERR_HOOK_INVALID_TYPE,
							 | 
						||
| 
								 | 
							
								  FST_ERR_HOOK_INVALID_HANDLER,
							 | 
						||
| 
								 | 
							
								  FST_ERR_SEND_UNDEFINED_ERR
							 | 
						||
| 
								 | 
							
								} = require('./errors')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const {
							 | 
						||
| 
								 | 
							
								  kReplyIsError,
							 | 
						||
| 
								 | 
							
								  kChildren,
							 | 
						||
| 
								 | 
							
								  kHooks
							 | 
						||
| 
								 | 
							
								} = require('./symbols')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function Hooks () {
							 | 
						||
| 
								 | 
							
								  this.onRequest = []
							 | 
						||
| 
								 | 
							
								  this.preParsing = []
							 | 
						||
| 
								 | 
							
								  this.preValidation = []
							 | 
						||
| 
								 | 
							
								  this.preSerialization = []
							 | 
						||
| 
								 | 
							
								  this.preHandler = []
							 | 
						||
| 
								 | 
							
								  this.onResponse = []
							 | 
						||
| 
								 | 
							
								  this.onSend = []
							 | 
						||
| 
								 | 
							
								  this.onError = []
							 | 
						||
| 
								 | 
							
								  this.onRoute = []
							 | 
						||
| 
								 | 
							
								  this.onRegister = []
							 | 
						||
| 
								 | 
							
								  this.onReady = []
							 | 
						||
| 
								 | 
							
								  this.onTimeout = []
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Hooks.prototype.validate = function (hook, fn) {
							 | 
						||
| 
								 | 
							
								  if (typeof hook !== 'string') throw new FST_ERR_HOOK_INVALID_TYPE()
							 | 
						||
| 
								 | 
							
								  if (typeof fn !== 'function') throw new FST_ERR_HOOK_INVALID_HANDLER()
							 | 
						||
| 
								 | 
							
								  if (supportedHooks.indexOf(hook) === -1) {
							 | 
						||
| 
								 | 
							
								    throw new Error(`${hook} hook not supported!`)
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Hooks.prototype.add = function (hook, fn) {
							 | 
						||
| 
								 | 
							
								  this.validate(hook, fn)
							 | 
						||
| 
								 | 
							
								  this[hook].push(fn)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function buildHooks (h) {
							 | 
						||
| 
								 | 
							
								  const hooks = new Hooks()
							 | 
						||
| 
								 | 
							
								  hooks.onRequest = h.onRequest.slice()
							 | 
						||
| 
								 | 
							
								  hooks.preParsing = h.preParsing.slice()
							 | 
						||
| 
								 | 
							
								  hooks.preValidation = h.preValidation.slice()
							 | 
						||
| 
								 | 
							
								  hooks.preSerialization = h.preSerialization.slice()
							 | 
						||
| 
								 | 
							
								  hooks.preHandler = h.preHandler.slice()
							 | 
						||
| 
								 | 
							
								  hooks.onSend = h.onSend.slice()
							 | 
						||
| 
								 | 
							
								  hooks.onResponse = h.onResponse.slice()
							 | 
						||
| 
								 | 
							
								  hooks.onError = h.onError.slice()
							 | 
						||
| 
								 | 
							
								  hooks.onRoute = h.onRoute.slice()
							 | 
						||
| 
								 | 
							
								  hooks.onRegister = h.onRegister.slice()
							 | 
						||
| 
								 | 
							
								  hooks.onTimeout = h.onTimeout.slice()
							 | 
						||
| 
								 | 
							
								  hooks.onReady = []
							 | 
						||
| 
								 | 
							
								  return hooks
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function hookRunnerApplication (hookName, boot, server, cb) {
							 | 
						||
| 
								 | 
							
								  const hooks = server[kHooks][hookName]
							 | 
						||
| 
								 | 
							
								  let i = 0
							 | 
						||
| 
								 | 
							
								  let c = 0
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  next()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function exit (err) {
							 | 
						||
| 
								 | 
							
								    if (err) {
							 | 
						||
| 
								 | 
							
								      cb(err)
							 | 
						||
| 
								 | 
							
								      return
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    cb()
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function next (err) {
							 | 
						||
| 
								 | 
							
								    if (err) {
							 | 
						||
| 
								 | 
							
								      exit(err)
							 | 
						||
| 
								 | 
							
								      return
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (i === hooks.length && c === server[kChildren].length) {
							 | 
						||
| 
								 | 
							
								      if (i === 0 && c === 0) { // speed up start
							 | 
						||
| 
								 | 
							
								        exit()
							 | 
						||
| 
								 | 
							
								      } else {
							 | 
						||
| 
								 | 
							
								        // This is the last function executed for every fastify instance
							 | 
						||
| 
								 | 
							
								        boot(function manageTimeout (err, done) {
							 | 
						||
| 
								 | 
							
								          // this callback is needed by fastify to provide an hook interface without the error
							 | 
						||
| 
								 | 
							
								          // as first parameter and managing it on behalf the user
							 | 
						||
| 
								 | 
							
								          exit(err)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          // this callback is needed by avvio to continue the loading of the next `register` plugins
							 | 
						||
| 
								 | 
							
								          done(err)
							 | 
						||
| 
								 | 
							
								        })
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      return
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (i === hooks.length && c < server[kChildren].length) {
							 | 
						||
| 
								 | 
							
								      const child = server[kChildren][c++]
							 | 
						||
| 
								 | 
							
								      hookRunnerApplication(hookName, boot, child, next)
							 | 
						||
| 
								 | 
							
								      return
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    boot(wrap(hooks[i++], server))
							 | 
						||
| 
								 | 
							
								    next()
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function wrap (fn, server) {
							 | 
						||
| 
								 | 
							
								    return function (err, done) {
							 | 
						||
| 
								 | 
							
								      if (err) {
							 | 
						||
| 
								 | 
							
								        done(err)
							 | 
						||
| 
								 | 
							
								        return
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (fn.length === 1) {
							 | 
						||
| 
								 | 
							
								        try {
							 | 
						||
| 
								 | 
							
								          fn.call(server, done)
							 | 
						||
| 
								 | 
							
								        } catch (error) {
							 | 
						||
| 
								 | 
							
								          done(error)
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        return
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      const ret = fn.call(server)
							 | 
						||
| 
								 | 
							
								      if (ret && typeof ret.then === 'function') {
							 | 
						||
| 
								 | 
							
								        ret.then(done, done)
							 | 
						||
| 
								 | 
							
								        return
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      done(err) // auto done
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function hookRunner (functions, runner, request, reply, cb) {
							 | 
						||
| 
								 | 
							
								  let i = 0
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function next (err) {
							 | 
						||
| 
								 | 
							
								    if (err || i === functions.length) {
							 | 
						||
| 
								 | 
							
								      cb(err, request, reply)
							 | 
						||
| 
								 | 
							
								      return
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    let result
							 | 
						||
| 
								 | 
							
								    try {
							 | 
						||
| 
								 | 
							
								      result = runner(functions[i++], request, reply, next)
							 | 
						||
| 
								 | 
							
								    } catch (error) {
							 | 
						||
| 
								 | 
							
								      next(error)
							 | 
						||
| 
								 | 
							
								      return
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (result && typeof result.then === 'function') {
							 | 
						||
| 
								 | 
							
								      result.then(handleResolve, handleReject)
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function handleResolve () {
							 | 
						||
| 
								 | 
							
								    next()
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function handleReject (err) {
							 | 
						||
| 
								 | 
							
								    if (!err) {
							 | 
						||
| 
								 | 
							
								      err = new FST_ERR_SEND_UNDEFINED_ERR()
							 | 
						||
| 
								 | 
							
								    } else if (!(err instanceof Error)) {
							 | 
						||
| 
								 | 
							
								      reply[kReplyIsError] = true
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    cb(err, request, reply)
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  next()
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function onSendHookRunner (functions, request, reply, payload, cb) {
							 | 
						||
| 
								 | 
							
								  let i = 0
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function next (err, newPayload) {
							 | 
						||
| 
								 | 
							
								    if (err) {
							 | 
						||
| 
								 | 
							
								      cb(err, request, reply, payload)
							 | 
						||
| 
								 | 
							
								      return
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (newPayload !== undefined) {
							 | 
						||
| 
								 | 
							
								      payload = newPayload
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (i === functions.length) {
							 | 
						||
| 
								 | 
							
								      try {
							 | 
						||
| 
								 | 
							
								        cb(null, request, reply, payload)
							 | 
						||
| 
								 | 
							
								      } catch (err) {
							 | 
						||
| 
								 | 
							
								        handleReject(err)
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      return
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    let result
							 | 
						||
| 
								 | 
							
								    try {
							 | 
						||
| 
								 | 
							
								      result = functions[i++](request, reply, payload, next)
							 | 
						||
| 
								 | 
							
								    } catch (error) {
							 | 
						||
| 
								 | 
							
								      next(error)
							 | 
						||
| 
								 | 
							
								      return
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (result && typeof result.then === 'function') {
							 | 
						||
| 
								 | 
							
								      result.then(handleResolve, handleReject)
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function handleResolve (newPayload) {
							 | 
						||
| 
								 | 
							
								    next(null, newPayload)
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function handleReject (err) {
							 | 
						||
| 
								 | 
							
								    cb(err, request, reply, payload)
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  next()
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function hookIterator (fn, request, reply, next) {
							 | 
						||
| 
								 | 
							
								  if (reply.sent === true) return undefined
							 | 
						||
| 
								 | 
							
								  return fn(request, reply, next)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								module.exports = {
							 | 
						||
| 
								 | 
							
								  Hooks,
							 | 
						||
| 
								 | 
							
								  buildHooks,
							 | 
						||
| 
								 | 
							
								  hookRunner,
							 | 
						||
| 
								 | 
							
								  onSendHookRunner,
							 | 
						||
| 
								 | 
							
								  hookIterator,
							 | 
						||
| 
								 | 
							
								  hookRunnerApplication,
							 | 
						||
| 
								 | 
							
								  lifecycleHooks,
							 | 
						||
| 
								 | 
							
								  supportedHooks
							 | 
						||
| 
								 | 
							
								}
							 |