Spaces:
Runtime error
Runtime error
| const applicationHooks = [ | |
| 'onRoute', | |
| 'onRegister', | |
| 'onReady', | |
| 'onListen', | |
| 'preClose', | |
| 'onClose' | |
| ] | |
| const lifecycleHooks = [ | |
| 'onTimeout', | |
| 'onRequest', | |
| 'preParsing', | |
| 'preValidation', | |
| 'preSerialization', | |
| 'preHandler', | |
| 'onSend', | |
| 'onResponse', | |
| 'onError', | |
| 'onRequestAbort' | |
| ] | |
| const supportedHooks = lifecycleHooks.concat(applicationHooks) | |
| const { | |
| FST_ERR_HOOK_INVALID_TYPE, | |
| FST_ERR_HOOK_INVALID_HANDLER, | |
| FST_ERR_SEND_UNDEFINED_ERR, | |
| FST_ERR_HOOK_TIMEOUT, | |
| FST_ERR_HOOK_NOT_SUPPORTED, | |
| AVVIO_ERRORS_MAP, | |
| appendStackTrace | |
| } = require('./errors') | |
| const { | |
| kChildren, | |
| kHooks, | |
| kRequestPayloadStream | |
| } = 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.onListen = [] | |
| this.onTimeout = [] | |
| this.onRequestAbort = [] | |
| this.preClose = [] | |
| } | |
| Hooks.prototype = Object.create(null) | |
| Hooks.prototype.validate = function (hook, fn) { | |
| if (typeof hook !== 'string') throw new FST_ERR_HOOK_INVALID_TYPE() | |
| if (Array.isArray(this[hook]) === false) { | |
| throw new FST_ERR_HOOK_NOT_SUPPORTED(hook) | |
| } | |
| if (typeof fn !== 'function') throw new FST_ERR_HOOK_INVALID_HANDLER(hook, Object.prototype.toString.call(fn)) | |
| } | |
| 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.onRequestAbort = h.onRequestAbort.slice() | |
| hooks.onReady = [] | |
| hooks.onListen = [] | |
| hooks.preClose = [] | |
| return hooks | |
| } | |
| function hookRunnerApplication (hookName, boot, server, cb) { | |
| const hooks = server[kHooks][hookName] | |
| let i = 0 | |
| let c = 0 | |
| next() | |
| function exit (err) { | |
| const hookFnName = hooks[i - 1]?.name | |
| const hookFnFragment = hookFnName ? ` "${hookFnName}"` : '' | |
| if (err) { | |
| if (err.code === 'AVV_ERR_READY_TIMEOUT') { | |
| err = appendStackTrace(err, new FST_ERR_HOOK_TIMEOUT(hookName, hookFnFragment)) | |
| } else { | |
| err = AVVIO_ERRORS_MAP[err.code] != null | |
| ? appendStackTrace(err, new AVVIO_ERRORS_MAP[err.code](err.message)) | |
| : 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 | |
| } | |
| try { | |
| const ret = fn.call(server) | |
| if (ret && typeof ret.then === 'function') { | |
| ret.then(done, done) | |
| return | |
| } | |
| } catch (error) { | |
| err = error | |
| } | |
| done(err) // auto done | |
| } | |
| } | |
| } | |
| function onListenHookRunner (server) { | |
| const hooks = server[kHooks].onListen | |
| const hooksLen = hooks.length | |
| let i = 0 | |
| let c = 0 | |
| next() | |
| function next (err) { | |
| err && server.log.error(err) | |
| if ( | |
| i === hooksLen | |
| ) { | |
| while (c < server[kChildren].length) { | |
| const child = server[kChildren][c++] | |
| onListenHookRunner(child) | |
| } | |
| return | |
| } | |
| wrap(hooks[i++], server, next) | |
| } | |
| async function wrap (fn, server, done) { | |
| if (fn.length === 1) { | |
| try { | |
| fn.call(server, done) | |
| } catch (e) { | |
| done(e) | |
| } | |
| return | |
| } | |
| try { | |
| const ret = fn.call(server) | |
| if (ret && typeof ret.then === 'function') { | |
| ret.then(done, done) | |
| return | |
| } | |
| done() | |
| } catch (error) { | |
| done(error) | |
| } | |
| } | |
| } | |
| function hookRunnerGenerator (iterator) { | |
| return function hookRunner (functions, request, reply, cb) { | |
| let i = 0 | |
| function next (err) { | |
| if (err || i === functions.length) { | |
| cb(err, request, reply) | |
| return | |
| } | |
| let result | |
| try { | |
| result = iterator(functions[i++], request, reply, next) | |
| } catch (error) { | |
| cb(error, request, reply) | |
| 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() | |
| } | |
| cb(err, request, reply) | |
| } | |
| next() | |
| } | |
| } | |
| function onResponseHookIterator (fn, request, reply, next) { | |
| return fn(request, reply, next) | |
| } | |
| const onResponseHookRunner = hookRunnerGenerator(onResponseHookIterator) | |
| const preValidationHookRunner = hookRunnerGenerator(hookIterator) | |
| const preHandlerHookRunner = hookRunnerGenerator(hookIterator) | |
| const onTimeoutHookRunner = hookRunnerGenerator(hookIterator) | |
| const onRequestHookRunner = hookRunnerGenerator(hookIterator) | |
| 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) { | |
| cb(null, request, reply, payload) | |
| return | |
| } | |
| let result | |
| try { | |
| result = functions[i++](request, reply, payload, next) | |
| } catch (error) { | |
| cb(error, request, reply) | |
| return | |
| } | |
| if (result && typeof result.then === 'function') { | |
| result.then(handleResolve, handleReject) | |
| } | |
| } | |
| function handleResolve (newPayload) { | |
| next(null, newPayload) | |
| } | |
| function handleReject (err) { | |
| if (!err) { | |
| err = new FST_ERR_SEND_UNDEFINED_ERR() | |
| } | |
| cb(err, request, reply, payload) | |
| } | |
| next() | |
| } | |
| const preSerializationHookRunner = onSendHookRunner | |
| function preParsingHookRunner (functions, request, reply, cb) { | |
| let i = 0 | |
| function next (err, newPayload) { | |
| if (reply.sent) { | |
| return | |
| } | |
| if (newPayload !== undefined) { | |
| request[kRequestPayloadStream] = newPayload | |
| } | |
| if (err || i === functions.length) { | |
| cb(err, request, reply) | |
| return | |
| } | |
| let result | |
| try { | |
| result = functions[i++](request, reply, request[kRequestPayloadStream], next) | |
| } catch (error) { | |
| cb(error, request, reply) | |
| return | |
| } | |
| if (result && typeof result.then === 'function') { | |
| result.then(handleResolve, handleReject) | |
| } | |
| } | |
| function handleResolve (newPayload) { | |
| next(null, newPayload) | |
| } | |
| function handleReject (err) { | |
| if (!err) { | |
| err = new FST_ERR_SEND_UNDEFINED_ERR() | |
| } | |
| cb(err, request, reply) | |
| } | |
| next() | |
| } | |
| function onRequestAbortHookRunner (functions, request, cb) { | |
| let i = 0 | |
| function next (err) { | |
| if (err || i === functions.length) { | |
| cb(err, request) | |
| return | |
| } | |
| let result | |
| try { | |
| result = functions[i++](request, next) | |
| } catch (error) { | |
| cb(error, request) | |
| 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() | |
| } | |
| cb(err, request) | |
| } | |
| next() | |
| } | |
| function hookIterator (fn, request, reply, next) { | |
| if (reply.sent === true) return undefined | |
| return fn(request, reply, next) | |
| } | |
| module.exports = { | |
| Hooks, | |
| buildHooks, | |
| hookRunnerGenerator, | |
| preParsingHookRunner, | |
| onResponseHookRunner, | |
| onSendHookRunner, | |
| preSerializationHookRunner, | |
| onRequestAbortHookRunner, | |
| hookIterator, | |
| hookRunnerApplication, | |
| onListenHookRunner, | |
| preHandlerHookRunner, | |
| preValidationHookRunner, | |
| onRequestHookRunner, | |
| onTimeoutHookRunner, | |
| lifecycleHooks, | |
| supportedHooks | |
| } | |