new(all): #327 OPEN AS web automation.

This commit is contained in:
rodrigorodriguez 2023-02-16 10:27:18 -03:00
parent 4c813ce02d
commit 649e08d7f2
3 changed files with 82 additions and 55 deletions

View file

@ -61,10 +61,8 @@ import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js';
* Basic services for BASIC manipulation. * Basic services for BASIC manipulation.
*/ */
export class GBVMService extends GBService { export class GBVMService extends GBService {
private static DEBUGGER_PORT = 9222; private static DEBUGGER_PORT = 9222;
public async loadDialogPackage(folder: string, min: GBMinInstance, core: IGBCoreService, deployer: GBDeployer) { public async loadDialogPackage(folder: string, min: GBMinInstance, core: IGBCoreService, deployer: GBDeployer) {
const files = await walkPromise(folder); const files = await walkPromise(folder);
@ -161,7 +159,7 @@ export class GBVMService extends GBService {
}); });
} }
public async translateBASIC(filename: any, mainName: string, min:GBMinInstance) { public async translateBASIC(filename: any, mainName: string, min: GBMinInstance) {
// Converts General Bots BASIC into regular VBS // Converts General Bots BASIC into regular VBS
let basicCode: string = Fs.readFileSync(filename, 'utf8'); let basicCode: string = Fs.readFileSync(filename, 'utf8');
@ -276,7 +274,6 @@ export class GBVMService extends GBService {
}); });
} }
/** /**
* Converts General Bots BASIC * Converts General Bots BASIC
* *
@ -312,7 +309,6 @@ export class GBVMService extends GBService {
* 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, deployer: GBDeployer, debug: boolean) { public static async callVM(text: string, min: GBMinInstance, step, deployer: GBDeployer, debug: boolean) {
// Creates a class DialogKeywords which is the *this* pointer // Creates a class DialogKeywords which is the *this* pointer
// in BASIC. // in BASIC.
@ -351,9 +347,9 @@ export class GBVMService extends GBService {
}; };
sandbox['id'] = dk.sys().getRandomId(); sandbox['id'] = dk.sys().getRandomId();
sandbox['username'] = await dk.userName({pid}); sandbox['username'] = await dk.userName({ pid });
sandbox['mobile'] = await dk.userMobile({pid}); sandbox['mobile'] = await dk.userMobile({ pid });
sandbox['from'] = await dk.userMobile({pid}); sandbox['from'] = await dk.userMobile({ pid });
sandbox['ENTER'] = String.fromCharCode(13); sandbox['ENTER'] = String.fromCharCode(13);
sandbox['headers'] = {}; sandbox['headers'] = {};
sandbox['data'] = {}; sandbox['data'] = {};
@ -362,8 +358,10 @@ export class GBVMService extends GBService {
sandbox['httpPs'] = ''; sandbox['httpPs'] = '';
sandbox['pid'] = pid; sandbox['pid'] = pid;
if (GBConfigService.get('GBVM') === 'false') { let result;
try { try {
if (GBConfigService.get('GBVM') === 'false') {
const vm1 = new NodeVM({ const vm1 = new NodeVM({
allowAsync: true, allowAsync: true,
sandbox: sandbox, sandbox: sandbox,
@ -377,11 +375,7 @@ export class GBVMService extends GBService {
} }
}); });
const s = new VMScript(code, { filename: scriptPath }); const s = new VMScript(code, { filename: scriptPath });
let x = vm1.run(s); result = vm1.run(s);
return x;
} catch (error) {
throw new Error(`BASIC RUNTIME ERR: ${error.message ? error.message : error}\n Stack:${error.stack}`);
}
} else { } else {
const runnerPath = urlJoin( const runnerPath = urlJoin(
process.cwd(), process.cwd(),
@ -393,7 +387,6 @@ export class GBVMService extends GBService {
'vm2ProcessRunner.js' 'vm2ProcessRunner.js'
); );
try {
const { run } = createVm2Pool({ const { run } = createVm2Pool({
min: 0, min: 0,
max: 0, max: 0,
@ -407,12 +400,23 @@ export class GBVMService extends GBService {
script: runnerPath script: runnerPath
}); });
const result = await run(code, { filename: scriptPath, sandbox: sandbox }); result = await run(code, { filename: scriptPath, sandbox: sandbox });
}
return result;
} catch (error) { } catch (error) {
throw new Error(`BASIC RUNTIME ERR: ${error.message ? error.message : error}\n Stack:${error.stack}`); throw new Error(`BASIC RUNTIME ERR: ${error.message ? error.message : error}\n Stack:${error.stack}`);
} finally {
// Releases previous allocated OPEN semaphores.
let keys = Object.keys(GBServer.globals.webSessions);
for (let i = 0; i < keys.length; i++) {
const session = GBServer.globals.webSessions[keys[i]];
if (session.pid === pid) {
session.semaphore.release();
} }
} }
} }
return result;
}
} }

View file

@ -36,7 +36,6 @@
* Image processing services of conversation to be called by BASIC. * Image processing services of conversation to be called by BASIC.
*/ */
export class KeywordsExpressions { export class KeywordsExpressions {
private static getParams = (text: string, names) => { private static getParams = (text: string, names) => {
let ret = {}; let ret = {};
const splitParamsButIgnoreCommasInDoublequotes = (str: string) => { const splitParamsButIgnoreCommasInDoublequotes = (str: string) => {
@ -74,7 +73,6 @@ export class KeywordsExpressions {
* Returns the list of BASIC keyword and their JS match. * Returns the list of BASIC keyword and their JS match.
*/ */
public static getKeywords() { public static getKeywords() {
// Keywords from General Bots BASIC. // Keywords from General Bots BASIC.
let keywords = []; let keywords = [];
@ -140,12 +138,19 @@ export class KeywordsExpressions {
keywords[i++] = [ keywords[i++] = [
/^\s*open\s*(.*)/gim, /^\s*open\s*(.*)/gim,
($0, $1, $2) => { ($0, $1, $2) => {
let pos;
let sessionName; let sessionName;
if (pos = $1.match(/\s*AS\s*\#/)){ let kind = '';
let pos;
if (pos = $1.match(/\s*AS\s*\#/)) {
kind = '"AS"';
} else if (pos = $1.match(/\s*WITH\s*\#/)) {
kind = '"WITH"';
}
if (pos) {
let part = $1.substr($1.lastIndexOf(pos[0])); let part = $1.substr($1.lastIndexOf(pos[0]));
sessionName = `"${part.substr(part.indexOf("#") + 1)}"`; sessionName = `"${part.substr(part.indexOf('#') + 1)}"`;
$1 = $1.substr(0, $1.lastIndexOf(pos[0])); $1 = $1.substr(0, $1.lastIndexOf(pos[0]));
} }
@ -154,7 +159,7 @@ export class KeywordsExpressions {
} }
const params = this.getParams($1, ['url', 'username', 'password']); const params = this.getParams($1, ['url', 'username', 'password']);
return `page = await wa.getPage({pid: pid, sessionName: ${sessionName}, ${params}})`; return `page = await wa.getPage({pid: pid, sessionKind: ${kind}, sessionName: ${sessionName}, ${params}})`;
} }
]; ];

View file

@ -44,15 +44,12 @@ import urlJoin from 'url-join';
import Fs from 'fs'; import Fs from 'fs';
import Path from 'path'; import Path from 'path';
import url from 'url'; import url from 'url';
import {Mutex, Semaphore, withTimeout} from 'async-mutex'; import { Mutex, Semaphore, withTimeout } from 'async-mutex';
/** /**
* Web Automation services of conversation to be called by BASIC. * Web Automation services of conversation to be called by BASIC.
*/ */
export class WebAutomationServices { export class WebAutomationServices {
static semaphoreWithTimeout = withTimeout(new Semaphore(5), 60 * 1000, new Error('new fancy error'));
/** /**
* Reference to minimal bot instance. * Reference to minimal bot instance.
*/ */
@ -124,25 +121,46 @@ export class WebAutomationServices {
* @example OPEN "https://wikipedia.org" * @example OPEN "https://wikipedia.org"
*/ */
public async getPage({ pid, sessionName, url, username, password }) { public async getPage({ pid, sessionKind, sessionName, url, username, password }) {
GBLog.info(`BASIC: Web Automation GET PAGE ${sessionName ? sessionName : ''} ${url}.`); GBLog.info(`BASIC: Web Automation GET PAGE ${sessionName ? sessionName : ''} ${url}.`);
// Semaphore logic to block multiple entries on the same session.
let page; let page;
if (url.startsWith('#')) { let session = GBServer.globals.webSessions[sessionName];
const [value, release] = await WebAutomationServices.semaphoreWithTimeout.acquire();
if (session) {
const [value, release] = await session.semaphore.acquire();
try { try {
GBServer.globals.webSessions[sessionName].release = release;
page = GBServer.globals.webSessions[url.substr(1)]; page = GBServer.globals.webSessions[url.substr(1)];
} finally { } catch {
release(); release();
} }
}
// There is no session yet,
if (!session && sessionKind === 'AS') {
// A new web session is being created.
GBServer.globals.webSessions[sessionName] = {};
GBServer.globals.webSessions[sessionName].pid = pid;
GBServer.globals.webSessions[sessionName].page = page;
GBServer.globals.webSessions[sessionName].semaphore = withTimeout(
new Semaphore(5),
60 * 1000,
new Error('Error waiting for OPEN keyword.')
);
}
if (url.startsWith('#') && sessionKind == 'WITH') {
} else { } else {
if (!this.browser) { if (!this.browser) {
this.browser = await createBrowser(null); this.browser = await createBrowser(null);
} }
page = (await this.browser.pages())[0]; page = (await this.browser.pages())[0];
if (sessionName) {
GBServer.globals.webSessions[sessionName] = page;
}
if (username || password) { if (username || password) {
await page.authenticate({ pid, username: username, password: password }); await page.authenticate({ pid, username: username, password: password });
} }