zcatalyst-cli
Version:
Command Line Tool for CATALYST
261 lines (260 loc) • 15.2 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
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.FnExecutionHandler = void 0;
const child_process_1 = require("child_process");
const fn_handler_1 = require("./fn-handler");
const fn_utils_1 = require("../../../fn-utils");
const path_1 = require("path");
const node_1 = __importDefault(require("./node"));
const java_1 = __importDefault(require("./java"));
const python_1 = __importDefault(require("./python"));
const project_1 = require("../../../util_modules/project");
const constants_1 = require("../../../util_modules/constants");
const error_1 = __importDefault(require("../../../error"));
const port_resolver_1 = __importDefault(require("../../../port-resolver"));
const http_functions_1 = require("../http-functions");
const logger_1 = require("../../../util_modules/logger");
const container_plugin_1 = require("@zcatalyst/container-plugin");
const ansi_colors_1 = require("ansi-colors");
const env_1 = require("../../../util_modules/env");
const server_1 = require("../../../util_modules/server");
const utils_1 = require("../../../serve/server/lib/master/utils");
const readline_1 = __importDefault(require("readline"));
class FnExecutionHandler extends fn_handler_1.FnHandler {
constructor(serverDetails, localFnEvents) {
super(serverDetails, localFnEvents);
}
execute(data, accessToken) {
var _a, _b, _c, _d, _e;
return __awaiter(this, void 0, void 0, function* () {
const projectRoot = (0, project_1.getProjectRoot)();
const slaveFnTarget = {
index: (_b = (_a = this.fn.target) === null || _a === void 0 ? void 0 : _a.index) === null || _b === void 0 ? void 0 : _b.replace((0, path_1.join)(projectRoot, constants_1.FOLDERNAME.functions, this.fn.target.name) + path_1.sep, ''),
name: (_c = this.fn.target) === null || _c === void 0 ? void 0 : _c.name
};
switch (this.stack) {
case 'node': {
this.slave = (0, node_1.default)(this.fn, JSON.stringify(data), { slaveFnTarget, accessToken });
break;
}
case 'java': {
const javaInvoker = (0, path_1.join)(projectRoot, constants_1.FOLDERNAME.build, '.catalyst', this.fn.target.stack, 'Java' + this.fn.target.type + 'Invoker');
fn_utils_1.fnUtils.java.ensureJavaInvoker(javaInvoker, (0, path_1.normalize)((0, path_1.join)(__dirname, '../invoker', this.fn.target.type, 'java', 'Java' + this.fn.target.type + 'Invoker.java')), this.fn.target);
this.slave = (0, java_1.default)(this.fn, JSON.stringify(data), {
javaInvoker,
slaveFnTarget,
accessToken
});
break;
}
case 'python': {
const pyFn = this.fn;
this.slave = yield (0, python_1.default)(pyFn);
const attachVsCodeDebugger = (port) => __awaiter(this, void 0, void 0, function* () {
try {
yield (0, server_1.isPortListening)(port, 25, env_1.isWindows ? 1000 : 500).catch((er) => (0, logger_1.debug)('error listening for port: ' + port, er));
utils_1.serverEvent.emit('connection');
yield new Promise((res, rej) => {
const connTimeout = setTimeout(() => rej('debugger connection timeout'), 10000);
utils_1.serverEvent.once('attach', () => {
clearTimeout(connTimeout);
res();
});
});
}
catch (er) {
utils_1.serverEvent.emit('error', er);
this.kill();
return;
}
});
if (!(this.slave instanceof child_process_1.ChildProcess)) {
throw new error_1.default('Slave not an instance of Child process', {
context: this.slave,
exit: 2
});
}
const debugConfig = (_d = pyFn.target.additionalInfo) === null || _d === void 0 ? void 0 : _d.debug;
if (this.fn.target.type === 'job') {
if (debugConfig && env_1.isVsCode) {
yield attachVsCodeDebugger(debugConfig.port);
}
const httpPort = yield port_resolver_1.default.getFreePort(constants_1.DEFAULT.serve_port.http[(_e = this.fn.target) === null || _e === void 0 ? void 0 : _e.type], 200);
this.processFlowHandler(data, httpPort);
break;
}
new Promise((resolve, reject) => {
var _a;
(_a = this.slave) === null || _a === void 0 ? void 0 : _a.once('spawn', () => __awaiter(this, void 0, void 0, function* () {
try {
if (debugConfig) {
if (env_1.isVsCode) {
yield attachVsCodeDebugger(debugConfig.port);
}
else {
yield new Promise((res, rej) => {
try {
const rl = readline_1.default.createInterface({
input: process.stdin,
output: process.stdout,
terminal: true
});
rl.on('line', () => {
rl.close();
res();
});
(0, logger_1.info)();
(0, logger_1.info)(`${(0, ansi_colors_1.dim)('>> ')} Please attach a ${(0, ansi_colors_1.bold)('DEBUGGER')} and press ${(0, ansi_colors_1.bold)('ANY KEY')} to continue executing the ${(0, ansi_colors_1.bold)(pyFn.target.name)} function`);
(0, logger_1.info)();
}
catch (er) {
rej(er);
}
});
}
}
yield (0, http_functions_1.checkIfRuntimeServerRunning)(this.fn.httpPort.toString());
yield this.fnRequestHandler({
httpPort: this.fn.httpPort,
data,
accessToken
}).finally(() => this.kill());
resolve();
}
catch (er) {
const _er = error_1.default.getErrorInstance(er);
reject(_er);
}
}));
}).catch((err) => {
(0, logger_1.debug)('Error with fnRequestHandling flow: ', err);
this.localFnEvents.emit('error', err);
});
break;
}
default: {
throw new error_1.default('Invalid stack for fn execution handling: ' + this.stack, {
exit: 2
});
}
}
return this.slave;
});
}
executeWithContainer(data, accessToken) {
var _a, _b, _c, _d, _e;
return __awaiter(this, void 0, void 0, function* () {
(0, logger_1.debug)('using container to serve the function: ' + ((_a = this.fn.target) === null || _a === void 0 ? void 0 : _a.name));
const container = yield Promise.resolve().then(() => __importStar(require('@zcatalyst/container-plugin')));
const httpPort = yield port_resolver_1.default.getFreePort(constants_1.DEFAULT.serve_port.http[(_b = this.fn.target) === null || _b === void 0 ? void 0 : _b.type], 200);
this.fn.target.env_var = Object.assign({ X_ZOHO_CATALYST_ACCOUNTS_URL: constants_1.ORIGIN.auth, X_ZOHO_CATALYST_CONSOLE_URL: constants_1.ORIGIN.admin, X_ZOHO_CATALYST_RESOURCE_ID: (_c = this.fn.target) === null || _c === void 0 ? void 0 : _c.id, X_ZOHO_STRATUS_RESOURCE_SUFFIX: constants_1.ORIGIN.stratusSuffix, X_ZOHO_CATALYST_CODE_LOCATION: '/catalyst/', CATALYST_PROJECT_TIMEZONE: (0, project_1.getProjectTimezone)(Intl.DateTimeFormat().resolvedOptions().timeZone), X_ZOHO_CATALYST_ORG: (0, project_1.getEnvId)(), X_ZOHO_ADMIN_CRED_TOKEN: accessToken, CATALYST_FUNCTION_TYPE: constants_1.REMOTE_REF.functions.type[(_d = this.fn.target) === null || _d === void 0 ? void 0 : _d.type] }, (_e = this.fn.target) === null || _e === void 0 ? void 0 : _e.env_var);
if (this.fn.target.type === 'job') {
const hostIp = 'host.docker.internal';
const sysEnvs = {
X_ZOHO_DATA_URL: `http://${hostIp}:${httpPort}/data`,
X_ZOHO_CALLBACK_URL: `http://${hostIp}:${httpPort}/callback`,
X_ZOHO_ADMIN_CRED_TYPE: 'token',
X_ZOHO_ADMIN_CRED_TOKEN: accessToken,
X_ZOHO_USER_CRED_TYPE: 'token',
X_ZOHO_USER_CRED_TOKEN: accessToken,
X_ZOHO_USER_TYPE: 'admin',
X_ZOHO_PROJECT_KEY: (0, project_1.getDomainKey)(),
X_ZOHO_PROJECTID: (0, project_1.getProjectId)(),
X_ZOHO_PROJECT_DOMAIN: (0, project_1.getDomainPrefix)() + '.' + constants_1.ORIGIN.app.replace('https://', ''),
X_ZOHO_CATALYST_ENVIRONMENT: 'Development',
CATALYST_API_DOMAIN: constants_1.ORIGIN.admin
};
this.fn.target.env_var = Object.assign(Object.assign({}, this.fn.target.env_var), sysEnvs);
}
else {
this.fn.httpPort = httpPort;
}
const pluginEvent = yield container.start({
details: this.fn,
projectId: (0, project_1.getProjectId)(),
ruok: this.fn.target.type === 'job'
? container_plugin_1.RUOK.SKIP
: this.fn.debugPort !== undefined && this.fn.debugPort !== -1
? container_plugin_1.RUOK.INFINITE
: container_plugin_1.RUOK.FINITE
});
pluginEvent.on('error', (er) => {
var _a;
(0, logger_1.debug)('Container Error: ', er);
(0, logger_1.info)();
(0, logger_1.error)(`Error running the function ${(0, ansi_colors_1.bold)(((_a = this.fn.target) === null || _a === void 0 ? void 0 : _a.name) + '')} in container`);
(0, logger_1.info)();
});
pluginEvent.emit('start', this.fn);
pluginEvent.once('ready', () => __awaiter(this, void 0, void 0, function* () {
var _f, _g;
try {
if (((_f = this.fn.target) === null || _f === void 0 ? void 0 : _f.type) === 'job') {
yield this.processFlowHandler(data, httpPort).finally(() => this.kill());
return;
}
if (((_g = this.fn.target) === null || _g === void 0 ? void 0 : _g.type) === 'cron') {
const cronData = {
project_details: {},
cron_details: {},
data,
remaining_count: 0
};
data = cronData;
}
yield this.fnRequestHandler({
httpPort: this.fn.httpPort,
data,
accessToken
}).finally(() => this.kill());
}
catch (er) {
pluginEvent.emit('error', er instanceof error_1.default
? er
: error_1.default.getErrorInstance(er, {
message: 'Error when communicating with the container function ',
skipHelp: true
}));
}
}));
this.slave = pluginEvent;
return this.slave;
});
}
}
exports.FnExecutionHandler = FnExecutionHandler;