11'use strict' ;
22
3+ const trimNewlines = require ( 'trim-newlines' ) ;
34const debugLog = require ( './debugLog' ) ;
45const fork = require ( 'child_process' ) . fork ;
56const _ = require ( 'lodash' ) ;
@@ -9,52 +10,76 @@ const uuid = require('uuid/v4');
910const handlerCache = { } ;
1011const messageCallbacks = { } ;
1112
12- function runPythonHandler ( funOptions , options ) {
13+ function runPythonHandler ( funOptions , options ) {
1314 var spawn = require ( "child_process" ) . spawn ;
14- return function ( event , context ) {
15- var process = spawn ( 'sls' , [ "invoke" , "local" , "-f" , funOptions . funName ] ,
16- { stdio : [ 'pipe' , 'pipe' , 'pipe' ] , shell : true , cwd :funOptions . servicePath } ) ;
17- process . stdin . write ( JSON . stringify ( event ) + "\n" ) ;
18- process . stdin . end ( ) ;
19- let results = ''
20- process . stdout . on ( 'data' , ( data ) => {
21- results = results + data ;
22- } ) ;
23- process . stderr . on ( 'data' , ( data ) => {
24- context . fail ( data ) ;
25- } ) ;
26- process . on ( 'close' , ( code ) => {
27- if ( code == 0 ) {
28- try {
29- context . succeed ( JSON . parse ( results ) ) ;
30- } catch ( ex ) {
31- context . fail ( results ) ;
32- }
33- } else {
34- context . succeed ( code , results ) ;
35- }
15+ return function ( event , context ) {
16+ var process = spawn ( 'sls' , [ "invoke" , "local" , "-f" , funOptions . funName ] ,
17+ { stdio : [ 'pipe' , 'pipe' , 'pipe' ] , shell : true , cwd : funOptions . servicePath } ) ;
18+ process . stdin . write ( JSON . stringify ( event ) + "\n" ) ;
19+ process . stdin . end ( ) ;
20+ let results = ''
21+ let hasDetectedJson = false ;
22+ process . stdout . on ( 'data' , ( data ) => {
23+ let str = data . toString ( 'utf8' ) ;
24+ if ( hasDetectedJson ) {
25+ // Assumes that all data after matching the start of the
26+ // JSON result is the rest of the context result.
27+ results = results + trimNewlines ( str ) ;
28+ } else {
29+ // Search for the start of the JSON result
30+ // https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-output-format
31+ const match = / { \n \s + " i s B a s e 6 4 E n c o d e d " | { \n \s + " s t a t u s C o d e " | { \n \s + " h e a d e r s " | { \n \s + " b o d y " / . exec ( str ) ;
32+ if ( match && match . index > - 1 ) {
33+ // The JSON result was in this chunk so slice it out
34+ hasDetectedJson = true ;
35+ results = results + trimNewlines ( str . slice ( match . index ) ) ;
36+ str = str . slice ( 0 , match . index ) ;
37+ }
38+
39+ if ( str . length > 0 ) {
40+ // The data does not look like JSON and we have not
41+ // detected the start of JSON, so write the
42+ // output to the console instead.
43+ console . log ( 'Python:' , '\x1b[34m' + str + '\x1b[0m' ) ;
44+ }
45+ }
3646 } ) ;
37- }
47+ process . stderr . on ( 'data' , ( data ) => {
48+ context . fail ( data ) ;
49+ } ) ;
50+ process . on ( 'close' , ( code ) => {
51+ if ( code == 0 ) {
52+ try {
53+ context . succeed ( JSON . parse ( results ) ) ;
54+ } catch ( ex ) {
55+ context . fail ( results ) ;
56+ }
57+ } else {
58+ context . succeed ( code , results ) ;
59+ }
60+ } ) ;
61+ }
3862}
3963
64+
4065module . exports = {
41- getFunctionOptions ( fun , funName , servicePath , serviceRuntime ) {
42- console . log ( fun , funName , servicePath )
43- // Split handler into method name and path i.e. handler.run
44- const handlerFile = fun . handler . split ( '.' ) [ 0 ] ;
45- const handlerName = fun . handler . split ( '/' ) . pop ( ) . split ( '.' ) [ 1 ] ;
46-
47- return {
48- funName,
49- handlerName, // i.e. run
50- handlerFile,
51- handlerPath : `${ servicePath } /${ handlerFile } ` ,
52- servicePath,
53- funTimeout : ( fun . timeout || 30 ) * 1000 ,
54- babelOptions : ( ( fun . custom || { } ) . runtime || { } ) . babel ,
55- serviceRuntime,
56- } ;
57- } ,
66+ getFunctionOptions ( fun , funName , servicePath , serviceRuntime ) {
67+ console . log ( fun , funName , servicePath )
68+ // Split handler into method name and path i.e. handler.run
69+ const handlerFile = fun . handler . split ( '.' ) [ 0 ] ;
70+ const handlerName = fun . handler . split ( '/' ) . pop ( ) . split ( '.' ) [ 1 ] ;
71+
72+ return {
73+ funName,
74+ handlerName, // i.e. run
75+ handlerFile,
76+ handlerPath : `${ servicePath } /${ handlerFile } ` ,
77+ servicePath,
78+ funTimeout : ( fun . timeout || 30 ) * 1000 ,
79+ babelOptions : ( ( fun . custom || { } ) . runtime || { } ) . babel ,
80+ serviceRuntime,
81+ } ;
82+ } ,
5883
5984 createExternalHandler ( funOptions , options ) {
6085 let handlerContext = handlerCache [ funOptions . handlerPath ] ;
0 commit comments