UNPKG

@azure/functions

Version:
138 lines (124 loc) 4.9 kB
// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT License. import { BindingDefinition, Context, ContextBindingData, ContextBindings, ExecutionContext, Logger, TraceContext, } from '@azure/functions'; import { RpcInvocationRequest, RpcLogLevel, RpcParameterBinding } from '@azure/functions-core'; import { randomUUID } from 'crypto'; import { convertKeysToCamelCase, getBindingDefinitions, getNormalizedBindingData, } from './converters/BindingConverters'; import { fromRpcTraceContext, fromTypedData } from './converters/RpcConverters'; import { FunctionInfo } from './FunctionInfo'; import { Request } from './http/Request'; import { Response } from './http/Response'; import EventEmitter = require('events'); export function CreateContextAndInputs( info: FunctionInfo, request: RpcInvocationRequest, userLogCallback: UserLogCallback, doneEmitter: EventEmitter ) { const context = new InvocationContext(info, request, userLogCallback, doneEmitter); const bindings: ContextBindings = {}; const inputs: any[] = []; let httpInput: Request | undefined; for (const binding of <RpcParameterBinding[]>request.inputData) { if (binding.data && binding.name) { let input; if (binding.data && binding.data.http) { input = httpInput = new Request(binding.data.http); } else { // TODO: Don't hard code fix for camelCase https://github.com/Azure/azure-functions-nodejs-worker/issues/188 if (info.getTimerTriggerName() === binding.name) { // v2 worker converts timer trigger object to camelCase input = convertKeysToCamelCase(binding)['data']; } else { input = fromTypedData(binding.data); } } bindings[binding.name] = input; inputs.push(input); } } context.bindings = bindings; if (httpInput) { context.req = httpInput; context.res = new Response(context.done); // This is added for backwards compatability with what the host used to send to the worker context.bindingData.sys = { methodName: info.name, utcNow: new Date().toISOString(), randGuid: randomUUID(), }; // Populate from HTTP request for backwards compatibility if missing if (!context.bindingData.query) { context.bindingData.query = Object.assign({}, httpInput.query); } if (!context.bindingData.headers) { context.bindingData.headers = Object.assign({}, httpInput.headers); } } return { context: <Context>context, inputs: inputs, }; } class InvocationContext implements Context { invocationId: string; executionContext: ExecutionContext; bindings: ContextBindings; bindingData: ContextBindingData; traceContext: TraceContext; bindingDefinitions: BindingDefinition[]; log: Logger; req?: Request; res?: Response; done: DoneCallback; constructor( info: FunctionInfo, request: RpcInvocationRequest, userLogCallback: UserLogCallback, doneEmitter: EventEmitter ) { this.invocationId = <string>request.invocationId; this.traceContext = fromRpcTraceContext(request.traceContext); const executionContext = <ExecutionContext>{ invocationId: this.invocationId, functionName: info.name, functionDirectory: info.directory, retryContext: request.retryContext, }; this.executionContext = executionContext; this.bindings = {}; // Log message that is tied to function invocation this.log = Object.assign((...args: any[]) => userLogCallback('information', ...args), { error: (...args: any[]) => userLogCallback('error', ...args), warn: (...args: any[]) => userLogCallback('warning', ...args), info: (...args: any[]) => userLogCallback('information', ...args), verbose: (...args: any[]) => userLogCallback('trace', ...args), }); this.bindingData = getNormalizedBindingData(request); this.bindingDefinitions = getBindingDefinitions(info); this.done = (err?: unknown, result?: any) => { doneEmitter.emit('done', err, result); }; } } export interface InvocationResult { return: any; bindings: ContextBindings; } export type DoneCallback = (err?: unknown, result?: any) => void; export type UserLogCallback = (level: RpcLogLevel, ...args: any[]) => void; export interface Dict<T> { [key: string]: T; }