new(all): TRUE multicloud.
|
@ -313,7 +313,7 @@ export class AdminDialog extends IGBDialog {
|
|||
}
|
||||
|
||||
if (packageName.indexOf('.') !== -1) {
|
||||
cmd1 = `deployPackage ${process.env.STORAGE_SITE} /${process.env.STORAGE_LIBRARY}/${botId}.gbai/${packageName}`;
|
||||
cmd1 = `deployPackage ${process.env.STORAGE_SITE} /${GBConfigService.get('STORAGE_LIBRARY')}/${botId}.gbai/${packageName}`;
|
||||
} else {
|
||||
cmd1 = `deployPackage ${packageName}`;
|
||||
}
|
||||
|
|
|
@ -187,8 +187,8 @@ export class GBAdminService implements IGBAdminService {
|
|||
await deployer['cleanupPackage'](min.instance, packageName);
|
||||
}
|
||||
|
||||
if (process.env.STORAGE_FILE) {
|
||||
const path = Path.join(process.env.STORAGE_LIBRARY, gbaiPath);
|
||||
if (GBConfigService.get('STORAGE_FILE')) {
|
||||
const path = Path.join(GBConfigService.get('STORAGE_LIBRARY'), gbaiPath);
|
||||
Fs.cpSync(path, localFolder, { errorOnExist: false, force: true, recursive: true});
|
||||
} else {
|
||||
await deployer['downloadFolder'](min, Path.join('work', `${gbai}`), Path.basename(localFolder));
|
||||
|
|
|
@ -36,11 +36,11 @@
|
|||
|
||||
import { BotAdapter } from 'botbuilder';
|
||||
import { WaterfallDialog } from 'botbuilder-dialogs';
|
||||
import { GBLog, GBMinInstance, IGBDialog } from 'botlib';
|
||||
import { GBMinInstance, IGBDialog } from 'botlib';
|
||||
import { GBServer } from '../../../src/app.js';
|
||||
import { GBConversationalService } from '../services/GBConversationalService.js';
|
||||
import { Messages } from '../strings.js';
|
||||
import { GBLogEx } from '../services/GBLogEx.js';
|
||||
import { GBConfigService } from '../services/GBConfigService.js';
|
||||
|
||||
/**
|
||||
* Dialog for Welcoming people.
|
||||
|
@ -65,7 +65,7 @@ export class WelcomeDialog extends IGBDialog {
|
|||
async step => {
|
||||
if (
|
||||
GBServer.globals.entryPointDialog !== null &&
|
||||
min.instance.botId === process.env.BOT_ID &&
|
||||
min.instance.botId === GBConfigService.get('BOT_ID') &&
|
||||
step.context.activity.channelId === 'webchat'
|
||||
) {
|
||||
return step.replaceDialog(GBServer.globals.entryPointDialog);
|
||||
|
|
|
@ -42,7 +42,7 @@ import * as en from 'dotenv-extended';
|
|||
*/
|
||||
export class GBConfigService {
|
||||
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 {
|
||||
if (process.env.PORT) {
|
||||
|
@ -84,8 +84,11 @@ export class GBConfigService {
|
|||
case 'CLOUD_USERNAME':
|
||||
value = undefined;
|
||||
break;
|
||||
case 'STORAGE_LIBRARY':
|
||||
value = `${process.env.HOME}/gbpackages`;
|
||||
break;
|
||||
case 'BOT_ID':
|
||||
value = undefined;
|
||||
value = 'default';
|
||||
break;
|
||||
case 'CLOUD_PASSWORD':
|
||||
value = undefined;
|
||||
|
@ -103,7 +106,7 @@ export class GBConfigService {
|
|||
value = undefined;
|
||||
break;
|
||||
case 'STORAGE_DIALECT':
|
||||
value = undefined;
|
||||
value = 'sqlite';
|
||||
break;
|
||||
case 'STORAGE_FILE':
|
||||
value = './data.db';
|
||||
|
@ -160,7 +163,7 @@ export class GBConfigService {
|
|||
value = true;
|
||||
break;
|
||||
case 'BOT_URL':
|
||||
value = undefined;
|
||||
value = 'http://localhost:4242';
|
||||
break;
|
||||
case 'STORAGE_SERVER':
|
||||
value = undefined;
|
||||
|
|
|
@ -50,6 +50,7 @@ import { GBSecurityPackage } from '../../security.gbapp/index.js';
|
|||
import { GBWhatsappPackage } from '../../whatsapp.gblib/index.js';
|
||||
import { GuaribasApplications, GuaribasInstance, GuaribasLog } from '../models/GBModel.js';
|
||||
import { GBConfigService } from './GBConfigService.js';
|
||||
import mkdirp from 'mkdirp';
|
||||
import { GBAzureDeployerPackage } from '../../azuredeployer.gbapp/index.js';
|
||||
import { GBSharePointPackage } from '../../sharepoint.gblib/index.js';
|
||||
import { CollectionUtil } from 'pragmatismo-io-framework';
|
||||
|
@ -109,7 +110,7 @@ export class GBCoreService implements IGBCoreService {
|
|||
constructor() {
|
||||
this.adminService = new GBAdminService(this);
|
||||
}
|
||||
public async ensureInstances(instances: IGBInstance[], bootInstance: any, core: IGBCoreService) { }
|
||||
public async ensureInstances(instances: IGBInstance[], bootInstance: any, core: IGBCoreService) {}
|
||||
|
||||
/**
|
||||
* Gets database config and connect to storage. Currently two databases
|
||||
|
@ -138,8 +139,8 @@ export class GBCoreService implements IGBCoreService {
|
|||
const logging: boolean | Function =
|
||||
GBConfigService.get('STORAGE_LOGGING') === 'true'
|
||||
? (str: string): void => {
|
||||
GBLogEx.info(0, str);
|
||||
}
|
||||
GBLogEx.info(0, str);
|
||||
}
|
||||
: false;
|
||||
|
||||
const encrypt: boolean = GBConfigService.get('STORAGE_ENCRYPT') === 'true';
|
||||
|
@ -231,7 +232,6 @@ export class GBCoreService implements IGBCoreService {
|
|||
return out;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Loads all items to start several listeners.
|
||||
*/
|
||||
|
@ -426,12 +426,11 @@ ENDPOINT_UPDATE=true
|
|||
let instances: IGBInstance[];
|
||||
try {
|
||||
instances = await core.loadInstances();
|
||||
const group = GBConfigService.get('CLOUD_GROUP')??GBConfigService.get('BOT_ID');
|
||||
const group = GBConfigService.get('CLOUD_GROUP') ?? GBConfigService.get('BOT_ID');
|
||||
if (process.env.ENDPOINT_UPDATE === 'true') {
|
||||
await CollectionUtil.asyncForEach(instances, async instance => {
|
||||
GBLogEx.info(instance.instanceId, `Updating bot endpoint for ${instance.botId}...`);
|
||||
try {
|
||||
|
||||
await installationDeployer.updateBotProxy(
|
||||
instance.botId,
|
||||
group,
|
||||
|
@ -459,7 +458,10 @@ ENDPOINT_UPDATE=true
|
|||
Try setting STORAGE_SYNC to true in .env file. Error: ${error.message}.`
|
||||
);
|
||||
} else {
|
||||
GBLogEx.info(0, `Storage is empty. After collecting storage structure from all .gbapps it will get synced.`);
|
||||
GBLogEx.info(
|
||||
0,
|
||||
`Storage is empty. After collecting storage structure from all .gbapps it will get synced.`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
throw new Error(`Cannot connect to operating storage: ${error.message}.`);
|
||||
|
@ -520,7 +522,6 @@ ENDPOINT_UPDATE=true
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public async createBootInstance(
|
||||
core: GBCoreService,
|
||||
installationDeployer: IGBInstallationDeployer,
|
||||
|
@ -529,9 +530,10 @@ ENDPOINT_UPDATE=true
|
|||
return await this.createBootInstanceEx(
|
||||
core,
|
||||
installationDeployer,
|
||||
proxyAddress, null,
|
||||
GBConfigService.get('FREE_TIER'));
|
||||
|
||||
proxyAddress,
|
||||
null,
|
||||
GBConfigService.get('FREE_TIER')
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Creates the first bot instance (boot instance) used to "boot" the server.
|
||||
|
@ -548,8 +550,10 @@ ENDPOINT_UPDATE=true
|
|||
) {
|
||||
GBLogEx.info(0, `Deploying cognitive infrastructure (on the cloud / on premises)...`);
|
||||
try {
|
||||
const { instance, credentials, subscriptionId, installationDeployer }
|
||||
= await StartDialog.createBaseInstance(deployer, freeTier);
|
||||
const { instance, credentials, subscriptionId, installationDeployer } = await StartDialog.createBaseInstance(
|
||||
deployer,
|
||||
freeTier
|
||||
);
|
||||
installationDeployer['core'] = this;
|
||||
const changedInstance = await installationDeployer['deployFarm2'](
|
||||
proxyAddress,
|
||||
|
@ -668,27 +672,26 @@ ENDPOINT_UPDATE=true
|
|||
}
|
||||
|
||||
public async setConfig(min, name: string, value: any): Promise<any> {
|
||||
|
||||
// Handles calls for BASIC persistence on sheet files.
|
||||
|
||||
GBLog.info( `Defining Config.xlsx variable ${name}= '${value}'...`);
|
||||
GBLog.info(`Defining Config.xlsx variable ${name}= '${value}'...`);
|
||||
|
||||
let { baseUrl, client } = await GBDeployer.internalGetDriveClient(min);
|
||||
|
||||
const maxLines = 512;
|
||||
const file = "Config.xlsx";
|
||||
const path = DialogKeywords.getGBAIPath(min.botId, `gbot`);;
|
||||
const file = 'Config.xlsx';
|
||||
const path = DialogKeywords.getGBAIPath(min.botId, `gbot`);
|
||||
|
||||
let document = await (new SystemKeywords()).internalGetDocument(client, baseUrl, path, file);
|
||||
let document = await new SystemKeywords().internalGetDocument(client, baseUrl, path, file);
|
||||
|
||||
// Creates workbook session that will be discarded.
|
||||
// Creates book session that will be discarded.
|
||||
|
||||
let sheets = await client
|
||||
.api(`${baseUrl}/drive/items/${document.id}/workbook/worksheets`)
|
||||
.get();
|
||||
let sheets = await client.api(`${baseUrl}/drive/items/${document.id}/workbook/worksheets`).get();
|
||||
|
||||
let results = await client
|
||||
.api(`${baseUrl}/drive/items/${document.id}/workbook/worksheets('${sheets.value[0].name}')/range(address='A1:A${maxLines}')`)
|
||||
.api(
|
||||
`${baseUrl}/drive/items/${document.id}/workbook/worksheets('${sheets.value[0].name}')/range(address='A1:A${maxLines}')`
|
||||
)
|
||||
.get();
|
||||
|
||||
const rows = results.text;
|
||||
|
@ -708,12 +711,12 @@ ENDPOINT_UPDATE=true
|
|||
body.values[0][0] = value;
|
||||
|
||||
await client
|
||||
.api(`${baseUrl}/drive/items/${document.id}/workbook/worksheets('${sheets.value[0].name}')/range(address='${address}')`)
|
||||
.api(
|
||||
`${baseUrl}/drive/items/${document.id}/workbook/worksheets('${sheets.value[0].name}')/range(address='${address}')`
|
||||
)
|
||||
.patch(body);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get a dynamic param from instance. Dynamic params are defined in Config.xlsx
|
||||
* and loaded into the work folder from comida command.
|
||||
|
@ -729,8 +732,7 @@ ENDPOINT_UPDATE=true
|
|||
// Gets .gbot Params from specified bot.
|
||||
|
||||
if (instance.params) {
|
||||
|
||||
params = typeof (instance.params) === 'object' ? instance.params : JSON.parse(instance.params);
|
||||
params = typeof instance.params === 'object' ? instance.params : JSON.parse(instance.params);
|
||||
params = GBUtil.caseInsensitive(params);
|
||||
value = params ? params[name] : defaultValue;
|
||||
}
|
||||
|
@ -740,7 +742,6 @@ ENDPOINT_UPDATE=true
|
|||
params = GBUtil.caseInsensitive(instance['dataValues']);
|
||||
|
||||
if (params && !value) {
|
||||
|
||||
// Retrieves the value from specified bot instance (no params collection).
|
||||
|
||||
value = instance['dataValues'][name];
|
||||
|
@ -749,27 +750,23 @@ ENDPOINT_UPDATE=true
|
|||
|
||||
const minBoot = GBServer.globals.minBoot as any;
|
||||
|
||||
if (
|
||||
minBoot.instance &&
|
||||
!value && instance.botId != minBoot.instance.botId) {
|
||||
|
||||
if (minBoot.instance && !value && instance.botId != minBoot.instance.botId) {
|
||||
instance = minBoot.instance;
|
||||
|
||||
if(instance.params){
|
||||
params = typeof (instance.params) === 'object' ? instance.params : JSON.parse(instance.params);
|
||||
if (instance.params) {
|
||||
params = typeof instance.params === 'object' ? instance.params : JSON.parse(instance.params);
|
||||
params = GBUtil.caseInsensitive(params);
|
||||
value = params ? params[name] : defaultValue;
|
||||
}
|
||||
|
||||
// If still did not found in boot bot params, try instance fields.
|
||||
|
||||
if (!value){
|
||||
if (!value) {
|
||||
value = instance['dataValues'][name];
|
||||
}
|
||||
if (!value){
|
||||
if (!value) {
|
||||
value = instance[name];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -787,7 +784,7 @@ ENDPOINT_UPDATE=true
|
|||
return new Number(value ? value : defaultValue ? defaultValue : 0).valueOf();
|
||||
}
|
||||
|
||||
const ret = value ?? defaultValue;
|
||||
const ret = value ?? defaultValue;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -798,7 +795,7 @@ ENDPOINT_UPDATE=true
|
|||
let params = null;
|
||||
const list = [];
|
||||
if (instance.params) {
|
||||
params = typeof (instance.params) === 'object' ? instance.params : JSON.parse(instance.params);
|
||||
params = typeof instance.params === 'object' ? instance.params : JSON.parse(instance.params);
|
||||
}
|
||||
|
||||
Object.keys(params).forEach(e => {
|
||||
|
@ -810,5 +807,83 @@ ENDPOINT_UPDATE=true
|
|||
return list;
|
||||
}
|
||||
|
||||
public async ensureFolders(instances, deployer: GBDeployer) {
|
||||
let libraryPath = GBConfigService.get('STORAGE_LIBRARY');
|
||||
|
||||
if (!Fs.existsSync(libraryPath)) {
|
||||
mkdirp.sync(libraryPath);
|
||||
}
|
||||
|
||||
|
||||
|
||||
await this.syncBotStorage(instances, 'default', deployer, libraryPath);
|
||||
|
||||
const files = Fs.readdirSync(libraryPath);
|
||||
await CollectionUtil.asyncForEach(files, async file => {
|
||||
|
||||
if (file.trim().toLowerCase() !== 'default.gbai'){
|
||||
|
||||
let botId = file.replace(/\.gbai/, '');
|
||||
|
||||
await this.syncBotStorage(instances, botId, deployer, libraryPath);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private async syncBotStorage(instances: any, botId: any, deployer: GBDeployer, libraryPath: string) {
|
||||
let instance = instances.find(p => p.botId.toLowerCase().trim() === botId.toLowerCase().trim());
|
||||
|
||||
if (!instance) {
|
||||
|
||||
GBLog.info(`Importing package ${botId}...`);
|
||||
|
||||
// Creates a bot.
|
||||
|
||||
let mobile = null,
|
||||
email = null;
|
||||
|
||||
instance = await deployer.deployBlankBot(botId, mobile, email);
|
||||
const gbaiPath = Path.join(libraryPath, `${botId}.gbai`);
|
||||
|
||||
if (!Fs.existsSync(gbaiPath)) {
|
||||
|
||||
Fs.mkdirSync(gbaiPath, { recursive: true });
|
||||
|
||||
const base = Path.join(process.env.PWD, 'templates', 'default.gbai');
|
||||
|
||||
Fs.cpSync(Path.join(base, `default.gbkb`), gbaiPath, {
|
||||
errorOnExist: false,
|
||||
force: true,
|
||||
recursive: true
|
||||
});
|
||||
Fs.cpSync(Path.join(base, `default.gbot`), gbaiPath, {
|
||||
errorOnExist: false,
|
||||
force: true,
|
||||
recursive: true
|
||||
});
|
||||
Fs.cpSync(Path.join(base, `default.gbtheme`), gbaiPath, {
|
||||
errorOnExist: false,
|
||||
force: true,
|
||||
recursive: true
|
||||
});
|
||||
Fs.cpSync(Path.join(base, `default.gbdata`), gbaiPath, {
|
||||
errorOnExist: false,
|
||||
force: true,
|
||||
recursive: true
|
||||
});
|
||||
Fs.cpSync(Path.join(base, `default.gbdialog`), gbaiPath, {
|
||||
errorOnExist: false,
|
||||
force: true,
|
||||
recursive: true
|
||||
});
|
||||
Fs.cpSync(Path.join(base, `default.gbdrive`), gbaiPath, {
|
||||
errorOnExist: false,
|
||||
force: true,
|
||||
recursive: true
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -120,7 +120,7 @@ export class GBDeployer implements IGBDeployer {
|
|||
);
|
||||
|
||||
const siteId = process.env.STORAGE_SITE_ID;
|
||||
const libraryId = process.env.STORAGE_LIBRARY;
|
||||
const libraryId = GBConfigService.get('STORAGE_LIBRARY');
|
||||
|
||||
const client = MicrosoftGraph.Client.init({
|
||||
authProvider: done => {
|
||||
|
@ -222,22 +222,24 @@ export class GBDeployer implements IGBDeployer {
|
|||
const instance = await this.importer.createBotInstance(botId);
|
||||
const bootInstance = GBServer.globals.bootInstance;
|
||||
|
||||
// Gets the access token to perform service operations.
|
||||
if (!GBConfigService.get('STORAGE_FILE')) {
|
||||
// Gets the access token to perform service operations.
|
||||
|
||||
const accessToken = await (GBServer.globals.minBoot.adminService as any)['acquireElevatedToken'](
|
||||
bootInstance.instanceId,
|
||||
true
|
||||
);
|
||||
const accessToken = await (GBServer.globals.minBoot.adminService as any)['acquireElevatedToken'](
|
||||
bootInstance.instanceId,
|
||||
true
|
||||
);
|
||||
|
||||
// Creates the MSFT application that will be associated to the bot.
|
||||
// Creates the MSFT application that will be associated to the bot.
|
||||
|
||||
const service = await AzureDeployerService.createInstance(this);
|
||||
const application = await service.createApplication(accessToken, botId);
|
||||
const service = await AzureDeployerService.createInstance(this);
|
||||
const application = await service.createApplication(accessToken, botId);
|
||||
// Fills new instance base information and get App secret.
|
||||
|
||||
// Fills new instance base information and get App secret.
|
||||
instance.marketplaceId = (application as any).appId;
|
||||
instance.marketplacePassword = await service.createApplicationSecret(accessToken, (application as any).id);
|
||||
}
|
||||
|
||||
instance.marketplaceId = (application as any).appId;
|
||||
instance.marketplacePassword = await service.createApplicationSecret(accessToken, (application as any).id);
|
||||
instance.adminPass = GBAdminService.getRndPassword();
|
||||
instance.title = botId;
|
||||
instance.activationCode = instance.botId.substring(0, 15);
|
||||
|
@ -249,10 +251,12 @@ export class GBDeployer implements IGBDeployer {
|
|||
// Saves bot information to the store.
|
||||
|
||||
await this.core.saveInstance(instance);
|
||||
|
||||
if (!GBConfigService.get('STORAGE_FILE')) {
|
||||
await this.deployBotOnAzure(instance, GBServer.globals.publicAddress);
|
||||
}
|
||||
// Creates remaining objects on the cloud and updates instance information.
|
||||
|
||||
return await this.deployBotFull(instance, GBServer.globals.publicAddress);
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -267,7 +271,7 @@ export class GBDeployer implements IGBDeployer {
|
|||
/**
|
||||
* Performs all tasks of deploying a new bot on the cloud.
|
||||
*/
|
||||
public async deployBotFull(instance: IGBInstance, publicAddress: string): Promise<IGBInstance> {
|
||||
public async deployBotOnAzure(instance: IGBInstance, publicAddress: string): Promise<IGBInstance> {
|
||||
// Reads base configuration from environent file.
|
||||
|
||||
const service = await AzureDeployerService.createInstance(this);
|
||||
|
@ -411,7 +415,7 @@ export class GBDeployer implements IGBDeployer {
|
|||
public async deployBotFromLocalPath(localPath: string, publicAddress: string): Promise<void> {
|
||||
const packageName = Path.basename(localPath);
|
||||
const instance = await this.importer.importIfNotExistsBotPackage(undefined, packageName, localPath);
|
||||
await this.deployBotFull(instance, publicAddress);
|
||||
await this.deployBotOnAzure(instance, publicAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -42,10 +42,11 @@ import { FacebookAdapter } from 'botbuilder-adapter-facebook';
|
|||
import mkdirp from 'mkdirp';
|
||||
import Fs from 'fs';
|
||||
import arrayBufferToBuffer from 'arraybuffer-to-buffer';
|
||||
import { v2 as webdav } from 'webdav-server';
|
||||
import { NlpManager } from 'node-nlp';
|
||||
import Koa from 'koa';
|
||||
import { v2 as webdav } from 'webdav-server';
|
||||
import { createRpcServer } from '@push-rpc/core';
|
||||
import { start as startRouter } from '../../../packages/core.gbapp/services/router/bridge.js';
|
||||
import wash from 'washyourmouthoutwithsoap';
|
||||
import {
|
||||
AutoSaveStateMiddleware,
|
||||
|
@ -172,6 +173,9 @@ export class GBMinService {
|
|||
await CollectionUtil.asyncForEach(
|
||||
instances,
|
||||
(async instance => {
|
||||
|
||||
startRouter(GBServer.globals.server, instance.botId);
|
||||
|
||||
try {
|
||||
GBLog.info(`Mounting ${instance.botId}...`);
|
||||
await this['mountBot'](instance);
|
||||
|
@ -256,7 +260,7 @@ export class GBMinService {
|
|||
|
||||
// Serves individual URL for each bot conversational interface.
|
||||
|
||||
await this.deployer['deployPackage2'](min, user, 'packages/default.gbtheme');
|
||||
await this.deployer['deployPackage2'](min, user, 'templates/default.gbai/default.gbtheme');
|
||||
|
||||
// Install per bot deployed packages.
|
||||
|
||||
|
@ -317,12 +321,12 @@ export class GBMinService {
|
|||
mkdirp.sync(dir);
|
||||
}
|
||||
|
||||
if (process.env.STORAGE_FILE) {
|
||||
dir = Path.join(process.env.STORAGE_LIBRARY, 'work', gbai);
|
||||
if (GBConfigService.get('STORAGE_FILE')) {
|
||||
dir = Path.join(GBConfigService.get('STORAGE_LIBRARY'), 'work', gbai);
|
||||
|
||||
const server = new webdav.WebDAVServer();
|
||||
const server = GBServer.globals.webDavServer;
|
||||
server.setFileSystem(`/${botId}`, new webdav.PhysicalFileSystem(dir), success => {
|
||||
server.start(() => console.log('WEBDAV READY'));
|
||||
GBLogEx.info(1, `WebDav for ${botId} loaded.`);
|
||||
});
|
||||
}
|
||||
// Loads Named Entity data for this bot.
|
||||
|
@ -691,8 +695,8 @@ export class GBMinService {
|
|||
color2: this.core.getParam(instance, 'Color2', null)
|
||||
};
|
||||
|
||||
if (process.env.STORAGE_FILE) {
|
||||
config['domain'] = `http://localhost:${process.env.PORT}/directline`;
|
||||
if (GBConfigService.get('STORAGE_FILE')) {
|
||||
config['domain'] = `http://localhost:${process.env.PORT}/directline/${botId}`;
|
||||
} else {
|
||||
const webchatTokenContainer = await this.getWebchatToken(instance);
|
||||
config['conversationId']= webchatTokenContainer.conversationId,
|
||||
|
@ -763,7 +767,7 @@ export class GBMinService {
|
|||
? instance.marketplacePassword
|
||||
: GBConfigService.get('MARKETPLACE_SECRET')
|
||||
};
|
||||
if (process.env.STORAGE_FILE) {
|
||||
if (GBConfigService.get('STORAGE_FILE')) {
|
||||
config['clientOptions'] = { baseUri: `http://localhost:${process.env.PORT}` };
|
||||
}
|
||||
|
||||
|
@ -830,8 +834,6 @@ export class GBMinService {
|
|||
|
||||
let url = `/api/messages/${instance.botId}`;
|
||||
GBServer.globals.server.post(url, receiver);
|
||||
url = `/api/messages`;
|
||||
GBServer.globals.server.post(url, receiver);
|
||||
|
||||
// NLP Manager.
|
||||
|
||||
|
@ -843,6 +845,10 @@ export class GBMinService {
|
|||
GBServer.globals.minBoot.instance.marketplaceId = GBConfigService.get('MARKETPLACE_ID');
|
||||
GBServer.globals.minBoot.instance.marketplacePassword = GBConfigService.get('MARKETPLACE_SECRET');
|
||||
}
|
||||
else{
|
||||
url = `/api/messages`;
|
||||
GBServer.globals.server.post(url, receiver);
|
||||
}
|
||||
|
||||
if (min.instance.facebookWorkplaceVerifyToken) {
|
||||
min['fbAdapter'] = new FacebookAdapter({
|
||||
|
@ -1192,7 +1198,7 @@ export class GBMinService {
|
|||
};
|
||||
|
||||
try {
|
||||
if (process.env.STORAGE_FILE) {
|
||||
if (GBConfigService.get('STORAGE_FILE')) {
|
||||
const context = adapter['createContext'](req);
|
||||
context['_activity'] = context.activity.body;
|
||||
await handler(context);
|
||||
|
|
|
@ -11,7 +11,7 @@ const conversationsCleanupInterval = 10000;
|
|||
const conversations: { [key: string]: IConversation } = {};
|
||||
const botDataStore: { [key: string]: IBotData } = {};
|
||||
|
||||
export const getRouter = (serviceUrl: string, botUrl: string, conversationInitRequired = true): express.Router => {
|
||||
export const getRouter = (serviceUrl: string, botUrl: string, conversationInitRequired = true, botId): express.Router => {
|
||||
const router = express.Router();
|
||||
|
||||
router.use(bodyParser.json()); // for parsing application/json
|
||||
|
@ -22,8 +22,9 @@ export const getRouter = (serviceUrl: string, botUrl: string, conversationInitRe
|
|||
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization, x-ms-bot-agent');
|
||||
next();
|
||||
});
|
||||
|
||||
// CLIENT ENDPOINT
|
||||
router.options('/directline', (req, res) => {
|
||||
router.options(`/directline/${botId}/`, (req, res) => {
|
||||
res.status(200).end();
|
||||
});
|
||||
|
||||
|
@ -53,7 +54,7 @@ export const getRouter = (serviceUrl: string, botUrl: string, conversationInitRe
|
|||
};
|
||||
|
||||
router.post('/v3/directline/conversations',reqs );
|
||||
router.post('/directline/conversations',reqs );
|
||||
router.post(`/directline/${botId}/conversations`,reqs );
|
||||
|
||||
// Reconnect API
|
||||
router.get('/v3/directline/conversations/:conversationId', (req, res) => {
|
||||
|
@ -69,7 +70,7 @@ export const getRouter = (serviceUrl: string, botUrl: string, conversationInitRe
|
|||
});
|
||||
|
||||
// Gets activities from store (local history array for now)
|
||||
router.get('/directline/conversations/:conversationId/activities', (req, res) => {
|
||||
router.get(`/directline/${botId}/conversations/:conversationId/activities`, (req, res) => {
|
||||
const watermark = req.query.watermark && req.query.watermark !== 'null' ? Number(req.query.watermark) : 0;
|
||||
|
||||
const conversation = getConversation(req.params.conversationId, conversationInitRequired);
|
||||
|
@ -95,7 +96,7 @@ export const getRouter = (serviceUrl: string, botUrl: string, conversationInitRe
|
|||
});
|
||||
|
||||
// Sends message to bot. Assumes message activities
|
||||
router.post('/directline/conversations/:conversationId/activities', (req, res) => {
|
||||
router.post(`/directline/${botId}/conversations/:conversationId/activities`, (req, res) => {
|
||||
const incomingActivity = req.body;
|
||||
// Make copy of activity. Add required fields
|
||||
const activity = createMessageActivity(incomingActivity, serviceUrl, req.params.conversationId);
|
||||
|
@ -209,11 +210,11 @@ export const getRouter = (serviceUrl: string, botUrl: string, conversationInitRe
|
|||
* @param conversationInitRequired Requires that a conversation is initialized before it is accessed, returning a 400
|
||||
* when not the case. If set to false, a new conversation reference is created on the fly. This is true by default.
|
||||
*/
|
||||
export const initializeRoutes = (app: express.Express, port: number, botUrl: string, conversationInitRequired = true) => {
|
||||
export const initializeRoutes = (app: express.Express, port: number, botUrl: string, conversationInitRequired = true, botId) => {
|
||||
conversationsCleanup();
|
||||
|
||||
const directLineEndpoint = `http://127.0.0.1:${port}`;
|
||||
const router = getRouter(directLineEndpoint, botUrl, conversationInitRequired);
|
||||
const router = getRouter(directLineEndpoint, botUrl, conversationInitRequired, botId);
|
||||
|
||||
app.use(router);
|
||||
console.log(`Routing messages to bot on ${botUrl}`);
|
||||
|
@ -272,9 +273,9 @@ const setPrivateConversationData = (req: express.Request, res: express.Response)
|
|||
res.status(200).send(setBotData(req.params.channelId, req.params.conversationId, req.params.userId, req.body));
|
||||
};
|
||||
|
||||
export const start = (server)=>{
|
||||
export const start = (server, botId)=>{
|
||||
|
||||
initializeRoutes(server, Number(process.env.PORT), `http://127.0.0.1:${process.env.PORT}/api/messages`);
|
||||
initializeRoutes(server, Number(process.env.PORT), `http://127.0.0.1:${process.env.PORT}/api/messages/${botId}`, null, botId);
|
||||
}
|
||||
|
||||
const deleteStateForUser = (req: express.Request, res: express.Response) => {
|
||||
|
|
|
@ -1370,7 +1370,7 @@ export class KBService implements IGBKBService {
|
|||
await this.importKbPackage(min, localPath, p, instance);
|
||||
GBDeployer.mountGBKBAssets(packageName, min.botId, localPath);
|
||||
|
||||
if (!process.env.STORAGE_FILE) {
|
||||
if (!GBConfigService.get('STORAGE_FILE')) {
|
||||
const service = await AzureDeployerService.createInstance(deployer);
|
||||
const searchIndex = instance.searchIndex ? instance.searchIndex : GBServer.globals.minBoot.instance.searchIndex;
|
||||
await deployer.rebuildIndex(instance, service.getKBSearchSchema(searchIndex));
|
||||
|
|
|
@ -65,4 +65,5 @@ export class RootData {
|
|||
public dbg;
|
||||
public img;
|
||||
indexSemaphore: any;
|
||||
public webDavServer;
|
||||
}
|
||||
|
|
53
src/app.ts
|
@ -40,8 +40,7 @@ import bodyParser from 'body-parser';
|
|||
import { GBLog, GBMinInstance, IGBCoreService, IGBInstance } from 'botlib';
|
||||
import child_process from 'child_process';
|
||||
import express from 'express';
|
||||
import {start as startRouter} from '../packages/core.gbapp/services/router/bridge.js'
|
||||
|
||||
import { v2 as webdav } from 'webdav-server';
|
||||
import fs from 'fs';
|
||||
import http from 'http';
|
||||
import httpProxy from 'http-proxy';
|
||||
|
@ -89,7 +88,7 @@ export class GBServer {
|
|||
|
||||
const server = express();
|
||||
this.initEndpointsDocs(server);
|
||||
startRouter(server);
|
||||
|
||||
GBServer.globals.server = server;
|
||||
|
||||
GBServer.globals.httpsServer = null;
|
||||
|
@ -105,6 +104,8 @@ export class GBServer {
|
|||
GBServer.globals.debuggers = [];
|
||||
GBServer.globals.users = [];
|
||||
GBServer.globals.indexSemaphore = new Mutex();
|
||||
GBServer.globals.webDavServer = new webdav.WebDAVServer();
|
||||
GBServer.globals.webDavServer.start();
|
||||
|
||||
server.use(bodyParser.json());
|
||||
server.use(bodyParser.json({ limit: '1mb' }));
|
||||
|
@ -121,7 +122,10 @@ export class GBServer {
|
|||
});
|
||||
|
||||
process.on('uncaughtException', (err, p) => {
|
||||
GBLogEx.error(0, `GBEXCEPTION: ${GBUtil.toYAML(JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))))}`);
|
||||
GBLogEx.error(
|
||||
0,
|
||||
`GBEXCEPTION: ${GBUtil.toYAML(JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))))}`
|
||||
);
|
||||
});
|
||||
|
||||
process.on('unhandledRejection', (err, p) => {
|
||||
|
@ -134,7 +138,10 @@ export class GBServer {
|
|||
}
|
||||
|
||||
if (!bypass) {
|
||||
GBLogEx.error(0,`GBREJECTION: ${GBUtil.toYAML(JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))))}`);
|
||||
GBLogEx.error(
|
||||
0,
|
||||
`GBREJECTION: ${GBUtil.toYAML(JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))))}`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -186,7 +193,6 @@ export class GBServer {
|
|||
} else if (GBConfigService.get('STORAGE_FILE')) {
|
||||
await core.initStorage();
|
||||
} else {
|
||||
runOnce = true;
|
||||
[GBServer.globals.bootInstance, azureDeployer] = await core['createBootInstanceEx'](
|
||||
core,
|
||||
null,
|
||||
|
@ -194,6 +200,7 @@ export class GBServer {
|
|||
deployer,
|
||||
GBConfigService.get('FREE_TIER')
|
||||
);
|
||||
await core.saveInstance(GBServer.globals.bootInstance);
|
||||
}
|
||||
|
||||
core.ensureAdminIsSecured();
|
||||
|
@ -207,10 +214,6 @@ export class GBServer {
|
|||
await deployer.deployPackages(core, server, GBServer.globals.appPackages);
|
||||
await core.syncDatabaseStructure();
|
||||
|
||||
if (runOnce) {
|
||||
await core.saveInstance(GBServer.globals.bootInstance);
|
||||
}
|
||||
|
||||
// Deployment of local applications for the first time.
|
||||
|
||||
if (GBConfigService.get('DISABLE_WEB') !== 'true') {
|
||||
|
@ -224,24 +227,28 @@ export class GBServer {
|
|||
GBServer.globals.publicAddress
|
||||
);
|
||||
|
||||
if (instances.length === 0) {
|
||||
const instance = await importer.importIfNotExistsBotPackage(
|
||||
GBConfigService.get('BOT_ID'),
|
||||
'boot.gbot',
|
||||
'packages/boot.gbot',
|
||||
GBServer.globals.bootInstance
|
||||
);
|
||||
if (instances. length === 0) {
|
||||
if (!GBConfigService.get('STORAGE_FILE')) {
|
||||
const instance = await importer.importIfNotExistsBotPackage(
|
||||
GBConfigService.get('BOT_ID'),
|
||||
'boot.gbot',
|
||||
'packages/boot.gbot',
|
||||
GBServer.globals.bootInstance
|
||||
);
|
||||
|
||||
instances.push(instance);
|
||||
GBServer.globals.minBoot.instance = instances[0];
|
||||
GBServer.globals.bootInstance = instances[0];
|
||||
await deployer.deployBotFull(instance, GBServer.globals.publicAddress);
|
||||
instances.push(instance);
|
||||
GBServer.globals.minBoot.instance = instances[0];
|
||||
GBServer.globals.bootInstance = instances[0];
|
||||
await deployer.deployBotOnAzure(instance, GBServer.globals.publicAddress);
|
||||
|
||||
// Runs the search even with empty content to create structure.
|
||||
// Runs the search even with empty content to create structure.
|
||||
|
||||
await azureDeployer['runSearch'](instance);
|
||||
await azureDeployer['runSearch'](instance);
|
||||
}
|
||||
}
|
||||
|
||||
await core['ensureFolders'](instances, deployer);
|
||||
|
||||
GBServer.globals.bootInstance = instances[0];
|
||||
|
||||
// Builds minimal service infrastructure.
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
import * as YAML from 'yaml';
|
||||
import SwaggerClient from 'swagger-client';
|
||||
import Fs from 'fs';
|
||||
import { GBConfigService } from '../packages/core.gbapp/services/GBConfigService.js';
|
||||
|
||||
export class GBUtil {
|
||||
public static repeat(chr, count) {
|
||||
|
@ -69,14 +70,14 @@ export class GBUtil {
|
|||
public static async getDirectLineClient(min) {
|
||||
|
||||
let config = {
|
||||
url: `http://127.0.0.1:${process.env.port}/api/messages`,
|
||||
url: `http://127.0.0.1:${GBConfigService.get('PORT')}/api/messages`,
|
||||
spec: JSON.parse(Fs.readFileSync('directline-3.0.json', 'utf8')),
|
||||
requestInterceptor: req => {
|
||||
req.headers['Authorization'] = `Bearer ${min.instance.webchatKey}`;
|
||||
}
|
||||
};
|
||||
if (process.env.STORAGE_FILE) {
|
||||
config['spec'].servers = [{ url: `http://127.0.0.1:${process.env.PORT}/api/messages` }];
|
||||
if (GBConfigService.get('STORAGE_FILE')) {
|
||||
config['spec'].servers = [{ url: `http://127.0.0.1:${GBConfigService.get('PORT')}/api/messages` }];
|
||||
config['openapi'] = '3.0.0';
|
||||
}
|
||||
return await new SwaggerClient(config);
|
||||
|
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 8.8 KiB |
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 8.8 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 2 KiB After Width: | Height: | Size: 2 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 70 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 958 B After Width: | Height: | Size: 958 B |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 6.5 KiB |
Before Width: | Height: | Size: 247 KiB After Width: | Height: | Size: 247 KiB |
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 64 KiB |
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 79 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |