From f3c756b01576ebbe5266ed9699e6c06ed3c05263 Mon Sep 17 00:00:00 2001 From: rodrigorodriguez Date: Sun, 5 Mar 2023 11:09:36 -0300 Subject: [PATCH] fix(basic.gblib): Upgrade to https://github.com/vasyas/push-rpc from WS to HTTPS. --- package.json | 7 +- packages/basic.gblib/index.ts | 144 +++++++++--------- .../basic.gblib/services/DialogKeywords.ts | 30 ++-- packages/basic.gblib/services/GBVMService.ts | 39 +++-- .../services/KeywordsExpressions.ts | 34 ++--- 5 files changed, 132 insertions(+), 122 deletions(-) diff --git a/package.json b/package.json index b33950604..6c3bf73e2 100644 --- a/package.json +++ b/package.json @@ -68,9 +68,9 @@ "@microsoft/microsoft-graph-client": "3.0.4", "@nlpjs/basic": "4.26.1", "@nosferatu500/textract": "3.1.2", - "@push-rpc/core": "^1.5.7", - "@push-rpc/http": "^1.5.7", - "@push-rpc/websocket": "^1.5.7", + "@push-rpc/core": "1.1.5", + "@push-rpc/http": "1.1.5", + "@push-rpc/websocket": "1.1.5", "@semantic-release/changelog": "5.0.1", "@semantic-release/exec": "5.0.0", "@semantic-release/git": "9.0.0", @@ -165,7 +165,6 @@ "textract": "2.5.0", "twitter-api-v2": "1.12.9", "typescript": "4.9.5", - "typescript-rest-rpc": "1.0.7", "url-join": "5.0.0", "vbscript-to-typescript": "1.0.8", "vhost": "3.0.2", diff --git a/packages/basic.gblib/index.ts b/packages/basic.gblib/index.ts index 9e05e11c8..4fa54578f 100644 --- a/packages/basic.gblib/index.ts +++ b/packages/basic.gblib/index.ts @@ -36,7 +36,7 @@ 'use strict'; -import { GBDialogStep, GBLog, GBMinInstance, IGBCoreService, IGBPackage } from 'botlib'; +import { GBDialogStep, GBLog, GBMinInstance, IGBCoreService, IGBInstance, IGBPackage } from 'botlib'; import { GuaribasSchedule } from '../core.gbapp/models/GBModel.js'; import { Sequelize } from 'sequelize-typescript'; import { DialogKeywords } from './services/DialogKeywords.js'; @@ -45,38 +45,38 @@ import { WebAutomationServices } from './services/WebAutomationServices.js'; import { ImageProcessingServices } from './services/ImageProcessingServices.js'; import { DebuggerService } from './services/DebuggerService.js'; import Koa from 'koa'; -import {createRpcServer, createRpcClient} from "@push-rpc/core" -import {createKoaHttpMiddleware, createExpressHttpMiddleware, createHttpClient} from "@push-rpc/http" +import { createRpcServer, createRpcClient } from '@push-rpc/core'; +import { createHttpKoaMiddleware, createHttpClient } from '@push-rpc/http'; +import { HttpServerOptions } from '@push-rpc/http/dist/server.js'; import { GBServer } from '../../src/app.js'; const app = new Koa(); -import {SocketServer} from "@push-rpc/core" -import * as koaBody from "koa-body" - +import { SocketServer } from '@push-rpc/core'; +import * as koaBody from 'koa-body'; +import { GBVMService } from './services/GBVMService.js'; +import { GBLogEx } from '../core.gbapp/services/GBLogEx.js'; +import { CollectionUtil } from 'pragmatismo-io-framework'; export function createKoaHttpServer( port: number, - getRemoteId: (ctx: Koa.Context) => string + getRemoteId: (ctx: Koa.Context) => string, + opts: Partial = {} ): SocketServer { - const {onError, onConnection, middleware} = createKoaHttpMiddleware(getRemoteId) + const { onError, onConnection, middleware } = createHttpKoaMiddleware(getRemoteId, opts); - const app = new Koa() - app.use(koaBody.koaBody({multipart: true})) - app.use(middleware) - const server = app.listen(port) + const app = new Koa(); + app.use(koaBody.koaBody({ multipart: true })); + app.use(middleware); + const server = app.listen(port); return { onError, onConnection, close(cb) { - server.close(cb) - }, - } + server.close(cb); + } + }; } - - - - /** * Package for core.gbapp. */ @@ -85,71 +85,74 @@ export class GBBasicPackage implements IGBPackage { public sysPackages: IGBPackage[]; public CurrentEngineName = 'guaribas-1.0.0'; - public async loadPackage (core: IGBCoreService, sequelize: Sequelize): Promise { + public async loadPackage(core: IGBCoreService, sequelize: Sequelize): Promise { core.sequelize.addModels([GuaribasSchedule]); - - const dk = new DialogKeywords(); - const wa = new WebAutomationServices(); - const sys = new SystemKeywords(); - const dbg = new DebuggerService(); - const img = new ImageProcessingServices(); - -// remote id is required for assigning separate HTTP requests to a single session -function getRemoteId(ctx: Koa.Context) { - return "1" // share a single session for now, real impl could use cookies or some other meaning for HTTP sessions -} - - - - - - GBServer.globals.server.dk = createRpcServer(dk, createKoaHttpServer(5555, getRemoteId),{ - listeners: { - unsubscribed(subscriptions: number): void {}, - subscribed(subscriptions: number): void {}, - disconnected(remoteId: string, connections: number): void { - console.log(`Client ${remoteId} disconnected`) - }, - connected(remoteId: string, connections: number): void { - console.log(`New client ${remoteId} connected`) - }, - messageIn(...params): void { - console.log("IN ", params) - }, - messageOut(...params): void { - console.log("OUT ", params) - }, - }, - pingSendTimeout: null, - keepAliveTimeout: null, - }) - - console.log("RPC Server started at ws://localhost:5555") - - // GBServer.globals.wa = createRpcServer(wa, createWebsocketServer({port: 1112})); - // GBServer.globals.sys = createRpcServer(sys, createWebsocketServer({port: 1113})); - // GBServer.globals.dbg = createRpcServer(dbg, createWebsocketServer({port: 1114})); - // GBServer.globals.img = createRpcServer(img, createWebsocketServer({port: 1115})); } - public async getDialogs (min: GBMinInstance) { + public async getDialogs(min: GBMinInstance) { GBLog.verbose(`getDialogs called.`); } - public async unloadPackage (core: IGBCoreService): Promise { + public async unloadPackage(core: IGBCoreService): Promise { GBLog.verbose(`unloadPackage called.`); } - public async unloadBot (min: GBMinInstance): Promise { + public async unloadBot(min: GBMinInstance): Promise { GBLog.verbose(`unloadBot called.`); } - public async onNewSession (min: GBMinInstance, step: GBDialogStep): Promise { + public async onNewSession(min: GBMinInstance, step: GBDialogStep): Promise { GBLog.verbose(`onNewSession called.`); } - public async onExchangeData (min: GBMinInstance, kind: string, data: any) { + public async onExchangeData(min: GBMinInstance, kind: string, data: any) { GBLog.verbose(`onExchangeData called.`); } - public async loadBot (min: GBMinInstance): Promise { - + public async loadBot(min: GBMinInstance): Promise { const botId = min.botId; + + const opts = { + pingSendTimeout: null, + keepAliveTimeout: null, + listeners: { + unsubscribed(subscriptions: number): void {}, + subscribed(subscriptions: number): void {}, + disconnected(remoteId: string, connections: number): void { + GBLogEx.info(min, `[GBAPI]: New client ${remoteId} disconnected`); + }, + connected(remoteId: string, connections: number): void { + GBLogEx.info(min, `[GBAPI]: New client ${remoteId} connected`); + }, + messageIn(...params): void { + GBLogEx.info(min, '[GBAPI]: IN ' + params); + }, + messageOut(...params): void { + GBLogEx.info(min, '[GBAPI]: OUT ' + params); + } + } + }; + + function getRemoteId(ctx: Koa.Context) { + return '1'; // share a single session for now, real impl could use cookies or some other meaning for HTTP sessions + } + let instances: IGBInstance[]; + instances = await min.core.loadInstances(); + let proxies = {}; + await CollectionUtil.asyncForEach(instances, async instance => { + const proxy = { + dk: new DialogKeywords(), + wa: new WebAutomationServices(), + sys: new SystemKeywords(), + dbg: new DebuggerService(), + img: new ImageProcessingServices() + }; + proxies[instance.botId] = proxy; + }); + + GBServer.globals.server.dk = createRpcServer( + proxies, + createKoaHttpServer(GBVMService.API_PORT, getRemoteId, { prefix: `api/v3` }), + opts + ); + + GBLogEx.info(min, '[GBAPI] RPC HTTP Server started at http://localhost:' + GBVMService.API_PORT); + GBServer.globals.debuggers[botId] = {}; GBServer.globals.debuggers[botId].state = 0; GBServer.globals.debuggers[botId].breaks = []; @@ -158,6 +161,5 @@ function getRemoteId(ctx: Koa.Context) { GBServer.globals.debuggers[botId].client = null; GBServer.globals.debuggers[botId].conversationsMap = {}; GBServer.globals.debuggers[botId].watermarkMap = {}; - } } diff --git a/packages/basic.gblib/services/DialogKeywords.ts b/packages/basic.gblib/services/DialogKeywords.ts index 99c836cd2..19d4092ca 100644 --- a/packages/basic.gblib/services/DialogKeywords.ts +++ b/packages/basic.gblib/services/DialogKeywords.ts @@ -695,7 +695,7 @@ export class DialogKeywords { * @example HEAR name * */ - public async getHear({ pid, kind, arg }) { + public async hear({ pid, kind, arg }) { let { min, user, params } = await DialogKeywords.getProcessInfo(pid); // Handles first arg as an array of args. @@ -828,7 +828,7 @@ export class DialogKeywords { if (result === null) { await this.talk({ pid, text: `Escolha por favor um dos itens sugeridos.` }); - return await this.getHear({ pid, kind, arg }); + return await this.hear({ pid, kind, arg }); } } else if (kind === 'file') { @@ -851,7 +851,7 @@ export class DialogKeywords { if (value === null) { await this.talk({ pid, text: 'Por favor, digite um e-mail válido.' }); - return await this.getHear({ pid, kind, arg }); + return await this.hear({ pid, kind, arg }); } result = value; @@ -864,7 +864,7 @@ export class DialogKeywords { if (value === null || value.length != 1) { await this.talk({ pid, text: 'Por favor, digite um nome válido.' }); - return await this.getHear({ pid, kind, arg }); + return await this.hear({ pid, kind, arg }); } result = value; @@ -877,7 +877,7 @@ export class DialogKeywords { if (value === null || value.length != 1) { await this.talk({ pid, text: 'Por favor, digite um número válido.' }); - return await this.getHear({ pid, kind, arg }); + return await this.hear({ pid, kind, arg }); } result = value; @@ -892,7 +892,7 @@ export class DialogKeywords { if (value === null || value.length != 1) { await this.talk({ pid, text: 'Por favor, digite uma data no formato 12/12/2020.' }); - return await this.getHear({ pid, kind, arg }); + return await this.hear({ pid, kind, arg }); } result = value; @@ -905,7 +905,7 @@ export class DialogKeywords { if (value === null || value.length != 1) { await this.talk({ pid, text: 'Por favor, digite um horário no formato hh:ss.' }); - return await this.getHear({ pid, kind, arg }); + return await this.hear({ pid, kind, arg }); } result = value; @@ -924,7 +924,7 @@ export class DialogKeywords { if (value === null || value.length != 1) { await this.talk({ pid, text: 'Por favor, digite um valor monetário.' }); - return await this.getHear({ pid, kind, arg }); + return await this.hear({ pid, kind, arg }); } result = value; @@ -937,18 +937,18 @@ export class DialogKeywords { } catch (error) { await this.talk({ pid, text: Messages[locale].validation_enter_valid_mobile }); - return await this.getHear({ pid, kind, arg }); + return await this.hear({ pid, kind, arg }); } if (!phoneUtil.isPossibleNumber(phoneNumber)) { await this.talk({ pid, text: 'Por favor, digite um número de telefone válido.' }); - return await this.getHear({ pid, kind, arg }); + return await this.hear({ pid, kind, arg }); } result = phoneNumber; } else if (kind === 'qr-scanner'){ //https://github.com/GeneralBots/BotServer/issues/171 GBLog.info(`BASIC (${min.botId}): Upload done for ${answer.filename}.`); - const handle = WebAutomationServices.cyrb53(this.min.botId + answer.filename); + const handle = WebAutomationServices.cyrb53(min.botId + answer.filename); GBServer.globals.files[handle] = answer; QrScanner.scanImage(GBServer.globals.files[handle]).then(result => console.log(result)).catch(error => console.log(error || 'no QR code found.')); @@ -968,7 +968,7 @@ export class DialogKeywords { if (value === null || value.length != 1) { await this.talk({ pid, text: 'Por favor, digite um CEP válido.' }); - return await this.getHear({ pid, kind, arg }); + return await this.hear({ pid, kind, arg }); } result = value[0]; @@ -983,7 +983,7 @@ export class DialogKeywords { if (result === null) { await this.talk({ pid, text: `Escolha por favor um dos itens sugeridos.` }); - return await this.getHear({ pid, kind, arg }); + return await this.hear({ pid, kind, arg }); } } else if (kind === 'language') { result = null; @@ -1015,7 +1015,7 @@ export class DialogKeywords { if (result === null) { await this.talk({ pid, text: `Escolha por favor um dos itens sugeridos.` }); - return await this.getHear({ pid, kind, arg }); + return await this.hear({ pid, kind, arg }); } } return result; @@ -1077,7 +1077,7 @@ export class DialogKeywords { const { min, user } = await DialogKeywords.getProcessInfo(pid); if (user) { - // TODO: const translate = this.user ? this.user.basicOptions.translatorOn : false; + // TODO: const translate = user ? user.basicOptions.translatorOn : false; await min.conversationalService['sendOnConversation'](min, user, text); } diff --git a/packages/basic.gblib/services/GBVMService.ts b/packages/basic.gblib/services/GBVMService.ts index 04cb7a819..25bc9745e 100644 --- a/packages/basic.gblib/services/GBVMService.ts +++ b/packages/basic.gblib/services/GBVMService.ts @@ -63,6 +63,7 @@ import { SystemKeywords } from './SystemKeywords.js'; */ export class GBVMService extends GBService { private static DEBUGGER_PORT = 9222; + public static API_PORT = 1111; public async loadDialogPackage(folder: string, min: GBMinInstance, core: IGBCoreService, deployer: GBDeployer) { const files = await walkPromise(folder); @@ -125,7 +126,8 @@ export class GBVMService extends GBService { "encoding": "0.1.13", "isomorphic-fetch": "3.0.0", "punycode": "2.1.1", - "typescript-rest-rpc": "1.0.10", + "@push-rpc/core": "1.1.5", + "@push-rpc/http": "1.1.5", "vm2": "3.9.11" } }`; @@ -199,17 +201,26 @@ export class GBVMService extends GBService { code = ` return (async () => { - require('isomorphic-fetch'); - const rest = require('typescript-rest-rpc/lib/client'); - // Interprocess communication from local HTTP to the BotServer. + // Imports npm packages for this .gbdialog conversational application. + + require('isomorphic-fetch'); + const createRpcClient = require("@push-rpc/core").createRpcClient; + const createHttpClient = require("@push-rpc/http").createHttpClient; - const dk = rest.createClient('http://localhost:1111/api/v2/${min.botId}/dialog'); - const sys = rest.createClient('http://localhost:1111/api/v2/${min.botId}/system'); - const wa = rest.createClient('http://localhost:1111/api/v2/${min.botId}/webautomation'); - const img = rest.createClient('http://localhost:1111/api/v2/${min.botId}/imagprocessing'); - - // Local variables. + // Setups interprocess communication from .gbdialog run-time to the BotServer API. + + let url; + url = 'http://localhost:${GBVMService.API_PORT}/api/v3/${min.botId}/dk'; + const dk = (await createRpcClient(0, async () => createHttpClient(url))).remote; + url = 'http://localhost:${GBVMService.API_PORT}/api/v3/${min.botId}/sys'; + const sys = (await createRpcClient(0, async () => createHttpClient(url))).remote; + url = 'http://localhost:${GBVMService.API_PORT}/api/v3/${min.botId}/wa'; + const wa = (await createRpcClient(0, async () => createHttpClient(url))).remote; + url = 'http://localhost:${GBVMService.API_PORT}/api/v3/${min.botId}/img'; + const img = (await createRpcClient(0, async () => createHttpClient(url))).remote; + + // Unmarshalls Local variables from server VM. let pid = this.pid; let id = this.id; @@ -228,14 +239,12 @@ export class GBVMService extends GBService { global[i] = this.variables[i]; } - debugger; - - // Local functions. + // Defines local utility BASIC functions. const ubound = (array) => {return array.length}; const isarray = (array) => {return Array.isArray(array) }; - // Remote functions. + // Proxies remote functions as BASIC functions. const weekday = (v) => { return (async () => { return await dk.getWeekFromDate({v}) })(); }; const hour = (v) => { return (async () => { return await dk.getHourFromDate({v}) })(); }; @@ -423,7 +432,7 @@ export class GBVMService extends GBService { min: 0, max: 0, debug: debug, - debuggerPort: GBVMService.DEBUGGER_PORT, + debuggerport: GBVMService.DEBUGGER_PORT, botId: botId, cpu: 100, memory: 50000, diff --git a/packages/basic.gblib/services/KeywordsExpressions.ts b/packages/basic.gblib/services/KeywordsExpressions.ts index 7fe81be8f..2e20a01c6 100644 --- a/packages/basic.gblib/services/KeywordsExpressions.ts +++ b/packages/basic.gblib/services/KeywordsExpressions.ts @@ -173,112 +173,112 @@ export class KeywordsExpressions { keywords[i++] = [ /^\s*hear (\w+) as (\w+( \w+)*.xlsx)/gim, ($0, $1, $2) => { - return `${$1} = await dk.getHear({pid: pid, kind:"sheet", arg: "${$2}"})`; + return `${$1} = await dk.hear({pid: pid, kind:"sheet", arg: "${$2}"})`; } ]; keywords[i++] = [ /^\s*hear (\w+) as\s*login/gim, ($0, $1) => { - return `${$1} = await dk.getHear({pid: pid, kind:"login"})`; + return `${$1} = await dk.hear({pid: pid, kind:"login"})`; } ]; keywords[i++] = [ /^\s*hear (\w+) as\s*email/gim, ($0, $1) => { - return `${$1} = await dk.getHear({pid: pid, kind:"email"})`; + return `${$1} = await dk.hear({pid: pid, kind:"email"})`; } ]; keywords[i++] = [ /^\s*hear (\w+) as\s*integer/gim, ($0, $1) => { - return `${$1} = await dk.getHear({pid: pid, kind:"integer"})`; + return `${$1} = await dk.hear({pid: pid, kind:"integer"})`; } ]; keywords[i++] = [ /^\s*hear (\w+) as\s*file/gim, ($0, $1) => { - return `${$1} = await dk.getHear({pid: pid, kind:"file"})`; + return `${$1} = await dk.hear({pid: pid, kind:"file"})`; } ]; keywords[i++] = [ /^\s*hear (\w+) as\s*boolean/gim, ($0, $1) => { - return `${$1} = await dk.getHear({pid: pid, kind:"boolean"})`; + return `${$1} = await dk.hear({pid: pid, kind:"boolean"})`; } ]; keywords[i++] = [ /^\s*hear (\w+) as\s*name/gim, ($0, $1) => { - return `${$1} = await dk.getHear({pid: pid, kind:"name"})`; + return `${$1} = await dk.hear({pid: pid, kind:"name"})`; } ]; keywords[i++] = [ /^\s*hear (\w+) as\s*date/gim, ($0, $1) => { - return `${$1} = await dk.getHear({pid: pid, kind:"date"})`; + return `${$1} = await dk.hear({pid: pid, kind:"date"})`; } ]; keywords[i++] = [ /^\s*hear (\w+) as\s*hour/gim, ($0, $1) => { - return `${$1} = await dk.getHear({pid: pid, kind:"hour"})`; + return `${$1} = await dk.hear({pid: pid, kind:"hour"})`; } ]; keywords[i++] = [ /^\s*hear (\w+) as\s*phone/gim, ($0, $1) => { - return `${$1} = await dk.getHear({pid: pid, kind:"phone"})`; + return `${$1} = await dk.hear({pid: pid, kind:"phone"})`; } ]; keywords[i++] = [ /^\s*hear (\w+) as\s*money/gim, ($0, $1) => { - return `${$1} = await dk.getHear({pid: pid, kind:"money")}`; + return `${$1} = await dk.hear({pid: pid, kind:"money")}`; } ]; keywords[i++] = [ /^\s*hear (\w+) as\s*qrcode/gim, ($0, $1) => { - return `${$1} = await dk.getHear({pid: pid, kind:"qrcode")}`; + return `${$1} = await dk.hear({pid: pid, kind:"qrcode")}`; } ]; keywords[i++] = [ /^\s*hear (\w+) as\s*language/gim, ($0, $1) => { - return `${$1} = await dk.getHear({pid: pid, kind:"language")}`; + return `${$1} = await dk.hear({pid: pid, kind:"language")}`; } ]; keywords[i++] = [ /^\s*hear (\w+) as\s*zipcode/gim, ($0, $1) => { - return `${$1} = await dk.getHear({pid: pid, kind:"zipcode")}`; + return `${$1} = await dk.hear({pid: pid, kind:"zipcode")}`; } ]; keywords[i++] = [ /^\s*hear (\w+) as\s*(.*)/gim, ($0, $1, $2) => { - return `${$1} = await dk.getHear({pid: pid, kind:"menu", args: [${$2}]})`; + return `${$1} = await dk.hear({pid: pid, kind:"menu", args: [${$2}]})`; } ]; keywords[i++] = [ /^\s*(hear)\s*(\w+)/gim, ($0, $1, $2) => { - return `${$2} = await dk.getHear({pid: pid})`; + return `${$2} = await dk.hear({pid: pid})`; } ]; @@ -604,7 +604,7 @@ export class KeywordsExpressions { if ($3.substr(0, 1) !== '"') { $3 = `"${$3}"`; } - return `await dk.getTalk ({pid: pid, text: ${$3}})`; + return `await dk.talk ({pid: pid, text: ${$3}})`; } ];