/** Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. */ "use strict" ; import BeforeExitListener from "./BeforeExitListener" ; import { ErrorStringOrUndefinedOrNull , ICallbackContext , ErrorStringOrUndefined , CallbackFunction , } from "../Common" ; import * as Errors from "../Errors" ; import { IRuntimeClient } from "../RuntimeClient" ; param client { Client } param id { string } param scheduleNext { function } returns export const build = function ( client , id , scheduleNext ) : [ CallbackFunction , ICallbackContext ] { const [ callback , context ] = _rawCallbackContext ( client , id , scheduleNext ) ; return _wrappedCallbackContext ( callback , context ) ; } ; function _homogeneousError ( err ) { if ( err instanceof Error ) { return err ; } else { return new Error ( err ) ; } } param client { Client } param id { string } param scheduleNext { function } function _rawCallbackContext ( client , id , scheduleNext ) { const postError = ( err , callback ) => { const homogeneousError = _homogeneousError ( err ) ; console . error ( "Invoke Error" , Errors . toFormatted ( homogeneousError ) ) ; client . postInvocationError ( err , id , callback ) ; } ; const complete = ( result , callback ) => { client . postInvocationResponse ( result , id , callback ) ; } ; let waitForEmptyEventLoop = true ; const callback = ( err , result ) : void => { BeforeExitListener . reset ( ) ; if ( err !== undefined && err !== null ) { postError ( err , scheduleNext ) ; } else { complete ( result , ( ) => { if ( ! waitForEmptyEventLoop ) { scheduleNext ( ) ; } else { BeforeExitListener . set ( scheduleNext ) ; } } ) ; } } ; const done = ( err , result ? ) => { BeforeExitListener . reset ( ) ; if ( err !== undefined && err !== null ) { postError ( err , scheduleNext ) ; } else { complete ( result , scheduleNext ) ; } } ; const succeed = ( result ) => { done ( null , result ) ; } ; const fail = ( err ) => { if ( err === undefined || err === null ) { done ( "handled" ) ; } else { done ( err ) ; } } ; const callbackContext = { get callbackWaitsForEmptyEventLoop ( ) : boolean { return waitForEmptyEventLoop ; } , set callbackWaitsForEmptyEventLoop ( value ) { waitForEmptyEventLoop = value ; } , succeed , fail , done , } ; return [ callback , callbackContext ] ; } param callback { function } param callbackContext { object } return function _wrappedCallbackContext ( callback , callbackContext ) { let finished = false ; const onlyAllowFirstCall = function ( toWrap ) { return function ( ... args ) { if ( ! finished ) { toWrap . apply ( null , args ) ; finished = true ; } } ; } ; callbackContext . succeed = onlyAllowFirstCall ( callbackContext . succeed ) ; callbackContext . fail = onlyAllowFirstCall ( callbackContext . fail ) ; callbackContext . done = onlyAllowFirstCall ( callbackContext . done ) ; return [ onlyAllowFirstCall ( callback ) , callbackContext ] ; }