zcatalyst-cli 1.17.5 → 1.18.0-beta.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.
Files changed (33) hide show
  1. package/docs/commands/functions/shell.toml +4 -0
  2. package/docs/endpoints/lib/env.toml +3 -0
  3. package/docs/shell/dependencies/tunnel-server.toml +4 -0
  4. package/docs/shell/index.toml +7 -0
  5. package/lib/appsail-utils.js +7 -1
  6. package/lib/commands/functions/shell.js +97 -1
  7. package/lib/commands/serve.js +1 -1
  8. package/lib/endpoints/index.js +8 -1
  9. package/lib/endpoints/lib/env.js +20 -2
  10. package/lib/endpoints/lib/sdk.js +2 -2
  11. package/lib/endpoints/lib/tunnel.js +66 -0
  12. package/lib/internal/api.js +5 -0
  13. package/lib/port-resolver.js +1 -1
  14. package/lib/repl-server.js +9 -0
  15. package/lib/serve/server/lib/master.js +18 -9
  16. package/lib/serve/server/lib/python/index.js +3 -0
  17. package/lib/shell/dependencies/http-functions.js +21 -8
  18. package/lib/shell/dependencies/invoker/bio/java/JavabioInvoker.java +28 -32
  19. package/lib/shell/dependencies/invoker/bio/node.mjs +2 -2
  20. package/lib/shell/dependencies/invoker/cron/java/JavacronInvoker.java +62 -13
  21. package/lib/shell/dependencies/invoker/cron/node.mjs +28 -24
  22. package/lib/shell/dependencies/invoker/event/java/JavaeventInvoker.java +40 -6
  23. package/lib/shell/dependencies/invoker/event/node.mjs +22 -9
  24. package/lib/shell/dependencies/invoker/integ/java/JavaintegInvoker.java +3 -3
  25. package/lib/shell/dependencies/invoker/integ/node.mjs +6 -6
  26. package/lib/shell/dependencies/local-function.js +290 -199
  27. package/lib/shell/dependencies/tunnel-server.js +173 -0
  28. package/lib/shell/index.js +55 -1
  29. package/lib/util_modules/constants/index.js +3 -1
  30. package/lib/util_modules/constants/lib/needed-scopes.js +52 -0
  31. package/lib/util_modules/constants/lib/scopes.js +5 -0
  32. package/lib/util_modules/constants/lib/urls.js +8 -0
  33. package/package.json +3 -3
@@ -14,6 +14,9 @@ import java.nio.file.Path;
14
14
  import java.nio.file.Paths;
15
15
  import java.util.HashMap;
16
16
  import java.util.Iterator;
17
+ import java.util.Timer;
18
+ import java.util.TimerTask;
19
+ import java.util.concurrent.TimeoutException;
17
20
  import java.util.logging.Handler;
18
21
  import java.util.logging.LogManager;
19
22
  import java.util.logging.LogRecord;
@@ -76,10 +79,22 @@ public class JavacronInvoker {
76
79
  return stringWriter.toString();
77
80
  }
78
81
 
