newrelic
Version:
New Relic agent
116 lines (103 loc) • 3.94 kB
JavaScript
/*
* Copyright 2023 New Relic Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
const { MiddlewareMounterSpec } = require('../specs')
/**
* Wraps route mounter and all middleware defined within mounter(arguments to mounter)
*
* @private
* @param {object} spec for the middleware mounter
* @param {Shim} shim instance of shim
* @param {Function} fn middleware mounter function
* @param {string} fnName name of middleware mounter
* @returns {Function} wrapped function
*/
function wrapMounter(spec, shim, fn, fnName) {
if (!shim.isFunction(fn)) {
return fn
}
return function wrappedMounter(...args) {
// Normalize the route index and pull out the route argument if provided.
let routeIdx = null
let route = null
if (shim.isNumber(spec.route)) {
routeIdx = shim.normalizeIndex(args.length, spec.route)
route = routeIdx === null ? null : args[routeIdx]
const isArrayOfFunctions = shim.isArray(route) && shim.isFunction(route[0])
if (shim.isFunction(route) || isArrayOfFunctions) {
routeIdx = null
route = null
} else if (shim.isArray(route)) {
route = route.map((routeArg) => {
return shim._routeParser.call(this, shim, fn, fnName, routeArg)
})
} else {
route = shim._routeParser.call(this, shim, fn, fnName, route)
}
} else if (spec.route !== null) {
route = shim._routeParser.call(this, shim, fn, fnName, spec.route)
}
wrapAllMiddleware.call(this, { routeIdx, middlewares: args, shim, spec, route })
return fn.apply(this, args)
}
}
/**
* Wraps every middleware defined within middleware route mounter
*
* @private
* @param {object} params object passed to function
* @param {number} params.routeIdx index of the router arg
* @param {Array} params.middlewares remaining args(middleware) on route mounter
* @param {Shim} params.shim instance of shim
* @param {object} params.spec for the middleware mounter
* @param {Array | string} params.route route(s)
*/
function wrapAllMiddleware({ routeIdx, middlewares, shim, spec, route }) {
for (let i = 0; i < middlewares.length; ++i) {
// If this argument is the route argument skip it.
if (i === routeIdx) {
continue
}
// Some platforms accept an arbitrarily nested array of middlewares,
// so if this argument is an array we must recurse into it.
const middleware = middlewares[i]
if (middleware instanceof Array) {
wrapAllMiddleware({ middlewares: middleware, shim, spec, route })
continue
}
middlewares[i] = spec.wrapper.call(this, shim, middleware, shim.getName(middleware), route)
}
}
/**
* Wraps a method that is used to add middleware to a server. The middleware
* can then be recorded as metrics.
*
* - `wrapMiddlewareMounter(nodule, properties [, spec])`
* - `wrapMiddlewareMounter(func [, spec])`
*
* @memberof WebFrameworkShim.prototype
* @param {object | Function} nodule
* The source for the properties to wrap, or a single function to wrap.
* @param {string|Array.<string>} [properties]
* One or more properties to wrap. If omitted, the `nodule` parameter is
* assumed to be the function to wrap.
* @param {object} [spec] spec for the middleware mounter
* Spec describing the parameters for this middleware mount point.
* @returns {object | Function} The first parameter to this function, after
* wrapping it or its properties.
* @see WebFrameworkShim#recordMiddleware
*/
module.exports = function wrapMiddlewareMounter(nodule, properties, spec) {
if (properties && !this.isString(properties) && !this.isArray(properties)) {
// wrapMiddlewareMounter(func, spec)
spec = properties
properties = null
}
const wrapSpec = new MiddlewareMounterSpec({
matchArity: spec.matchArity,
wrapper: wrapMounter.bind(null, spec)
})
return this.wrap(nodule, properties, wrapSpec)
}