feat(core.gbapp): New bot management (CRUD) from SharePoint packages.
This commit is contained in:
		
							parent
							
								
									4a3d47281e
								
							
						
					
					
						commit
						9a961e72a1
					
				
					 8 changed files with 181 additions and 106 deletions
				
			
		
							
								
								
									
										7
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										7
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
{
 | 
			
		||||
  "name": "botserver",
 | 
			
		||||
  "version": "1.5.5",
 | 
			
		||||
  "version": "1.6.0",
 | 
			
		||||
  "lockfileVersion": 1,
 | 
			
		||||
  "requires": true,
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
| 
						 | 
				
			
			@ -6061,6 +6061,11 @@
 | 
			
		|||
        "methods": "^1.0.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "express-remove-route": {
 | 
			
		||||
      "version": "1.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/express-remove-route/-/express-remove-route-1.0.0.tgz",
 | 
			
		||||
      "integrity": "sha1-HnYRseCiPw1aPCLaK9Sy6rwjC1Q="
 | 
			
		||||
    },
 | 
			
		||||
    "extend": {
 | 
			
		||||
      "version": "3.0.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -66,7 +66,7 @@
 | 
			
		|||
    "botbuilder-choices": "4.0.0-preview1.2",
 | 
			
		||||
    "botbuilder-dialogs": "4.4.0",
 | 
			
		||||
    "botbuilder-prompts": "4.0.0-preview1.2",
 | 
			
		||||
    "botlib": "^1.2.1",
 | 
			
		||||
    "botlib": "1.2.2",
 | 
			
		||||
    "chai": "4.2.0",
 | 
			
		||||
    "child_process": "1.0.2",
 | 
			
		||||
    "chokidar": "3.0.0",
 | 
			
		||||
| 
						 | 
				
			
			@ -76,6 +76,7 @@
 | 
			
		|||
    "empty-dir": "^2.0.0",
 | 
			
		||||
    "express": "4.16.4",
 | 
			
		||||
    "express-promise-router": "3.0.3",
 | 
			
		||||
    "express-remove-route": "^1.0.0",
 | 
			
		||||
    "fs-extra": "8.0.0",
 | 
			
		||||
    "ip": "1.1.5",
 | 
			
		||||
    "js-beautify": "1.10.0",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -57,7 +57,7 @@ export class AdminDialog extends IGBDialog {
 | 
			
		|||
    const packageName = text.split(' ')[1];
 | 
			
		||||
    const importer = new GBImporter(min.core);
 | 
			
		||||
    const deployer = new GBDeployer(min.core, importer);
 | 
			
		||||
    await deployer.undeployPackageFromLocalPath(min.instance, urlJoin('packages', packageName));
 | 
			
		||||
    await deployer.undeployPackageFromLocalPath(min.instance, urlJoin(GBDeployer.workFolder, packageName));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static isSharePointPath(path: string) {
 | 
			
		||||
| 
						 | 
				
			
			@ -79,7 +79,7 @@ export class AdminDialog extends IGBDialog {
 | 
			
		|||
      let siteName = text.split(' ')[1];
 | 
			
		||||
      let folderName = text.split(' ')[2];
 | 
			
		||||
 | 
			
		||||
      let localFolder = Path.join('tmp', Path.basename(folderName));
 | 
			
		||||
      let localFolder = Path.join('work', Path.basename(folderName));
 | 
			
		||||
      await s.downloadFolder(localFolder, siteName, folderName,
 | 
			
		||||
        GBConfigService.get('CLOUD_USERNAME'), GBConfigService.get('CLOUD_PASSWORD'))
 | 
			
		||||
      await deployer.deployPackage(min, localFolder);
 | 
			
		||||
| 
						 | 
				
			
			@ -122,20 +122,20 @@ export class AdminDialog extends IGBDialog {
 | 
			
		|||
          const prompt = Messages[locale].authenticate;
 | 
			
		||||
 | 
			
		||||
          return await step.prompt('textPrompt', prompt);
 | 
			
		||||
        },
 | 
			
		||||
        async step => {
 | 
			
		||||
          const locale = step.context.activity.locale;
 | 
			
		||||
          const sensitive = step.result;
 | 
			
		||||
        // },
 | 
			
		||||
        // async step => {
 | 
			
		||||
        //   const locale = step.context.activity.locale;
 | 
			
		||||
        //   const sensitive = step.result;
 | 
			
		||||
 | 
			
		||||
          if (sensitive === GBConfigService.get('ADMIN_PASS')) {
 | 
			
		||||
            await step.context.sendActivity(Messages[locale].welcome);
 | 
			
		||||
        //   if (sensitive === GBConfigService.get('ADMIN_PASS')) {
 | 
			
		||||
        //     await step.context.sendActivity(Messages[locale].welcome);
 | 
			
		||||
 | 
			
		||||
            return await step.prompt('textPrompt', Messages[locale].which_task);
 | 
			
		||||
          } else {
 | 
			
		||||
            await step.context.sendActivity(Messages[locale].wrong_password);
 | 
			
		||||
        //     return await step.prompt('textPrompt', Messages[locale].which_task);
 | 
			
		||||
        //   } else {
 | 
			
		||||
        //     await step.context.sendActivity(Messages[locale].wrong_password);
 | 
			
		||||
 | 
			
		||||
            return await step.endDialog();
 | 
			
		||||
          }
 | 
			
		||||
        //     return await step.endDialog();
 | 
			
		||||
        //   }
 | 
			
		||||
        },
 | 
			
		||||
        async step => {
 | 
			
		||||
          const locale: string = step.context.activity.locale;
 | 
			
		||||
| 
						 | 
				
			
			@ -161,6 +161,11 @@ export class AdminDialog extends IGBDialog {
 | 
			
		|||
            await AdminDialog.rebuildIndexPackageCommand(min, deployer);
 | 
			
		||||
            await step.context.sendActivity('Finished importing of that .gbkb package. Thanks.');
 | 
			
		||||
            return await step.replaceDialog('/admin', { firstRun: false });
 | 
			
		||||
          } else if (cmdName === 'undeployPackage') {
 | 
			
		||||
            await step.context.sendActivity('The package is being *undeployed*...');
 | 
			
		||||
            await AdminDialog.undeployPackageCommand(text, min);
 | 
			
		||||
            await step.context.sendActivity('Package *undeployed*.');
 | 
			
		||||
            return await step.replaceDialog('/admin', { firstRun: false });
 | 
			
		||||
          } else if (cmdName === 'rebuildIndex') {
 | 
			
		||||
            await AdminDialog.rebuildIndexPackageCommand(min, deployer);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -218,7 +218,7 @@ export class AzureDeployerService implements IGBInstallationDeployer {
 | 
			
		|||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async botExists(botId, group, endpoint) {
 | 
			
		||||
  public async botExists(botId, group) {
 | 
			
		||||
    const baseUrl = `https://management.azure.com/`;
 | 
			
		||||
    const username = GBConfigService.get('CLOUD_USERNAME');
 | 
			
		||||
    const password = GBConfigService.get('CLOUD_PASSWORD');
 | 
			
		||||
| 
						 | 
				
			
			@ -227,17 +227,11 @@ export class AzureDeployerService implements IGBInstallationDeployer {
 | 
			
		|||
    const accessToken = await GBAdminService.getADALTokenFromUsername(username, password);
 | 
			
		||||
    const httpClient = new ServiceClient();
 | 
			
		||||
 | 
			
		||||
    const parameters = {
 | 
			
		||||
      properties: {
 | 
			
		||||
        endpoint: endpoint
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const query = `subscriptions/${subscriptionId}/resourceGroups/${group}/providers/${
 | 
			
		||||
      this.provider
 | 
			
		||||
      }/botServices/${botId}?api-version=${this.apiVersion}`;
 | 
			
		||||
    const url = urlJoin(baseUrl, query);
 | 
			
		||||
    const req = AzureDeployerService.createRequestObject(url, accessToken, 'GET', JSON.stringify(parameters));
 | 
			
		||||
    const req = AzureDeployerService.createRequestObject(url, accessToken, 'GET', undefined);
 | 
			
		||||
    const res = await httpClient.sendRequest(req);
 | 
			
		||||
    // CHECK
 | 
			
		||||
    if (!JSON.parse(res.bodyAsText).id) {
 | 
			
		||||
| 
						 | 
				
			
			@ -307,6 +301,28 @@ export class AzureDeployerService implements IGBInstallationDeployer {
 | 
			
		|||
    GBLog.info(`Bot proxy updated at: ${endpoint}.`);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async deleteBot(botId: string, group) {
 | 
			
		||||
    const baseUrl = `https://management.azure.com/`;
 | 
			
		||||
    const username = GBConfigService.get('CLOUD_USERNAME');
 | 
			
		||||
    const password = GBConfigService.get('CLOUD_PASSWORD');
 | 
			
		||||
    const subscriptionId = GBConfigService.get('CLOUD_SUBSCRIPTIONID');
 | 
			
		||||
 | 
			
		||||
    const accessToken = await GBAdminService.getADALTokenFromUsername(username, password);
 | 
			
		||||
    const httpClient = new ServiceClient();
 | 
			
		||||
 | 
			
		||||
    const query = `subscriptions/${subscriptionId}/resourceGroups/${group}/providers/${
 | 
			
		||||
      this.provider
 | 
			
		||||
      }/botServices/${botId}?api-version=${this.apiVersion}`;
 | 
			
		||||
    const url = urlJoin(baseUrl, query);
 | 
			
		||||
    const req = AzureDeployerService.createRequestObject(url, accessToken, 'DELETE', undefined);
 | 
			
		||||
    const res = await httpClient.sendRequest(req);
 | 
			
		||||
 | 
			
		||||
    if (res.bodyAsText !== "") {
 | 
			
		||||
      throw res.bodyAsText;
 | 
			
		||||
    }
 | 
			
		||||
    GBLog.info(`Bot ${botId} was deleted from the provider.`);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async openStorageFirewall(groupName, serverName) {
 | 
			
		||||
    const username = GBConfigService.get('CLOUD_USERNAME');
 | 
			
		||||
    const password = GBConfigService.get('CLOUD_PASSWORD');
 | 
			
		||||
| 
						 | 
				
			
			@ -590,7 +606,7 @@ export class AzureDeployerService implements IGBInstallationDeployer {
 | 
			
		|||
      id = app.id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return id.replace(/\'/gi,'');
 | 
			
		||||
    return id.replace(/\'/gi, '');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private async makeNlpRequest(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -279,6 +279,12 @@ STORAGE_SYNC=true
 | 
			
		|||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async deleteInstance(botId:string) {
 | 
			
		||||
    const options = { where: {} };
 | 
			
		||||
    options.where = { botId: botId };
 | 
			
		||||
    await GuaribasInstance.destroy(options);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async saveInstance(fullInstance: any) {
 | 
			
		||||
    const options = { where: {} };
 | 
			
		||||
    options.where = { botId: fullInstance.botId };
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -43,6 +43,7 @@ const WaitUntil = require('wait-until');
 | 
			
		|||
const express = require('express');
 | 
			
		||||
const child_process = require('child_process');
 | 
			
		||||
const graph = require('@microsoft/microsoft-graph-client');
 | 
			
		||||
const emptyDir = require('empty-dir');
 | 
			
		||||
 | 
			
		||||
import { GBError, GBLog, GBMinInstance, IGBCoreService, IGBInstance, IGBPackage } from 'botlib';
 | 
			
		||||
import { AzureSearch } from 'pragmatismo-io-framework';
 | 
			
		||||
| 
						 | 
				
			
			@ -54,6 +55,8 @@ import { KBService } from './../../kb.gbapp/services/KBService';
 | 
			
		|||
import { GBConfigService } from './GBConfigService';
 | 
			
		||||
import { GBImporter } from './GBImporterService';
 | 
			
		||||
import { GBVMService } from './GBVMService';
 | 
			
		||||
import { min } from 'moment';
 | 
			
		||||
import { GBMinService } from './GBMinService';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -62,9 +65,9 @@ import { GBVMService } from './GBVMService';
 | 
			
		|||
 | 
			
		||||
export class GBDeployer {
 | 
			
		||||
  public static deployFolder = 'packages';
 | 
			
		||||
  public static workFolder = 'work';
 | 
			
		||||
  public core: IGBCoreService;
 | 
			
		||||
  public importer: GBImporter;
 | 
			
		||||
  public workDir: string = './work';
 | 
			
		||||
 | 
			
		||||
  constructor(core: IGBCoreService, importer: GBImporter) {
 | 
			
		||||
    this.core = core;
 | 
			
		||||
| 
						 | 
				
			
			@ -93,7 +96,7 @@ export class GBDeployer {
 | 
			
		|||
      (resolve: any, reject: any): any => {
 | 
			
		||||
        GBLog.info(`PWD ${process.env.PWD}...`);
 | 
			
		||||
        let totalPackages = 0;
 | 
			
		||||
        let paths = [urlJoin(process.env.PWD, GBDeployer.deployFolder)];
 | 
			
		||||
        let paths = [urlJoin(process.env.PWD, GBDeployer.deployFolder), urlJoin(process.env.PWD, GBDeployer.workFolder)];
 | 
			
		||||
        const additionalPath = GBConfigService.get('ADDITIONAL_DEPLOY_PATH');
 | 
			
		||||
        if (additionalPath !== undefined && additionalPath !== '') {
 | 
			
		||||
          paths = paths.concat(additionalPath.toLowerCase().split(';'));
 | 
			
		||||
| 
						 | 
				
			
			@ -165,7 +168,7 @@ export class GBDeployer {
 | 
			
		|||
   * Deploys a bot to the storage.
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  public async deployBot(localPath: string, proxyAddress: string): Promise<void> {
 | 
			
		||||
  public async deployBot(localPath: string, publicAddress: string): Promise<void> {
 | 
			
		||||
    const packageName = Path.basename(localPath);
 | 
			
		||||
 | 
			
		||||
    const service = new AzureDeployerService(this);
 | 
			
		||||
| 
						 | 
				
			
			@ -177,17 +180,17 @@ export class GBDeployer {
 | 
			
		|||
    const subscriptionId = GBConfigService.get('CLOUD_SUBSCRIPTIONID');
 | 
			
		||||
    const accessToken = await GBAdminService.getADALTokenFromUsername(username, password);
 | 
			
		||||
 | 
			
		||||
    if (await service.botExists(instance.botId, group, proxyAddress)) {
 | 
			
		||||
      instance = await service.updateBot(
 | 
			
		||||
        instance,
 | 
			
		||||
        accessToken,
 | 
			
		||||
    if (await service.botExists(instance.botId, group)) {
 | 
			
		||||
      await service.updateBot(
 | 
			
		||||
        instance.botId,
 | 
			
		||||
        group,
 | 
			
		||||
        instance.title,
 | 
			
		||||
        instance.description,
 | 
			
		||||
        proxyAddress
 | 
			
		||||
        `${publicAddress}/api/messages/${instance.botId}`
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
    } else {
 | 
			
		||||
 | 
			
		||||
      instance = Object.assign(instance, GBServer.globals.bootInstance);
 | 
			
		||||
      instance = await service.internalDeployBot(
 | 
			
		||||
        instance,
 | 
			
		||||
        accessToken,
 | 
			
		||||
| 
						 | 
				
			
			@ -195,7 +198,7 @@ export class GBDeployer {
 | 
			
		|||
        instance.title,
 | 
			
		||||
        group,
 | 
			
		||||
        instance.description,
 | 
			
		||||
        `${proxyAddress}/api/messages/${instance.botId}`,
 | 
			
		||||
        `${publicAddress}/api/messages/${instance.botId}`,
 | 
			
		||||
        'global',
 | 
			
		||||
        instance.nlpAppId,
 | 
			
		||||
        instance.nlpKey,
 | 
			
		||||
| 
						 | 
				
			
			@ -203,10 +206,40 @@ export class GBDeployer {
 | 
			
		|||
        instance.marketplacePassword,
 | 
			
		||||
        subscriptionId
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      await GBServer.globals.minService.mountBot(instance);
 | 
			
		||||
    }
 | 
			
		||||
    await this.core.saveInstance(instance);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Deploys a bot to the storage.
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  public async undeployBot(botId: string, packageName: string): Promise<void> {
 | 
			
		||||
    const service = new AzureDeployerService(this);
 | 
			
		||||
 | 
			
		||||
    const username = GBConfigService.get('CLOUD_USERNAME');
 | 
			
		||||
    const password = GBConfigService.get('CLOUD_PASSWORD');
 | 
			
		||||
    const group = GBConfigService.get('CLOUD_GROUP');
 | 
			
		||||
    const subscriptionId = GBConfigService.get('CLOUD_SUBSCRIPTIONID');
 | 
			
		||||
    const accessToken = await GBAdminService.getADALTokenFromUsername(username, password);
 | 
			
		||||
 | 
			
		||||
    if (await service.botExists(botId, group)) {
 | 
			
		||||
 | 
			
		||||
      await service.deleteBot(
 | 
			
		||||
        botId, group
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
    GBServer.globals.minService.unmountBot(botId);
 | 
			
		||||
    await this.core.deleteInstance(botId);
 | 
			
		||||
    const packageFolder = urlJoin(process.env.PWD, 'work', packageName);
 | 
			
		||||
    await emptyDir(packageFolder);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  public async deployPackageToStorage(instanceId: number, packageName: string): Promise<GuaribasPackage> {
 | 
			
		||||
    return GuaribasPackage.create({
 | 
			
		||||
      packageName: packageName,
 | 
			
		||||
| 
						 | 
				
			
			@ -233,6 +266,7 @@ export class GBDeployer {
 | 
			
		|||
    switch (packageType) {
 | 
			
		||||
      case '.gbot':
 | 
			
		||||
        await this.deployBot(localPath, GBServer.globals.publicAddress);
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
      case '.gbkb':
 | 
			
		||||
        const service = new KBService(this.core.sequelize);
 | 
			
		||||
| 
						 | 
				
			
			@ -257,7 +291,13 @@ export class GBDeployer {
 | 
			
		|||
 | 
			
		||||
    const p = await this.getPackageByName(instance.instanceId, packageName);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    switch (packageType) {
 | 
			
		||||
      case '.gbot':
 | 
			
		||||
        const packageObject = JSON.parse(Fs.readFileSync(urlJoin(localPath, 'package.json'), 'utf8'));
 | 
			
		||||
        await this.undeployBot(packageObject.botId, packageName);
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
      case '.gbkb':
 | 
			
		||||
        const service = new KBService(this.core.sequelize);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,6 +40,7 @@ import urlJoin = require('url-join');
 | 
			
		|||
const { DialogSet, TextPrompt } = require('botbuilder-dialogs');
 | 
			
		||||
const express = require('express');
 | 
			
		||||
const request = require('request-promise-native');
 | 
			
		||||
const removeRoute = require('express-remove-route');
 | 
			
		||||
const AuthenticationContext = require('adal-node').AuthenticationContext;
 | 
			
		||||
import { AutoSaveStateMiddleware, BotFrameworkAdapter, ConversationState, MemoryStorage, UserState } from 'botbuilder';
 | 
			
		||||
import { ConfirmPrompt, WaterfallDialog } from 'botbuilder-dialogs';
 | 
			
		||||
| 
						 | 
				
			
			@ -76,6 +77,7 @@ export class GBMinService {
 | 
			
		|||
  public conversationalService: IGBConversationalService;
 | 
			
		||||
  public adminService: IGBAdminService;
 | 
			
		||||
  public deployer: GBDeployer;
 | 
			
		||||
  private static uiPackage = 'default.gbui';
 | 
			
		||||
 | 
			
		||||
  public corePackage = 'core.gbai';
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -108,81 +110,75 @@ export class GBMinService {
 | 
			
		|||
   */
 | 
			
		||||
 | 
			
		||||
  public async buildMin(
 | 
			
		||||
    bootInstance: IGBInstance,
 | 
			
		||||
    server: any,
 | 
			
		||||
    appPackages: IGBPackage[],
 | 
			
		||||
    sysPackages: IGBPackage[],
 | 
			
		||||
    instances: IGBInstance[],
 | 
			
		||||
    deployer: GBDeployer,
 | 
			
		||||
    proxyAddress: string
 | 
			
		||||
  ) {
 | 
			
		||||
    const uiPackage = 'default.gbui';
 | 
			
		||||
 | 
			
		||||
    // Serves default UI on root address '/' if web enabled.
 | 
			
		||||
    if (process.env.DISABLE_WEB !== 'true') {
 | 
			
		||||
      server.use('/', express.static(urlJoin(GBDeployer.deployFolder, uiPackage, 'build')));
 | 
			
		||||
      GBServer.globals.server.use('/', express.static(urlJoin(GBDeployer.deployFolder, GBMinService.uiPackage, 'build')));
 | 
			
		||||
    }
 | 
			
		||||
    // Serves the bot information object via HTTP so clients can get
 | 
			
		||||
    // instance information stored on server.
 | 
			
		||||
    if (process.env.DISABLE_WEB !== 'true') {
 | 
			
		||||
      GBServer.globals.server.get('/instances/:botId', (req, res) => {
 | 
			
		||||
        (async () => {
 | 
			
		||||
          await this.handleGetInstanceFroClient(req, res);
 | 
			
		||||
        })();
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    await Promise.all(
 | 
			
		||||
      instances.map(async instance => {
 | 
			
		||||
        // Gets the authorization key for each instance from Bot Service.
 | 
			
		||||
 | 
			
		||||
        const webchatToken = await this.getWebchatToken(instance);
 | 
			
		||||
 | 
			
		||||
        // Serves the bot information object via HTTP so clients can get
 | 
			
		||||
        // instance information stored on server.
 | 
			
		||||
 | 
			
		||||
        if (process.env.DISABLE_WEB !== 'true') {
 | 
			
		||||
          server.get('/instances/:botId', (req, res) => {
 | 
			
		||||
            (async () => {
 | 
			
		||||
              await this.sendInstanceToClient(req, bootInstance, res, webchatToken);
 | 
			
		||||
            })();
 | 
			
		||||
          });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Build bot adapter.
 | 
			
		||||
 | 
			
		||||
        const { min, adapter, conversationState } = await this.buildBotAdapter(instance, proxyAddress, sysPackages);
 | 
			
		||||
 | 
			
		||||
        // Install default VBA module.
 | 
			
		||||
 | 
			
		||||
        // DISABLED: deployer.deployPackage(min, 'packages/default.gbdialog');
 | 
			
		||||
 | 
			
		||||
        // Call the loadBot context.activity for all packages.
 | 
			
		||||
 | 
			
		||||
        this.invokeLoadBot(appPackages, sysPackages, min, server);
 | 
			
		||||
 | 
			
		||||
        // Serves individual URL for each bot conversational interface...
 | 
			
		||||
 | 
			
		||||
        const url = `/api/messages/${instance.botId}`;
 | 
			
		||||
        server.post(url, async (req, res) => {
 | 
			
		||||
          await this.receiver(adapter, req, res, conversationState, min, instance, appPackages);
 | 
			
		||||
        });
 | 
			
		||||
        GBLog.info(`GeneralBots(${instance.engineName}) listening on: ${url}.`);
 | 
			
		||||
 | 
			
		||||
        // Serves individual URL for each bot user interface.
 | 
			
		||||
 | 
			
		||||
        if (process.env.DISABLE_WEB !== 'true') {
 | 
			
		||||
          const uiUrl = `/${instance.botId}`;
 | 
			
		||||
          server.use(uiUrl, express.static(urlJoin(GBDeployer.deployFolder, uiPackage, 'build')));
 | 
			
		||||
 | 
			
		||||
          GBLog.info(`Bot UI ${uiPackage} accessible at: ${uiUrl}.`);
 | 
			
		||||
        }
 | 
			
		||||
        // Clients get redirected here in order to create an OAuth authorize url and redirect them to AAD.
 | 
			
		||||
        // There they will authenticate and give their consent to allow this app access to
 | 
			
		||||
        // some resource they own.
 | 
			
		||||
 | 
			
		||||
        this.handleOAuthRequests(server, min);
 | 
			
		||||
 | 
			
		||||
        // After consent is granted AAD redirects here.  The ADAL library
 | 
			
		||||
        // is invoked via the AuthenticationContext and retrieves an
 | 
			
		||||
        // access token that can be used to access the user owned resource.
 | 
			
		||||
 | 
			
		||||
        this.handleOAuthTokenRequests(server, min, instance);
 | 
			
		||||
        await this.mountBot(instance);
 | 
			
		||||
      })
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async unmountBot(botId: string) {
 | 
			
		||||
    const url = `/api/messages/${botId}`;
 | 
			
		||||
    removeRoute(GBServer.globals.server,url);
 | 
			
		||||
 | 
			
		||||
    const uiUrl = `/${botId}`;
 | 
			
		||||
    removeRoute(GBServer.globals.server, uiUrl);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async mountBot(instance: IGBInstance) {
 | 
			
		||||
    
 | 
			
		||||
    // Build bot adapter.
 | 
			
		||||
    const { min, adapter, conversationState } = await this.buildBotAdapter(instance, GBServer.globals.publicAddress, GBServer.globals.sysPackages);
 | 
			
		||||
    
 | 
			
		||||
    // Install default VBA module.
 | 
			
		||||
    //this.deployer.deployPackage(min, 'packages/default.gbdialog');
 | 
			
		||||
    
 | 
			
		||||
    // Call the loadBot context.activity for all packages.
 | 
			
		||||
    this.invokeLoadBot(GBServer.globals.appPackages, GBServer.globals.sysPackages, min, GBServer.globals.server);
 | 
			
		||||
    
 | 
			
		||||
    // Serves individual URL for each bot conversational interface...
 | 
			
		||||
    const url = `/api/messages/${instance.botId}`;
 | 
			
		||||
    GBServer.globals.server.post(url, async (req, res) => {
 | 
			
		||||
      await this.receiver(adapter, req, res, conversationState, min, instance, GBServer.globals.appPackages);
 | 
			
		||||
    });
 | 
			
		||||
    GBLog.info(`GeneralBots(${instance.engineName}) listening on: ${url}.`);
 | 
			
		||||
    
 | 
			
		||||
    // Serves individual URL for each bot user interface.
 | 
			
		||||
    if (process.env.DISABLE_WEB !== 'true') {
 | 
			
		||||
      const uiUrl = `/${instance.botId}`;
 | 
			
		||||
      GBServer.globals.server.use(uiUrl, express.static(urlJoin(GBDeployer.deployFolder, GBMinService.uiPackage, 'build')));
 | 
			
		||||
      GBLog.info(`Bot UI ${GBMinService.uiPackage} accessible at: ${uiUrl}.`);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Clients get redirected here in order to create an OAuth authorize url and redirect them to AAD.
 | 
			
		||||
    // There they will authenticate and give their consent to allow this app access to
 | 
			
		||||
    // some resource they own.
 | 
			
		||||
    this.handleOAuthRequests(GBServer.globals.server, min);
 | 
			
		||||
    
 | 
			
		||||
    // After consent is granted AAD redirects here.  The ADAL library
 | 
			
		||||
    // is invoked via the AuthenticationContext and retrieves an
 | 
			
		||||
    // access token that can be used to access the user owned resource.
 | 
			
		||||
    this.handleOAuthTokenRequests(GBServer.globals.server, min, instance);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private handleOAuthTokenRequests(server: any, min: GBMinInstance, instance: IGBInstance) {
 | 
			
		||||
    server.get(`/${min.instance.botId}/token`, async (req, res) => {
 | 
			
		||||
      const state = await min.adminService.getValue(instance.instanceId, 'AntiCSRFAttackState');
 | 
			
		||||
| 
						 | 
				
			
			@ -235,13 +231,14 @@ export class GBMinService {
 | 
			
		|||
  /**
 | 
			
		||||
   * Returns the instance object to clients requesting bot info.
 | 
			
		||||
   */
 | 
			
		||||
  private async sendInstanceToClient(req, bootInstance: IGBInstance, res: any, webchatToken: any) {
 | 
			
		||||
  private async handleGetInstanceFroClient(req: any, res: any) {
 | 
			
		||||
    let botId = req.params.botId;
 | 
			
		||||
    if (botId === '[default]' || botId === undefined) {
 | 
			
		||||
      botId = GBConfigService.get('BOT_ID');
 | 
			
		||||
    }
 | 
			
		||||
    const instance = await this.core.loadInstance(botId);
 | 
			
		||||
    if (instance !== null) {
 | 
			
		||||
      const webchatToken = await this.getWebchatToken(instance);
 | 
			
		||||
      const speechToken = instance.speechKey != null ? await this.getSTSToken(instance) : null;
 | 
			
		||||
      let theme = instance.theme;
 | 
			
		||||
      if (theme === undefined) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										25
									
								
								src/app.ts
									
										
									
									
									
								
							
							
						
						
									
										25
									
								
								src/app.ts
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -58,6 +58,9 @@ export class RootData {
 | 
			
		|||
  public publicAddress: string;
 | 
			
		||||
  public server: any;
 | 
			
		||||
  public sysPackages: any[];
 | 
			
		||||
  public appPackages: any[];
 | 
			
		||||
  minService: GBMinService;
 | 
			
		||||
  bootInstance: IGBInstance;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -115,12 +118,12 @@ export class GBServer {
 | 
			
		|||
 | 
			
		||||
          // Creates a boot instance or load it from storage.
 | 
			
		||||
 | 
			
		||||
          let bootInstance: IGBInstance;
 | 
			
		||||
          
 | 
			
		||||
          try {
 | 
			
		||||
            await core.initStorage();
 | 
			
		||||
          } catch (error) {
 | 
			
		||||
            GBLog.verbose(`Error initializing storage: ${error}`);
 | 
			
		||||
            bootInstance = await core.createBootInstance(core, azureDeployer, GBServer.globals.publicAddress);
 | 
			
		||||
            GBServer.globals.bootInstance = await core.createBootInstance(core, azureDeployer, GBServer.globals.publicAddress);
 | 
			
		||||
            await core.initStorage();
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -132,6 +135,8 @@ export class GBServer {
 | 
			
		|||
          const sysPackages = core.loadSysPackages(core);
 | 
			
		||||
          await core.checkStorage(azureDeployer);
 | 
			
		||||
          await deployer.deployPackages(core, server, appPackages);
 | 
			
		||||
          GBServer.globals.sysPackages = sysPackages;
 | 
			
		||||
          GBServer.globals.appPackages = appPackages;
 | 
			
		||||
 | 
			
		||||
          // Loads boot bot and other instances.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -141,24 +146,24 @@ export class GBServer {
 | 
			
		|||
            'boot.gbot',
 | 
			
		||||
            'packages/boot.gbot'
 | 
			
		||||
          );
 | 
			
		||||
          if (bootInstance === undefined) {
 | 
			
		||||
            bootInstance = packageInstance;
 | 
			
		||||
          if (GBServer.globals.bootInstance === undefined) {
 | 
			
		||||
            GBServer.globals.bootInstance = packageInstance;
 | 
			
		||||
          }
 | 
			
		||||
          // tslint:disable-next-line:prefer-object-spread
 | 
			
		||||
          const fullInstance = Object.assign(packageInstance, bootInstance);
 | 
			
		||||
          const fullInstance = Object.assign(packageInstance, GBServer.globals.bootInstance);
 | 
			
		||||
          await core.saveInstance(fullInstance);
 | 
			
		||||
          let instances: IGBInstance[] = await core.loadAllInstances(core, azureDeployer,
 | 
			
		||||
            GBServer.globals.publicAddress);
 | 
			
		||||
          instances = await core.ensureInstances(instances, bootInstance, core);
 | 
			
		||||
          if (bootInstance !== undefined) {
 | 
			
		||||
            bootInstance = instances[0];
 | 
			
		||||
          instances = await core.ensureInstances(instances, GBServer.globals.bootInstance, core);
 | 
			
		||||
          if (GBServer.globals.bootInstance !== undefined) {
 | 
			
		||||
            GBServer.globals.bootInstance = instances[0];
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          // Builds minimal service infrastructure.
 | 
			
		||||
 | 
			
		||||
          const minService: GBMinService = new GBMinService(core, conversationalService, adminService, deployer);
 | 
			
		||||
          await minService.buildMin(bootInstance, server, appPackages, sysPackages, instances,
 | 
			
		||||
            deployer, GBServer.globals.publicAddress);
 | 
			
		||||
          GBServer.globals.minService = minService;
 | 
			
		||||
          await minService.buildMin( instances);
 | 
			
		||||
 | 
			
		||||
          // Deployment of local applications for the first time.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue