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
						
					
					
				'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
 | 
						|
}
 |