import * as azure from "@pulumi/azure" ; import * as cloud from "@pulumi/cloud" ; import * as pulumi from "@pulumi/pulumi" ; import { interpolate } from "@pulumi/pulumi" ; import * as awsServerlessExpress from "aws-serverless-express" ; import * as express from "express" ; import * as http from "http" ; import * as url from "url" ; import * as shared from "./shared" ; interface AWSEvent { path : string ; httpMethod : string ; headers : Record < string , string | undefined > ; queryStringParameters : Record < string , string | undefined > ; body : string ; isBase64Encoded : boolean ; } interface AWSResponse { statusCode : number ; body : string ; headers : Record < string , string > ; isBase64Encoded : boolean ; } interface AWSContext { succeed : ( awsResponse : AWSResponse ) => void ; } export class HttpServer extends pulumi . ComponentResource implements cloud . HttpServer { public readonly url : pulumi . Output < string > ; public constructor ( name , createRequestListener , opts = { } ) { super ( "cloud:httpserver:HttpServer" , name , { } , opts ) ; const factoryFunc = createFactoryFunction ( createRequestListener ) ; const eventSubscription = new azure . appservice . HttpEventSubscription ( name , { ... shared . defaultSubscriptionArgs , account : shared . getGlobalStorageAccount ( ) , callbackFactory : factoryFunc , route : "{*segments}" , } , { parent : this } ) ; this . url = interpolate `https://${ eventSubscription . functionApp . name }.azurewebsites.net/api/` ; super . registerOutputs ( { url : this . url , } ) ; } } function createFactoryFunction ( createRequestListener ) { return ( ) => { let server ; try { server = createServer ( createRequestListener ) ; } catch ( err ) { return context => { context . log ( "Error occurred creating server: " + err . message + "\n" + err . stack ) ; context . done ( ) ; } ; } return azureContext => handleIncomingMessage ( server , azureContext ) ; } ; } function createServer ( createRequestListener ) { const dir = __dirname ; process . chdir ( dir ) ; const requestListener = createRequestListener ( ) ; const app = express ( ) ; app . use ( "/api" , requestListener ) ; const server = awsServerlessExpress . createServer ( app , undefined , [ "*/*" ] ) ; return server ; } function handleIncomingMessage ( server , azureContext ) { try { if ( ! azureContext . req ) { throw new Error ( "Azure context missing [req] property." ) ; } if ( ! azureContext . res ) { throw new Error ( "Azure context missing [res] property." ) ; } const azureRequest = azureContext . req ; if ( azureRequest . url === undefined ) { throw new Error ( "Azure context.req missing [url] property." ) ; } const parsedURL = url . parse ( azureRequest . url ) ; const path = parsedURL . pathname ; if ( path === null ) { throw new Error ( "Could not determine pathname in: " + azureRequest . url ) ; } const awsEvent = { path : path ! , httpMethod : azureRequest . method as AWSEvent [ "httpMethod" ] , headers : azureRequest . headers || { } , queryStringParameters : azureRequest . query || { } , body : azureRequest . body , isBase64Encoded : false , } ; const awsContext = { succeed ( awsResponse ) { const azureResponse = azureContext . res ! ; azureResponse . status = awsResponse . statusCode ; azureResponse . body = Buffer . from ( awsResponse . body , awsResponse . isBase64Encoded ? "base64" : "utf8" ) ; azureResponse . isRaw = true ; const headers = azureResponse . headers || { } ; Object . assign ( headers , awsResponse . headers ) ; azureResponse . headers = headers ; azureContext . done ( ) ; } , } ; awsServerlessExpress . proxy ( server , < any > awsEvent , < any > awsContext ) ; } catch ( err ) { azureContext . log ( "Error executing handler: " + err . message + "\n" + err . stack ) ; azureContext . done ( ) ; } }