82
+ private static HashMap<String, Object> jsonToMap(Object ob) throws Exception {
83
+ if(ob instanceof String) {
84
+ return jsonToMap((String) ob);
85
+ }
86
+
87
+ if (ob instanceof JSONObject) {
88
+ return jsonToMap((JSONObject) ob);
89
+ }
90
+ throw new Exception("Unexpected json input");
91
+ }
79
92
  private static HashMap<String, Object> jsonToMap(String t) throws Exception {
93
+ return jsonToMap(new JSONObject(t));
94
+ }
95
+ private static HashMap<String, Object> jsonToMap(JSONObject jObject) throws Exception {
80
96
 
81
97
  HashMap<String, Object> map = new HashMap<String, Object>();
82
- JSONObject jObject = new JSONObject(t);
83
98
  Iterator<?> keys = jObject.keys();
84
99
 
85
100
  while (keys.hasNext()) {
@@ -91,18 +106,33 @@ public class JavacronInvoker {
91
106
  return map;
92
107
  }
93
108
 
94
- private static void writeResponse(String response, String invokerDir) throws Exception {
109
+ private static void writeResponse(String response, Integer status, String invokerDir) throws Exception {
110
+ // write response data
95
111
  String responseFilePath = Paths.get(invokerDir, "../user_res_body").toString();
112
+
96
113
  BufferedWriter responseWriter = new BufferedWriter(new FileWriter(responseFilePath));
97
114
  responseWriter.write(response);
98
115
  responseWriter.close();
116
+
117
+ // write response meta
118
+ String metaFilePath = Paths.get(invokerDir, "../user_meta.json").toString();
119
+
120
+ BufferedWriter metaWriter = new BufferedWriter(new FileWriter(metaFilePath));
121
+ JSONObject metaJson = new JSONObject();
122
+ metaJson.put("statusCode", status);
123
+ metaWriter.write(new JSONObject().put("response", metaJson).toString());
124
+ metaWriter.close();
99
125
  }
100
126
 
101
127
  private static void throwAndExit(Exception err, int exitCode, String invokerDir) {
102
128
  try {
103
129
  String sStackTrace = getStackTraceAsString(err); // stack trace as a string
104
- if (exitCode > 0) {
105
- writeResponse(CRON_STATUS.FAILURE.name(), invokerDir);
130
+ if (exitCode == 532) {
131
+ writeResponse("CODE_EXCEPTION", exitCode, invokerDir);
132
+ } else if (exitCode == 500) {
133
+ writeResponse("INTERNAL_SERVER_ERROR", 500, invokerDir);
134
+ } else if (exitCode == 408) {
135
+ writeResponse("TIMEOUT", exitCode, invokerDir);
106
136
  }
107
137
  System.out.println(sStackTrace);
108
138
  } catch (Exception e) {
@@ -198,7 +228,8 @@ public class JavacronInvoker {
198
228
  String fnExePath = Paths.get(invokerDir, "../../", "functions", fnName).normalize().toString();
199
229
 
200
230
  HashMap<String, Object> queryData = jsonToMap(args[2]);
201
- HashMap<String, Object> projectData = jsonToMap(args[3]);
231
+ String projectData = args[3];
232
+ HashMap<String, Object> projectDataMap = jsonToMap(projectData);
202
233
  HashMap<String, Object> authData = jsonToMap(args[4]);
203
234
 
204
235
  File[] jarFiles = new File(fnExePath).listFiles(new FilenameFilter() {
@@ -219,7 +250,7 @@ public class JavacronInvoker {
219
250
  URLClassLoader child = new URLClassLoader(URLs, JavacronInvoker.class.getClassLoader());
220
251
  Class<?> cls = Class.forName(fnExeName, true, child);
221
252
 
222
- setZCThreadLocalProject(projectData);
253
+ setZCThreadLocalProject(projectDataMap);
223
254
  setZCThreadLocalAuth(authData);
224
255
 
225
256
  DefaultCronRequest defaultCron = new DefaultCronRequest();
@@ -233,9 +264,10 @@ public class JavacronInvoker {
233
264
  userData.put(key, value);
234
265
  });
235
266
 
236
- defaultCron.setCronDetails(null);
237
- defaultCron.setRemainingExecutionCount(-1);
238
- defaultCron.setCronParam(userData);
267
+ defaultCron.setCronDetails(userData.get("cron_details") != null ? (JSONObject) userData.get("cron_details") : null);
268
+ defaultCron.setRemainingExecutionCount(userData.get("remaining_count") != null ? (Integer) userData.get("remaining_count") : -1);
269
+ defaultCron.setCronParam(jsonToMap(userData.get("data")));
270
+ defaultCron.setProjectDetails(userData.get("project_details") != null ? (JSONObject) userData.get("project_details") : new JSONObject(projectData));
239
271
  CronRequest cronRequest = defaultCron;
240
272
 
241
273
  DefaultContext defaultContext = new DefaultContext(cls.getName(), 900000L);
@@ -243,16 +275,33 @@ public class JavacronInvoker {
243
275
 
244
276
  Method runner = cls.getMethod("handleCronExecute", CronRequest.class, Context.class);
245
277
  CRON_STATUS cronStatus = null;
246
- try {
278
+
279
+ if(System.getenv("DEBUG").equals("false")) {
280
+ Timer executionTimer = new Timer(true);
281
+ executionTimer.schedule(new TimerTask() {
282
+ @Override
283
+ public void run() {
284
+ throwAndExit(new TimeoutException("function execution timeout"), 408, invokerDir);
285
+ }
286
+ }, defaultContext.getMaxExecutionTimeMs());
287
+ }
288
+
289
+ try {
247
290
  cronStatus = (CRON_STATUS) runner.invoke(cls.getDeclaredConstructor().newInstance(), cronRequest, context);
248
291
  } catch (Exception e) {
249
- throwAndExit(e, 2, invokerDir);
292
+ throwAndExit(e, 532, invokerDir);
293
+ }
294
+
295
+ if(cronStatus == null) {
296
+ writeResponse("UNINTENTIONAL_TERMINATION", 531, invokerDir);
297
+ } else {
298
+ int status = cronStatus.getStatus();
299
+ writeResponse(cronStatus.name(), status == 500 ? 530 : status, invokerDir);
250
300
  }
251
301
 
252
- writeResponse(cronStatus.name(), invokerDir);
253
302
  System.exit(0);
254
303
  } catch (Exception e) {
255
- throwAndExit(e, 0, invokerDir);
304
+ throwAndExit(e, 500, invokerDir);
256
305
  }
257
306
  }
258
307
  }
@@ -13,9 +13,11 @@ const buildDir = JSON.parse(args[4]);
13
13
 
14
14
  const requestFile = path.join(buildDir, '.catalyst', 'user_req_body');
15
15
  const responseFile = path.join(buildDir, '.catalyst', 'user_res_body');
16
+ const metaFile = path.join(buildDir, '.catalyst', 'user_meta.json');
16
17
 
17
- const writeToFile = (resp) => {
18
+ const writeToFile = (resp, status) => {
18
19
  fs.writeFileSync(responseFile, resp);
20
+ fs.writeFileSync(metaFile, JSON.stringify({ response: { statusCode: status } }));
19
21
  };
20
22
 
21
23
  let body = {};
@@ -29,27 +31,39 @@ if (fs.existsSync(requestFile)) {
29
31
  }
30
32
  }
31
33
 
32
- const endTime = 15 * 60 * 1000 + Date.now();
34
+ /**
35
+ * execution timeout 15 minutes
36
+ */
37
+ const timeout = 15 * 60 * 1000;
38
+ const endTime = timeout + Date.now();
39
+
40
+ // exit on timeout
41
+ process.env.DEBUG === 'false' &&
42
+ setTimeout(() => {
43
+ writeToFile('TIMEOUT', 408);
44
+ process.exit(0);
45
+ }, timeout);
33
46
 
34
47
  const context = {
35
48
  catalystHeaders: Object.assign(projectJson, authJson),
36
- getMaxExecutionTimeMs: () => 15 * 60 * 1000, // 15 mins
49
+ getMaxExecutionTimeMs: () => timeout,
37
50
  getRemainingExecutionTimeMs: () => endTime - Date.now(),
38
51
  closeWithSuccess: () => {
39
- writeToFile('SUCCESS');
52
+ writeToFile('SUCCESS', 200);
40
53
  process.exit(0);
41
54
  },
42
55
  closeWithFailure: () => {
43
- writeToFile('FAILURE');
56
+ writeToFile('FAILURE', 530);
44
57
  process.exit(0);
45
58
  }
46
59
  };
60
+
47
61
  const cronReq = {
48
- getCronParam: (KEY) => userData[KEY] || body[KEY],
49
- getAllCronParam: () => (userData && Object.keys(userData).length > 0 ? userData : body),
50
- getRemainingExecutionCount: () => -1,
51
- getCronDetails: () => null,
52
- getProjectDetails: () => projectJson
62
+ getCronParam: (KEY) => userData.data[KEY] || body[KEY],
63
+ getAllCronParams: () => (Object.keys(userData.data).length > 0 ? userData.data : body),
64
+ getRemainingExecutionCount: () => userData.remaining_count || -1,
65
+ getCronDetails: () => userData.cron_details || null,
66
+ getProjectDetails: () => userData.project_details || projectJson
53
67
  };
54
68
 
55
69
  import(pathToFileURL(target.index))
@@ -65,23 +79,13 @@ import(pathToFileURL(target.index))
65
79
  } catch (e) {
66
80
  // eslint-disable-next-line no-console
67
81
  console.error(e);
68
- writeToFile(
69
- {
70
- error: inspect(e)
71
- },
72
- { response: { statusCode: 500 } }
73
- );
74
- process.exit(2);
82
+ writeToFile('CODE_EXCEPTION', 532);
83
+ process.exit(0);
75
84
  }
76
85
  })
77
86
  .catch((e) => {
78
87
  // eslint-disable-next-line no-console
79
88
  console.error(e);
80
- writeToFile(
81
- {
82
- error: inspect(e)
83
- },
84
- { response: { statusCode: 500 } }
85
- );
86
- process.exit(2);
89
+ writeToFile('INTERNAL_SERVER_ERROR', 500);
90
+ process.exit(0);
87
91
  });
@@ -14,6 +14,9 @@ import java.nio.file.Path;
14
14
  import java.nio.file.Paths;
15
15
  import java.util.HashMap;
16
16
  import java.util.Iterator;
17
+ import java.util.Timer;
18
+ import java.util.TimerTask;
19
+ import java.util.concurrent.TimeoutException;
17
20
  import java.util.logging.Handler;
18
21
  import java.util.logging.LogManager;
19
22
  import java.util.logging.LogRecord;
@@ -91,19 +94,33 @@ public class JavaeventInvoker {
91
94
  return map;
92
95
  }
93
96
 
94
- private static void writeResponse(String response, String invokerDir) throws Exception {
97
+ private static void writeResponse(String response, Integer status, String invokerDir) throws Exception {
98
+ // write response data
95
99
  String responseFilePath = Paths.get(invokerDir, "../user_res_body").toString();
96
100
 
97
101
  BufferedWriter responseWriter = new BufferedWriter(new FileWriter(responseFilePath));
98
102
  responseWriter.write(response);
99
103
  responseWriter.close();
104
+
105
+ // write response meta
106
+ String metaFilePath = Paths.get(invokerDir, "../user_meta.json").toString();
107
+
108
+ BufferedWriter metaWriter = new BufferedWriter(new FileWriter(metaFilePath));
109
+ JSONObject metaJson = new JSONObject();
110
+ metaJson.put("statusCode", status);
111
+ metaWriter.write(new JSONObject().put("response", metaJson).toString());
112
+ metaWriter.close();
100
113
  }
101
114
 
102
115
  private static void throwAndExit(Exception err, int exitCode, String invokerDir) {
103
116
  try {
104
117
  String sStackTrace = getStackTraceAsString(err); // stack trace as a string
105
- if (exitCode > 0) {
106
- writeResponse(EVENT_STATUS.FAILURE.name(), invokerDir);
118
+ if (exitCode == 532) {
119
+ writeResponse("CODE_EXCEPTION", exitCode, invokerDir);
120
+ } else if (exitCode == 500) {
121
+ writeResponse("INTERNAL_SERVER_ERROR", exitCode, invokerDir);
122
+ } else if (exitCode == 408) {
123
+ writeResponse("TIMEOUT", exitCode, invokerDir);
107
124
  }
108
125
  System.out.println(sStackTrace);
109
126
  } catch (Exception e) {
@@ -250,16 +267,33 @@ public class JavaeventInvoker {
250
267
 
251
268
  Method runner = cls.getMethod("handleEvent", EventRequest.class, Context.class);
252
269
  EVENT_STATUS eventStatus = null;
270
+
271
+ if(System.getenv("DEBUG").equals("false")) {
272
+ Timer executionTimer = new Timer(true);
273
+ executionTimer.schedule(new TimerTask() {
274
+ @Override
275
+ public void run() {
276
+ throwAndExit(new TimeoutException("function execution timeout"), 408, invokerDir);
277
+ }
278
+ }, defaultContext.getMaxExecutionTimeMs());
279
+ }
280
+
253
281
  try {
254
282
  eventStatus = (EVENT_STATUS) runner.invoke(cls.getDeclaredConstructor().newInstance(), eventRequest, context);
255
283
  } catch (Exception e) {
256
- throwAndExit(e, 2, invokerDir);
284
+ throwAndExit(e, 532, invokerDir);
257
285
  }
258
286
 
259
- writeResponse(eventStatus.name(), invokerDir);
287
+ if(eventStatus == null) {
288
+ writeResponse("UNINTENTIONAL_TERMINATION", 531, invokerDir);
289
+ } else {
290
+ int status = eventStatus.getStatus();
291
+ writeResponse(eventStatus.name(), status == 500 ? 530 : status, invokerDir);
292
+ }
293
+
260
294
  System.exit(0);
261
295
  } catch (Exception e) {
262
- throwAndExit(e, 0, invokerDir);
296
+ throwAndExit(e, 500, invokerDir);
263
297
  }
264
298
  }
265
299
  }
@@ -12,23 +12,36 @@ const authJson = JSON.parse(args[3]);
12
12
  const buildDir = JSON.parse(args[4]);
13
13
 
14
14
  const responseFile = path.join(buildDir, '.catalyst', 'user_res_body');
15
+ const metaFile = path.join(buildDir, '.catalyst', 'user_meta.json');
15
16
 
16
- const writeToFile = (resp) => {
17
+ const writeToFile = (resp, status) => {
17
18
  fs.writeFileSync(responseFile, resp);
19
+ fs.writeFileSync(metaFile, JSON.stringify({ response: { statusCode: status } }));
18
20
  };
19
21
 
20
- const endTime = 15 * 60 * 1000 + Date.now();
22
+ /**
23
+ * execution timeout of 15 minutes
24
+ */
25
+ const timeout = 15 * 60 * 1000;
26
+ const endTime = timeout + Date.now();
27
+
28
+ // exit on timeout
29
+ process.env.DEBUG === 'false' &&
30
+ setTimeout(() => {
31
+ writeToFile('TIMEOUT', 408);
32
+ process.exit(0);
33
+ }, timeout);
21
34
 
22
35
  const context = {
23
36
  catalystHeaders: Object.assign(projectJson, authJson),
24
- getMaxExecutionTimeMs: () => 15 * 60 * 1000, // 15 mins
37
+ getMaxExecutionTimeMs: () => timeout,
25
38
  getRemainingExecutionTimeMs: () => endTime - Date.now(),
26
39
  closeWithSuccess: () => {
27
- writeToFile('SUCCESS');
40
+ writeToFile('SUCCESS', 200);
28
41
  process.exit(0);
29
42
  },
30
43
  closeWithFailure: () => {
31
- writeToFile('FAILURE');
44
+ writeToFile('FAILURE', 530);
32
45
  process.exit(0);
33
46
  }
34
47
  };
@@ -72,13 +85,13 @@ import(pathToFileURL(target.index))
72
85
  } catch (e) {
73
86
  // eslint-disable-next-line no-console
74
87
  console.error(e);
75
- writeToFile('FAILURE');
76
- process.exit(2);
88
+ writeToFile('CODE_EXCEPTION', 532);
89
+ process.exit(0);
77
90
  }
78
91
  })
79
92
  .catch((e) => {
80
93
  // eslint-disable-next-line no-console
81
94
  console.error(e);
82
- writeToFile('FAILURE');
83
- process.exit(2);
95
+ writeToFile('INTERNAL_ERROR', 500);
96
+ process.exit(0);
84
97
  });
@@ -189,13 +189,13 @@ public class JavaintegInvoker {
189
189
  }
190
190
 
191
191
  } catch (IOException e) {
192
- throwAndExit(e, 1, invokerDir);
192
+ throwAndExit(e, 500, invokerDir);
193
193
  }
194
194
 
195
195
  try {
196
196
  configJson = new JSONObject(sb.toString());
197
197
  } catch (JSONException ex) {
198
- throwAndExit(ex, 1, invokerDir);
198
+ throwAndExit(ex, 500, invokerDir);
199
199
  }
200
200
  }
201
201
  ZCThreadLocal.putValue("CONFIG_JSON", configJson);
@@ -234,7 +234,7 @@ public class JavaintegInvoker {
234
234
  try {
235
235
  integResponse = (ZCIntegResponse) runner.invoke(cls.getDeclaredConstructor().newInstance(), integRequest);
236
236
  } catch (Exception e) {
237
- throwAndExit(e, 2, invokerDir);
237
+ throwAndExit(e, 532, invokerDir);
238
238
  }
239
239
 
240
240
  if(integResponse == null) {
@@ -15,9 +15,9 @@ const buildDir = JSON.parse(args[4]);
15
15
 
16
16
  const responseFile = join(buildDir, '.catalyst', 'user_res_body');
17
17
 
18
- const writeAndExit = (resp, exitCode = 0) => {
18
+ const writeAndExit = (resp) => {
19
19
  writeFileSync(responseFile, JSON.stringify(resp));
20
- process.exit(exitCode);
20
+ process.exit(0);
21
21
  };
22
22
 
23
23
  const integrationRequest = data || {};
@@ -38,7 +38,7 @@ const integrationResponse = {
38
38
  ) {
39
39
  // eslint-disable-next-line no-console
40
40
  console.error('Invalid response object: ', response);
41
- return writeAndExit({ Status: 500 }, 2);
41
+ return writeAndExit({ Status: 500 });
42
42
  }
43
43
 
44
44
  const clean_response = response.buildResponse();
@@ -55,7 +55,7 @@ const integrationResponse = {
55
55
  "Invalid value returned from function 'buildResponse()': ",
56
56
  clean_response
57
57
  );
58
- return writeAndExit({ Status: 500 }, 2);
58
+ return writeAndExit({ Status: 500 });
59
59
  }
60
60
  return writeAndExit({
61
61
  Status: clean_response.status,
@@ -78,11 +78,11 @@ import(pathToFileURL(target.index))
78
78
  } catch (e) {
79
79
  // eslint-disable-next-line no-console
80
80
  console.error(e);
81
- writeAndExit({ error: inspect(e) }, 2);
81
+ writeAndExit({ error: inspect(e) }, 0);
82
82
  }
83
83
  })
84
84
  .catch((e) => {
85
85
  // eslint-disable-next-line no-console
86
86
  console.error(e);
87
- writeAndExit({ error: inspect(e) }, 2);
87
+ writeAndExit({ error: inspect(e) });
88
88
  });