fix(all): Create bot working again.

This commit is contained in:
Rodrigo Rodriguez 2023-07-14 18:45:17 -03:00
parent e9717302e0
commit b92fbca72a
9 changed files with 119 additions and 77 deletions

View file

@ -182,7 +182,8 @@
"winston": "3.8.2", "winston": "3.8.2",
"winston-logs-display": "1.0.0", "winston-logs-display": "1.0.0",
"ws": "8.12.1", "ws": "8.12.1",
"yarn": "1.22.19" "yarn": "1.22.19",
"ngrok": "4.3.3"
}, },
"devDependencies": { "devDependencies": {
"@types/qrcode": "1.5.0", "@types/qrcode": "1.5.0",
@ -193,7 +194,6 @@
"dependency-check": "4.1.0", "dependency-check": "4.1.0",
"git-issues": "1.0.0", "git-issues": "1.0.0",
"license-checker": "25.0.1", "license-checker": "25.0.1",
"ngrok": "4.3.3",
"prettier-standard": "15.0.1", "prettier-standard": "15.0.1",
"semantic-release": "17.2.4", "semantic-release": "17.2.4",
"simple-commit-message": "4.0.13", "simple-commit-message": "4.0.13",

View file

@ -41,12 +41,13 @@ import * as Fs from 'fs';
import { GBAdminService } from '../../../packages/admin.gbapp/services/GBAdminService.js'; import { GBAdminService } from '../../../packages/admin.gbapp/services/GBAdminService.js';
import { GBConfigService } from '../../../packages/core.gbapp/services/GBConfigService.js'; import { GBConfigService } from '../../../packages/core.gbapp/services/GBConfigService.js';
import scanf from 'scanf'; import scanf from 'scanf';
import { AzureDeployerService } from '../services/AzureDeployerService.js';
/** /**
* Handles command-line dialog for getting info for Boot Bot. * Handles command-line dialog for getting info for Boot Bot.
*/ */
export class StartDialog { export class StartDialog {
public static async createBaseInstance (installationDeployer: IGBInstallationDeployer) { public static async createBaseInstance (deployer, freeTier) {
// No .env so asks for cloud credentials to start a new farm. // No .env so asks for cloud credentials to start a new farm.
if (!Fs.existsSync(`.env`)) { if (!Fs.existsSync(`.env`)) {
@ -76,10 +77,13 @@ export class StartDialog {
let subscriptionId: string; let subscriptionId: string;
while (subscriptionId === undefined) { while (subscriptionId === undefined) {
const list = await installationDeployer.getSubscriptions(credentials); const list = await (new AzureDeployerService()).getSubscriptions(credentials);
subscriptionId = this.retrieveSubscriptionId(list); subscriptionId = this.retrieveSubscriptionId(list);
} }
const installationDeployer = await AzureDeployerService.createInstanceWithADALCredentials(
deployer, freeTier, subscriptionId, credentials);
let location: string; let location: string;
while (location === undefined) { while (location === undefined) {
location = this.retrieveLocation(); location = this.retrieveLocation();
@ -108,7 +112,7 @@ export class StartDialog {
instance.marketplacePassword = appPassword; instance.marketplacePassword = appPassword;
instance.adminPass = GBAdminService.getRndPassword(); instance.adminPass = GBAdminService.getRndPassword();
return { instance, credentials, subscriptionId }; return { instance, credentials, subscriptionId , installationDeployer};
} }
private static retrieveUsername () { private static retrieveUsername () {

View file

@ -84,17 +84,22 @@ export class AzureDeployerService implements IGBInstallationDeployer {
await this.deployer.rebuildIndex(instance, this.getKBSearchSchema(instance.searchIndex)); await this.deployer.rebuildIndex(instance, this.getKBSearchSchema(instance.searchIndex));
} }
public static async createInstance(deployer: GBDeployer, freeTier: boolean = true): Promise<AzureDeployerService> { public static async createInstance(deployer: GBDeployer, freeTier: boolean = true): Promise<AzureDeployerService> {
const username = GBConfigService.get('CLOUD_USERNAME'); const username = GBConfigService.get('CLOUD_USERNAME');
const password = GBConfigService.get('CLOUD_PASSWORD'); const password = GBConfigService.get('CLOUD_PASSWORD');
const subscriptionId = GBConfigService.get('CLOUD_SUBSCRIPTIONID'); const subscriptionId = GBConfigService.get('CLOUD_SUBSCRIPTIONID');
return await this.createInstanceWithCredentials(deployer, freeTier, subscriptionId, username, password);
}
public static async createInstanceWithADALCredentials(deployer: GBDeployer, freeTier: boolean = true,
subscriptionId: string, credentials): Promise<AzureDeployerService> {
const service = new AzureDeployerService(); const service = new AzureDeployerService();
service.core = deployer.core; service.core = deployer.core;
service.deployer = deployer; service.deployer = deployer;
service.freeTier = freeTier; service.freeTier = freeTier;
const credentials = await GBAdminService.getADALCredentialsFromUsername(username, password);
const token = credentials['tokenCache']._entries[0]; const token = credentials['tokenCache']._entries[0];
await service.initServices(token.accessToken, token.expiresOn, subscriptionId); await service.initServices(token.accessToken, token.expiresOn, subscriptionId);
@ -102,6 +107,13 @@ export class AzureDeployerService implements IGBInstallationDeployer {
return service; return service;
} }
public static async createInstanceWithCredentials(deployer: GBDeployer, freeTier: boolean = true,
subscriptionId: string, username: string, password: string): Promise<AzureDeployerService> {
const service = new AzureDeployerService();
const credentials = await GBAdminService.getADALCredentialsFromUsername(username, password);
return await this.createInstanceWithADALCredentials(deployer, freeTier, subscriptionId, credentials);
}
private static createRequestObject(url: string, accessToken: string, verb: HttpMethods, body: string) { private static createRequestObject(url: string, accessToken: string, verb: HttpMethods, body: string) {
const req = new WebResource(); const req = new WebResource();
req.method = verb; req.method = verb;
@ -399,24 +411,24 @@ export class AzureDeployerService implements IGBInstallationDeployer {
instance.searchIndexer = 'azuresql-indexer'; instance.searchIndexer = 'azuresql-indexer';
instance.searchKey = searchKeys.primaryKey; instance.searchKey = searchKeys.primaryKey;
GBLog.info(`Deploying Speech...`); // GBLog.info(`Deploying Speech...`);
const speech = await this.createSpeech(name, `${name}speech`, instance.cloudLocation); // const speech = await this.createSpeech(name, `${name}speech`, instance.cloudLocation);
keys = await this.cognitiveClient.accounts.listKeys(name, speech.name); // keys = await this.cognitiveClient.accounts.listKeys(name, speech.name);
instance.speechEndpoint = speech.properties.endpoint; // instance.speechEndpoint = speech.properties.endpoint;
instance.speechKey = keys.key1; // instance.speechKey = keys.key1;
GBLog.info(`Deploying Text Analytics...`); // GBLog.info(`Deploying Text Analytics...`);
const textAnalytics = await this.createTextAnalytics(name, `${name}-textanalytics`, instance.cloudLocation); // const textAnalytics = await this.createTextAnalytics(name, `${name}-textanalytics`, instance.cloudLocation);
instance.textAnalyticsEndpoint = textAnalytics.properties.endpoint.replace(`/text/analytics/v2.0`, ''); // instance.textAnalyticsEndpoint = textAnalytics.properties.endpoint.replace(`/text/analytics/v2.0`, '');
GBLog.info(`Deploying SpellChecker...`); GBLog.info(`Deploying SpellChecker...`);
const spellChecker = await this.createSpellChecker(name, `${name}-spellchecker`); const spellChecker = await this.createSpellChecker(name, `${name}-spellchecker`);
instance.spellcheckerEndpoint = spellChecker.properties.endpoint; instance.spellcheckerEndpoint = spellChecker.properties.endpoint;
GBLog.info(`Deploying NLP...`); // GBLog.info(`Deploying NLP...`);
const nlp = await this.createNLP(name, `${name}-nlp`, instance.cloudLocation); // const nlp = await this.createNLP(name, `${name}-nlp`, instance.cloudLocation);
const nlpa = await this.createNLPAuthoring(name, `${name}-nlpa`, instance.cloudLocation); // const nlpa = await this.createNLPAuthoring(name, `${name}-nlpa`, instance.cloudLocation);
instance.nlpEndpoint = nlp.properties.endpoint; // instance.nlpEndpoint = nlp.properties.endpoint;
const sleep = ms => { const sleep = ms => {
return new Promise(resolve => { return new Promise(resolve => {
@ -443,19 +455,19 @@ export class AzureDeployerService implements IGBInstallationDeployer {
instance.cloudSubscriptionId instance.cloudSubscriptionId
); );
GBLog.info(`Waiting one minute to finishing NLP service and keys creation...`); GBLog.info(`Waiting one minute to finish NLP service and keys creation...`);
await sleep(60000); await sleep(60000);
keys = await this.cognitiveClient.accounts.listKeys(name, textAnalytics.name); // keys = await this.cognitiveClient.accounts.listKeys(name, textAnalytics.name);
instance.textAnalyticsKey = keys.key1; // instance.textAnalyticsKey = keys.key1;
keys = await this.cognitiveClient.accounts.listKeys(name, spellChecker.name); keys = await this.cognitiveClient.accounts.listKeys(name, spellChecker.name);
instance.spellcheckerKey = keys.key1; instance.spellcheckerKey = keys.key1;
let authoringKeys = await this.cognitiveClient.accounts.listKeys(name, nlpa.name); // let authoringKeys = await this.cognitiveClient.accounts.listKeys(name, nlpa.name);
keys = await this.cognitiveClient.accounts.listKeys(name, nlp.name); // keys = await this.cognitiveClient.accounts.listKeys(name, nlp.name);
instance.nlpKey = keys.key1; // instance.nlpKey = keys.key1;
instance.nlpAuthoringKey = authoringKeys.key1; // instance.nlpAuthoringKey = authoringKeys.key1;
const nlpAppId = await this.createNLPService(name, name, instance.cloudLocation, culture, instance.nlpAuthoringKey); // const nlpAppId = await this.createNLPService(name, name, instance.cloudLocation, culture, instance.nlpAuthoringKey);
instance.nlpAppId = nlpAppId; // instance.nlpAppId = nlpAppId;
GBLog.info('Updating server environment variables...'); GBLog.info('Updating server environment variables...');
await this.updateWebisteConfig(name, serverName, serverFarm.id, instance); await this.updateWebisteConfig(name, serverName, serverFarm.id, instance);

View file

@ -51,7 +51,7 @@ import PizZip from 'pizzip';
import Docxtemplater from 'docxtemplater'; import Docxtemplater from 'docxtemplater';
import pptxTemplaterModule from 'pptxtemplater'; import pptxTemplaterModule from 'pptxtemplater';
import _ from 'lodash'; import _ from 'lodash';
import { pdfToPng, PngPageOutput } from 'pdf-to-png-converter'; // TODO: canvas error import { pdfToPng, PngPageOutput } from 'pdf-to-png-converter';
import sharp from 'sharp'; import sharp from 'sharp';
import ImageModule from 'open-docxtemplater-image-module'; import ImageModule from 'open-docxtemplater-image-module';
import DynamicsWebApi from 'dynamics-web-api'; import DynamicsWebApi from 'dynamics-web-api';
@ -350,14 +350,16 @@ export class SystemKeywords {
// Converts the PDF to PNG. // Converts the PDF to PNG.
const pngPages: PngPageOutput[] = await pdfToPng(gbfile.data, { const pngPages /*: PngPageOutput*/ = [];
disableFontFace: false, // TODO: https://github.com/GeneralBots/BotServer/issues/350
useSystemFonts: false, // await pdfToPng(gbfile.data, {
viewportScale: 2.0, // disableFontFace: false,
pagesToProcess: [1], // useSystemFonts: false,
strictPagesToProcess: false, // viewportScale: 2.0,
verbosityLevel: 0 // pagesToProcess: [1],
}); // strictPagesToProcess: false,
// verbosityLevel: 0
// });
// Prepare an image on cache and return the GBFILE information. // Prepare an image on cache and return the GBFILE information.

View file

@ -158,6 +158,15 @@ export class GBConfigService {
case 'DEV_GBAI': case 'DEV_GBAI':
value = undefined; value = undefined;
break; break;
case 'FREE_TIER':
value = true;
break;
case 'BOT_URL':
value = undefined;
break;
case 'STORAGE_SERVER':
value = undefined;
break;
default: default:
GBLog.warn(`Invalid key on .env file: '${key}'`); GBLog.warn(`Invalid key on .env file: '${key}'`);
break; break;

View file

@ -318,10 +318,10 @@ ENDPOINT_UPDATE=true
*/ */
public async ensureProxy(port): Promise<string> { public async ensureProxy(port): Promise<string> {
try { try {
if (Fs.existsSync('node_modules/ngrok/bin/ngrok.exe') || Fs.existsSync('node_modules/ngrok/bin/ngrok')) { if (Fs.existsSync('node_modules/ngrok/bin/ngrok.exe') || Fs.existsSync('node_modules/.bin/ngrok')) {
return await ngrok.connect({ port: port }); return await ngrok.connect({ port: port });
} else { } else {
GBLog.warn('ngrok executable not found (only tested on Windows). Check installation or node_modules folder.'); GBLog.warn('ngrok executable not found. Check installation or node_modules folder.');
return 'https://localhost'; return 'https://localhost';
} }
@ -500,20 +500,36 @@ ENDPOINT_UPDATE=true
} }
} }
public async createBootInstance(
core: GBCoreService,
installationDeployer: IGBInstallationDeployer,
proxyAddress: string
) {
return await this.createBootInstanceEx(
core,
installationDeployer,
proxyAddress, null,
GBConfigService.get('FREE_TIER'));
}
/** /**
* Creates the first bot instance (boot instance) used to "boot" the server. * Creates the first bot instance (boot instance) used to "boot" the server.
* At least one bot is required to perform conversational administrative tasks. * At least one bot is required to perform conversational administrative tasks.
* So a base main bot is always deployed and will act as root bot for * So a base main bot is always deployed and will act as root bot for
* configuration tree with three levels: .env > root bot > all other bots. * configuration tree with three levels: .env > root bot > all other bots.
*/ */
public async createBootInstance( public async createBootInstanceEx(
core: GBCoreService, core: GBCoreService,
installationDeployer: IGBInstallationDeployer, installationDeployer: IGBInstallationDeployer,
proxyAddress: string proxyAddress: string,
deployer,
freeTier
) { ) {
GBLog.info(`Deploying cognitive infrastructure (on the cloud / on premises)...`); GBLog.info(`Deploying cognitive infrastructure (on the cloud / on premises)...`);
try { try {
const { instance, credentials, subscriptionId } = await StartDialog.createBaseInstance(installationDeployer); const { instance, credentials, subscriptionId, installationDeployer }
= await StartDialog.createBaseInstance(deployer, freeTier);
installationDeployer['core'] = this; installationDeployer['core'] = this;
const changedInstance = await installationDeployer.deployFarm( const changedInstance = await installationDeployer.deployFarm(
proxyAddress, proxyAddress,
@ -528,7 +544,7 @@ ENDPOINT_UPDATE=true
await this.openStorageFrontier(installationDeployer); await this.openStorageFrontier(installationDeployer);
await this.initStorage(); await this.initStorage();
return changedInstance; return [changedInstance, installationDeployer];
} catch (error) { } catch (error) {
GBLog.warn( GBLog.warn(
`There is an error being thrown, so please cleanup any infrastructure objects `There is an error being thrown, so please cleanup any infrastructure objects

View file

@ -336,7 +336,7 @@ export class GBSSR {
if (GBServer.globals.wwwroot && url === '/') { if (GBServer.globals.wwwroot && url === '/') {
path = GBServer.globals.wwwroot + "/index.html"; // TODO. path = GBServer.globals.wwwroot + "/index.html"; // TODO.
} }
if (!min && !url.startsWith("/static")) { if (!min && !url.startsWith("/static") && GBServer.globals.wwwroot) {
path = Path.join(GBServer.globals.wwwroot, url); path = Path.join(GBServer.globals.wwwroot, url);
} }
if (Fs.existsSync(path)) { if (Fs.existsSync(path)) {

View file

@ -39,7 +39,7 @@
import { GBLog, GBMinInstance, IGBDialog } from 'botlib'; import { GBLog, GBMinInstance, IGBDialog } from 'botlib';
import { GBAdminService } from '../../admin.gbapp/services/GBAdminService.js'; import { GBAdminService } from '../../admin.gbapp/services/GBAdminService.js';
import { Messages } from '../strings.js'; import { Messages } from '../strings.js';
import * as phone from 'google-libphonenumber'; import libphonenumber from 'google-libphonenumber';
/** /**
* Dialogs for handling Menu control. * Dialogs for handling Menu control.
@ -101,17 +101,16 @@ export class ProfileDialog extends IGBDialog {
}, },
async step => { async step => {
const locale = step.context.activity.locale; const locale = step.context.activity.locale;
let phoneNumber; let phoneNumber = step.context.activity.text;
try { try {
let p = phone.PhoneNumberUtil.getInstance(); let p = libphonenumber.PhoneNumberUtil.getInstance();
phoneNumber = p(step.result, 'BRA')[0]; // https://github.com/GeneralBots/BotServer/issues/307 phoneNumber = p.parse(phoneNumber);
phoneNumber = phone.phoneUtil.parse(phoneNumber);
} catch (error) { } catch (error) {
await step.context.sendActivity(Messages[locale].validation_enter_valid_mobile); await step.context.sendActivity(Messages[locale].validation_enter_valid_mobile);
return await step.replaceDialog('/profile_mobile', step.activeDialog.state.options); return await step.replaceDialog('/profile_mobile', step.activeDialog.state.options);
} }
if (!phone.phoneUtil.isPossibleNumber(phoneNumber)) { if (!libphonenumber.phoneUtil.isPossibleNumber(phoneNumber)) {
await step.context.sendActivity(Messages[locale].validation_enter_valid_mobile); await step.context.sendActivity(Messages[locale].validation_enter_valid_mobile);
return await step.replaceDialog('/profile_mobile', step.activeDialog.state.options); return await step.replaceDialog('/profile_mobile', step.activeDialog.state.options);

View file

@ -140,16 +140,16 @@ export class GBServer {
const core: IGBCoreService = new GBCoreService(); const core: IGBCoreService = new GBCoreService();
const importer: GBImporter = new GBImporter(core); const importer: GBImporter = new GBImporter(core);
const deployer: GBDeployer = new GBDeployer(core, importer); const deployer: GBDeployer = new GBDeployer(core, importer);
const azureDeployer: AzureDeployerService = await AzureDeployerService.createInstance(deployer); const subscriptionId = GBConfigService.get('CLOUD_SUBSCRIPTIONID');
const adminService: GBAdminService = new GBAdminService(core); let azureDeployer: AzureDeployerService;
// Ensure that local proxy is setup.
if (process.env.NODE_ENV === 'development') { if (process.env.NODE_ENV === 'development') {
const proxy = GBConfigService.get('BOT_URL'); const proxy = GBConfigService.get('BOT_URL');
if (proxy !== undefined) { if (proxy !== undefined) {
GBServer.globals.publicAddress = proxy; GBServer.globals.publicAddress = proxy;
} else { } else {
// Ensure that local development proxy is setup.
GBLog.info(`Establishing a development local proxy (proxy) on BOT_URL...`); GBLog.info(`Establishing a development local proxy (proxy) on BOT_URL...`);
GBServer.globals.publicAddress = await core.ensureProxy(port); GBServer.globals.publicAddress = await core.ensureProxy(port);
} }
@ -159,16 +159,19 @@ export class GBServer {
GBServer.globals.publicAddress = serverAddress; GBServer.globals.publicAddress = serverAddress;
} }
// Creates a boot instance or load it from storage. // Creates a boot instance or load it from storage.
try { if (GBConfigService.get('STORAGE_SERVER')) {
azureDeployer = await AzureDeployerService.createInstance(deployer);
await core.initStorage(); await core.initStorage();
} catch (error) { } else {
GBLog.verbose(`Error initializing storage: ${error}`); [GBServer.globals.bootInstance, azureDeployer] = await core['createBootInstanceEx'](
GBServer.globals.bootInstance = await core.createBootInstance(
core, core,
azureDeployer, null,
GBServer.globals.publicAddress GBServer.globals.publicAddress,
deployer,
GBConfigService.get('FREE_TIER')
); );
} }
@ -216,6 +219,7 @@ export class GBServer {
// Builds minimal service infrastructure. // Builds minimal service infrastructure.
const conversationalService: GBConversationalService = new GBConversationalService(core); const conversationalService: GBConversationalService = new GBConversationalService(core);
const adminService: GBAdminService = new GBAdminService(core);
const minService: GBMinService = new GBMinService(core, conversationalService, adminService, deployer); const minService: GBMinService = new GBMinService(core, conversationalService, adminService, deployer);
GBServer.globals.minService = minService; GBServer.globals.minService = minService;
await minService.buildMin(instances); await minService.buildMin(instances);
@ -231,11 +235,6 @@ export class GBServer {
} }
} }
// let s = new GBVMService();
// await s.translateBASIC('work/gptA.vbs', GBServer.globals.minBoot );
// await s.translateBASIC('work/gptB.vbs', GBServer.globals.minBoot );
// await s.translateBASIC('work/gptC.vbs', GBServer.globals.minBoot );
// process.exit(9);
if (process.env.ENABLE_WEBLOG) { if (process.env.ENABLE_WEBLOG) {
// If global log enabled, reorders transports adding web logging. // If global log enabled, reorders transports adding web logging.
@ -280,6 +279,7 @@ export class GBServer {
// Setups unsecure http redirect. // Setups unsecure http redirect.
if (process.env.NODE_ENV === 'production') {
const server1 = http.createServer((req, res) => { const server1 = http.createServer((req, res) => {
const host = req.headers.host.startsWith('www.') ? const host = req.headers.host.startsWith('www.') ?
req.headers.host.substring(4) : req.headers.host; req.headers.host.substring(4) : req.headers.host;
@ -287,8 +287,8 @@ export class GBServer {
Location: "https://" + host + req.url Location: "https://" + host + req.url
}).end(); }).end();
}); });
server1.listen(80); server1.listen(80);
}
if (process.env.CERTIFICATE_PFX) { if (process.env.CERTIFICATE_PFX) {
const options1 = { const options1 = {