import crypto = require("crypto"); import fs = require("fs-extra"); const babel = require("babel-core"); const presetEnv = require('babel-preset-env'); const chalk = require("chalk"); const os = require("os"); const path = require("path"); const { fork } = require('child_process'); const { spawn } = require('child_process'); import {HttpClient} from "./http-client"; import {Unzip} from "./unzip"; import {User} from "./service/user"; import {Facebook, Telegram, Viber} from './platform'; export class Runnable { private config:any; constructor(config){ this.config = config; } run(){ const homedir = os.homedir(); const homeFolder = path.join(homedir, `recime-cli-${this.config.version}`); // create the directory if (!fs.existsSync(homeFolder)){ fs.mkdirSync(homeFolder); } const botTemplatePath = require("url").parse(this.config.botTemplateUrl).path; const zipFileName = path.basename(botTemplatePath); const destFileName = path.join(homeFolder, zipFileName); HttpClient.download(this.config.botTemplateUrl, destFileName).then(()=>{ Unzip.extract(destFileName, homeFolder).then (()=>{ const filePath = path.join(process.cwd(), 'bot.json'); if (!fs.existsSync(filePath)) return this.printError("No configuration found."); fs.readJson(filePath).then(pkgObj =>{ const dirname = `recime-bot-template-${path.basename(zipFileName, ".zip")}`; const uid = pkgObj.id; const bin = path.join(homeFolder, dirname); this.install(bin) .then(() => new User(this.config).getUser()) .then((user) => { const filePath = path.join(process.cwd(), "config.json"); if (fs.existsSync(filePath)) { fs.readJson(filePath).then((env) => { env["BOT_UNIQUE_ID"] = uid; env["UID"] = uid; env["BOT_NAME"] = pkgObj.title; env["BOT_DESC"] = pkgObj.description; env["HOME_DIR"] = path.join(homeFolder, dirname); env["SYSTEM_RECIME_API_KEY"] = user.apiKey; this.startServer(path.join(homeFolder, dirname), env); }).catch(this.printError); } else { this.startServer(path.join(homeFolder, dirname), { "BOT_UNIQUE_ID": uid, "UID": uid, "BOT_NAME": pkgObj.title, "BOT_DESC": pkgObj.description, "HOME_DIR": path.join(homeFolder, dirname), "SYSTEM_RECIME_API_KEY": user.apiKey }); } }).catch(this.printError); }); }); }); } build(path){ return this.execCmd("npm", ["run", "build"], path); } install(path){ return this.execCmd("npm", ["install"], path) } execCmd(name, args, path){ return new Promise((resolve)=>{ const child = spawn(name, args, { shell : true, stdio: 'inherit', cwd : path }); child.on("exit", (code, signal)=>{ resolve(); }); }); } startServer(home, env, flag = false){ if (User.currentUser.name){ const names = User.currentUser.name .replace(/[\s]+/ig,"+") .split("+"); env["USER_FIRST_NAME"] = names[0]; env["USER_LAST_NAME"] = names[1]; } fs.writeJson(path.join(home, "nodemon.json"), { env: env, watch: [ env.UID ], ext: "js", ignore: [ ".git", "node_modules/**/node_modules", ".recime", "gulpfile.js", "nedb.json" ], }, { spaces: '\t' }) .then(() => { let cmd = "npm"; if (os.platform() == "win32") cmd = "npm.cmd"; const child = spawn(cmd, ["run", "serve"], { // shell: true, // stdio: 'inherit', cwd: home }); const messages = []; child.stdout.on("data", (data)=>{ const dat = data.toString(); console.log(dat); messages.push(dat); try { if (dat.match(/READY/ig)){ const callbackURL = messages.find(msg=>{ if (msg.match(/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/ig)){ return msg; } return void 0; }); if (callbackURL){ const facebook = new Facebook(env); facebook.setWebhook(callbackURL) .then(()=> facebook.subscribeToPage()) .then(()=> facebook.setWecomeScreen()) .then(() => facebook.setPersistentMenu()) .catch(this.printError); const telegram = new Telegram(env); // configure telegram telegram.setWebhook(callbackURL).catch(this.printError); const viber = new Viber(env); // configure viber viber.setWebhook(callbackURL).catch(this.printError); } } } catch (ex){ this.printError(ex.message); } }); child.on("error", (err)=>{ this.printError(err); }) this.subscribeToChangeEvent(path.join(home, env.UID), flag); child.on("exit", (code, signal) => { process.exit(code); }); }).catch(this.printError); } subscribeToChangeEvent(botdir, flag){ if (flag){ fs.watch(process.cwd(), { recursive : true }, (event, filename)=>{ switch(event){ case "change":{ const source = path.join(process.cwd(), filename); if (path.extname(filename) === '.js'){ fs.readFile(source).then ((code)=>{ const transformed = babel.transform(code, { "presets" : [presetEnv] }); fs.writeFile(path.join(botdir, filename), transformed.code) .then(()=> {}) .catch(this.printError); }); } } } }); } } printError(err){ console.log(chalk.red(err.message)); process.exit(1) } }