@cloudbase/cli 3.0.0-alpha.9 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudbase/cli",
3
- "version": "3.0.0-alpha.9",
3
+ "version": "3.0.0",
4
4
  "description": "CLI for Tencent CloudBase (standalone bundle)",
5
5
  "bin": {
6
6
  "tcb": "bin/tcb",
@@ -11,7 +11,8 @@
11
11
  "files": [
12
12
  "bin",
13
13
  "dist/standalone",
14
- "dist/fonts"
14
+ "dist/fonts",
15
+ "runtime/nodejs"
15
16
  ],
16
17
  "license": "ISC"
17
18
  }
@@ -0,0 +1,255 @@
1
+ /* eslint-disable */
2
+ var runtime = require('./runtime')
3
+ var util = require('util')
4
+
5
+ var initHandlerFault = 'function initialization failed'
6
+ var maxRetMsgLen = 6 * 1024 * 1024 // byte
7
+ var maxRetMsgLenExceedError = 'body size is too long'
8
+ var httpHandler, eventHandler
9
+
10
+ var _result, _fault
11
+ var _user_exception = false
12
+
13
+ function wrapLog(invokeId) {
14
+ console.log = console.info = function prettyConsoleLog() {
15
+ var message = `${util.format.apply(this, arguments)}`
16
+ runtime.console_log(message)
17
+ }
18
+ console.error = console.warn = function prettyConsoleLogErr() {
19
+ var message = `${util.format.apply(this, arguments)}`
20
+ runtime.console_log(message, (err = true))
21
+ }
22
+ }
23
+
24
+ function main() {
25
+ if (0 != runtime.init()) {
26
+ console.log('runtime init failed')
27
+ return
28
+ }
29
+ runtime.log('init succ')
30
+
31
+ cleanEnv()
32
+
33
+ process.on('beforeExit', () => {
34
+ runtime.log('catch exit')
35
+ finish(null, null, false)
36
+ })
37
+ process.on('uncaughtException', err => {
38
+ runtime.log('catch exception')
39
+ finish(err, null, false)
40
+ })
41
+
42
+ waitForInvoke()
43
+ }
44
+
45
+ function cleanEnv() {
46
+ var envToDelete = ['SOCKETPATH', 'CONTAINERID']
47
+ for (var k in process.env) {
48
+ if (k.startsWith('KUBERNETES')) {
49
+ envToDelete.push(k)
50
+ }
51
+ }
52
+
53
+ envToDelete.forEach(e => {
54
+ delete process.env[e]
55
+ })
56
+ }
57
+
58
+ function waitForInvoke() {
59
+ runtime.log('wait for invoke')
60
+ var invokeInfo = runtime.wait_for_invoke()
61
+ setTimeout(() => {
62
+ runtime.log('timed out, invoke')
63
+ invoke(invokeInfo)
64
+ }, 0)
65
+ }
66
+
67
+ function invoke(invokeInfo) {
68
+ if (invokeInfo.cmd === 'RELOAD') {
69
+ runtime.log(`get reload request: ${invokeInfo.context}`)
70
+ // 路径中可能包含 . 符号
71
+ var ff = invokeInfo.globalHandler.split('.')
72
+ initHandler(invokeInfo.filePath + ff[0], ff[1])
73
+ runtime.log('handlers reloaded')
74
+ _result = 'reload'
75
+ finish(null, null, false)
76
+ return
77
+ }
78
+
79
+ _result = undefined
80
+ _fault = undefined
81
+
82
+ runtime.report_running()
83
+
84
+ var ev, ctx
85
+ if (invokeInfo.event || invokeInfo.context) {
86
+ try {
87
+ ev = JSON.parse(invokeInfo.event)
88
+ ctx = JSON.parse(invokeInfo.context)
89
+ } catch (err) {
90
+ _fault = `eval event[${invokeInfo.event}] or context [${invokeInfo.context}] failed\n${err}`
91
+ return
92
+ }
93
+ }
94
+
95
+ ctx['environ'].split(';').forEach(e => {
96
+ if (e == '') return
97
+ var kv = e.split('=', 2)
98
+ process.env[kv[0]] = kv[1]
99
+ })
100
+
101
+ runtime.log(`request[${ctx['request_id']}] invoked`)
102
+
103
+ if (!httpHandler && !eventHandler) {
104
+ _fault = initHandlerFault
105
+ return
106
+ }
107
+
108
+ wrapLog(ctx['request_id'])
109
+ if (invokeInfo.cmd === 'HTTP') {
110
+ httpHandler.handle(invokeInfo.sockfd)
111
+ } else if (invokeInfo.cmd === 'EVENT') {
112
+ eventHandler.handle(ev, ctx)
113
+ } else {
114
+ _fault = `recv unknown task type: ${invokeInfo.cmd}`
115
+ runtime.log(`recv unknown task type: ${invokeInfo.cmd}`)
116
+ }
117
+
118
+ runtime.log('process finished')
119
+ }
120
+
121
+ function initHandler(file, func) {
122
+ try {
123
+ var path = require('path')
124
+ var current_path = path.dirname(file)
125
+ process.chdir(current_path)
126
+ runtime.log(`working directory: ${process.cwd()}`)
127
+
128
+ for (var item in require.cache) {
129
+ delete require.cache[item]
130
+ }
131
+ var usermod = require(file)
132
+ httpHandler = new HttpHandler(usermod[func])
133
+ eventHandler = new EventHandler(usermod[func])
134
+ } catch (err) {
135
+ runtime.log(`get user function[${file}:${func}] failed`)
136
+ runtime.log(err.stack)
137
+ initHandlerFault = err.message
138
+ _user_exception = true
139
+ }
140
+ }
141
+
142
+ function finish(err, data, wait) {
143
+ runtime.log('finish')
144
+ runtime.log(wait ? 'wait' : 'not wait')
145
+
146
+ if (_result === undefined) {
147
+ if (err == null) {
148
+ try {
149
+ _result = JSON.stringify(data === undefined ? null : data)
150
+ } catch (err) {
151
+ _result = 'faulted'
152
+ _fault = `stringify response to json failed: ${err.message}`
153
+ return
154
+ }
155
+ } else {
156
+ _result = 'faulted'
157
+ if (err instanceof Error) {
158
+ runtime.console_log(err.stack, true)
159
+ _fault = err.message
160
+ } else {
161
+ var errStr = String(err)
162
+ _fault = `${errStr}(callback err is not instance of Error)`
163
+ }
164
+ }
165
+ }
166
+
167
+ if (wait) {
168
+ return
169
+ }
170
+
171
+ runtime.log(_result)
172
+ process.nextTick(() => {
173
+ if (_result == 'reload') {
174
+ // reload response, do nothing
175
+ } else if (_fault !== undefined) {
176
+ _user_exception = true
177
+ var errType = _user_exception ? 2 : 1
178
+ runtime.report_fail(_fault, 0, errType)
179
+ } else if (_result.length > maxRetMsgLen) {
180
+ runtime.report_fail(maxRetMsgLenExceedError, 0, 1)
181
+ } else {
182
+ runtime.report_done(_result, 0)
183
+ }
184
+ waitForInvoke()
185
+ })
186
+ }
187
+
188
+ class HttpHandler {
189
+ constructor(func) {
190
+ this.realHandler = func
191
+ }
192
+
193
+ handle(fd) {}
194
+ }
195
+
196
+ class EventHandler {
197
+ constructor(func) {
198
+ this.realHandler = func
199
+ }
200
+
201
+ handle(ev, ctx) {
202
+ var called = false
203
+ var wait = true
204
+ var callback = (err, data) => {
205
+ if (called) {
206
+ return
207
+ }
208
+ called = true
209
+ finish(err, data, wait)
210
+ }
211
+
212
+ var ctxx = Object.assign(
213
+ {
214
+ set callbackWaitsForEmptyEventLoop(value) {
215
+ wait = value
216
+ },
217
+ get callbackWaitsForEmptyEventLoop() {
218
+ return wait
219
+ },
220
+ getContext() {
221
+ return ctx
222
+ },
223
+ done: function(err, data) {
224
+ wait = false
225
+ callback(err, data)
226
+ },
227
+ succeed: function(data) {
228
+ ctxx.done(null, data)
229
+ },
230
+ fail: function(err) {
231
+ ctxx.done(err, null)
232
+ }
233
+ },
234
+ ctx
235
+ )
236
+
237
+ try {
238
+ _user_exception = false
239
+ var ret = this.realHandler(ev, ctxx, callback)
240
+ if (
241
+ ret &&
242
+ ret.then !== undefined &&
243
+ typeof ret.then === 'function'
244
+ ) {
245
+ ret.then(ctxx.succeed, ctxx.fail)
246
+ }
247
+ } catch (err) {
248
+ runtime.console_log(err.stack, true)
249
+ _fault = err.stack
250
+ _user_exception = true
251
+ }
252
+ }
253
+ }
254
+
255
+ main()
@@ -0,0 +1,183 @@
1
+ /* eslint-disable */
2
+ const fs = require('fs')
3
+ const crypto = require('crypto')
4
+
5
+ var GLOBAL_FUNCTION_HANDLER = process.argv[2] || process.env.SCF_FUNCTION_HANDLER || 'index.main'
6
+ var GLOBAL_FUNCTION_NAME = process.env.SCF_FUNCTION_NAME || 'main'
7
+ var GLOBAL_EVENT_BODY =
8
+ process.argv[3] ||
9
+ process.env.SCF_EVENT_BODY ||
10
+ (process.env.DOCKER_USE_STDIN && fs.readFileSync('/dev/stdin', 'utf8')) ||
11
+ '{}'
12
+
13
+ var GLOBAL_USER_FILE_PATH = process.env.GLOBAL_USER_FILE_PATH || ''
14
+ var GLOBAL_VERSION = process.env.SCF_FUNCTION_VERSION || '$LATEST'
15
+ var GLOBAL_MEM_SIZE = process.env.SCF_FUNCTION_MEMORY_SIZE || '256'
16
+ var GLOBAL_TIMEOUT = process.env.SCF_FUNCTION_TIMEOUT || '3'
17
+ var GLOBAL_ENVIRON = process.env.SCF_FUNCTION_ENVIRON || ''
18
+ var GLOBAL_IS_QUIET = process.env.SCF_DISPLAY_IS_QUIET === 'True' || false
19
+
20
+ var GLOBAL_REQUEST_ID = uuid()
21
+ var GLOBAL_START_TIME = process.hrtime()
22
+ var GLOBAL_SOCK = -1
23
+ var GLOBAL_STAGE = 0
24
+
25
+ module.exports = {
26
+ init: function() {
27
+ if (!GLOBAL_IS_QUIET) {
28
+ consoleLog('开始本地执行云函数,受环境影响,执行结果可能与云端存在一定差异!')
29
+ consoleLog('START RequestId: ' + GLOBAL_REQUEST_ID)
30
+ }
31
+ return 0
32
+ },
33
+ wait_for_invoke: function() {
34
+ var invokeInfo = []
35
+
36
+ GLOBAL_STAGE += 1
37
+ switch (GLOBAL_STAGE) {
38
+ case 1:
39
+ invokeInfo.cmd = 'RELOAD'
40
+ invokeInfo.context = GLOBAL_USER_FILE_PATH + GLOBAL_FUNCTION_HANDLER
41
+ invokeInfo.globalHandler = GLOBAL_FUNCTION_HANDLER
42
+ invokeInfo.filePath = GLOBAL_USER_FILE_PATH
43
+ break
44
+ case 2:
45
+ invokeInfo.cmd = 'EVENT'
46
+ invokeInfo.sockfd = GLOBAL_SOCK
47
+ invokeInfo.event = GLOBAL_EVENT_BODY
48
+ invokeInfo.context = initContext()
49
+ break
50
+ default:
51
+ process.exit()
52
+ }
53
+
54
+ return invokeInfo
55
+ },
56
+ log: function(str) {
57
+ // consoleLog(formatSystem(str))
58
+ },
59
+ console_log: function(str, err = false) {
60
+ if (!GLOBAL_IS_QUIET) {
61
+ if (err === false) {
62
+ consoleLog(formatConsole(str))
63
+ } else {
64
+ consoleLogErr(formatConsole(str))
65
+ }
66
+ }
67
+ },
68
+ report_fail: function(stackTrace, errNum, errType = 0) {
69
+ const result = {}
70
+
71
+ result['errorCode'] = 1
72
+ result['errorMessage'] = 'user code exception caught'
73
+ if (stackTrace) {
74
+ result['stackTrace'] = stackTrace
75
+ }
76
+
77
+ reportDone('', (errType = 1))
78
+ // console.dir(result);
79
+ consoleLogErr(JSON.stringify(result))
80
+ },
81
+ report_running: function() {
82
+ GLOBAL_START_TIME = process.hrtime()
83
+ },
84
+ report_done: function(resultStr, errType = 0) {
85
+ reportDone(resultStr, errType)
86
+ }
87
+ }
88
+
89
+ function initContext() {
90
+ var context = {}
91
+ context['function_version'] = GLOBAL_VERSION
92
+ context['function_name'] = GLOBAL_FUNCTION_NAME
93
+
94
+ context['time_limit_in_ms'] = GLOBAL_TIMEOUT
95
+ context['memory_limit_in_mb'] = GLOBAL_MEM_SIZE
96
+
97
+ context['request_id'] = GLOBAL_REQUEST_ID
98
+ context['environ'] = GLOBAL_ENVIRON
99
+
100
+ return JSON.stringify(context)
101
+ }
102
+
103
+ function reportDone(resultStr, errType = 0) {
104
+ if (GLOBAL_IS_QUIET) {
105
+ if (typeof resultStr === 'string') {
106
+ if (errType === 0) consoleLog(resultStr)
107
+ else consoleLogErr(resultStr)
108
+ }
109
+ return
110
+ }
111
+
112
+ var diffMs = hrTimeMs(process.hrtime(GLOBAL_START_TIME))
113
+ var billedMs = Math.min(100 * (Math.floor(diffMs / 100) + 1), GLOBAL_TIMEOUT * 1000)
114
+ if (errType === 0) {
115
+ consoleLog('END RequestId: ' + GLOBAL_REQUEST_ID)
116
+ consoleLog(
117
+ [
118
+ '运行信息:',
119
+ 'REPORT RequestId: ' + GLOBAL_REQUEST_ID,
120
+ 'Duration: ' + diffMs.toFixed(2) + ' ms',
121
+ 'Billed Duration: ' + billedMs + ' ms',
122
+ 'Memory Size: ' + GLOBAL_MEM_SIZE + ' MB',
123
+ 'Max Memory Used: ' + Math.round(process.memoryUsage().rss / (1024 * 1024)) + ' MB'
124
+ ].join('\n')
125
+ )
126
+ } else {
127
+ consoleLogErr(
128
+ [
129
+ '运行信息:',
130
+ 'REPORT RequestId: ' + GLOBAL_REQUEST_ID,
131
+ 'Duration: ' + diffMs.toFixed(2) + ' ms',
132
+ 'Billed Duration: ' + billedMs + ' ms',
133
+ 'Memory Size: ' + GLOBAL_MEM_SIZE + ' MB',
134
+ 'Max Memory Used: ' + Math.round(process.memoryUsage().rss / (1024 * 1024)) + ' MB'
135
+ ].join('\n')
136
+ )
137
+ }
138
+
139
+ if (typeof resultStr === 'string') {
140
+ if (errType === 0) {
141
+ consoleLog('返回结果:\n' + resultStr)
142
+ } else {
143
+ consoleLogErr('返回结果:\n' + resultStr)
144
+ }
145
+ }
146
+ }
147
+
148
+ function consoleLog(str) {
149
+ process.stdout.write(str + '\n')
150
+ }
151
+
152
+ function consoleLogErr(str) {
153
+ process.stderr.write(str + '\n')
154
+ }
155
+
156
+ function formatConsole(str) {
157
+ return str.replace(/^[0-9TZ:.-]+\t[0-9a-f-]+\t/, '\u001b[34m$&\u001b[0m')
158
+ }
159
+
160
+ function formatSystem(str) {
161
+ return '\u001b[32m' + str + '\u001b[0m'
162
+ }
163
+
164
+ function hrTimeMs(hrtime) {
165
+ return (hrtime[0] * 1e9 + hrtime[1]) / 1e6
166
+ }
167
+
168
+ function uuid() {
169
+ return (
170
+ crypto.randomBytes(4).toString('hex') +
171
+ '-' +
172
+ crypto.randomBytes(2).toString('hex') +
173
+ '-' +
174
+ crypto
175
+ .randomBytes(2)
176
+ .toString('hex')
177
+ .replace(/^./, '1') +
178
+ '-' +
179
+ crypto.randomBytes(2).toString('hex') +
180
+ '-' +
181
+ crypto.randomBytes(6).toString('hex')
182
+ )
183
+ }