3
3
const chalk = require ( 'chalk' ) ;
4
4
const path = require ( 'path' ) ;
5
5
const _ = require ( 'lodash' ) ;
6
+ const { getReqRes } = require ( './httpReqRes' ) ;
6
7
7
8
const tryToRequirePaths = ( paths ) => {
8
9
let loaded ;
@@ -19,10 +20,10 @@ const tryToRequirePaths = (paths) => {
19
20
return loaded ;
20
21
} ;
21
22
23
+ const jsonContentType = 'application/json' ;
24
+
22
25
module . exports = {
23
26
async invokeLocalNodeJs ( functionObj , event , customContext ) {
24
- let hasResponded = false ;
25
-
26
27
// index.js and function.js are the two files supported by default by a cloud-function
27
28
// TODO add the file pointed by the main key of the package.json
28
29
const paths = [ 'index.js' , 'function.js' ] . map ( ( fileName ) =>
@@ -41,27 +42,41 @@ module.exports = {
41
42
42
43
this . addEnvironmentVariablesToProcessEnv ( functionObj ) ;
43
44
44
- function handleError ( err ) {
45
- let errorResult ;
46
- if ( err instanceof Error ) {
47
- errorResult = {
48
- errorMessage : err . message ,
49
- errorType : err . constructor . name ,
50
- stackTrace : err . stack && err . stack . split ( '\n' ) ,
51
- } ;
52
- } else {
53
- errorResult = {
54
- errorMessage : err ,
55
- } ;
56
- }
45
+ const eventType = Object . keys ( functionObj . events [ 0 ] ) [ 0 ] ;
57
46
58
- this . serverless . cli . consoleLog ( chalk . red ( JSON . stringify ( errorResult , null , 4 ) ) ) ;
59
- process . exitCode = 1 ;
47
+ switch ( eventType ) {
48
+ case 'event' :
49
+ return this . handleEvent ( cloudFunction , event , customContext ) ;
50
+ case 'http' :
51
+ return this . handleHttp ( cloudFunction , event , customContext ) ;
52
+ default :
53
+ throw new Error ( `${ eventType } is not supported` ) ;
60
54
}
55
+ } ,
56
+ handleError ( err , resolve ) {
57
+ let errorResult ;
58
+ if ( err instanceof Error ) {
59
+ errorResult = {
60
+ errorMessage : err . message ,
61
+ errorType : err . constructor . name ,
62
+ stackTrace : err . stack && err . stack . split ( '\n' ) ,
63
+ } ;
64
+ } else {
65
+ errorResult = {
66
+ errorMessage : err ,
67
+ } ;
68
+ }
69
+
70
+ this . serverless . cli . consoleLog ( chalk . red ( JSON . stringify ( errorResult , null , 4 ) ) ) ;
71
+ resolve ( ) ;
72
+ process . exitCode = 1 ;
73
+ } ,
74
+ handleEvent ( cloudFunction , event , customContext ) {
75
+ let hasResponded = false ;
61
76
62
77
function handleResult ( result ) {
63
78
if ( result instanceof Error ) {
64
- handleError . call ( this , result ) ;
79
+ this . handleError . call ( this , result ) ;
65
80
return ;
66
81
}
67
82
this . serverless . cli . consoleLog ( JSON . stringify ( result , null , 4 ) ) ;
@@ -72,26 +87,68 @@ module.exports = {
72
87
if ( ! hasResponded ) {
73
88
hasResponded = true ;
74
89
if ( err ) {
75
- handleError . call ( this , err ) ;
90
+ this . handleError ( err , resolve ) ;
76
91
} else if ( result ) {
77
92
handleResult . call ( this , result ) ;
78
93
}
94
+ resolve ( ) ;
79
95
}
80
- resolve ( ) ;
81
96
} ;
82
97
83
98
let context = { } ;
84
99
85
100
if ( customContext ) {
86
101
context = customContext ;
87
102
}
88
-
89
- const maybeThennable = cloudFunction ( event , context , callback ) ;
90
- if ( maybeThennable ) {
91
- return Promise . resolve ( maybeThennable ) . then ( callback . bind ( this , null ) , callback . bind ( this ) ) ;
103
+ try {
104
+ const maybeThennable = cloudFunction ( event , context , callback ) ;
105
+ if ( maybeThennable ) {
106
+ Promise . resolve ( maybeThennable ) . then ( callback . bind ( this , null ) , callback . bind ( this ) ) ;
107
+ }
108
+ } catch ( error ) {
109
+ this . handleError ( error , resolve ) ;
92
110
}
111
+ } ) ;
112
+ } ,
113
+ handleHttp ( cloudFunction , event ) {
114
+ const { expressRequest, expressResponse : response } = getReqRes ( ) ;
115
+ const request = Object . assign ( expressRequest , event ) ;
116
+
117
+ return new Promise ( ( resolve ) => {
118
+ const endCallback = ( data ) => {
119
+ if ( data && Buffer . isBuffer ( data ) ) {
120
+ data = data . toString ( ) ;
121
+ }
122
+ const headers = response . getHeaders ( ) ;
123
+ const bodyIsJson =
124
+ headers [ 'content-type' ] && headers [ 'content-type' ] . includes ( jsonContentType ) ;
125
+ if ( data && bodyIsJson ) {
126
+ data = JSON . parse ( data ) ;
127
+ }
128
+ this . serverless . cli . consoleLog (
129
+ JSON . stringify (
130
+ {
131
+ status : response . statusCode ,
132
+ headers,
133
+ body : data ,
134
+ } ,
135
+ null ,
136
+ 4
137
+ )
138
+ ) ;
139
+ resolve ( ) ;
140
+ } ;
93
141
94
- return maybeThennable ;
142
+ Object . assign ( response , { end : endCallback } ) ; // Override of the end method which is always called to send the response of the http request
143
+
144
+ try {
145
+ const maybeThennable = cloudFunction ( request , response ) ;
146
+ if ( maybeThennable ) {
147
+ Promise . resolve ( maybeThennable ) . catch ( ( error ) => this . handleError ( error , resolve ) ) ;
148
+ }
149
+ } catch ( error ) {
150
+ this . handleError ( error , resolve ) ;
151
+ }
95
152
} ) ;
96
153
} ,
97
154
0 commit comments