From b7ac946fe7778c4bc65164d90a49bdbb4ddeed11 Mon Sep 17 00:00:00 2001 From: Rodrigo Rodriguez Date: Sat, 16 Sep 2023 17:41:36 -0300 Subject: [PATCH] fix(kb.gbapp): API after new Bot #370. --- packages/basic.gblib/index.ts | 2 +- packages/core.gbapp/services/GBDeployer.ts | 1 + packages/core.gbapp/services/GBMinService.ts | 190 +++++++++++-------- src/RootData.ts | 1 + 4 files changed, 113 insertions(+), 81 deletions(-) diff --git a/packages/basic.gblib/index.ts b/packages/basic.gblib/index.ts index 78bad742..b9aae1b0 100644 --- a/packages/basic.gblib/index.ts +++ b/packages/basic.gblib/index.ts @@ -60,7 +60,7 @@ export function createKoaHttpServer( app.use(koaBody.koaBody({ multipart: true })); app.use(middleware); const server = app.listen(port); - const SERVER_TIMEOUT = 60 * 60 * 24 * 1000; // Equals to client RPC set . + const SERVER_TIMEOUT = 60 * 60 * 24 * 1000; // Equals to client RPC set. server.timeout = SERVER_TIMEOUT; return { diff --git a/packages/core.gbapp/services/GBDeployer.ts b/packages/core.gbapp/services/GBDeployer.ts index 7c552bc8..85e301a0 100644 --- a/packages/core.gbapp/services/GBDeployer.ts +++ b/packages/core.gbapp/services/GBDeployer.ts @@ -310,6 +310,7 @@ export class GBDeployer implements IGBDeployer { // Makes available bot to the channels and .gbui interfaces. await GBServer.globals.minService.mountBot(instance); + await GBServer.globals.minService.ensureAPI(); } // Saves final instance object and returns it. diff --git a/packages/core.gbapp/services/GBMinService.ts b/packages/core.gbapp/services/GBMinService.ts index ee3fbb13..d261b060 100644 --- a/packages/core.gbapp/services/GBMinService.ts +++ b/packages/core.gbapp/services/GBMinService.ts @@ -148,6 +148,11 @@ export class GBMinService { this.deployer = deployer; } + + public async enableAPI(min: GBMinInstance) { + + } + /** * Constructs a new minimal instance for each bot. */ @@ -167,51 +172,10 @@ export class GBMinService { GBServer.globals.server.get('/instances/:botId', this.handleGetInstanceForClient.bind(this)); } - - 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 - } - - GBLogEx.info(0, 'Loading General Bots API...'); - - 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; - }); - - const opts = { - pingSendTimeout: null, - keepAliveTimeout: null, - listeners: { - unsubscribed(subscriptions: number): void {}, - subscribed(subscriptions: number): void {}, - disconnected(remoteId: string, connections: number): void {}, - connected(remoteId: string, connections: number): void {}, - messageIn(...params): void { - params.shift(); - GBLogEx.verbose(0, '[IN] ' + params); - }, - messageOut(...params): void { - params.shift(); - GBLogEx.verbose(0, '[OUT] ' + params); - } - } - }; - - GBServer.globals.server.dk = createRpcServer( - proxies, - createKoaHttpServer(GBVMService.API_PORT, getRemoteId, { prefix: `api/v3` }), - opts - ); - + await this.ensureAPI(); + // Calls mountBot event to all bots. + let i = 1; if (instances.length > 1) { @@ -292,7 +256,7 @@ export class GBMinService { /** * Unmounts the bot web site (default.gbui) secure domain, if any. */ - public async unloadDomain(instance: IGBInstance) {} + public async unloadDomain(instance: IGBInstance) { } /** * Mount the instance by creating an BOT Framework bot object, @@ -579,9 +543,8 @@ export class GBMinService { min.instance.authenticatorTenant, '/oauth2/authorize' ); - authorizationUrl = `${authorizationUrl}?response_type=code&client_id=${ - min.instance.marketplaceId - }&redirect_uri=${urlJoin(process.env.BOT_URL, min.instance.botId, 'token')}`; + authorizationUrl = `${authorizationUrl}?response_type=code&client_id=${min.instance.marketplaceId + }&redirect_uri=${urlJoin(process.env.BOT_URL, min.instance.botId, 'token')}`; GBLog.info(`HandleOAuthRequests: ${authorizationUrl}.`); res.redirect(authorizationUrl); }); @@ -769,14 +732,14 @@ export class GBMinService { } const group = min.core.getParam(min.instance, 'WhatsApp Group ID', null); - + WhatsappDirectLine.botGroups[min.botId] = group; - + const minBoot = GBServer.globals.minBoot as any; - + // If there is WhatsApp configuration specified, initialize // infrastructure objects. - + if (min.instance.whatsappServiceKey) { min.whatsAppDirectLine = new WhatsappDirectLine( min, @@ -799,23 +762,23 @@ export class GBMinService { minBoot.instance.whatsappServiceNumber, minBoot.instance.whatsappServiceUrl, group - ); - await min.whatsAppDirectLine.setup(false); - } + ); + await min.whatsAppDirectLine.setup(false); } - - // Builds bot numbers map in WhatsAppDirectLine globals. + } - let botNumber = min.core.getParam(min.instance, 'Bot Number', null); - if (botNumber){ - WhatsappDirectLine.botsByNumber[botNumber] = min.whatsAppDirectLine; - } + // Builds bot numbers map in WhatsAppDirectLine globals. + + let botNumber = min.core.getParam(min.instance, 'Bot Number', null); + if (botNumber) { + WhatsappDirectLine.botsByNumber[botNumber] = min.whatsAppDirectLine; + } + + // Setups default BOT Framework dialogs. - // Setups default BOT Framework dialogs. - min.userProfile = conversationState.createProperty('userProfile'); const dialogState = conversationState.createProperty('dialogState'); - + min.dialogs = new DialogSet(dialogState); min.dialogs.add(new TextPrompt('textPrompt')); min.dialogs.add(new AttachmentPrompt('attachmentPrompt')); @@ -919,7 +882,7 @@ export class GBMinService { const step = await min.dialogs.createContext(context); step.context.activity.locale = 'pt-BR'; - + const member = context.activity.from; const sec = new SecService(); const user = await sec.ensureUser(instance.instanceId, member.id, member.name, '', 'web', member.name, null); @@ -947,7 +910,7 @@ export class GBMinService { await sec.setParam(userId, 'wholeWord', true); await sec.setParam(userId, 'theme', 'white'); await sec.setParam(userId, 'maxColumns', 40); - + // This same event is dispatched either to all participants // including the bot, that is filtered bellow. @@ -1077,9 +1040,8 @@ export class GBMinService { await this.processEventActivity(min, user, context, step); } } catch (error) { - const msg = `ERROR: ${error.message} ${error.stack} ${error.error ? error.error.body : ''} ${ - error.error ? (error.error.stack ? error.error.stack : '') : '' - }`; + const msg = `ERROR: ${error.message} ${error.stack} ${error.error ? error.error.body : ''} ${error.error ? (error.error.stack ? error.error.stack : '') : '' + }`; GBLog.error(msg); await min.conversationalService.sendText( @@ -1184,8 +1146,7 @@ export class GBMinService { return utterance.match(Messages.global_quit); } - private async handleUploads(min, step, user, params, autoSave) - { + private async handleUploads(min, step, user, params, autoSave) { // Prepare Promises to download each attachment and then execute each Promise. if ( @@ -1411,19 +1372,19 @@ export class GBMinService { } else { // Removes unwanted chars in input text. - + step.context.activity['originalText'] = context.activity.text; const text = await GBConversationalService.handleText(min, user, step, context.activity.text); step.context.activity['originalText'] step.context.activity['text'] = text; - - if (notes && text && text !== "") { + + if (notes && text && text !== "") { const sys = new SystemKeywords(); - await sys.note({pid, text}); + await sys.note({ pid, text }); await step.context.sendActivity('OK.'); return; - } + } // Checks for bad words on input text. @@ -1468,9 +1429,8 @@ export class GBMinService { try { await step.continueDialog(); } catch (error) { - const msg = `ERROR: ${error.message} ${error.stack} ${error.error ? error.error.body : ''} ${ - error.error ? (error.error.stack ? error.error.stack : '') : '' - }`; + const msg = `ERROR: ${error.message} ${error.stack} ${error.error ? error.error.body : ''} ${error.error ? (error.error.stack ? error.error.stack : '') : '' + }`; GBLog.error(msg); await min.conversationalService.sendText( min, @@ -1511,4 +1471,74 @@ export class GBMinService { } } } -} + + public async ensureAPI() { + + const instances = GBServer.globals.minInstances; + + + function getRemoteId(ctx: Koa.Context) { + return '1'; // Each bot has its own API. + } + + const close = async () => { + return new Promise(resolve => { + if (GBServer.globals.server.apiServer) { + GBServer.globals.server.apiServer.close( + cb => { + resolve(true); + GBLogEx.info(0, 'Reloading General Bots API...'); + } + ); + } + else{ + resolve(true); + GBLogEx.info(0, 'Loading General Bots API...'); + } + }); + }; + + await close(); + + 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; + }); + + const opts = { + pingSendTimeout: null, + keepAliveTimeout: null, + listeners: { + unsubscribed(subscriptions: number): void { }, + subscribed(subscriptions: number): void { }, + disconnected(remoteId: string, connections: number): void { }, + connected(remoteId: string, connections: number): void { }, + messageIn(...params): void { + params.shift(); + GBLogEx.verbose(0, '[IN] ' + params); + }, + messageOut(...params): void { + params.shift(); + GBLogEx.verbose(0, '[OUT] ' + params); + } + } + }; + + GBServer.globals.server.apiServer = createKoaHttpServer(GBVMService.API_PORT, getRemoteId, { prefix: `api/v3` }); + + createRpcServer( + proxies, + GBServer.globals.server.apiServer, + opts + ); + + } + +} \ No newline at end of file diff --git a/src/RootData.ts b/src/RootData.ts index f0737579..a886ff0e 100644 --- a/src/RootData.ts +++ b/src/RootData.ts @@ -48,6 +48,7 @@ export class RootData { public publicAddress: string; // URI for BotServer. public server: any; // Express reference. public httpsServer: any; // Express reference (HTTPS). + public apiServer: any; // Koa reference (HTTPS) for GB API (isolated from /). public sysPackages: any[]; // Loaded system package list. public appPackages: any[]; // Loaded .gbapp package list. public minService: GBMinService; // Minimalist service core.