new(all): Vm isolated working with IPC BASIC 3.0;

This commit is contained in:
rodrigorodriguez 2022-11-02 19:40:59 -03:00
parent 45f4a48f88
commit 4bbd384501
5 changed files with 335 additions and 320 deletions

View file

@ -2,7 +2,7 @@
| ( )_ _ | | ( )_ _ |
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ | | _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ | | ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' v `\ /'_`\ |
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| (˅) |( (_) ) | | | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__,\| (˅) |( (_) ) |
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' | | | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
| | | ( )_) | | | | | ( )_) | |
| (_) \___/' | | (_) \___/' |
@ -10,22 +10,22 @@
| General Bots Copyright (c) Pragmatismo.io. All rights reserved. | | General Bots Copyright (c) Pragmatismo.io. All rights reserved. |
| Licensed under the AGPL-3.0. | | Licensed under the AGPL-3.0. |
| | | |
| According to our dual licensing model, this program can be used either | | According to our dual licensing model,this program can be used either |
| under the terms of the GNU Affero General Public License, version 3, | | under the terms of the GNU Affero General Public License,version 3, |
| or under a proprietary license. | | or under a proprietary license. |
| | | |
| The texts of the GNU Affero General Public License with an additional | | The texts of the GNU Affero General Public License with an additional |
| permission and of our proprietary license can be found at and | | permission and of our proprietary license can be found at and |
| in the LICENSE file you have received along with this program. | | in the LICENSE file you have received along with this program. |
| | | |
| This program is distributed in the hope that it will be useful, | | This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY, without even the implied warranty of | | but WITHOUT ANY WARRANTY,without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Affero General Public License for more details. | | GNU Affero General Public License for more details. |
| | | |
| "General Bots" is a registered trademark of Pragmatismo.io. | | "General Bots" is a registered trademark of Pragmatismo.io. |
| The licensing of the program under the AGPLv3 does not imply a | | The licensing of the program under the AGPLv3 does not imply a |
| trademark license. Therefore any rights, title and interest in | | trademark license. Therefore any rights,title and interest in |
| our trademarks remain entirely with us. | | our trademarks remain entirely with us. |
| | | |
\*****************************************************************************/ \*****************************************************************************/
@ -99,7 +99,7 @@ export class DialogKeywords {
lastDebugWeb: Date; lastDebugWeb: Date;
/** /**
* SYSTEM account maxLines, when used with impersonated contexts (eg. running in SET SCHEDULE). * SYSTEM account maxLines,when used with impersonated contexts (eg. running in SET SCHEDULE).
*/ */
maxLines: number = 2000; maxLines: number = 2000;
@ -112,7 +112,7 @@ export class DialogKeywords {
} }
/** /**
* When creating this keyword facade, a bot instance is * When creating this keyword facade,a bot instance is
* specified among the deployer service. * specified among the deployer service.
*/ */
constructor(min: GBMinInstance, deployer: GBDeployer, user) { constructor(min: GBMinInstance, deployer: GBDeployer, user) {
@ -129,7 +129,7 @@ export class DialogKeywords {
} }
/** /**
* Base reference of system keyword facade, called directly * Base reference of system keyword facade,called directly
* by the script. * by the script.
*/ */
public sys(): SystemKeywords { public sys(): SystemKeywords {
@ -141,7 +141,7 @@ export class DialogKeywords {
* *
* @example x = GET PAGE * @example x = GET PAGE
*/ */
public async getPage(url, username, password) { public async getPage({url, username, password}) {
GBLog.info(`BASIC: Web Automation GET PAGE ${url}.`); GBLog.info(`BASIC: Web Automation GET PAGE ${url}.`);
if (!this.browser) { if (!this.browser) {
this.browser = await createBrowser(null); this.browser = await createBrowser(null);
@ -157,9 +157,9 @@ export class DialogKeywords {
/** /**
* *
* *
* Data = [10, 20, 30] * Data = [10,20,30]
* Legends = "Steve;Yui;Carlos" * Legends = "Steve;Yui;Carlos"
* img = CHART "pie", data, legends * img = CHART "pie",data,legends
* *
* https://c3js.org/examples.html * https://c3js.org/examples.html
* *
@ -167,7 +167,7 @@ export class DialogKeywords {
* @param legends * @param legends
* @see https://www.npmjs.com/package/plot * @see https://www.npmjs.com/package/plot
*/ */
public async chart(type, data, legends, transpose) { public async chart({type, data, legends, transpose}) {
let table = [[]]; let table = [[]];
@ -177,8 +177,8 @@ export class DialogKeywords {
// Columns and data are merged like: // Columns and data are merged like:
// columns: [ // columns: [
// ['data1', 30, 200, 100, 400, 150, 250], // ['data1',30,200,100,400,150,250],
// ['data2', 50, 20, 10, 40, 15, 25] // ['data2',50,20,10,40,15,25]
// ] // ]
for (let i = 0; i < legends_.length; i++) { for (let i = 0; i < legends_.length; i++) {
@ -246,18 +246,18 @@ export class DialogKeywords {
/** /**
* Find element on page DOM. * Find element on page DOM.
* *
* @example GET page, "elementName" * @example GET page,"selector"
*/ */
public async getBySelector(page, elementName) { public async getBySelector({page, selector}) {
GBLog.info(`BASIC: Web Automation GET element: ${elementName}.`); GBLog.info(`BASIC: Web Automation GET element: ${selector}.`);
await page.waitForSelector(elementName) await page.waitForSelector(selector)
let elements = await page.$$(elementName); let elements = await page.$$(selector);
if (elements && elements.length > 1) { if (elements && elements.length > 1) {
return elements; return elements;
} }
else { else {
const el = elements[0]; const el = elements[0];
el['originalSelector'] = elementName; el['originalSelector'] = selector;
el['href'] = await page.evaluate(e => e.getAttribute('href'), el); el['href'] = await page.evaluate(e => e.getAttribute('href'), el);
el['value'] = await page.evaluate(e => e.getAttribute('value'), el); el['value'] = await page.evaluate(e => e.getAttribute('value'), el);
el['name'] = await page.evaluate(e => e.getAttribute('name'), el); el['name'] = await page.evaluate(e => e.getAttribute('name'), el);
@ -269,9 +269,9 @@ export class DialogKeywords {
/** /**
* Find element on page DOM. * Find element on page DOM.
* *
* @example GET page, "frameSelector, "elementSelector" * @example GET page,"frameSelector,"elementSelector"
*/ */
public async getByFrame(page, frame, selector) { public async getByFrame({page, frame, selector}) {
GBLog.info(`BASIC: Web Automation GET element by frame: ${selector}.`); GBLog.info(`BASIC: Web Automation GET element by frame: ${selector}.`);
await page.waitForSelector(frame) await page.waitForSelector(frame)
let frameHandle = await page.$(frame); let frameHandle = await page.$(frame);
@ -290,19 +290,19 @@ export class DialogKeywords {
/** /**
* Simulates a mouse hover an web page element. * Simulates a mouse hover an web page element.
*/ */
public async hover(page, idOrName) { public async hover({page, selector}) {
GBLog.info(`BASIC: Web Automation HOVER element: ${idOrName}.`); GBLog.info(`BASIC: Web Automation HOVER element: ${selector}.`);
await this.getBySelector(page, idOrName); await this.getBySelector({page, selector: selector});
await page.hover(idOrName); await page.hover(selector);
await this.debugStepWeb(page); await this.debugStepWeb(page);
} }
/** /**
* Clicks on an element in a web page. * Clicks on an element in a web page.
* *
* @example CLICK page, "#idElement" * @example CLICK page,"#idElement"
*/ */
public async click(page, frameOrSelector, selector) { public async click({page, frameOrSelector, selector}) {
GBLog.info(`BASIC: Web Automation CLICK element: ${frameOrSelector}.`); GBLog.info(`BASIC: Web Automation CLICK element: ${frameOrSelector}.`);
if (selector) { if (selector) {
await page.waitForSelector(frameOrSelector) await page.waitForSelector(frameOrSelector)
@ -326,20 +326,21 @@ export class DialogKeywords {
} }
if (this.debugWeb && refresh) { if (this.debugWeb && refresh) {
const adminNumber = this.min.core.getParam(this.min.instance, 'Bot Admin Number', null); const mobile = this.min.core.getParam(this.min.instance, 'Bot Admin Number', null);
if (adminNumber) { const filename = page;
await this.sendFileTo(adminNumber, page, "General Bots Debugger"); if (mobile) {
await this.sendFileTo({mobile , filename, caption:"General Bots Debugger"});
} }
this.lastDebugWeb = new Date(); this.lastDebugWeb = new Date();
} }
} }
/** /**
* Press ENTER in a web page, useful for logins. * Press ENTER in a web page,useful for logins.
* *
* @example PRESS ENTER ON page * @example PRESS ENTER ON page
*/ */
public async pressKey(page, char, frame) { public async pressKey({page, char, frame}) {
GBLog.info(`BASIC: Web Automation PRESS ${char} ON element: ${frame}.`); GBLog.info(`BASIC: Web Automation PRESS ${char} ON element: ${frame}.`);
if (char.toLowerCase() === "enter") { if (char.toLowerCase() === "enter") {
char = '\n'; char = '\n';
@ -355,12 +356,12 @@ export class DialogKeywords {
} }
} }
public async linkByText(page, text, index) { public async linkByText({page, text, index}) {
GBLog.info(`BASIC: Web Automation CLICK LINK TEXT: ${text} ${index}.`); GBLog.info(`BASIC: Web Automation CLICK LINK TEXT: ${text} ${index}.`);
if (!index) { if (!index) {
index = 1 index = 1
} }
const els = await page.$x(`//a[contains(., '${text}')]`); const els = await page.$x(`//a[contains(.,'${text}')]`);
await els[index - 1].click(); await els[index - 1].click();
await this.debugStepWeb(page); await this.debugStepWeb(page);
} }
@ -372,8 +373,8 @@ export class DialogKeywords {
* *
* @example file = SCREENSHOT page * @example file = SCREENSHOT page
*/ */
public async screenshot(page, idOrName) { public async screenshot({page, selector}) {
GBLog.info(`BASIC: Web Automation SCREENSHOT ${idOrName}.`); GBLog.info(`BASIC: Web Automation SCREENSHOT ${selector}.`);
const gbaiName = `${this.min.botId}.gbai`; const gbaiName = `${this.min.botId}.gbai`;
const localName = Path.join('work', gbaiName, 'cache', `screen-${GBAdminService.getRndReadableIdentifier()}.jpg`); const localName = Path.join('work', gbaiName, 'cache', `screen-${GBAdminService.getRndReadableIdentifier()}.jpg`);
@ -395,11 +396,11 @@ export class DialogKeywords {
/** /**
* Types the text into the text field. * Types the text into the text field.
* *
* @example SET page, "elementName", "text" * @example SET page,"selector","text"
*/ */
public async setElementText(page, idOrName, text) { public async setElementText({page, selector, text}) {
GBLog.info(`BASIC: Web Automation TYPE on ${idOrName}: ${text}.`); GBLog.info(`BASIC: Web Automation TYPE on ${selector}: ${text}.`);
const e = await this.getBySelector(page, idOrName); const e = await this.getBySelector({page, selector});
await e.click({ clickCount: 3 }); await e.click({ clickCount: 3 });
await page.keyboard.press('Backspace'); await page.keyboard.press('Backspace');
await e.type(text, { delay: 200 }); await e.type(text, { delay: 200 });
@ -410,7 +411,7 @@ export class DialogKeywords {
* Returns the OCR of image file. * Returns the OCR of image file.
* *
*/ */
public async getOCR(localFile) { public async getOCR({localFile}) {
GBLog.info(`BASIC: OCR processing on ${localFile}.`); GBLog.info(`BASIC: OCR processing on ${localFile}.`);
const tesseract = require("node-tesseract-ocr") const tesseract = require("node-tesseract-ocr")
@ -428,7 +429,7 @@ export class DialogKeywords {
* *
* @example x = TODAY * @example x = TODAY
*/ */
public async getToday() { public async getToday({}) {
let d = new Date(), let d = new Date(),
month = '' + (d.getMonth() + 1), month = '' + (d.getMonth() + 1),
day = '' + d.getDate(), day = '' + d.getDate(),
@ -456,11 +457,11 @@ export class DialogKeywords {
} }
/** /**
* Quits the dialog, currently required to get out of VM context. * Quits the dialog,currently required to get out of VM context.
* *
* @example EXIT * @example EXIT
*/ */
public async exit() { public async exit({}) {
} }
@ -469,7 +470,7 @@ export class DialogKeywords {
* *
* @example list = ACTIVE TASKS * @example list = ACTIVE TASKS
*/ */
public async getActiveTasks() { public async getActiveTasks({}) {
let s = new HubSpotServices(null, null, process.env.HUBSPOT_KEY); let s = new HubSpotServices(null, null, process.env.HUBSPOT_KEY);
return await s.getActiveTasks(); return await s.getActiveTasks();
} }
@ -477,9 +478,9 @@ export class DialogKeywords {
/** /**
* Creates a new deal. * Creates a new deal.
* *
* @example CREATE DEAL dealname, contato, empresa, amount * @example CREATE DEAL dealname,contato,empresa,amount
*/ */
public async createDeal(dealName, contact, company, amount) { public async createDeal({dealName, contact, company, amount}) {
let s = new HubSpotServices(null, null, process.env.HUBSPOT_KEY); let s = new HubSpotServices(null, null, process.env.HUBSPOT_KEY);
let deal = await s.createDeal(dealName, contact, company, amount); let deal = await s.createDeal(dealName, contact, company, amount);
return deal; return deal;
@ -490,7 +491,7 @@ export class DialogKeywords {
* *
* @example list = FIND CONTACT "Sandra" * @example list = FIND CONTACT "Sandra"
*/ */
public async fndContact(name) { public async fndContact({name}) {
let s = new HubSpotServices(null, null, process.env.HUBSPOT_KEY); let s = new HubSpotServices(null, null, process.env.HUBSPOT_KEY);
return await s.searchContact(name); return await s.searchContact(name);
} }
@ -510,7 +511,7 @@ export class DialogKeywords {
} }
public async getCoded(value) { public async getCoded({value}) {
// Checks if it is a GB FILE object. // Checks if it is a GB FILE object.
@ -552,9 +553,9 @@ export class DialogKeywords {
/** /**
* Returns an object ready to get information about difference in several ways * Returns an object ready to get information about difference in several ways
* like years, months or days. * like years,months or days.
* *
* @example days = DATEDIFF date1, date2, mode * @example days = DATEDIFF date1,date2,mode
* *
*/ */
public dateDiff(date1, date2, mode) { public dateDiff(date1, date2, mode) {
@ -580,7 +581,7 @@ export class DialogKeywords {
/** /**
* Returns specified date week day in format 'Mon'. * Returns specified date week day in format 'Mon'.
* *
* @example DATEADD date, "minute", 60 * @example DATEADD date,"minute",60
* *
* https://stackoverflow.com/a/1214753/18511 * https://stackoverflow.com/a/1214753/18511
*/ */
@ -610,7 +611,7 @@ export class DialogKeywords {
/** /**
* Returns specified list member separated by comma. * Returns specified list member separated by comma.
* *
* @example TALK TOLIST (array, member) * @example TALK TOLIST (array,member)
* *
*/ */
public getToLst(array, member) { public getToLst(array, member) {
@ -623,7 +624,7 @@ export class DialogKeywords {
array = array.filter((v, i, a) => a.findIndex(t => (t[member] === v[member])) === i); array = array.filter((v, i, a) => a.findIndex(t => (t[member] === v[member])) === i);
array = array.filter(function (item, pos) { return item != undefined; }); array = array.filter(function (item, pos) { return item != undefined; });
array = array.map((item) => { return item[member]; }) array = array.map((item) => { return item[member]; })
array = array.join(", "); array = array.join(",");
return array; return array;
} }
@ -662,10 +663,10 @@ export class DialogKeywords {
/** /**
* Returns current time in format hh:dd. * Returns current time in format hh:dd.
* *
* @example SAVE "file.xlsx", name, email, NOW * @example SAVE "file.xlsx",name,email,NOW
* *
*/ */
public async getNow() { public async getNow({}) {
const contentLocale = this.min.core.getParam<string>( const contentLocale = this.min.core.getParam<string>(
this.min.instance, this.min.instance,
'Default Content Language', 'Default Content Language',
@ -689,14 +690,14 @@ export class DialogKeywords {
* *
* @example * @example
* *
* SEND MAIL "email@domain.com", "Subject", "Message text." * SEND MAIL "email@domain.com","Subject", "Message text."
* *
*/ */
public async sendEmail(to, subject, body) { public async sendEmail({to, subject, body}) {
// tslint:disable-next-line:no-console // tslint:disable-next-line:no-console
GBLog.info(`[E-mail]: to:${to}, subject: ${subject}, body: ${body}.`); GBLog.info(`[E-mail]: to:${to},subject: ${subject},body: ${body}.`);
const emailToken = process.env.EMAIL_API_KEY; const emailToken = process.env.EMAIL_API_KEY;
// Inline word document used as e-mail body. // Inline word document used as e-mail body.
@ -729,12 +730,12 @@ export class DialogKeywords {
/** /**
* Sends a file to a given mobile. * Sends a file to a given mobile.
* *
* @example SEND FILE TO "+199988887777", "image.jpg", caption * @example SEND FILE TO "+199988887777","image.jpg",caption
* *
*/ */
public async sendFileTo(mobile, filename, caption) { public async sendFileTo({mobile, filename, caption}) {
GBLog.info(`BASIC: SEND FILE TO '${mobile}', filename '${filename}'.`); GBLog.info(`BASIC: SEND FILE TO '${mobile}',filename '${filename}'.`);
return await this.internalSendFile(mobile, filename, caption); return await this.internalSendFile({mobile, filename, caption});
} }
/** /**
@ -743,10 +744,10 @@ export class DialogKeywords {
* @example SEND FILE "image.jpg" * @example SEND FILE "image.jpg"
* *
*/ */
public async sendFile(filename, caption) { public async sendFile({filename, caption}) {
const mobile = await this.userMobile(); const mobile = await this.userMobile();
GBLog.info(`BASIC: SEND FILE (current: ${mobile}, filename '${filename}'.`); GBLog.info(`BASIC: SEND FILE (current: ${mobile},filename '${filename}'.`);
return await this.internalSendFile(mobile, filename, caption); return await this.internalSendFile({mobile, filename, caption});
} }
/** /**
@ -755,7 +756,7 @@ export class DialogKeywords {
* @example SET LANGUAGE "pt" * @example SET LANGUAGE "pt"
* *
*/ */
public async setLanguage(language) { public async setLanguage({language}) {
const sec = new SecService(); const sec = new SecService();
await sec.updateUserLocale(this.user.userId, language); await sec.updateUserLocale(this.user.userId, language);
} }
@ -766,7 +767,7 @@ export class DialogKeywords {
* @example SET ID NUMBER * @example SET ID NUMBER
* *
*/ */
public async setIdGeneration(mode) { public async setIdGeneration({mode}) {
this['idGeneration'] = mode; this['idGeneration'] = mode;
this['id'] = await this.sys().getRandomId(); this['id'] = await this.sys().getRandomId();
} }
@ -777,7 +778,7 @@ export class DialogKeywords {
* @example SET MAX LINES 5000 * @example SET MAX LINES 5000
* *
*/ */
public async setMaxLines(count) { public async setMaxLines({count}) {
if (this.user) { if (this.user) {
// TODO: PARAM user.basicOptions.maxLines = count; // TODO: PARAM user.basicOptions.maxLines = count;
} }
@ -793,7 +794,7 @@ export class DialogKeywords {
* @example SET MAX COLUMNS 5000 * @example SET MAX COLUMNS 5000
* *
*/ */
public async setMaxColumns(count) { public async setMaxColumns({count}) {
// TODO: user.basicOptions.maxColumns = count; // TODO: user.basicOptions.maxColumns = count;
} }
@ -805,7 +806,7 @@ export class DialogKeywords {
* @example SET WHOLE WORD ON * @example SET WHOLE WORD ON
* *
*/ */
public async setWholeWord(on) { public async setWholeWord({on}) {
// TODO: user.basicOptions.wholeWord = (on.trim() === "on"); // TODO: user.basicOptions.wholeWord = (on.trim() === "on");
} }
@ -815,7 +816,7 @@ export class DialogKeywords {
* @example SET THEME "themename" * @example SET THEME "themename"
* *
*/ */
public async setTheme(theme) { public async setTheme({theme}) {
// TODO: user.basicOptions.theme = theme.trim(); // TODO: user.basicOptions.theme = theme.trim();
} }
@ -825,7 +826,7 @@ export class DialogKeywords {
* @example SET TRANSLATOR ON | OFF * @example SET TRANSLATOR ON | OFF
* *
*/ */
public async setTranslatorOn(on) { public async setTranslatorOn({on}) {
// TODO: user.basicOptions.translatorOn = (on.trim() === "on"); // TODO: user.basicOptions.translatorOn = (on.trim() === "on");
} }
@ -853,14 +854,14 @@ export class DialogKeywords {
* @example MENU * @example MENU
* *
*/ */
public async showMenu() { public async showMenu({}) {
// TODO: return await beginDialog('/menu'); // TODO: return await beginDialog('/menu');
} }
private static async downloadAttachmentAndWrite(attachment) { private static async downloadAttachmentAndWrite(attachment) {
const url = attachment.contentUrl; const url = attachment.contentUrl;
const localFolder = Path.join('work'); // TODO: , '${botId}', 'uploads'); const localFolder = Path.join('work'); // TODO: ,'${botId}','uploads');
const localFileName = Path.join(localFolder, attachment.name); const localFileName = Path.join(localFolder, attachment.name);
try { try {
@ -892,7 +893,7 @@ export class DialogKeywords {
console.error(error); console.error(error);
return undefined; return undefined;
} }
// If no error was thrown while writing to disk, return the attachment's name // If no error was thrown while writing to disk,return the attachment's name
// and localFilePath for the response back to the user. // and localFilePath for the response back to the user.
return { return {
fileName: attachment.name, fileName: attachment.name,
@ -906,8 +907,8 @@ export class DialogKeywords {
* @example TRANSFER * @example TRANSFER
* *
*/ */
public async transferTo(to: string = null) { public async transferTo({to}) {
// TODO: return await beginDialog('/t', { to: to }); // TODO: return await beginDialog('/t',{ to: to });
} }
/** /**
@ -916,7 +917,15 @@ export class DialogKeywords {
* @example HEAR name * @example HEAR name
* *
*/ */
public async hear(kind, ...args) { public async getHear({kind, arg}) {
// Handles first arg as an array of args.
let args = [];
if (arg && arg.length) {
args = arg;
}
try { try {
@ -942,15 +951,16 @@ export class DialogKeywords {
let choices = []; let choices = [];
let i = 0; let i = 0;
args.forEach(arg => { await CollectionUtil.asyncForEach(args, async arg => {
i++; i++;
choices.push({ body: arg, id: `button${i}` }); // DISABLED: choices.push({ body: arg, id: `button${i}` });
await this.talk(arg);
}); });
const button = new Buttons(Messages[locale].choices, choices, ' ', ' '); // DISABLED const button = new Buttons(Messages[locale].choices, choices, ' ', ' ');
// await this.talk(button);
await this.talk(button); GBLog.info(`BASIC: HEAR with [${args.toString()}] (Asking for input).`);
GBLog.info(`BASIC: HEAR with ${args.toString()} (Asking for input).`);
} }
else { else {
@ -974,7 +984,7 @@ export class DialogKeywords {
const text = this.min.cbMap[userId].promise; const text = this.min.cbMap[userId].promise;
if (kind === "file") { if (kind === "file") {
// await prompt('attachmentPrompt', {}); // await prompt('attachmentPrompt',{});
// // Prepare Promises to download each attachment and then execute each Promise. // // Prepare Promises to download each attachment and then execute each Promise.
// const promises = step.context.activity.attachments.map( // const promises = step.context.activity.attachments.map(
@ -983,11 +993,11 @@ export class DialogKeywords {
// async function replyForReceivedAttachments(localAttachmentData) { // async function replyForReceivedAttachments(localAttachmentData) {
// if (localAttachmentData) { // if (localAttachmentData) {
// // Because the TurnContext was bound to this function, the bot can call // // Because the TurnContext was bound to this function,the bot can call
// // `TurnContext.sendActivity` via `this.sendActivity`; // // `TurnContext.sendActivity` via `this.sendActivity`;
// await this.sendActivity(`Upload OK.`); // await this.sendActivity(`Upload OK.`);
// } else { // } else {
// await this.sendActivity('Error uploading file. Please, start again.'); // await this.sendActivity('Error uploading file. Please,start again.');
// } // }
// } // }
@ -1019,8 +1029,8 @@ export class DialogKeywords {
const value = extractEntity(text); const value = extractEntity(text);
if (value === null) { if (value === null) {
await this.talk("Por favor, digite um e-mail válido."); await this.talk({text: "Por favor,digite um e-mail válido."});
return await this.hear(kind, args); return await this.getHear({kind, arg});
} }
result = value; result = value;
@ -1034,8 +1044,8 @@ export class DialogKeywords {
const value = extractEntity(text); const value = extractEntity(text);
if (value === null || value.length != 1) { if (value === null || value.length != 1) {
await this.talk("Por favor, digite um nome válido."); await this.talk({text:"Por favor,digite um nome válido."});
return await this.hear(kind, args); return await this.getHear({kind, arg});
} }
result = value; result = value;
@ -1049,8 +1059,8 @@ export class DialogKeywords {
const value = extractEntity(text); const value = extractEntity(text);
if (value === null || value.length != 1) { if (value === null || value.length != 1) {
await this.talk("Por favor, digite um número válido."); await this.talk({text:"Por favor,digite um número válido."});
return await this.hear(kind, args); return await this.getHear({kind, arg});
} }
result = value; result = value;
@ -1063,8 +1073,8 @@ export class DialogKeywords {
const value = extractEntity(text); const value = extractEntity(text);
if (value === null || value.length != 1) { if (value === null || value.length != 1) {
await this.talk("Por favor, digite uma data no formato 12/12/2020."); await this.talk({text:"Por favor,digite uma data no formato 12/12/2020."});
return await this.hear(kind, args); return await this.getHear({kind, arg});
} }
result = value; result = value;
@ -1078,8 +1088,8 @@ export class DialogKeywords {
const value = extractEntity(text); const value = extractEntity(text);
if (value === null || value.length != 1) { if (value === null || value.length != 1) {
await this.talk("Por favor, digite um horário no formato hh:ss."); await this.talk({text:"Por favor,digite um horário no formato hh:ss."});
return await this.hear(kind, args); return await this.getHear({kind, arg});
} }
result = value; result = value;
@ -1099,8 +1109,8 @@ export class DialogKeywords {
const value = extractEntity(text); const value = extractEntity(text);
if (value === null || value.length != 1) { if (value === null || value.length != 1) {
await this.talk("Por favor, digite um valor monetário."); await this.talk({text:"Por favor,digite um valor monetário."});
return await this.hear(kind, args); return await this.getHear({kind, arg});
} }
result = value; result = value;
@ -1114,11 +1124,11 @@ export class DialogKeywords {
} catch (error) { } catch (error) {
await this.talk(Messages[locale].validation_enter_valid_mobile); await this.talk(Messages[locale].validation_enter_valid_mobile);
return await this.hear(kind, args); return await this.getHear({kind, arg});
} }
if (!phoneUtil.isPossibleNumber(phoneNumber)) { if (!phoneUtil.isPossibleNumber(phoneNumber)) {
await this.talk("Por favor, digite um número de telefone válido."); await this.talk({text:"Por favor,digite um número de telefone válido."});
return await this.hear(kind, args); return await this.getHear({kind, arg});
} }
result = phoneNumber; result = phoneNumber;
@ -1141,8 +1151,8 @@ export class DialogKeywords {
const value = extractEntity(text); const value = extractEntity(text);
if (value === null || value.length != 1) { if (value === null || value.length != 1) {
await this.talk("Por favor, digite um valor monetário."); await this.talk({text:"Por favor, digite um CEP válido."});
return await this.hear(kind, args); return await this.getHear({kind, arg});
} }
result = value[0]; result = value[0];
@ -1159,8 +1169,8 @@ export class DialogKeywords {
}); });
if (result === null) { if (result === null) {
await this.talk(`Escolha por favor um dos itens sugeridos.`); await this.talk({text:`Escolha por favor um dos itens sugeridos.`});
return await this.hear(kind, args); return await this.getHear({kind, arg});
} }
} }
else if (kind === "language") { else if (kind === "language") {
@ -1184,8 +1194,6 @@ export class DialogKeywords {
]; ];
// TODO: const text = step.context.activity['originalText'];
await CollectionUtil.asyncForEach(list, async item => { await CollectionUtil.asyncForEach(list, async item => {
if (GBConversationalService.kmpSearch(text.toLowerCase(), item.name.toLowerCase()) != -1 || if (GBConversationalService.kmpSearch(text.toLowerCase(), item.name.toLowerCase()) != -1 ||
GBConversationalService.kmpSearch(text.toLowerCase(), item.code.toLowerCase()) != -1) { GBConversationalService.kmpSearch(text.toLowerCase(), item.code.toLowerCase()) != -1) {
@ -1194,9 +1202,8 @@ export class DialogKeywords {
}); });
if (result === null) { if (result === null) {
// TODO: await this.talk({text:`Escolha por favor um dos itens sugeridos.`});
await this.min.conversationalService.sendText(this.min, null, `Escolha por favor um dos idiomas sugeridos.`); return await this.getHear({kind, arg});
return await this.hear(kind, args);
} }
} }
return result; return result;
@ -1208,7 +1215,7 @@ export class DialogKeywords {
/** /**
* Prepares the next dialog to be shown to the specified user. * Prepares the next dialog to be shown to the specified user.
*/ */
public async gotoDialog(fromOrDialogName: string, dialogName: string) { public async gotoDialog({fromOrDialogName, dialogName}) {
if (dialogName) { if (dialogName) {
if (dialogName.charAt(0) === '/') { if (dialogName.charAt(0) === '/') {
// TODO: await step.beginDialog(fromOrDialogName); // TODO: await step.beginDialog(fromOrDialogName);
@ -1227,7 +1234,7 @@ export class DialogKeywords {
} }
} }
public async getSingleton() { public async getSingleton({}) {
return { return {
id: this.sys().getRandomId(), id: this.sys().getRandomId(),
username: this.userName(), username: this.userName(),
@ -1245,7 +1252,7 @@ export class DialogKeywords {
/** /**
* Talks to the user by using the specified text. * Talks to the user by using the specified text.
*/ */
public async talk(text: string) { public async talk({text}) {
GBLog.info(`BASIC: TALK '${text}'.`); GBLog.info(`BASIC: TALK '${text}'.`);
if (this.user) { if (this.user) {
const translate = this.user ? this.user.basicOptions.translatorOn : false; const translate = this.user ? this.user.basicOptions.translatorOn : false;
@ -1264,9 +1271,9 @@ export class DialogKeywords {
/** /**
* Processes the sending of the file. * Processes the sending of the file.
*/ */
private async internalSendFile(mobile, filename, caption) { private async internalSendFile({mobile, filename, caption}) {
// Handles SEND FILE TO mobile, element in Web Automation. // Handles SEND FILE TO mobile,element in Web Automation.
const element = filename._page ? filename._page : (filename.screenshot ? filename : null); const element = filename._page ? filename._page : (filename.screenshot ? filename : null);
@ -1319,7 +1326,7 @@ export class DialogKeywords {
} }
} }
public async getQRCode(text) { public async getQRCode({text}) {
const img = await qrcode.toDataURL(text); const img = await qrcode.toDataURL(text);
const data = img.replace(/^data:image\/\w+;base64,/, ""); const data = img.replace(/^data:image\/\w+;base64,/, "");
const buf = Buffer.from(data, "base64"); const buf = Buffer.from(data, "base64");

View file

@ -161,6 +161,124 @@ export class GBVMService extends GBService {
}); });
} }
public async translateBASIC(filename: any, min: GBMinInstance, deployer: GBDeployer, mainName: string) {
// Converts General Bots BASIC into regular VBS
let basicCode: string = fs.readFileSync(filename, 'utf8');
// Processes END keyword, removing extracode, useful
// for development.
let end = /(\nend\n)/gi.exec(basicCode);
if (end) {
basicCode = basicCode.substring(0, end.index);
}
// Removes comments.
basicCode = basicCode.replace(/((^|\W)REM.*\n)/gi, '');
// Process INCLUDE keyword to include another
// dialog inside the dialog.
let include = null;
do {
include = /^include\b(.*)$/gmi.exec(basicCode);
if (include) {
let includeName = include[1].trim();
includeName = Path.join(Path.dirname(filename), includeName);
includeName = includeName.substr(0, includeName.lastIndexOf(".")) + ".vbs";
// To use include, two /publish will be necessary (for now)
// because of alphabet order may raise not found errors.
let includeCode: string = fs.readFileSync(includeName, 'utf8');
basicCode = basicCode.replace(/^include\b.*$/gmi, includeCode);
}
} while (include);
const vbsCode = this.convertGBASICToVBS(min, basicCode);
const vbsFile = `${filename}.compiled`;
fs.writeFileSync(vbsFile, vbsCode);
// Converts VBS into TS.
vb2ts.convertFile(vbsFile);
// Convert TS into JS.
const tsfile: string = `${filename}.ts`;
let tsCode: string = fs.readFileSync(tsfile, 'utf8');
fs.writeFileSync(tsfile, tsCode);
const tsc = new TSCompiler();
tsc.compile([tsfile]);
// Run JS into the GB context.
const jsfile = `${tsfile}.js`.replace('.ts', '');
if (fs.existsSync(jsfile)) {
let code: string = fs.readFileSync(jsfile, 'utf8');
code = code.replace(/^.*exports.*$/gm, '');
code = `
return (async () => {
require('isomorphic-fetch');
const rest = require ('typescript-rest-rpc/lib/client');
// Interprocess communication from local HTTP to the BotServer.
const dk = rest.createClient('http://localhost:1111/api/v2/${min.botId}/dialog');
const sys = rest.createClient('http://localhost:1111/api/v2/${min.botId}/system');
// Local variables.
const gb = await dk.getSingleton();
const id = gb.id;
const username = gb.username;
const mobile = gb.mobile;
const from = gb.from;
const ENTER = gb.ENTER;
const headers = gb.headers;
const data = gb.data;
const list = gb.list;
const httpUsername = gb.httpUsername;
const httpPs = gb.httpPs;
// Local functions.
const ubound = (array) => {return array.length};
const isarray = (array) => {return Array.isArray(array) };
// Remote functions.
const weekday = (v) => { return (async () => { return await client.getWeekFromDate(v) })(); };
const hour = (v) => { return (async () => { return await client.getHourFromDate(v) })(); };
const base64 = (v) => { return (async () => { return await client.getCoded(v) })(); };
const tolist = (v) => { return (async () => { return await client.getToLst(v) })(); };
const now = (v) => { return (async () => { return await client.getNow(v) })(); };
const today = (v) => { return (async () => { return await client.getToday(v) })(); };
${code}
})();
`;
// Finds all hear calls.
const parsedCode = beautify(code, { indent_size: 2, space_in_empty_paren: true });
fs.writeFileSync(jsfile, parsedCode);
min.sandBoxMap[mainName.toLowerCase().trim()] = parsedCode;
GBLog.info(`[GBVMService] Finished loading of ${filename}, JavaScript from Word: \n ${parsedCode}`);
}
}
public static getMethodNameFromVBSFilename(filename: string) { public static getMethodNameFromVBSFilename(filename: string) {
let mainName = filename.replace(/\s|\-/gi, '').split('.')[0]; let mainName = filename.replace(/\s|\-/gi, '').split('.')[0];
return mainName.toLowerCase(); return mainName.toLowerCase();
@ -220,7 +338,7 @@ export class GBVMService extends GBService {
}); });
code = code.replace(/(\w+)\s*\=\s*get html\s*(.*)/gi, ($0, $1, $2, $3) => { code = code.replace(/(\w+)\s*\=\s*get html\s*(.*)/gi, ($0, $1, $2, $3) => {
return `${$1} = await dk.getPage(step, ${$2})\n`; return `${$1} = await dk.getPage(${$2})\n`;
}); });
code = code.replace(/(set hear on)(\s*)(.*)/gi, ($0, $1, $2, $3) => { code = code.replace(/(set hear on)(\s*)(.*)/gi, ($0, $1, $2, $3) => {
@ -228,59 +346,59 @@ export class GBVMService extends GBService {
}); });
code = code.replace(/hear (\w+) as login/gi, ($0, $1) => { code = code.replace(/hear (\w+) as login/gi, ($0, $1) => {
return `${$1} = await dk.hear("login")`; return `${$1} = await dk.getHear({{"login"})`;
}); });
code = code.replace(/hear (\w+) as email/gi, ($0, $1) => { code = code.replace(/hear (\w+) as email/gi, ($0, $1) => {
return `${$1} = await dk.hear("email")`; return `${$1} = await dk.getHear({"email"})`;
}); });
code = code.replace(/hear (\w+) as integer/gi, ($0, $1, $2) => { code = code.replace(/hear (\w+) as integer/gi, ($0, $1, $2) => {
return `${$1} = await dk.hear("integer")`; return `${$1} = await dk.getHear({"integer"})`;
}); });
code = code.replace(/hear (\w+) as file/gi, ($0, $1, $2) => { code = code.replace(/hear (\w+) as file/gi, ($0, $1, $2) => {
return `${$1} = await dk.hear("file")`; return `${$1} = await dk.getHear({"file"})`;
}); });
code = code.replace(/hear (\w+) as boolean/gi, ($0, $1, $2) => { code = code.replace(/hear (\w+) as boolean/gi, ($0, $1, $2) => {
return `${$1} = await dk.hear("boolean")`; return `${$1} = await dk.getHear({"boolean"})`;
}); });
code = code.replace(/hear (\w+) as name/gi, ($0, $1, $2) => { code = code.replace(/hear (\w+) as name/gi, ($0, $1, $2) => {
return `${$1} = await dk.hear("name")`; return `${$1} = await dk.getHear({"name"})`;
}); });
code = code.replace(/hear (\w+) as date/gi, ($0, $1, $2) => { code = code.replace(/hear (\w+) as date/gi, ($0, $1, $2) => {
return `${$1} = await dk.hear("date")`; return `${$1} = await dk.getHear({"date"})`;
}); });
code = code.replace(/hear (\w+) as hour/gi, ($0, $1, $2) => { code = code.replace(/hear (\w+) as hour/gi, ($0, $1, $2) => {
return `${$1} = await dk.hear("hour")`; return `${$1} = await dk.getHear({"hour"})`;
}); });
code = code.replace(/hear (\w+) as phone/gi, ($0, $1, $2) => { code = code.replace(/hear (\w+) as phone/gi, ($0, $1, $2) => {
return `${$1} = await dk.hear("phone")`; return `${$1} = await dk.getHear({"phone"})`;
}); });
code = code.replace(/hear (\w+) as money/gi, ($0, $1, $2) => { code = code.replace(/hear (\w+) as money/gi, ($0, $1, $2) => {
return `${$1} = await dk.hear("money")`; return `${$1} = await dk.getHear({"money")}`;
}); });
code = code.replace(/hear (\w+) as language/gi, ($0, $1, $2) => { code = code.replace(/hear (\w+) as language/gi, ($0, $1, $2) => {
return `${$1} = await dk.hear("language")`; return `${$1} = await dk.getHear({"language")}`;
}); });
code = code.replace(/hear (\w+) as zipcode/gi, ($0, $1, $2) => { code = code.replace(/hear (\w+) as zipcode/gi, ($0, $1, $2) => {
return `${$1} = await dk.hear("zipcode")`; return `${$1} = await dk.getHear({"zipcode")}`;
}); });
code = code.replace(/hear (\w+) as (.*)/gi, ($0, $1, $2) => { code = code.replace(/hear (\w+) as (.*)/gi, ($0, $1, $2) => {
return `${$1} = await dk.hear("menu", ${$2})`; return `${$1} = await dk.getHear({"menu", [${$2}])}`;
}); });
code = code.replace(/(hear)\s*(\w+)/gi, ($0, $1, $2) => { code = code.replace(/(hear)\s*(\w+)/gi, ($0, $1, $2) => {
return `${$2} = await dk.hear()`; return `${$2} = await dk.getHear({})`;
}); });
code = code.replace(/(\w)\s*\=\s*find contact\s*(.*)/gi, ($0, $1, $2, $3) => { code = code.replace(/(\w)\s*\=\s*find contact\s*(.*)/gi, ($0, $1, $2, $3) => {
@ -313,7 +431,7 @@ export class GBVMService extends GBService {
}); });
code = code.replace(/(\w)\s*\=\s*append\s*(.*)/gi, ($0, $1, $2, $3) => { code = code.replace(/(\w)\s*\=\s*append\s*(.*)/gi, ($0, $1, $2, $3) => {
return `${$1} = await sys.append(${$2})\n`; return `${$1} = await sys.append([${$2}])\n`;
}); });
code = code.replace(/(\w+)\s*\=\s*sort\s*(\w+)\s*by(.*)/gi, ($0, $1, $2, $3) => { code = code.replace(/(\w+)\s*\=\s*sort\s*(\w+)\s*by(.*)/gi, ($0, $1, $2, $3) => {
@ -374,11 +492,11 @@ export class GBVMService extends GBService {
code = code.replace(/(go to)(\s)(.*)/gi, ($0, $1, $2, $3) => { code = code.replace(/(go to)(\s)(.*)/gi, ($0, $1, $2, $3) => {
return `await dk.gotoDialog(step, ${$3})\n`; return `await dk.gotoDialog(${$3})\n`;
}); });
code = code.replace(/(set language)(\s*)(.*)/gi, ($0, $1, $2, $3) => { code = code.replace(/(set language)(\s*)(.*)/gi, ($0, $1, $2, $3) => {
return `await dk.setLanguage (step, ${$3})\n`; return `await dk.setLanguage (${$3})\n`;
}); });
code = code.replace(/set header\s*(.*)\sas\s(.*)/gi, ($0, $1, $2) => { code = code.replace(/set header\s*(.*)\sas\s(.*)/gi, ($0, $1, $2) => {
@ -394,31 +512,31 @@ export class GBVMService extends GBService {
}); });
code = code.replace(/(datediff)(\s*)(.*)/gi, ($0, $1, $2, $3) => { code = code.replace(/(datediff)(\s*)(.*)/gi, ($0, $1, $2, $3) => {
return `await dk.dateDiff (step, ${$3})\n`; return `await dk.dateDiff (${$3})\n`;
}); });
code = code.replace(/(dateadd)(\s*)(.*)/gi, ($0, $1, $2, $3) => { code = code.replace(/(dateadd)(\s*)(.*)/gi, ($0, $1, $2, $3) => {
return `await dk.dateAdd (step, ${$3})\n`; return `await dk.dateAdd (${$3})\n`;
}); });
code = code.replace(/(set max lines)(\s*)(.*)/gi, ($0, $1, $2, $3) => { code = code.replace(/(set max lines)(\s*)(.*)/gi, ($0, $1, $2, $3) => {
return `await dk.setMaxLines (step, ${$3})\n`; return `await dk.setMaxLines (${$3})\n`;
}); });
code = code.replace(/(set max columns)(\s*)(.*)/gi, ($0, $1, $2, $3) => { code = code.replace(/(set max columns)(\s*)(.*)/gi, ($0, $1, $2, $3) => {
return `await dk.setMaxColumns (step, ${$3})\n`; return `await dk.setMaxColumns (${$3})\n`;
}); });
code = code.replace(/(set translator)(\s*)(.*)/gi, ($0, $1, $2, $3) => { code = code.replace(/(set translator)(\s*)(.*)/gi, ($0, $1, $2, $3) => {
return `await dk.setTranslatorOn (step, "${$3.toLowerCase()}")\n`; return `await dk.setTranslatorOn ("${$3.toLowerCase()}")\n`;
}); });
code = code.replace(/(set theme)(\s*)(.*)/gi, ($0, $1, $2, $3) => { code = code.replace(/(set theme)(\s*)(.*)/gi, ($0, $1, $2, $3) => {
return `await dk.setTheme (step, "${$3.toLowerCase()}")\n`; return `await dk.setTheme ("${$3.toLowerCase()}")\n`;
}); });
code = code.replace(/(set whole word)(\s*)(.*)/gi, ($0, $1, $2, $3) => { code = code.replace(/(set whole word)(\s*)(.*)/gi, ($0, $1, $2, $3) => {
return `await dk.setWholeWord (step, "${$3.toLowerCase()}")\n`; return `await dk.setWholeWord ("${$3.toLowerCase()}")\n`;
}); });
code = code.replace(/(\w+)\s*\=\s*post\s*(.*),\s*(.*)/gi, ($0, $1, $2, $3) => { code = code.replace(/(\w+)\s*\=\s*post\s*(.*),\s*(.*)/gi, ($0, $1, $2, $3) => {
@ -446,11 +564,11 @@ export class GBVMService extends GBService {
}); });
code = code.replace(/(chart)(\s)(.*)/gi, ($0, $1, $2, $3) => { code = code.replace(/(chart)(\s)(.*)/gi, ($0, $1, $2, $3) => {
return `await dk.chart (step, ${$3})\n`; return `await dk.chart (${$3})\n`;
}); });
code = code.replace(/(transfer to)(\s)(.*)/gi, ($0, $1, $2, $3) => { code = code.replace(/(transfer to)(\s)(.*)/gi, ($0, $1, $2, $3) => {
return `await dk.transferTo (step, ${$3})\n`; return `await dk.transferTo (${$3})\n`;
}); });
code = code.replace(/(\btransfer\b)(?=(?:[^"]|"[^"]*")*$)/gi, () => { code = code.replace(/(\btransfer\b)(?=(?:[^"]|"[^"]*")*$)/gi, () => {
@ -470,7 +588,7 @@ export class GBVMService extends GBService {
}); });
code = code.replace(/(talk)(\s)(.*)/gi, ($0, $1, $2, $3) => { code = code.replace(/(talk)(\s)(.*)/gi, ($0, $1, $2, $3) => {
return `await dk.talk (step, ${$3})\n`; return `await dk.talk (${$3})\n`;
}); });
code = code.replace(/(send sms to)(\s*)(.*)/gi, ($0, $1, $2, $3) => { code = code.replace(/(send sms to)(\s*)(.*)/gi, ($0, $1, $2, $3) => {
@ -486,23 +604,23 @@ export class GBVMService extends GBService {
}); });
code = code.replace(/(send file to)(\s*)(.*)/gi, ($0, $1, $2, $3) => { code = code.replace(/(send file to)(\s*)(.*)/gi, ($0, $1, $2, $3) => {
return `await dk.sendFileTo (step, ${$3})\n`; return `await dk.sendFileTo (${$3})\n`;
}); });
code = code.replace(/(hover)(\s*)(.*)/gi, ($0, $1, $2, $3) => { code = code.replace(/(hover)(\s*)(.*)/gi, ($0, $1, $2, $3) => {
return `await dk.hover (step, ${$3})\n`; return `await dk.hover (${$3})\n`;
}); });
code = code.replace(/(click link text)(\s*)(.*)/gi, ($0, $1, $2, $3) => { code = code.replace(/(click link text)(\s*)(.*)/gi, ($0, $1, $2, $3) => {
return `await dk.linkByText (step, ${$3})\n`; return `await dk.linkByText (${$3})\n`;
}); });
code = code.replace(/(click)(\s*)(.*)/gi, ($0, $1, $2, $3) => { code = code.replace(/(click)(\s*)(.*)/gi, ($0, $1, $2, $3) => {
return `await dk.click (step, ${$3})\n`; return `await dk.click (${$3})\n`;
}); });
code = code.replace(/(send file)(\s*)(.*)/gi, ($0, $1, $2, $3) => { code = code.replace(/(send file)(\s*)(.*)/gi, ($0, $1, $2, $3) => {
return `await dk.sendFile (step, ${$3})\n`; return `await dk.sendFile (${$3})\n`;
}); });
code = code.replace(/(copy)(\s*)(.*)/gi, ($0, $1, $2, $3) => { code = code.replace(/(copy)(\s*)(.*)/gi, ($0, $1, $2, $3) => {
@ -523,15 +641,15 @@ export class GBVMService extends GBService {
}); });
code = code.replace(/PRESS\s(.*)\sON\s(.*)/gi, ($0, $1, $2) => { code = code.replace(/PRESS\s(.*)\sON\s(.*)/gi, ($0, $1, $2) => {
return `await dk.pressKey(step, ${$2}, ${$1})\n`; return `await dk.pressKey(${$2}, ${$1})\n`;
}); });
code = code.replace(/SCREENSHOT\s(.*)/gi, ($0, $1, $2) => { code = code.replace(/SCREENSHOT\s(.*)/gi, ($0, $1, $2) => {
return `await dk.screenshot(step, ${$1})\n`; return `await dk.screenshot(${$1})\n`;
}); });
code = code.replace(/TWEET\s(.*)/gi, ($0, $1, $2) => { code = code.replace(/TWEET\s(.*)/gi, ($0, $1, $2) => {
return `await sys.tweet(step, ${$1})\n`; return `await sys.tweet(${$1})\n`;
}); });
code = code.replace(/(\w+)\s*\=\s*(.*)\s*as image/gi, ($0, $1, $2) => { code = code.replace(/(\w+)\s*\=\s*(.*)\s*as image/gi, ($0, $1, $2) => {
@ -550,7 +668,7 @@ export class GBVMService extends GBService {
return `await sys.saveFile(${$2}, ${$1})\n`; return `await sys.saveFile(${$2}, ${$1})\n`;
}); });
code = code.replace(/(save)(\s)(.*)/gi, ($0, $1, $2, $3) => { code = code.replace(/(save)(\s)(.*)/gi, ($0, $1, $2, $3) => {
return `await sys.save(${$3})\n`; return `await sys.save([${$3}])\n`;
}); });
code = code.replace(/set\s(.*)/gi, ($0, $1, $2) => { code = code.replace(/set\s(.*)/gi, ($0, $1, $2) => {
@ -562,137 +680,17 @@ export class GBVMService extends GBService {
return code; return code;
} }
public async translateBASIC(filename: any, min: GBMinInstance, deployer: GBDeployer, mainName: string) {
// Converts General Bots BASIC into regular VBS
let basicCode: string = fs.readFileSync(filename, 'utf8');
// Processes END keyword, removing extracode, useful
// for development.
let end = /(\nend\n)/gi.exec(basicCode);
if (end) {
basicCode = basicCode.substring(0, end.index);
}
// Removes comments.
basicCode = basicCode.replace(/((^|\W)REM.*\n)/gi, '');
// Process INCLUDE keyword to include another
// dialog inside the dialog.
let include = null;
do {
include = /^include\b(.*)$/gmi.exec(basicCode);
if (include) {
let includeName = include[1].trim();
includeName = Path.join(Path.dirname(filename), includeName);
includeName = includeName.substr(0, includeName.lastIndexOf(".")) + ".vbs";
// To use include, two /publish will be necessary (for now)
// because of alphabet order may raise not found errors.
let includeCode: string = fs.readFileSync(includeName, 'utf8');
basicCode = basicCode.replace(/^include\b.*$/gmi, includeCode);
}
} while (include);
const vbsCode = this.convertGBASICToVBS(min, basicCode);
const vbsFile = `${filename}.compiled`;
fs.writeFileSync(vbsFile, vbsCode);
// Converts VBS into TS.
vb2ts.convertFile(vbsFile);
// Convert TS into JS.
const tsfile: string = `${filename}.ts`;
let tsCode: string = fs.readFileSync(tsfile, 'utf8');
tsCode = tsCode + `let resolve;`;
fs.writeFileSync(tsfile, tsCode);
const tsc = new TSCompiler();
tsc.compile([tsfile]);
// Run JS into the GB context.
const jsfile = `${tsfile}.js`.replace('.ts', '');
if (fs.existsSync(jsfile)) {
let code: string = fs.readFileSync(jsfile, 'utf8');
code = code.replace(/^.*exports.*$/gm, '');
code = `
return (async () => {
require('isomorphic-fetch);
const rest = require ('typescript-rest-rpc/lib/client');
// Interprocess communication from local HTTP to the BotServer.
dk = rest.createClient('http://localhost:1111/api/v2/${min.botId}/dialog');
sys = rest.createClient('http://localhost:1111/api/v2/${min.botId}/system');
// Local variables.
gb = dk.getSingleton(url);
const id = gb.id;
const username = gb.username;
const mobile = gb.mobile;
const from = gb.from;
const ENTER = gb.ENTER;
const headers = gb.headers;
const data = gb.data;
const list = gb.list;
const httpUsername = gb.httpUsername;
const httpPs = gb.httpPs;
// Local functions.
const ubound = (array) => {return array.length};
const isarray = (array) => {return Array.isArray(array) };
// Remote functions.
const weekday = (v) => { (async () => { await client.getWeekFromDate(v) })(); };
const hour = (v) => { (async () => { await client.getHourFromDate(v) })(); };
const base64 = (v) => { (async () => { await client.getCoded(v) })(); };
const tolist = (v) => { (async () => { await client.getToLst(v) })(); };
const now = (v) => { (async () => { await client.getNow(v) })(); };
const today = (v) => { (async () => { await client.getToday(v) })(); };
${code}
})();
`;
// Finds all hear calls.
const parsedCode = beautify(code, { indent_size: 2, space_in_empty_paren: true });
fs.writeFileSync(jsfile, parsedCode);
min.sandBoxMap[mainName.toLowerCase().trim()] = parsedCode;
GBLog.info(`[GBVMService] Finished loading of ${filename}, JavaScript from Word: \n ${parsedCode}`);
}
}
/** /**
* Executes the converted JavaScript from BASIC code inside execution context. * Executes the converted JavaScript from BASIC code inside execution context.
*/ */
public static async callVM(text: string, min: GBMinInstance, step: GBDialogStep, deployer: GBDeployer) { public static async callVM(text: string, min: GBMinInstance, step, GBDialogdeployer: GBDeployer) {
// Creates a class DialogKeywords which is the *this* pointer // Creates a class DialogKeywords which is the *this* pointer
// in BASIC. // in BASIC.
const user = step ? await min.userProfile.get(step.context, {}) : null; const user = step ? await min.userProfile.get(step.context, {}) : null;
const sandbox = { user: user.ssystemUser }; const sandbox = { user: user.systemUser };
const contentLocale = min.core.getParam<string>( const contentLocale = min.core.getParam<string>(
min.instance, min.instance,

View file

@ -92,11 +92,17 @@ export class SystemKeywords {
} }
public async callVM(text: string, min: GBMinInstance, step, deployer: GBDeployer) { public async callVM({text}) {
// TODO:
const min = null;
const step = null;
const deployer = null;
return await GBVMService.callVM(text, min, step, deployer); return await GBVMService.callVM(text, min, step, deployer);
} }
public async append(...args) { public async append({args}) {
let array = [].concat(...args); let array = [].concat(...args);
return array.filter(function (item, pos) { return item; }); return array.filter(function (item, pos) { return item; });
} }
@ -107,7 +113,7 @@ export class SystemKeywords {
* @example SEE CAPTION OF url AS variable * @example SEE CAPTION OF url AS variable
* *
*/ */
public async seeCaption(url) { public async seeCaption({url}) {
const computerVisionClient = new ComputerVisionClient( const computerVisionClient = new ComputerVisionClient(
new ApiKeyCredentials({ inHeader: { 'Ocp-Apim-Subscription-Key': process.env.VISION_KEY } }), new ApiKeyCredentials({ inHeader: { 'Ocp-Apim-Subscription-Key': process.env.VISION_KEY } }),
process.env.VISION_ENDPOINT); process.env.VISION_ENDPOINT);
@ -135,7 +141,7 @@ export class SystemKeywords {
* @example SEE TEXT OF url AS variable * @example SEE TEXT OF url AS variable
* *
*/ */
public async seeText(url) { public async seeText({url}) {
const computerVisionClient = new ComputerVisionClient( const computerVisionClient = new ComputerVisionClient(
new ApiKeyCredentials({ inHeader: { 'Ocp-Apim-Subscription-Key': process.env.VISION_KEY } }), new ApiKeyCredentials({ inHeader: { 'Ocp-Apim-Subscription-Key': process.env.VISION_KEY } }),
process.env.VISION_ENDPOINT); process.env.VISION_ENDPOINT);
@ -160,7 +166,7 @@ export class SystemKeywords {
return final; return final;
} }
public async sortBy(array, memberName) { public async sortBy({array, memberName}) {
memberName = memberName.trim(); memberName = memberName.trim();
const contentLocale = this.min.core.getParam<string>( const contentLocale = this.min.core.getParam<string>(
this.min.instance, this.min.instance,
@ -345,18 +351,18 @@ export class SystemKeywords {
return [url, localName]; return [url, localName];
} }
public async asPDF(data, filename) { public async asPDF({data, filename}) {
let file = await this.renderTable(data, true, false); let file = await this.renderTable(data, true, false);
return file[0]; return file[0];
} }
public async asImage(data, filename) { public async asImage({data, filename}) {
let file = await this.renderTable(data, false, true); let file = await this.renderTable(data, false, true);
return file[0]; return file[0];
} }
public async executeSQL(data, sql, tableName) { public async executeSQL({data, sql, tableName}) {
let objectMode = false; let objectMode = false;
if (Object.keys(data[0])) { if (Object.keys(data[0])) {
@ -377,7 +383,7 @@ export class SystemKeywords {
/** /**
* Retrives the content of a given URL. * Retrives the content of a given URL.
*/ */
public async getFileContents(url, headers) { public async getFileContents({url, headers}) {
const options = { const options = {
url: url, url: url,
method: 'GET', method: 'GET',
@ -405,7 +411,7 @@ export class SystemKeywords {
/** /**
* Retrives stock inforation for a given symbol. * Retrives stock inforation for a given symbol.
*/ */
public async getStock(symbol) { public async getStock({symbol}) {
var options = { var options = {
uri: `http://live-nse.herokuapp.com/?symbol=${symbol}` uri: `http://live-nse.herokuapp.com/?symbol=${symbol}`
}; };
@ -421,7 +427,7 @@ export class SystemKeywords {
* @example WAIT 5 ' This will wait five seconds. * @example WAIT 5 ' This will wait five seconds.
* *
*/ */
public async wait(seconds: number) { public async wait({seconds}) {
// tslint:disable-next-line no-string-based-set-timeout // tslint:disable-next-line no-string-based-set-timeout
GBLog.info(`BASIC: WAIT for ${seconds} second(s).`); GBLog.info(`BASIC: WAIT for ${seconds} second(s).`);
const timeout = async (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); const timeout = async (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
@ -434,7 +440,7 @@ export class SystemKeywords {
* @example TALK TO "+199988887777", "Message text here" * @example TALK TO "+199988887777", "Message text here"
* *
*/ */
public async talkTo(mobile: any, message: string) { public async talkTo({mobile, message}) {
GBLog.info(`BASIC: Talking '${message}' to a specific user (${mobile}) (TALK TO). `); GBLog.info(`BASIC: Talking '${message}' to a specific user (${mobile}) (TALK TO). `);
await this.min.conversationalService.sendMarkdownToMobile(this.min, null, mobile, message); await this.min.conversationalService.sendMarkdownToMobile(this.min, null, mobile, message);
} }
@ -445,7 +451,7 @@ export class SystemKeywords {
* @example SEND SMS TO "+199988887777", "Message text here" * @example SEND SMS TO "+199988887777", "Message text here"
* *
*/ */
public async sendSmsTo(mobile, message) { public async sendSmsTo({mobile, message}) {
GBLog.info(`BASIC: SEND SMS TO '${mobile}', message '${message}'.`); GBLog.info(`BASIC: SEND SMS TO '${mobile}', message '${message}'.`);
await this.min.conversationalService.sendSms(this.min, mobile, message); await this.min.conversationalService.sendSms(this.min, mobile, message);
} }
@ -459,13 +465,14 @@ export class SystemKeywords {
* @example SET page, "elementHTMLSelector", "text" * @example SET page, "elementHTMLSelector", "text"
* *
*/ */
public async set(file: any, address: string, value: any): Promise<any> { public async set({file, address, value}): Promise<any> {
// Handles calls for HTML stuff // Handles calls for HTML stuff
if (file._javascriptEnabled) { if (file._javascriptEnabled) {
GBLog.info(`BASIC: Web automation setting ${file}' to '${value}' (SET). `); const page = file;
await this.dk.setElementText(file, address, value); GBLog.info(`BASIC: Web automation setting ${page}' to '${value}' (SET). `);
await this.dk.setElementText({page, selector: address, text: value});
return; return;
} }
@ -520,7 +527,7 @@ export class SystemKeywords {
* @exaple SAVE variable as "my.txt" * @exaple SAVE variable as "my.txt"
* *
*/ */
public async saveFile(file: any, data: any): Promise<any> { public async saveFile({file, data}): Promise<any> {
GBLog.info(`BASIC: Saving '${file}' (SAVE file).`); GBLog.info(`BASIC: Saving '${file}' (SAVE file).`);
let [baseUrl, client] = await GBDeployer.internalGetDriveClient(this.min); let [baseUrl, client] = await GBDeployer.internalGetDriveClient(this.min);
@ -556,7 +563,9 @@ export class SystemKeywords {
* @exaple SAVE "customers.xlsx", name, email, phone, address, city, state, country * @exaple SAVE "customers.xlsx", name, email, phone, address, city, state, country
* *
*/ */
public async save(file: string, ...args): Promise<any> { public async save({args}): Promise<any> {
const file = args[0];
args.shift();
GBLog.info(`BASIC: Saving '${file}' (SAVE). Args: ${args.join(',')}.`); GBLog.info(`BASIC: Saving '${file}' (SAVE). Args: ${args.join(',')}.`);
let [baseUrl, client] = await GBDeployer.internalGetDriveClient(this.min); let [baseUrl, client] = await GBDeployer.internalGetDriveClient(this.min);
const botId = this.min.instance.botId; const botId = this.min.instance.botId;
@ -597,11 +606,12 @@ export class SystemKeywords {
* @example value = GET "file.xlsx", "A2" * @example value = GET "file.xlsx", "A2"
* *
*/ */
public async get(file: string, addressOrHeaders: string, httpUsername, httpPs, qs, streaming): Promise<any> { public async get({file, addressOrHeaders, httpUsername, httpPs, qs, streaming}): Promise<any> {
if (file.startsWith('http')) { if (file.startsWith('http')) {
return await this.getByHttp(file, addressOrHeaders, httpUsername, httpPs, qs, streaming); return await this.getByHttp({url:file, headers: addressOrHeaders, username: httpUsername,
ps: httpPs, qs, streaming});
} }
else { else {
GBLog.info(`BASIC: GET '${addressOrHeaders}' in '${file}'.`); GBLog.info(`BASIC: GET '${addressOrHeaders}' in '${file}'.`);
@ -627,7 +637,7 @@ export class SystemKeywords {
} }
} }
public isValidDate(dt) { public isValidDate({dt}) {
const contentLocale = this.min.core.getParam<string>( const contentLocale = this.min.core.getParam<string>(
this.min.instance, this.min.instance,
'Default Content Language', 'Default Content Language',
@ -646,12 +656,12 @@ export class SystemKeywords {
return !isNaN(date.valueOf()); return !isNaN(date.valueOf());
} }
public isValidNumber(number) { public isValidNumber({number}) {
if (number === '') { return false } if (number === '') { return false }
return !isNaN(number); return !isNaN(number);
} }
public isValidHour(value) { public isValidHour({value}) {
return /^([01]?[0-9]|2[0-3]):[0-5][0-9]$/.test(value); return /^([01]?[0-9]|2[0-3]):[0-5][0-9]$/.test(value);
} }
@ -671,7 +681,9 @@ export class SystemKeywords {
* *
* // TODO: https://www.npmjs.com/package/parse-markdown-table * // TODO: https://www.npmjs.com/package/parse-markdown-table
*/ */
public async find(file: string, ...args): Promise<any> { public async find({args}): Promise<any> {
const file = args[0];
args.shift();
GBLog.info(`BASIC: FIND running on ${file} and args: ${JSON.stringify(args)}...`); GBLog.info(`BASIC: FIND running on ${file} and args: ${JSON.stringify(args)}...`);
const botId = this.min.instance.botId; const botId = this.min.instance.botId;
@ -1051,7 +1063,7 @@ export class SystemKeywords {
* *
* @example file = DOWNLOAD element, folder * @example file = DOWNLOAD element, folder
*/ */
public async download(element, folder) { public async download({element, folder}) {
const page = element['_page']; const page = element['_page'];
const container = element['_frame'] ? element['_frame'] : element['_page']; const container = element['_frame'] ? element['_frame'] : element['_page'];
@ -1142,7 +1154,7 @@ export class SystemKeywords {
* @example folder = CREATE FOLDER "notes\01" * @example folder = CREATE FOLDER "notes\01"
* *
*/ */
public async createFolder(name: string) { public async createFolder({name}) {
let [baseUrl, client] = await GBDeployer.internalGetDriveClient(this.min); let [baseUrl, client] = await GBDeployer.internalGetDriveClient(this.min);
const botId = this.min.instance.botId; const botId = this.min.instance.botId;
@ -1199,7 +1211,7 @@ export class SystemKeywords {
* SHARE FOLDER folder, "nome@domain.com", "E-mail message" * SHARE FOLDER folder, "nome@domain.com", "E-mail message"
* *
*/ */
public async shareFolder(folderReference, email: string, message: string) { public async shareFolder({folderReference, email, message}) {
let [, client] = await GBDeployer.internalGetDriveClient(this.min); let [, client] = await GBDeployer.internalGetDriveClient(this.min);
const driveId = folderReference.parentReference.driveId; const driveId = folderReference.parentReference.driveId;
const itemId = folderReference.id; const itemId = folderReference.id;
@ -1224,7 +1236,7 @@ export class SystemKeywords {
* COPY "template.xlsx", "reports\" + customerName + "\final.xlsx" * COPY "template.xlsx", "reports\" + customerName + "\final.xlsx"
* *
*/ */
public async copyFile(src, dest) { public async copyFile({src, dest}) {
GBLog.info(`BASIC: BEGINING COPY '${src}' to '${dest}'`); GBLog.info(`BASIC: BEGINING COPY '${src}' to '${dest}'`);
let [baseUrl, client] = await GBDeployer.internalGetDriveClient(this.min); let [baseUrl, client] = await GBDeployer.internalGetDriveClient(this.min);
const botId = this.min.instance.botId; const botId = this.min.instance.botId;
@ -1293,7 +1305,7 @@ export class SystemKeywords {
* CONVERT "customers.xlsx" TO "reports\" + today + ".pdf" * CONVERT "customers.xlsx" TO "reports\" + today + ".pdf"
* *
*/ */
public async convert(src, dest) { public async convert({src, dest}) {
GBLog.info(`BASIC: CONVERT '${src}' to '${dest}'`); GBLog.info(`BASIC: CONVERT '${src}' to '${dest}'`);
let [baseUrl, client] = await GBDeployer.internalGetDriveClient(this.min); let [baseUrl, client] = await GBDeployer.internalGetDriveClient(this.min);
const botId = this.min.instance.botId; const botId = this.min.instance.botId;
@ -1375,7 +1387,7 @@ export class SystemKeywords {
* @example user = get "http://server/users/1" * @example user = get "http://server/users/1"
* *
*/ */
public async getByHttp(url: string, headers: any, username: string, ps: string, qs: any, streaming = false) { public async getByHttp({url, headers, username, ps, qs, streaming}) {
let options = { url: url }; let options = { url: url };
if (headers) { if (headers) {
options['headers'] = headers; options['headers'] = headers;
@ -1415,7 +1427,7 @@ export class SystemKeywords {
* talk "The updated user area is" + user.area * talk "The updated user area is" + user.area
* *
*/ */
public async putByHttp(url: string, data, headers) { public async putByHttp({url, data, headers}) {
const options = { const options = {
uri: url, uri: url,
json: data, json: data,
@ -1436,7 +1448,7 @@ export class SystemKeywords {
* talk "The updated user area is" + user.area * talk "The updated user area is" + user.area
* *
*/ */
public async postByHttp(url: string, data, headers) { public async postByHttp({url, data, headers}) {
const options = { const options = {
uri: url, uri: url,
json: data, json: data,
@ -1460,7 +1472,7 @@ export class SystemKeywords {
* doc = FILL "templates/template.docx", data * doc = FILL "templates/template.docx", data
* *
*/ */
public async fill(templateName, data) { public async fill({templateName, data}) {
const botId = this.min.instance.botId; const botId = this.min.instance.botId;
const gbaiName = `${botId}.gbai`; const gbaiName = `${botId}.gbai`;
@ -1555,7 +1567,7 @@ export class SystemKeywords {
* MERGE "second.xlsx" WITH data BY customer_id * MERGE "second.xlsx" WITH data BY customer_id
* *
*/ */
public async merge(file: string, data: [], key1, key2): Promise<any> { public async merge({file, data, key1, key2}): Promise<any> {
GBLog.info(`BASIC: MERGE running on ${file} and key1: ${key1}, key2: ${key2}...`); GBLog.info(`BASIC: MERGE running on ${file} and key1: ${key1}, key2: ${key2}...`);
const botId = this.min.instance.botId; const botId = this.min.instance.botId;
@ -1658,19 +1670,19 @@ export class SystemKeywords {
if (value !== found[columnName]) { if (value !== found[columnName]) {
await this.set(file, address, value); await this.set({file, address, value});
merges++; merges++;
} }
} }
} }
else { else {
let args = []; let args = [file];
let keys = Object.keys(row); let keys = Object.keys(row);
for (let j = 0; j < keys.length; j++) { for (let j = 0; j < keys.length; j++) {
args.push(row[keys[j]]); args.push(row[keys[j]]);
} }
await this.save(file, ...args); await this.save({args});
adds++; adds++;
} }
} }
@ -1684,7 +1696,7 @@ export class SystemKeywords {
} }
} }
public async tweet(text: string) { public async tweet({text}) {
const consumer_key = this.min.core.getParam(this.min.instance, 'Twitter Consumer Key', null); const consumer_key = this.min.core.getParam(this.min.instance, 'Twitter Consumer Key', null);
const consumer_secret = this.min.core.getParam(this.min.instance, 'Twitter Consumer Key Secret', null); const consumer_secret = this.min.core.getParam(this.min.instance, 'Twitter Consumer Key Secret', null);
@ -1704,7 +1716,5 @@ export class SystemKeywords {
await client.v2.tweet(text); await client.v2.tweet(text);
GBLog.info(`Twitter Automation: ${text}.`); GBLog.info(`Twitter Automation: ${text}.`);
} }
} }

View file

@ -66,7 +66,7 @@ export class TSCompiler {
noImplicitUseStrict: true, noImplicitUseStrict: true,
noEmitOnError: false, noEmitOnError: false,
noImplicitAny: true, noImplicitAny: true,
target: ts.ScriptTarget.ES5, target: ts.ScriptTarget.ESNext,
module: ts.ModuleKind.None, module: ts.ModuleKind.None,
moduleResolution: ts.ModuleResolutionKind.Classic, moduleResolution: ts.ModuleResolutionKind.Classic,
noEmitHelpers: true, noEmitHelpers: true,

View file

@ -36,10 +36,10 @@ const server = net1.createServer((socket) => {
}); });
console.log(JSON.stringify({ result })); console.log(JSON.stringify({ result }));
debugger;
socket.write(JSON.stringify({ result }) + '\n'); socket.write(JSON.stringify({ result }) + '\n');
socket.end(); socket.end();
} catch (error) { } catch (error) {
console.log(`BASIC: RUNTIME: ${error.message}, ${error.stack}`)
socket.write(JSON.stringify({ error: error.message }) + '\n'); socket.write(JSON.stringify({ error: error.message }) + '\n');
socket.end(); socket.end();
} }