fix(all): Fixes in production.
This commit is contained in:
parent
3e68858bb0
commit
56b687792b
15 changed files with 213 additions and 161 deletions
1
.vscode/launch.json
vendored
1
.vscode/launch.json
vendored
|
@ -15,6 +15,7 @@
|
||||||
"args": [
|
"args": [
|
||||||
"--no-deprecation",
|
"--no-deprecation",
|
||||||
"--loader ts-node/esm",
|
"--loader ts-node/esm",
|
||||||
|
"--openssl-legacy-provider",
|
||||||
"--require ${workspaceRoot}/suppress-node-warnings.cjs",
|
"--require ${workspaceRoot}/suppress-node-warnings.cjs",
|
||||||
],
|
],
|
||||||
"skipFiles": [
|
"skipFiles": [
|
||||||
|
|
0
gbot.sh
Executable file → Normal file
0
gbot.sh
Executable file → Normal file
|
@ -144,6 +144,7 @@
|
||||||
"punycode": "2.1.1",
|
"punycode": "2.1.1",
|
||||||
"puppeteer": "19.6.3",
|
"puppeteer": "19.6.3",
|
||||||
"puppeteer-extra": "3.3.4",
|
"puppeteer-extra": "3.3.4",
|
||||||
|
"puppeteer-extra-plugin-minmax": "1.1.2",
|
||||||
"puppeteer-extra-plugin-stealth": "2.11.1",
|
"puppeteer-extra-plugin-stealth": "2.11.1",
|
||||||
"qr-scanner": "1.4.2",
|
"qr-scanner": "1.4.2",
|
||||||
"qrcode": "1.5.1",
|
"qrcode": "1.5.1",
|
||||||
|
|
|
@ -109,50 +109,7 @@ export class GBBasicPackage implements IGBPackage {
|
||||||
}
|
}
|
||||||
public async loadBot(min: GBMinInstance): Promise<void> {
|
public async loadBot(min: GBMinInstance): Promise<void> {
|
||||||
const botId = min.botId;
|
const botId = min.botId;
|
||||||
|
GBServer.globals.debuggers[botId] = {};
|
||||||
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 {
|
|
||||||
GBLogEx.info(min, '[IN] ' + params);
|
|
||||||
},
|
|
||||||
messageOut(...params): void {
|
|
||||||
GBLogEx.info(min, '[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, 'API RPC HTTP Server started at http://localhost:' + GBVMService.API_PORT);
|
|
||||||
|
|
||||||
GBServer.globals.debuggers[botId] = {};
|
|
||||||
GBServer.globals.debuggers[botId].state = 0;
|
GBServer.globals.debuggers[botId].state = 0;
|
||||||
GBServer.globals.debuggers[botId].breaks = [];
|
GBServer.globals.debuggers[botId].breaks = [];
|
||||||
GBServer.globals.debuggers[botId].stateInfo = 'Stopped';
|
GBServer.globals.debuggers[botId].stateInfo = 'Stopped';
|
||||||
|
|
|
@ -551,9 +551,9 @@ export class DialogKeywords {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async setOption({ pid, name, value }) {
|
private async setOption({ pid, name, value }) {
|
||||||
if (this.isUserSystemParam(name)) {
|
// if (this.isUserSystemParam(name)) {
|
||||||
throw new Error(`Not possible to define ${name} as it is a reserved system param name.`);
|
// throw new Error(`Not possible to define ${name} as it is a reserved system param name.`);
|
||||||
}
|
// }
|
||||||
let { min, user, params } = await DialogKeywords.getProcessInfo(pid);
|
let { min, user, params } = await DialogKeywords.getProcessInfo(pid);
|
||||||
const sec = new SecService();
|
const sec = new SecService();
|
||||||
await sec.setParam(user.userId, name, value);
|
await sec.setParam(user.userId, name, value);
|
||||||
|
|
|
@ -297,11 +297,12 @@ export class GBVMService extends GBService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static normalizeQuotes(text: any) {
|
public static normalizeQuotes(text: any) {
|
||||||
text = text.replace('¨', '"');
|
text = text.replace(/\¨/gm, '"');
|
||||||
text = text.replace('“', '"');
|
text = text.replace(/\“/gm, '"');
|
||||||
text = text.replace('”', '"');
|
text = text.replace(/\”/gm, '"');
|
||||||
text = text.replace('‘', "'");
|
text = text.replace(/\‘/gm, "'");
|
||||||
text = text.replace('’', "'");
|
text = text.replace(/\’/gm, "'");
|
||||||
|
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,8 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
import { GBVMService } from "./GBVMService.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Image processing services of conversation to be called by BASIC.
|
* Image processing services of conversation to be called by BASIC.
|
||||||
*/
|
*/
|
||||||
|
@ -292,9 +294,9 @@ export class KeywordsExpressions {
|
||||||
keywords[i++] = [
|
keywords[i++] = [
|
||||||
/^\s*((?:[a-z]+.?)(?:(?:\w+).)(?:\w+)*)\s*=\s*find\s*(.*)\s*or talk\s*(.*)/gim,
|
/^\s*((?:[a-z]+.?)(?:(?:\w+).)(?:\w+)*)\s*=\s*find\s*(.*)\s*or talk\s*(.*)/gim,
|
||||||
($0, $1, $2, $3) => {
|
($0, $1, $2, $3) => {
|
||||||
return `${$1} = await sys.find({pid: pid, handle: page, args:[${$2}])\n
|
return `${$1} = await sys.find({pid: pid, handle: page, args:[${$2}]})\n
|
||||||
if (!${$1}) {s
|
if (!${$1}) {
|
||||||
await dk.talk ({pid: pid, ${$3}})\n;
|
await dk.talk ({pid: pid, text: ${$3}})\n;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -601,7 +603,12 @@ export class KeywordsExpressions {
|
||||||
keywords[i++] = [
|
keywords[i++] = [
|
||||||
/^\s*(talk)(\s*)(.*)/gim,
|
/^\s*(talk)(\s*)(.*)/gim,
|
||||||
($0, $1, $2, $3) => {
|
($0, $1, $2, $3) => {
|
||||||
if ($3.substr(0, 1) !== '"') {
|
$3 = GBVMService.normalizeQuotes($3);
|
||||||
|
|
||||||
|
// Uses auto quote if this is a frase with more then one word.
|
||||||
|
|
||||||
|
if (/\s/.test($3) && $3.substr(0, 1) !== '"') {
|
||||||
|
|
||||||
$3 = `"${$3}"`;
|
$3 = `"${$3}"`;
|
||||||
}
|
}
|
||||||
return `await dk.talk ({pid: pid, text: ${$3}})`;
|
return `await dk.talk ({pid: pid, text: ${$3}})`;
|
||||||
|
@ -755,15 +762,19 @@ export class KeywordsExpressions {
|
||||||
];
|
];
|
||||||
|
|
||||||
keywords[i++] = [
|
keywords[i++] = [
|
||||||
/^\s*save\s*(.*)\s*as\s*(.*)/gim,
|
/^\s*save\s*(\w+)\s*as\s*(.*)/gim,
|
||||||
($0, $1, $2, $3) => {
|
($0, $1, $2, $3) => {
|
||||||
return `await sys.saveFile({pid: pid, file: ${$2}, data: ${$1}})`;
|
return `await sys.saveFile({pid: pid, file: ${$2}, data: ${$1}})`;
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
keywords[i++] = [
|
keywords[i++] = [
|
||||||
/^\s*(save)(\s*)(.*)/gim,
|
/^\s*(save)(\s*)(.*\.xlsx)(.*)/gim,
|
||||||
($0, $1, $2, $3) => {
|
($0, $1, $2, $3, $4) => {
|
||||||
return `await sys.save({pid: pid, args: [${$3}]})`;
|
$3 = $3.replace (/\'/g, "")
|
||||||
|
$3 = $3.replace (/\"/g, "")
|
||||||
|
$4 = $4.substr(2)
|
||||||
|
return `await sys.save({pid: pid,file: "${$3}" , args: [${$4}]})`;
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -236,6 +236,7 @@ export class SystemKeywords {
|
||||||
const gbaiName = DialogKeywords.getGBAIPath(min.botId);
|
const gbaiName = DialogKeywords.getGBAIPath(min.botId);
|
||||||
const browser = await GBSSR.createBrowser(null);
|
const browser = await GBSSR.createBrowser(null);
|
||||||
const page = await browser.newPage();
|
const page = await browser.newPage();
|
||||||
|
await page.minimize();
|
||||||
|
|
||||||
// Includes the associated CSS related to current theme.
|
// Includes the associated CSS related to current theme.
|
||||||
|
|
||||||
|
@ -544,7 +545,7 @@ export class SystemKeywords {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
data = GBServer.globals.files[data].data;
|
data = GBServer.globals.files[data].data; // TODO
|
||||||
await client.api(`${baseUrl}/drive/root:/${path}/${file}:/content`).put(data);
|
await client.api(`${baseUrl}/drive/root:/${path}/${file}:/content`).put(data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.code === 'itemNotFound') {
|
if (error.code === 'itemNotFound') {
|
||||||
|
@ -562,9 +563,8 @@ 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({ pid, args }): Promise<any> {
|
public async save({ pid,file, args }): Promise<any> {
|
||||||
const { min, user } = await DialogKeywords.getProcessInfo(pid);
|
const { min, user } = await DialogKeywords.getProcessInfo(pid);
|
||||||
const file = args[0];
|
|
||||||
args.shift();
|
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(min);
|
let { baseUrl, client } = await GBDeployer.internalGetDriveClient(min);
|
||||||
|
@ -589,7 +589,7 @@ export class SystemKeywords {
|
||||||
const address = `A2:${this.numberToLetters(args.length - 1)}2`;
|
const address = `A2:${this.numberToLetters(args.length - 1)}2`;
|
||||||
for (let index = 0; index < args.length; index++) {
|
for (let index = 0; index < args.length; index++) {
|
||||||
let value = args[index];
|
let value = args[index];
|
||||||
if (value && this.isValidDate(value)) {
|
if (value && await this.isValidDate({pid, dt:value})) {
|
||||||
value = `'${value}`;
|
value = `'${value}`;
|
||||||
}
|
}
|
||||||
body.values[0][index] = value;
|
body.values[0][index] = value;
|
||||||
|
@ -699,8 +699,8 @@ export class SystemKeywords {
|
||||||
|
|
||||||
// MAX LINES property.
|
// MAX LINES property.
|
||||||
|
|
||||||
let maxLines;
|
let maxLines = 5000;
|
||||||
if (user && params && params.maxLines) {
|
if (params && params.maxLines) {
|
||||||
if (params.maxLines.toString().toLowerCase() !== 'default') {
|
if (params.maxLines.toString().toLowerCase() !== 'default') {
|
||||||
maxLines = Number.parseInt(params.maxLines).valueOf();
|
maxLines = Number.parseInt(params.maxLines).valueOf();
|
||||||
}
|
}
|
||||||
|
@ -718,7 +718,7 @@ export class SystemKeywords {
|
||||||
page = WebAutomationServices.getPageByHandle(handle);
|
page = WebAutomationServices.getPageByHandle(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (page['$eval'] && WebAutomationServices.isSelector(file)) {
|
if (handle &&page['$eval'] && WebAutomationServices.isSelector(file)) {
|
||||||
const container = page['frame'] ? page['frame'] : page;
|
const container = page['frame'] ? page['frame'] : page;
|
||||||
const originalSelector = file;
|
const originalSelector = file;
|
||||||
|
|
||||||
|
@ -857,10 +857,10 @@ export class SystemKeywords {
|
||||||
|
|
||||||
if (this.isValidHour(filter.value)) {
|
if (this.isValidHour(filter.value)) {
|
||||||
filter.dataType = fixed ? fixed : 'hourInterval';
|
filter.dataType = fixed ? fixed : 'hourInterval';
|
||||||
} else if (this.isValidDate(filter.value)) {
|
} else if (await this.isValidDate({pid, dt: filter.value})) {
|
||||||
filter.value = SystemKeywords.getDateFromLocaleString(pid, filter.value, contentLocale);
|
filter.value = SystemKeywords.getDateFromLocaleString(pid, filter.value, contentLocale);
|
||||||
filter.dataType = fixed ? fixed : 'date';
|
filter.dataType = fixed ? fixed : 'date';
|
||||||
} else if (this.isValidNumber(filter.value)) {
|
} else if (await this.isValidNumber({pid, number: filter.value})) {
|
||||||
filter.value = Number.parseInt(filter.value);
|
filter.value = Number.parseInt(filter.value);
|
||||||
filter.dataType = fixed ? fixed : 'number';
|
filter.dataType = fixed ? fixed : 'number';
|
||||||
} else {
|
} else {
|
||||||
|
@ -893,7 +893,7 @@ export class SystemKeywords {
|
||||||
switch (filter.dataType) {
|
switch (filter.dataType) {
|
||||||
case 'string':
|
case 'string':
|
||||||
const v1 = GBConversationalService.removeDiacritics(result.toLowerCase().trim());
|
const v1 = GBConversationalService.removeDiacritics(result.toLowerCase().trim());
|
||||||
const v2 = GBConversationalService.removeDiacritics(filter.toLowerCase().trim());
|
const v2 = GBConversationalService.removeDiacritics(filter.value.toLowerCase().trim());
|
||||||
|
|
||||||
switch (filter.operator) {
|
switch (filter.operator) {
|
||||||
case '=':
|
case '=':
|
||||||
|
@ -1003,7 +1003,7 @@ export class SystemKeywords {
|
||||||
const propertyName = header[colIndex];
|
const propertyName = header[colIndex];
|
||||||
let value = xlRow[colIndex];
|
let value = xlRow[colIndex];
|
||||||
if (value && value.charAt(0) === "'") {
|
if (value && value.charAt(0) === "'") {
|
||||||
if (this.isValidDate(value.substr(1))) {
|
if (await this.isValidDate({pid, dt:value.substr(1)})) {
|
||||||
value = value.substr(1);
|
value = value.substr(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1650,7 +1650,7 @@ export class SystemKeywords {
|
||||||
const propertyName = header[colIndex];
|
const propertyName = header[colIndex];
|
||||||
let value = xlRow[colIndex];
|
let value = xlRow[colIndex];
|
||||||
if (value && value.charAt(0) === "'") {
|
if (value && value.charAt(0) === "'") {
|
||||||
if (this.isValidDate(value.substr(1))) {
|
if (await this.isValidDate({pid, dt:value.substr(1)})) {
|
||||||
value = value.substr(1);
|
value = value.substr(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1702,13 +1702,13 @@ export class SystemKeywords {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let args = [file];
|
let args = [];
|
||||||
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({ pid, args });
|
await this.save({ pid,file, args });
|
||||||
adds++;
|
adds++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,10 +43,10 @@ import * as en from 'dotenv-extended';
|
||||||
* Base configuration for the server like storage.
|
* Base configuration for the server like storage.
|
||||||
*/
|
*/
|
||||||
export class GBConfigService {
|
export class GBConfigService {
|
||||||
public static getBoolean (value: string): boolean {
|
public static getBoolean(value: string): boolean {
|
||||||
return (this.get(value) as unknown) as boolean;
|
return (this.get(value) as unknown) as boolean;
|
||||||
}
|
}
|
||||||
public static getServerPort (): string {
|
public static getServerPort(): string {
|
||||||
if (process.env.PORT) {
|
if (process.env.PORT) {
|
||||||
return process.env.PORT;
|
return process.env.PORT;
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ export class GBConfigService {
|
||||||
return '4242';
|
return '4242';
|
||||||
}
|
}
|
||||||
|
|
||||||
public static init (): any {
|
public static init(): any {
|
||||||
try {
|
try {
|
||||||
en.load({
|
en.load({
|
||||||
encoding: 'utf8',
|
encoding: 'utf8',
|
||||||
|
@ -78,7 +78,7 @@ export class GBConfigService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static get (key: string): string | undefined {
|
public static get(key: string): string | undefined {
|
||||||
let value = GBConfigService.tryGet(key);
|
let value = GBConfigService.tryGet(key);
|
||||||
|
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
|
@ -155,6 +155,9 @@ export class GBConfigService {
|
||||||
case 'ENABLE_SPELLING_CHECKER':
|
case 'ENABLE_SPELLING_CHECKER':
|
||||||
value = false;
|
value = false;
|
||||||
break;
|
break;
|
||||||
|
case 'DEV_GBAI':
|
||||||
|
value = undefined;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
GBLog.warn(`Invalid key on .env file: '${key}'`);
|
GBLog.warn(`Invalid key on .env file: '${key}'`);
|
||||||
break;
|
break;
|
||||||
|
@ -164,7 +167,7 @@ export class GBConfigService {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static tryGet (key: string): any {
|
public static tryGet(key: string): any {
|
||||||
let value = process.env[`container:${key}`];
|
let value = process.env[`container:${key}`];
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
value = process.env[key];
|
value = process.env[key];
|
||||||
|
|
|
@ -900,6 +900,7 @@ export class GBConversationalService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async translate(min: GBMinInstance, text: string, language: string): Promise<string> {
|
public async translate(min: GBMinInstance, text: string, language: string): Promise<string> {
|
||||||
|
|
||||||
const translatorEnabled = () => {
|
const translatorEnabled = () => {
|
||||||
if (min.instance.params) {
|
if (min.instance.params) {
|
||||||
const params = JSON.parse(min.instance.params);
|
const params = JSON.parse(min.instance.params);
|
||||||
|
|
|
@ -77,10 +77,11 @@ export class GBLogEx {
|
||||||
*/
|
*/
|
||||||
public static async log(instance: IGBInstance, kind: string, message: string): Promise<GuaribasLog> {
|
public static async log(instance: IGBInstance, kind: string, message: string): Promise<GuaribasLog> {
|
||||||
message = message ? message.substring(0, 1023) : null;
|
message = message ? message.substring(0, 1023) : null;
|
||||||
return await GuaribasLog.create(<GuaribasLog>{
|
// return await GuaribasLog.create(<GuaribasLog>{
|
||||||
instanceId: instance ? instance.instanceId : 1,
|
// instanceId: instance ? instance.instanceId : 1,
|
||||||
message: message,
|
// message: message,
|
||||||
kind: kind
|
// kind: kind
|
||||||
});
|
// });
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,11 @@ import mkdirp from 'mkdirp';
|
||||||
import Fs from 'fs';
|
import Fs from 'fs';
|
||||||
import arrayBufferToBuffer from 'arraybuffer-to-buffer';
|
import arrayBufferToBuffer from 'arraybuffer-to-buffer';
|
||||||
import { NlpManager } from 'node-nlp';
|
import { NlpManager } from 'node-nlp';
|
||||||
|
import Koa from 'koa';
|
||||||
|
import cors from '@koa/cors';
|
||||||
|
import { createRpcServer } from '@push-rpc/core';
|
||||||
|
import { createHttpKoaMiddleware } from '@push-rpc/http';
|
||||||
|
import { HttpServerOptions } from '@push-rpc/http/dist/server.js';
|
||||||
import {
|
import {
|
||||||
AutoSaveStateMiddleware,
|
AutoSaveStateMiddleware,
|
||||||
BotFrameworkAdapter,
|
BotFrameworkAdapter,
|
||||||
|
@ -88,6 +93,11 @@ import { SystemKeywords } from '../../basic.gblib/services/SystemKeywords.js';
|
||||||
import Path from 'path';
|
import Path from 'path';
|
||||||
import { GBSSR } from './GBSSR.js';
|
import { GBSSR } from './GBSSR.js';
|
||||||
import { DialogKeywords } from '../../basic.gblib/services/DialogKeywords.js';
|
import { DialogKeywords } from '../../basic.gblib/services/DialogKeywords.js';
|
||||||
|
import { GBLogEx } from './GBLogEx.js';
|
||||||
|
import { WebAutomationServices } from '../../basic.gblib/services/WebAutomationServices.js';
|
||||||
|
import { createKoaHttpServer } from '../../basic.gblib/index.js';
|
||||||
|
import { DebuggerService } from '../../basic.gblib/services/DebuggerService.js';
|
||||||
|
import { ImageProcessingServices } from '../../basic.gblib/services/ImageProcessingServices.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Minimal service layer for a bot and encapsulation of BOT Framework calls.
|
* Minimal service layer for a bot and encapsulation of BOT Framework calls.
|
||||||
|
@ -156,6 +166,7 @@ export class GBMinService {
|
||||||
// Calls mountBot event to all bots.
|
// Calls mountBot event to all bots.
|
||||||
let i = 1;
|
let i = 1;
|
||||||
|
|
||||||
|
|
||||||
if (instances.length > 1) {
|
if (instances.length > 1) {
|
||||||
this.bar1 = new cliProgress.SingleBar(
|
this.bar1 = new cliProgress.SingleBar(
|
||||||
{
|
{
|
||||||
|
@ -168,45 +179,65 @@ export class GBMinService {
|
||||||
this.bar1.start(instances.length, i, { botId: 'Boot' });
|
this.bar1.start(instances.length, i, { botId: 'Boot' });
|
||||||
}
|
}
|
||||||
|
|
||||||
const throttledPromiseAll = async promises => {
|
|
||||||
const MAX_IN_PROCESS = 20;
|
|
||||||
const results = new Array(promises.length);
|
|
||||||
|
|
||||||
async function doBlock(startIndex) {
|
await CollectionUtil.asyncForEach(instances, (async instance => {
|
||||||
// Shallow-copy a block of promises to work on
|
try {
|
||||||
const currBlock = promises.slice(startIndex, startIndex + MAX_IN_PROCESS);
|
await this['mountBot'](instance);
|
||||||
// Await the completion. If any fail, it will throw and that's good.
|
} catch (error) {
|
||||||
const blockResults = await Promise.all(currBlock);
|
GBLog.error(`Error mounting bot ${instance.botId}: ${error.message}\n${error.stack}`);
|
||||||
// Assuming all succeeded, copy the results into the results array
|
}
|
||||||
for (let ix = 0; ix < blockResults.length; ix++) {
|
finally {
|
||||||
results[ix + startIndex] = blockResults[ix];
|
if (this.bar1) {
|
||||||
|
this.bar1.update(i++, { botId: instance.botId });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}).bind(this));
|
||||||
|
|
||||||
for (let iBlock = 0; iBlock < promises.length; iBlock += MAX_IN_PROCESS) {
|
|
||||||
await doBlock(iBlock);
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
};
|
|
||||||
|
|
||||||
await throttledPromiseAll(
|
|
||||||
instances.map(
|
|
||||||
(async instance => {
|
|
||||||
try {
|
|
||||||
await this['mountBot'](instance);
|
|
||||||
|
|
||||||
if (this.bar1) {
|
|
||||||
this.bar1.update(i++, { botId: instance.botId });
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
GBLog.error(`Error mounting bot ${instance.botId}: ${error.message}\n${error.stack}`);
|
|
||||||
}
|
|
||||||
}).bind(this)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
if (this.bar1) {
|
if (this.bar1) {
|
||||||
this.bar1.stop();
|
this.bar1.stop();
|
||||||
}
|
}
|
||||||
|
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 {
|
||||||
|
GBLogEx.info(0, '[IN] ' + params);
|
||||||
|
},
|
||||||
|
messageOut(...params): void {
|
||||||
|
GBLogEx.info(0, '[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 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(0, 'API RPC HTTP Server started.');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// // Loads schedules.
|
// // Loads schedules.
|
||||||
// GBLog.info(`Preparing SET SCHEDULE dialog calls...`);
|
// GBLog.info(`Preparing SET SCHEDULE dialog calls...`);
|
||||||
|
@ -255,7 +286,7 @@ export class GBMinService {
|
||||||
/**
|
/**
|
||||||
* Unmounts the bot web site (default.gbui) secure domain, if any.
|
* 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,
|
* Mount the instance by creating an BOT Framework bot object,
|
||||||
|
@ -297,11 +328,11 @@ export class GBMinService {
|
||||||
if (Fs.existsSync(packagePath)) {
|
if (Fs.existsSync(packagePath)) {
|
||||||
await this.deployer['deployPackage2'](min, user, packagePath);
|
await this.deployer['deployPackage2'](min, user, packagePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
const gbai = DialogKeywords.getGBAIPath(min.botId);
|
const gbai = DialogKeywords.getGBAIPath(min.botId);
|
||||||
let dir = `work/${gbai}/cache`;
|
let dir = `work/${gbai}/cache`;
|
||||||
const botId = gbai.replace(/\.[^/.]+$/, "");
|
const botId = gbai.replace(/\.[^/.]+$/, "");
|
||||||
|
|
||||||
if (!Fs.existsSync(dir)) {
|
if (!Fs.existsSync(dir)) {
|
||||||
mkdirp.sync(dir);
|
mkdirp.sync(dir);
|
||||||
}
|
}
|
||||||
|
@ -332,7 +363,7 @@ export class GBMinService {
|
||||||
|
|
||||||
// Loads Named Entity data for this bot.
|
// Loads Named Entity data for this bot.
|
||||||
|
|
||||||
await KBService.RefreshNER(min);
|
// TODO: await KBService.RefreshNER(min);
|
||||||
|
|
||||||
// Calls the loadBot context.activity for all packages.
|
// Calls the loadBot context.activity for all packages.
|
||||||
|
|
||||||
|
@ -452,7 +483,7 @@ export class GBMinService {
|
||||||
|
|
||||||
if (min.whatsAppDirectLine != undefined && instance.whatsappServiceKey !== null) {
|
if (min.whatsAppDirectLine != undefined && instance.whatsappServiceKey !== null) {
|
||||||
if (!(await min.whatsAppDirectLine.check(min))) {
|
if (!(await min.whatsAppDirectLine.check(min))) {
|
||||||
const error = `WhatsApp API lost connection.`;
|
const error = `WhatsApp API lost connection for: ${min.botId}.`;
|
||||||
GBLog.error(error);
|
GBLog.error(error);
|
||||||
res.status(500).send(error);
|
res.status(500).send(error);
|
||||||
|
|
||||||
|
@ -532,9 +563,8 @@ export class GBMinService {
|
||||||
min.instance.authenticatorTenant,
|
min.instance.authenticatorTenant,
|
||||||
'/oauth2/authorize'
|
'/oauth2/authorize'
|
||||||
);
|
);
|
||||||
authorizationUrl = `${authorizationUrl}?response_type=code&client_id=${
|
authorizationUrl = `${authorizationUrl}?response_type=code&client_id=${min.instance.marketplaceId
|
||||||
min.instance.marketplaceId
|
}&redirect_uri=${urlJoin(min.instance.botEndpoint, min.instance.botId, 'token')}`;
|
||||||
}&redirect_uri=${urlJoin(min.instance.botEndpoint, min.instance.botId, 'token')}`;
|
|
||||||
GBLog.info(`HandleOAuthRequests: ${authorizationUrl}.`);
|
GBLog.info(`HandleOAuthRequests: ${authorizationUrl}.`);
|
||||||
res.redirect(authorizationUrl);
|
res.redirect(authorizationUrl);
|
||||||
});
|
});
|
||||||
|
@ -743,18 +773,16 @@ export class GBMinService {
|
||||||
await min.whatsAppDirectLine.setup(true);
|
await min.whatsAppDirectLine.setup(true);
|
||||||
} else {
|
} else {
|
||||||
const minBoot = GBServer.globals.minBoot as any;
|
const minBoot = GBServer.globals.minBoot as any;
|
||||||
if (minBoot.whatsappServiceKey) {
|
min.whatsAppDirectLine = new WhatsappDirectLine(
|
||||||
min.whatsAppDirectLine = new WhatsappDirectLine(
|
min,
|
||||||
min,
|
min.botId,
|
||||||
min.botId,
|
min.instance.whatsappBotKey,
|
||||||
min.instance.whatsappBotKey,
|
minBoot.instance.whatsappServiceKey,
|
||||||
minBoot.instance.whatsappServiceKey,
|
minBoot.instance.whatsappServiceNumber,
|
||||||
minBoot.instance.whatsappServiceNumber,
|
minBoot.instance.whatsappServiceUrl,
|
||||||
minBoot.instance.whatsappServiceUrl,
|
group
|
||||||
group
|
);
|
||||||
);
|
await min.whatsAppDirectLine.setup(false);
|
||||||
await min.whatsAppDirectLine.setup(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setups default BOT Framework dialogs.
|
// Setups default BOT Framework dialogs.
|
||||||
|
@ -853,7 +881,7 @@ export class GBMinService {
|
||||||
|
|
||||||
// Default activity processing and handler.
|
// Default activity processing and handler.
|
||||||
|
|
||||||
const handler = async context => {
|
const handler = async context => {
|
||||||
// Handle activity text issues.
|
// Handle activity text issues.
|
||||||
|
|
||||||
if (!context.activity.text) {
|
if (!context.activity.text) {
|
||||||
|
@ -1035,9 +1063,8 @@ export class GBMinService {
|
||||||
await this.processEventActivity(min, user, context, step);
|
await this.processEventActivity(min, user, context, step);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const msg = `ERROR: ${error.message} ${error.error ? error.error.body : ''} ${
|
const msg = `ERROR: ${error.message} ${error.error ? error.error.body : ''} ${error.error ? (error.error.stack ? error.error.stack : '') : ''
|
||||||
error.error ? (error.error.stack ? error.error.stack : '') : ''
|
}`;
|
||||||
}`;
|
|
||||||
GBLog.error(msg);
|
GBLog.error(msg);
|
||||||
|
|
||||||
await min.conversationalService.sendText(
|
await min.conversationalService.sendText(
|
||||||
|
@ -1053,7 +1080,7 @@ export class GBMinService {
|
||||||
try {
|
try {
|
||||||
await adapter['processActivity'](req, res, handler);
|
await adapter['processActivity'](req, res, handler);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.code === 401){
|
if (error.code === 401) {
|
||||||
GBLog.error('Calling processActivity due to Signing Key could not be retrieved error.');
|
GBLog.error('Calling processActivity due to Signing Key could not be retrieved error.');
|
||||||
await adapter['processActivity'](req, res, handler);
|
await adapter['processActivity'](req, res, handler);
|
||||||
}
|
}
|
||||||
|
|
|
@ -125,9 +125,11 @@ export class GBSSR {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static async createBrowser(profilePath): Promise<any> {
|
public static async createBrowser(profilePath): Promise<any> {
|
||||||
const opts = this.preparePuppeteer(profilePath);
|
const opts = this.preparePuppeteer(profilePath);
|
||||||
puppeteer.use(hidden());
|
puppeteer.use(hidden());
|
||||||
|
puppeteer.use(require("puppeteer-extra-plugin-minmax")());
|
||||||
const browser = await puppeteer.launch(opts);
|
const browser = await puppeteer.launch(opts);
|
||||||
return browser;
|
return browser;
|
||||||
}
|
}
|
||||||
|
@ -143,6 +145,8 @@ export class GBSSR {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const page = await browser.newPage();
|
const page = await browser.newPage();
|
||||||
|
await page.minimize();
|
||||||
|
|
||||||
await page.setUserAgent(
|
await page.setUserAgent(
|
||||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36'
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36'
|
||||||
);
|
);
|
||||||
|
@ -277,35 +281,61 @@ export class GBSSR {
|
||||||
req.originalUrl
|
req.originalUrl
|
||||||
);
|
);
|
||||||
|
|
||||||
// Reads from static HTML when a bot is crawling.
|
// Tries to find botId from URL.
|
||||||
|
|
||||||
const botId =
|
const minBoot = GBServer.globals.minInstances[0];
|
||||||
req.originalUrl || req.originalUrl === '/' ? req.originalUrl.substr(1) : GBServer.globals.minInstances[0].botId;
|
let botId =
|
||||||
|
req.originalUrl && req.originalUrl === '/' ?
|
||||||
|
minBoot.botId :
|
||||||
|
/\/([A-Za-z0-9\-\_]+)\/*/.exec(req.originalUrl)[1]
|
||||||
let min: GBMinInstance =
|
let min: GBMinInstance =
|
||||||
req.url === '/'
|
req.url === '/'
|
||||||
? GBServer.globals.minInstances[0]
|
? minBoot
|
||||||
: GBServer.globals.minInstances.filter(p => p.instance.botId === botId)[0];
|
: GBServer.globals.minInstances.filter(p => p.instance.botId.toLowerCase() === botId.toLowerCase())[0];
|
||||||
|
if (!min) {
|
||||||
|
min = req.url === '/'
|
||||||
|
? minBoot
|
||||||
|
: GBServer.globals.minInstances.filter(p => p.instance.activationCode.toLowerCase() === botId.toLowerCase())[0];
|
||||||
|
}
|
||||||
|
if (!min) {
|
||||||
|
botId = minBoot.botId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
let path = DialogKeywords.getGBAIPath(botId, `gbui`);
|
let path = DialogKeywords.getGBAIPath(botId, `gbui`);
|
||||||
|
|
||||||
|
// Checks if the bot has an .gbui published or use default.gbui.
|
||||||
|
|
||||||
|
if (!Fs.existsSync(path)) {
|
||||||
|
path = DialogKeywords.getGBAIPath(minBoot.botId, `gbui`);
|
||||||
|
}
|
||||||
|
const url = req.url.replace(`/${botId}`, '');
|
||||||
|
|
||||||
if (min && req.originalUrl && prerender && exclude) {
|
if (min && req.originalUrl && prerender && exclude) {
|
||||||
|
|
||||||
|
// Reads from static HTML when a bot is crawling.
|
||||||
|
|
||||||
path = Path.join(process.env.PWD, 'work', path, 'index.html');
|
path = Path.join(process.env.PWD, 'work', path, 'index.html');
|
||||||
const html = Fs.readFileSync(path, 'utf8');
|
const html = Fs.readFileSync(path, 'utf8');
|
||||||
res.status(200).send(html);
|
res.status(200).send(html);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
// Servers default.gbui web application.
|
||||||
|
|
||||||
path = Path.join(
|
path = Path.join(
|
||||||
process.env.PWD,
|
process.env.PWD,
|
||||||
GBDeployer.deployFolder,
|
GBDeployer.deployFolder,
|
||||||
GBMinService.uiPackage,
|
GBMinService.uiPackage,
|
||||||
'build',
|
'build',
|
||||||
min ? `index.html` : req.url
|
url === '/' || url === '' ? `index.html` : url
|
||||||
);
|
);
|
||||||
if (Fs.existsSync(path)) {
|
if (Fs.existsSync(path)) {
|
||||||
if (min) {
|
if (min) {
|
||||||
let html = Fs.readFileSync(path, 'utf8');
|
let html = Fs.readFileSync(path, 'utf8');
|
||||||
html = html.replace(/\{botId\}/gi, min.botId);
|
html = html.replace(/\{botId\}/gi, min.botId);
|
||||||
html = html.replace(/\{theme\}/gi, min.instance.theme);
|
html = html.replace(/\{theme\}/gi, min.instance.theme ? min.instance.theme :
|
||||||
|
'default.gbtheme');
|
||||||
html = html.replace(/\{title\}/gi, min.instance.title);
|
html = html.replace(/\{title\}/gi, min.instance.title);
|
||||||
res.send(html).end();
|
res.send(html).end();
|
||||||
} else {
|
} else {
|
||||||
|
|
Binary file not shown.
|
@ -101,10 +101,10 @@ export class WhatsappDirectLine extends GBService {
|
||||||
whatsappServiceKey === 'internal'
|
whatsappServiceKey === 'internal'
|
||||||
? 'GeneralBots'
|
? 'GeneralBots'
|
||||||
: whatsappServiceNumber.indexOf(';') > -1
|
: whatsappServiceNumber.indexOf(';') > -1
|
||||||
? 'maytapi'
|
? 'maytapi'
|
||||||
: whatsappServiceKey !== 'internal'
|
: whatsappServiceKey !== 'internal'
|
||||||
? 'graphapi'
|
? 'graphapi'
|
||||||
: 'chatapi';
|
: 'chatapi';
|
||||||
this.groupId = groupId;
|
this.groupId = groupId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,7 +172,7 @@ export class WhatsappDirectLine extends GBService {
|
||||||
});
|
});
|
||||||
client.on('ready', async () => {
|
client.on('ready', async () => {
|
||||||
GBLog.verbose(`GBWhatsApp: Emptying chat list for ${this.botId}...`);
|
GBLog.verbose(`GBWhatsApp: Emptying chat list for ${this.botId}...`);
|
||||||
|
// TODO: await client.pupPage['minimize']();
|
||||||
// Keeps the chat list cleaned.
|
// Keeps the chat list cleaned.
|
||||||
const chats = await client.getChats();
|
const chats = await client.getChats();
|
||||||
await CollectionUtil.asyncForEach(chats, async chat => {
|
await CollectionUtil.asyncForEach(chats, async chat => {
|
||||||
|
@ -192,8 +192,15 @@ export class WhatsappDirectLine extends GBService {
|
||||||
});
|
});
|
||||||
client.initialize();
|
client.initialize();
|
||||||
};
|
};
|
||||||
createClient.bind(this)();
|
if (setUrl){
|
||||||
|
createClient.bind(this)();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.customClient = minBoot.whatsAppDirectLine.customClient;
|
||||||
|
}
|
||||||
setUrl = false;
|
setUrl = false;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 'chatapi':
|
case 'chatapi':
|
||||||
options = {
|
options = {
|
||||||
|
@ -650,8 +657,7 @@ export class WhatsappDirectLine extends GBService {
|
||||||
await this.printMessages(response.obj.activities, conversationId, from, fromName);
|
await this.printMessages(response.obj.activities, conversationId, from, fromName);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
GBLog.error(
|
GBLog.error(
|
||||||
`Error calling printMessages on Whatsapp channel ${err.data === undefined ? err : err.data} ${
|
`Error calling printMessages on Whatsapp channel ${err.data === undefined ? err : err.data} ${err.errObj ? err.errObj.message : ''
|
||||||
err.errObj ? err.errObj.message : ''
|
|
||||||
}`
|
}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -941,7 +947,7 @@ export class WhatsappDirectLine extends GBService {
|
||||||
id = req.from.split('@')[0];
|
id = req.from.split('@')[0];
|
||||||
senderName = req._data.notifyName;
|
senderName = req._data.notifyName;
|
||||||
text = req.body;
|
text = req.body;
|
||||||
|
botId = this.botId;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'chatapi':
|
case 'chatapi':
|
||||||
|
@ -992,11 +998,14 @@ export class WhatsappDirectLine extends GBService {
|
||||||
let urlMin: any = GBServer.globals.minInstances.filter(p => p.instance.botId === botId)[0];
|
let urlMin: any = GBServer.globals.minInstances.filter(p => p.instance.botId === botId)[0];
|
||||||
|
|
||||||
const botNumber = urlMin ? urlMin.core.getParam(urlMin.instance, 'Bot Number', null) : null;
|
const botNumber = urlMin ? urlMin.core.getParam(urlMin.instance, 'Bot Number', null) : null;
|
||||||
|
if (botNumber){
|
||||||
|
user = await sec.updateUserInstance(user.userSystemId, urlMin.instance.instanceId);
|
||||||
|
}
|
||||||
let activeMin;
|
let activeMin;
|
||||||
|
|
||||||
// Processes group behaviour.
|
// Processes group behaviour.
|
||||||
|
|
||||||
text = text.replace(/\@\d+ /gi, '');
|
text = text.replace(/\@\d+ /gi, '');
|
||||||
|
|
||||||
let group;
|
let group;
|
||||||
if (provider === 'chatapi') {
|
if (provider === 'chatapi') {
|
||||||
|
@ -1120,15 +1129,25 @@ export class WhatsappDirectLine extends GBService {
|
||||||
res.end();
|
res.end();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
let t;
|
||||||
activeMin = GBServer.globals.minInstances.filter(p => p.instance.instanceId === user.instanceId)[0];
|
activeMin = GBServer.globals.minInstances.filter(p => p.instance.instanceId === user.instanceId)[0];
|
||||||
if (activeMin === undefined) {
|
if (activeMin === undefined) {
|
||||||
activeMin = GBServer.globals.minBoot;
|
activeMin = GBServer.globals.minBoot;
|
||||||
await (activeMin as any).whatsAppDirectLine.sendToDevice(
|
t = (activeMin as any).whatsAppDirectLine;
|
||||||
|
await t.sendToDevice(
|
||||||
id,
|
id,
|
||||||
`O outro Bot que você estava falando(${user.instanceId}), não está mais disponível. Agora você está falando comigo, ${activeMin.instance.title}...`
|
`O outro Bot que você estava falando(${user.instanceId}), não está mais disponível. Agora você está falando comigo, ${activeMin.instance.title}...`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
await (activeMin as any).whatsAppDirectLine.received(req, res);
|
else {
|
||||||
|
if ((activeMin as any).whatsAppDirectLine) {
|
||||||
|
t = (activeMin as any).whatsAppDirectLine;
|
||||||
|
} else {
|
||||||
|
t = (GBServer.globals.minBoot as any).whatsAppDirectLine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t.received(req, res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Add table
Reference in a new issue