zcatalyst-cli
Version:
Command Line Tool for CATALYST
259 lines (258 loc) • 12.9 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.FnHandler = void 0;
const child_process_1 = require("child_process");
const fs_1 = require("../../../util_modules/fs");
const constants_1 = require("../../../util_modules/constants");
const http_1 = require("http");
const logger_1 = require("../../../util_modules/logger");
const server_1 = require("../../../util_modules/server");
const project_1 = require("../../../util_modules/project");
const error_1 = __importDefault(require("../../../error"));
const path_1 = require("path");
class FnHandler {
constructor(fn, localFnEvents) {
this.closed = false;
this.fn = fn;
this.stack = (() => {
var _a, _b, _c;
if ((_a = fn === null || fn === void 0 ? void 0 : fn.target.stack) === null || _a === void 0 ? void 0 : _a.startsWith(constants_1.RUNTIME.language.node.value)) {
return 'node';
}
if ((_b = fn === null || fn === void 0 ? void 0 : fn.target.stack) === null || _b === void 0 ? void 0 : _b.startsWith(constants_1.RUNTIME.language.java.value)) {
return 'java';
}
if ((_c = fn === null || fn === void 0 ? void 0 : fn.target.stack) === null || _c === void 0 ? void 0 : _c.startsWith(constants_1.RUNTIME.language.python.value)) {
return 'python';
}
throw new error_1.default('Invalid stack for execute command: ' + fn.target.stack, {
exit: 2
});
})();
this.localFnEvents = localFnEvents;
const projectRoot = (0, project_1.getProjectRoot)();
this.responseFile = (0, path_1.join)(projectRoot, constants_1.FOLDERNAME.build, '.catalyst', 'user_res_body');
this.metaFile = (0, path_1.join)(projectRoot, constants_1.FOLDERNAME.build, '.catalyst', 'user_meta.json');
}
writeResponse(response, status) {
fs_1.SYNC.writeFile(this.responseFile, response);
fs_1.SYNC.writeFile(this.metaFile, JSON.stringify({ response: { statusCode: status } }));
}
responseProcessor(statusCode, message) {
switch (statusCode) {
case 200: {
this.writeResponse('SUCCESS', 200);
break;
}
case 532: {
this.writeResponse('CODE_EXCEPTION', 532);
break;
}
case 530: {
this.writeResponse('FAILURE', 530);
break;
}
case 500: {
this.writeResponse('INTERNAL_SERVER_ERROR', 500);
break;
}
default: {
throw new error_1.default('INVALID STATUS CODE', {
context: {
statusCode: statusCode,
statusMessage: message
}
});
}
}
}
processFlowHandler(data, listenPort) {
return __awaiter(this, void 0, void 0, function* () {
return new Promise((resolve, reject) => {
var _a;
const jobDetailsServer = new http_1.Server((serverReq, serverRes) => __awaiter(this, void 0, void 0, function* () {
var _b, _c;
if ((_b = serverReq.url) === null || _b === void 0 ? void 0 : _b.includes('data')) {
serverRes.writeHead(200);
serverRes.write(JSON.stringify({
data
}));
serverRes.end();
}
else if ((_c = serverReq.url) === null || _c === void 0 ? void 0 : _c.includes('callback')) {
const reqData = yield new Promise((_resolve) => {
const data = [];
serverReq.on('data', (chunk) => data.push(chunk));
serverReq.on('end', () => _resolve(JSON.parse(Buffer.concat(data).toString())));
});
this.responseProcessor(reqData.job_status);
serverRes.writeHead(200);
serverRes.write(JSON.stringify({}));
serverRes.end();
resolve();
return;
}
else {
(0, logger_1.debug)(`Invalid request: (${serverReq.method}) ${serverReq.url}`);
this.writeResponse('INTERNAL_SERVER_ERROR', 500);
reject(`Invalid request: (${serverReq.method}) ${serverReq.url}`);
return;
}
}));
const jobConnDestroyer = new server_1.ConnectionDestroyer(jobDetailsServer);
jobDetailsServer.listen(listenPort, '127.0.0.1', () => {
(0, logger_1.debug)('server listening on port :' + listenPort);
});
jobDetailsServer.on('error', reject);
(_a = this.slave) === null || _a === void 0 ? void 0 : _a.once('exit', () => {
jobConnDestroyer.destroy();
});
});
});
}
fnRequestHandler({ httpPort, data = {}, accessToken }) {
return __awaiter(this, void 0, void 0, function* () {
data.project_details = Object.assign({ id: (0, project_1.getProjectId)(), project_name: (0, project_1.getProjectName)() }, (data.project_details || {}));
const reqJson = JSON.stringify(data);
return new Promise((resolve, reject) => {
const req = (0, http_1.request)(`http://127.0.0.1:${httpPort}`, {
headers: {
'x-zc-projectid': (0, project_1.getProjectId)(),
'x-zc-project-domain': (0, project_1.getDomainPrefix)() + '.' + constants_1.ORIGIN.app.replace('https://', ''),
'x-zc-project-key': (0, project_1.getDomainKey)(),
'x-zc-environment': (0, project_1.getEnvName)(),
'x-zc-user-cred-type': 'token',
'x-zc-user-cred-token': accessToken,
'x-zc-admin-cred-type': 'token',
'x-zc-admin-cred-token': accessToken,
'x-zc-user-type': 'admin',
'x-zc-instance-id': 'local',
'Content-Length': reqJson.length
}
}, (resp) => {
var _a;
if ([constants_1.REMOTE_REF.functions.type.cron, constants_1.REMOTE_REF.functions.type.event].includes(((_a = this.fn.target) === null || _a === void 0 ? void 0 : _a.type) + '')) {
try {
this.responseProcessor(resp.statusCode || -1, resp.statusMessage);
return resolve();
}
catch (er) {
reject(er);
}
}
resp.on('data', (data) => {
const respStr = data.toString();
fs_1.SYNC.writeFile(this.responseFile, respStr);
});
resp.on('close', () => {
const metaJson = {
response: { statusCode: resp.statusCode }
};
fs_1.SYNC.writeFile(this.metaFile, JSON.stringify(metaJson));
resolve();
});
}).on('error', (err) => {
if ('code' in err && err.code === 'ECONNRESET') {
(0, logger_1.debug)('ECONNRESET - when sending request to container function');
return;
}
reject(new error_1.default('Error when trying to send the request to container function', { original: err, exit: 2, skipHelp: true }));
});
req.write(reqJson);
req.end();
});
});
}
fnResponseHandler(code, sig) {
var _a, _b, _c, _d, _e;
return __awaiter(this, void 0, void 0, function* () {
if (code === 0) {
(0, logger_1.info)(`[CLI] Function ${(_a = this.fn.target) === null || _a === void 0 ? void 0 : _a.name} execution complete`);
(0, logger_1.info)();
const response = yield fs_1.ASYNC.readFile(this.responseFile);
let meta;
try {
meta = JSON.parse((yield fs_1.ASYNC.readFile(this.metaFile))).response;
}
catch (err) {
meta = {};
}
switch ((_b = this.fn.target) === null || _b === void 0 ? void 0 : _b.type) {
case constants_1.FN_TYPE.basic:
(0, logger_1.info)(`[response - ${this.fn.target.name}] ${response + ''}`);
(0, logger_1.info)(`[status - ${this.fn.target.name}] ${(meta.statusCode || 200) + ''}`);
this.localFnEvents.emit('response', {
data: response,
status: meta.statsCode
});
break;
case constants_1.FN_TYPE.cron:
case constants_1.FN_TYPE.job:
case constants_1.FN_TYPE.event:
(0, logger_1.info)(`[status - ${this.fn.target.name}] ${response || 'Unknown'}`);
if (!response) {
(0, logger_1.info)(`[CLI] Make sure to close the ${this.fn.target.name} (${this.fn.target.type}) function.`);
}
this.localFnEvents.emit('response', {
status: meta.statusCode
});
break;
case constants_1.FN_TYPE.integration:
(0, logger_1.info)(`[response - ${this.fn.target.name}] ${response + ''}`);
try {
this.localFnEvents.emit('response', JSON.parse(response || ''));
}
catch (er) {
(0, logger_1.debug)('Invalid integration response: ', er);
}
break;
}
}
else {
(code === 130 || sig === 'SIGINT') &&
(0, logger_1.info)(`[CLI] Function ${(_c = this.fn.target) === null || _c === void 0 ? void 0 : _c.name} interrupted`);
(code === 143 || sig === 'SIGTERM' || sig === 'SIGQUIT' || sig === 'SIGKILL') &&
(0, logger_1.info)(`[CLI] Function ${(_d = this.fn.target) === null || _d === void 0 ? void 0 : _d.name} process killed`);
this.localFnEvents.listenerCount('error') > 0 &&
this.localFnEvents.emit('error', new error_1.default(`Function(${(_e = this.fn.target) === null || _e === void 0 ? void 0 : _e.name}) process exited with ${code ? 'status: ' + code : 'signal: ' + sig}`, {
skipHelp: true
}));
}
});
}
shutdown() {
return __awaiter(this, void 0, void 0, function* () {
return new Promise((res) => {
this.closed = true;
this.kill();
if (this.watcher) {
this.watcher.close().then(res).catch(res);
}
else {
res();
}
});
});
}
kill() {
if (!this.slave) {
return;
}
this.slave instanceof child_process_1.ChildProcess
? !this.slave.killed && this.slave.kill('SIGTERM')
: this.slave.emit('close', this.fn);
}
}
exports.FnHandler = FnHandler;