import chalkPipe from 'chalk-pipe'; import inquirer from 'inquirer'; import tcpPortUsed from 'tcp-port-used'; import URL from 'url'; import Util from "../util/Util"; import path from 'path'; import Lang, {STR} from "../util/Lang"; import('colors'); const dbDefaults = { mysql2: { host: 'localhost', port: '3306', username: 'root', password: '', database: '' }, pg: { host: 'localhost', port: '5432', username: 'postgres', password: '', database: '' }, mssql: { host: 'localhost', port: '1433', username: 'sa', password: '', database: '' }, sqlite3: { host: 'localhost', port: '1433', username: 'sa', password: '', database: '' }, }; class TryMgr { /** * * Does the below : * - Get database input and make a DB URL from it. * - Create new folder and 'cd' to that folder. * - Return true/success * - Else failure * * @param args * @returns {Promise} */ public static async getProjectInput(args): Promise { let dbUrl; if (args._[0] !== 't' && args._[0] !== 'try') { if ( args._[1] === 'rest') { dbUrl = `sqlite3://sqlite3?d=${path.join(__dirname, 'sakila.db')}`; } else if (args._[1] === 'gql') { dbUrl = `sqlite3://sqlite3?d=${path.join(__dirname, 'sakila.db')}&api=graphql`; } } else { /* Construct database URL from prompt */ const dbTypes = Object.keys(dbDefaults); args.url = [] const finalAnswers = await inquirer .prompt([ { name: 'type', type: 'list', message: Lang.getString(STR.DB_TYPE),// 'šŸ”„ Choose SQL Database type\t:', choices: dbTypes.map(t => ({ name: t, value: t, short: t.green.bold })), default: 'mysql2', transformer(color) { return chalkPipe(color)(color.green.bold); } }, { name: 'host', type: 'input', message: Lang.getString(STR.DB_HOST),// 'šŸ‘‰ Enter database host name\t:', default(ans) { return dbDefaults[ans.type].host }, transformer(color) { return chalkPipe(color)(color.green.bold); }, when({type}) { return type !== 'sqlite3' } }, { name: 'port', type: 'number', message: Lang.getString(STR.DB_PORT),// 'šŸ‘‰ Enter database port number\t:', default(ans) { return dbDefaults[ans.type].port }, transformer(color) { try { return color.green.bold; } catch (e) { return color } }, validate(port, answers) { const done = this.async(); if (answers.host === 'host.docker.internal' || answers.host === 'docker.for.win.localhost') { done(null, true) } else { TryMgr.isPortOpen(answers.host, port).then(isOpen => { if (isOpen) { done(null, true) } else { // done('Port is not open') console.log(`\n\nšŸ˜© ${answers.host}:${port} is not open please start the database if you haven't\n`.red.bold) process.exit(0); } }).catch(done) } }, when({type}) { return type !== 'sqlite3' } }, { name: 'username', type: 'input', message: Lang.getString(STR.DB_USER), // 'šŸ‘‰ Enter database username\t:', default(ans) { return dbDefaults[ans.type].username }, transformer(color) { return chalkPipe(color)(color.green.bold); }, when({type}) { return type !== 'sqlite3' } }, { name: 'password', type: 'input', mask: true, message: Lang.getString(STR.DB_PASSWORD), // 'šŸ™ˆ Enter database password\t:', transformer(color) { return new Array(color.length).fill('*'.green.bold).join('') }, when({type}) { return type !== 'sqlite3' } }, { name: 'database', type: 'input', message: Lang.getString(STR.DB_SCHEMA), // 'šŸ‘‰ Enter database/schema name\t:', transformer(color) { return chalkPipe(color)(color.green.bold); }, when({type}) { return type !== 'sqlite3' } }, { name: 'apiType', type: 'list', message: Lang.getString(STR.DB_API), // 'šŸš€ Enter API type to generate\t:', choices: ['REST APIs', 'GRAPHQL APIs', 'gRPC APIs'].map(t => ({ name: t, value: t, short: t.green.bold })), transformer(color) { return chalkPipe(color)(color.green.bold); }, when({type}) { return type !== 'sqlite3' } }, ]) // console.log(finalAnswers); if (finalAnswers.type === 'sqlite3') { console.log('Please use desktop app to create Sqlite project'.green.bold) process.exit(0); } /* if not valid retry getting right input */ /* if (!finalAnswers.database) { console.log('\n\tWarning! Database name can NOT be empty. Retry.\n '.red.bold); this.getNewProjectInput(args); }*/ // /* prepare the args */ // const url = `${finalAnswers.type}://${finalAnswers.host}:${finalAnswers.port}?u=${finalAnswers.username}&p=${finalAnswers.password}&d=${finalAnswers.database}&api=${apiTypeMapping[finalAnswers.projectType]}`; // args._[0] = finalAnswers.projectType === 'REST APIs' ? 'gar' : 'gag'; switch (finalAnswers.apiType) { case 'REST APIs': finalAnswers.apiType = 'rest'; break; case 'GRAPHQL APIs': finalAnswers.apiType = 'graphql'; break; case 'gRPC APIs': finalAnswers.apiType = 'grpc'; break; default: finalAnswers.apiType = 'rest'; break; } dbUrl = `${finalAnswers.type}://${finalAnswers.host}:${finalAnswers.port}?u=${finalAnswers.username}&p=${finalAnswers.password}&d=${finalAnswers.database}&api=${finalAnswers.apiType}` } // await Util.runCmd(`cd ${__dirname};echo "const {XcTry} = require('xc-instant'); process.env.NC_DB_URL='${finalAnswers.dbUrl}'; XcTry().then(() => console.log('App started'));" | node`); await Util.runCmd(`echo "const {XcTry} = require('xc-instant'); XcTry('${dbUrl}').then(() => console.log('App started'));" | NODE_PATH=${path.join(__dirname, '..', 'node_modules')} node`); } public static async testConnection({url}) { for (const u of url) { const parsedUrlData = URL.parse(u, true); const queryParams = parsedUrlData.query; const client = parsedUrlData.protocol.slice(0, -1); const config = { client, connection: { database: client === 'pg' ? 'postgres' : (client === 'mssql' ? undefined : null), host: parsedUrlData.hostname, password: queryParams.p, port: +parsedUrlData.port, user: queryParams.u, } }; try { const knex = require('knex')(config) await knex.raw("SELECT 1+1 as data"); } catch (e) { console.log(`\nšŸ˜© Test connection failed for : ${url}\n`.red.bold) return false; } } return true; } public static async isPortOpen(host, port) { try { return await tcpPortUsed.check(+port, host) } catch (e) { console.log(e) console.log(`\nšŸ˜© ${host}:${port} is not reachable please check\n`.red.bold) return true; } } } export default TryMgr; /** * @copyright Copyright (c) 2021, Xgene Cloud Ltd * * @author Naveen MR * @author Pranav C Balan * * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * */