fix(VBA): Several bugs fixed and refactoring on Deployer Service done.
This commit is contained in:
parent
3cc92ecec7
commit
fecbd3e92c
10 changed files with 549 additions and 568 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -15,3 +15,6 @@
|
|||
/work
|
||||
/packages/default.gbdialog/bot.js
|
||||
/packages/default.gbdialog/bot.ts
|
||||
*.vbs.compiled
|
||||
*.vbs.js
|
||||
*.vbs.ts
|
||||
|
|
227
packages/azuredeployer.gbapp/dialogs/StartDialog.ts
Normal file
227
packages/azuredeployer.gbapp/dialogs/StartDialog.ts
Normal file
|
@ -0,0 +1,227 @@
|
|||
/*****************************************************************************\
|
||||
| ( )_ _ |
|
||||
| _ _ _ __ _ _ __ ___ ___ _ _ | ,_)(_) ___ ___ _ |
|
||||
| ( '_`\ ( '__)/'_` ) /'_ `\/' _ ` _ `\ /'_` )| | | |/',__)/' _ `\ /'_`\ |
|
||||
| | (_) )| | ( (_| |( (_) || ( ) ( ) |( (_| || |_ | |\__, \| ( ) |( (_) ) |
|
||||
| | ,__/'(_) `\__,_)`\__ |(_) (_) (_)`\__,_)`\__)(_)(____/(_) (_)`\___/' |
|
||||
| | | ( )_) | |
|
||||
| (_) \___/' |
|
||||
| |
|
||||
| General Bots Copyright (c) Pragmatismo.io. All rights reserved. |
|
||||
| Licensed under the AGPL-3.0. |
|
||||
| |
|
||||
| According to our dual licensing model, this program can be used either |
|
||||
| under the terms of the GNU Affero General Public License, version 3, |
|
||||
| or under a proprietary license. |
|
||||
| |
|
||||
| The texts of the GNU Affero General Public License with an additional |
|
||||
| permission and of our proprietary license can be found at and |
|
||||
| in the LICENSE file you have received along with this program. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY, without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU Affero General Public License for more details. |
|
||||
| |
|
||||
| "General Bots" is a registered trademark of Pragmatismo.io. |
|
||||
| The licensing of the program under the AGPLv3 does not imply a |
|
||||
| trademark license. Therefore any rights, title and interest in |
|
||||
| our trademarks remain entirely with us. |
|
||||
| |
|
||||
\*****************************************************************************/
|
||||
|
||||
/**
|
||||
* @fileoverview General Bots server core.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { IGBInstance } from 'botlib';
|
||||
import * as fs from 'fs';
|
||||
import { GBAdminService } from '../../../packages/admin.gbapp/services/GBAdminService';
|
||||
import { GBConfigService } from '../../../packages/core.gbapp/services/GBConfigService';
|
||||
import { AzureDeployerService } from '../services/AzureDeployerService';
|
||||
import { GuaribasInstance } from '../../../packages/core.gbapp/models/GBModel';
|
||||
const scanf = require('scanf');
|
||||
|
||||
/**
|
||||
* Handles command-line dialog for getting info for Boot Bot.
|
||||
*/
|
||||
export class StartDialog {
|
||||
|
||||
public static async createBaseInstance() {
|
||||
|
||||
// No .env so asks for cloud credentials to start a new farm.
|
||||
|
||||
if (!fs.existsSync(`.env`)) {
|
||||
process.stdout.write(
|
||||
'A empty enviroment is detected. To start automatic deploy, please enter some information:\n'
|
||||
);
|
||||
}
|
||||
|
||||
let botId: string;
|
||||
while (botId === undefined) {
|
||||
botId = this.retrieveBotId();
|
||||
}
|
||||
|
||||
let username: string;
|
||||
while (username === undefined) {
|
||||
username = this.retrieveUsername();
|
||||
}
|
||||
|
||||
let password: string;
|
||||
while (password === undefined) {
|
||||
password = this.retrievePassword();
|
||||
}
|
||||
|
||||
// Connects to the cloud and retrieves subscriptions.
|
||||
|
||||
const credentials = await GBAdminService.getADALCredentialsFromUsername(username, password);
|
||||
const list = await AzureDeployerService.getSubscriptions(credentials);
|
||||
|
||||
let subscriptionId: string;
|
||||
while (subscriptionId === undefined) {
|
||||
subscriptionId = this.retrieveSubscriptionId(list);
|
||||
}
|
||||
|
||||
let location: string;
|
||||
while (location === undefined) {
|
||||
location = this.retrieveLocation();
|
||||
}
|
||||
|
||||
let appId: string;
|
||||
while (appId === undefined) {
|
||||
appId = this.retrieveAppId();
|
||||
}
|
||||
|
||||
let appPassword: string;
|
||||
while (appPassword === undefined) {
|
||||
appPassword = this.retrieveAppPassword();
|
||||
}
|
||||
|
||||
let authoringKey: string;
|
||||
while (authoringKey === undefined) {
|
||||
authoringKey = this.retrieveAuthoringKey();
|
||||
}
|
||||
|
||||
// Prepares the first instance on bot farm.
|
||||
const instance = new GuaribasInstance();
|
||||
|
||||
instance.botId = botId;
|
||||
instance.cloudUsername = username;
|
||||
instance.cloudPassword = password;
|
||||
instance.cloudSubscriptionId = subscriptionId;
|
||||
instance.cloudLocation = location;
|
||||
instance.nlpAuthoringKey = authoringKey;
|
||||
instance.marketplaceId = appId;
|
||||
instance.marketplacePassword = appPassword;
|
||||
instance.adminPass = GBAdminService.getRndPassword();
|
||||
|
||||
return {instance, credentials, subscriptionId};
|
||||
}
|
||||
|
||||
private static retrieveUsername() {
|
||||
let value = GBConfigService.get('CLOUD_USERNAME');
|
||||
if (!value) {
|
||||
process.stdout.write(`${GBAdminService.GB_PROMPT}CLOUD_USERNAME:`);
|
||||
value = scanf('%s').replace(/(\n|\r)+$/, '');
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private static retrievePassword() {
|
||||
let password = GBConfigService.get('CLOUD_PASSWORD');
|
||||
if (!password) {
|
||||
process.stdout.write(`${GBAdminService.GB_PROMPT}CLOUD_PASSWORD:`);
|
||||
password = scanf('%s').replace(/(\n|\r)+$/, '');
|
||||
}
|
||||
return password;
|
||||
}
|
||||
|
||||
private static retrieveBotId() {
|
||||
let botId = GBConfigService.get('BOT_ID');
|
||||
if (!botId) {
|
||||
process.stdout.write(
|
||||
`${GBAdminService.GB_PROMPT}Choose a unique bot Id containing lowercase letters, digits or
|
||||
dashes (cannot use dash as the first two or last one characters),
|
||||
cannot start or end with or contain consecutive dashes and having 4 to 42 characters long.\n`
|
||||
);
|
||||
process.stdout.write(`${GBAdminService.GB_PROMPT}BOT_ID:`);
|
||||
|
||||
// TODO: Update this regexp to match description of it.
|
||||
|
||||
botId = scanf('%s').replace(/(\n|\r)+$/, '');
|
||||
}
|
||||
|
||||
return botId;
|
||||
}
|
||||
|
||||
private static retrieveAuthoringKey() {
|
||||
let authoringKey = GBConfigService.get('NLP_AUTHORING_KEY');
|
||||
if (!authoringKey) {
|
||||
process.stdout.write(
|
||||
`${
|
||||
GBAdminService.GB_PROMPT
|
||||
}Due to this opened issue: https://github.com/Microsoft/botbuilder-tools/issues/550\n`
|
||||
);
|
||||
process.stdout.write(`${GBAdminService.GB_PROMPT}Please enter your LUIS Authoring Key:`);
|
||||
authoringKey = scanf('%s').replace(/(\n|\r)+$/, '');
|
||||
}
|
||||
|
||||
return authoringKey;
|
||||
}
|
||||
|
||||
private static retrieveAppId() {
|
||||
let appId = GBConfigService.get('MARKETPLACE_ID');
|
||||
process.stdout.write(
|
||||
`Sorry, this part cannot be automated yet due to Microsoft schedule,
|
||||
please go to https://apps.dev.microsoft.com/portal/register-app to
|
||||
generate manually an App ID and App Secret.\n`
|
||||
);
|
||||
if (!appId) {
|
||||
process.stdout.write('Generated Application Id (MARKETPLACE_ID):');
|
||||
appId = scanf('%s').replace(/(\n|\r)+$/, '');
|
||||
}
|
||||
|
||||
return appId;
|
||||
}
|
||||
|
||||
private static retrieveAppPassword() {
|
||||
let appPassword = GBConfigService.get('MARKETPLACE_SECRET');
|
||||
if (!appPassword) {
|
||||
process.stdout.write('Generated Password (MARKETPLACE_SECRET):');
|
||||
appPassword = scanf('%s').replace(/(\n|\r)+$/, '');
|
||||
}
|
||||
|
||||
return appPassword;
|
||||
}
|
||||
|
||||
private static retrieveSubscriptionId(list) {
|
||||
let subscriptionId = GBConfigService.get('CLOUD_SUBSCRIPTIONID');
|
||||
const map = {};
|
||||
let index = 1;
|
||||
list.forEach(element => {
|
||||
console.log(`${index}: ${element.displayName} (${element.subscriptionId})`);
|
||||
map[index++] = element;
|
||||
});
|
||||
let subscriptionIndex;
|
||||
if (!subscriptionIndex) {
|
||||
process.stdout.write('CLOUD_SUBSCRIPTIONID (type a number):');
|
||||
subscriptionIndex = scanf('%d');
|
||||
subscriptionId = map[subscriptionIndex].subscriptionId;
|
||||
}
|
||||
|
||||
return subscriptionId;
|
||||
}
|
||||
|
||||
private static retrieveLocation() {
|
||||
let location = GBConfigService.get('CLOUD_LOCATION');
|
||||
if (!location) {
|
||||
process.stdout.write("CLOUD_LOCATION (eg. 'westus'):");
|
||||
location = scanf('%s');
|
||||
}
|
||||
|
||||
return location;
|
||||
}
|
||||
}
|
|
@ -38,40 +38,38 @@
|
|||
|
||||
import { CognitiveServicesManagementClient } from 'azure-arm-cognitiveservices';
|
||||
import { CognitiveServicesAccount } from 'azure-arm-cognitiveservices/lib/models';
|
||||
import {
|
||||
ResourceManagementClient,
|
||||
SubscriptionClient
|
||||
} from 'azure-arm-resource';
|
||||
import { ResourceManagementClient, SubscriptionClient } from 'azure-arm-resource';
|
||||
import { SearchManagementClient } from 'azure-arm-search';
|
||||
import { SqlManagementClient } from 'azure-arm-sql';
|
||||
import { WebSiteManagementClient } from 'azure-arm-website';
|
||||
import { AppServicePlan } from 'azure-arm-website/lib/models';
|
||||
import { GBService, IGBInstance } from 'botlib';
|
||||
import { HttpMethods, ServiceClient, WebResource } from 'ms-rest-js';
|
||||
import { GBDeployer } from 'packages/core.gbapp/services/GBDeployer';
|
||||
import { GBDeployer } from '../../../packages/core.gbapp/services/GBDeployer';
|
||||
import * as simplegit from 'simple-git/promise';
|
||||
import { GBAdminService } from '../../../packages/admin.gbapp/services/GBAdminService';
|
||||
import { GBCorePackage } from '../../../packages/core.gbapp';
|
||||
import { GBConfigService } from '../../../packages/core.gbapp/services/GBConfigService';
|
||||
import { GuaribasInstance } from '../../../packages/core.gbapp/models/GBModel';
|
||||
|
||||
const Spinner = require('cli-spinner').Spinner;
|
||||
const scanf = require('scanf');
|
||||
const git = simplegit();
|
||||
const logger = require('../../../src/logger');
|
||||
const UrlJoin = require('url-join');
|
||||
const iconUrl =
|
||||
'https://github.com/pragmatismo-io/BotServer/blob/master/docs/images/generalbots-logo-squared.png';
|
||||
const iconUrl = 'https://github.com/pragmatismo-io/BotServer/blob/master/docs/images/generalbots-logo-squared.png';
|
||||
const publicIp = require('public-ip');
|
||||
|
||||
export class AzureDeployerService extends GBService {
|
||||
public static apiVersion = '2017-12-01';
|
||||
public static defaultEndPoint = 'http://localhost:4242';
|
||||
public instance: IGBInstance;
|
||||
public resourceClient: ResourceManagementClient.ResourceManagementClient;
|
||||
public webSiteClient: WebSiteManagementClient;
|
||||
public storageClient: SqlManagementClient;
|
||||
public cognitiveClient: CognitiveServicesManagementClient;
|
||||
public searchClient: SearchManagementClient;
|
||||
public provider = 'Microsoft.BotService';
|
||||
public static provider = 'Microsoft.BotService';
|
||||
public subscriptionClient: SubscriptionClient.SubscriptionClient;
|
||||
public accessToken: string;
|
||||
public location: string;
|
||||
|
@ -189,228 +187,7 @@ export class AzureDeployerService extends GBService {
|
|||
};
|
||||
}
|
||||
|
||||
public async deployFarm(proxyAddress: string): Promise<IGBInstance> {
|
||||
const culture = 'en-us';
|
||||
|
||||
// Tries do get information from .env file otherwise asks in command-line.
|
||||
|
||||
let instance: IGBInstance = {};
|
||||
instance = await this.ensureConfiguration(instance);
|
||||
instance.marketplacePassword = GBAdminService.getRndPassword();
|
||||
|
||||
const spinner = new Spinner('%s');
|
||||
spinner.start();
|
||||
spinner.setSpinnerString('|/-\\');
|
||||
|
||||
let keys: any;
|
||||
const name = instance.botId;
|
||||
|
||||
logger.info(`Deploying Deploy Group (It may take a few minutes)...`);
|
||||
await this.createDeployGroup(name, instance.cloudLocation);
|
||||
|
||||
logger.info(`Deploying Bot Server...`);
|
||||
const serverFarm = await this.createHostingPlan(
|
||||
name,
|
||||
`${name}-server-plan`,
|
||||
instance.cloudLocation
|
||||
);
|
||||
await this.createServer(
|
||||
serverFarm.id,
|
||||
name,
|
||||
`${name}-server`,
|
||||
instance.cloudLocation
|
||||
);
|
||||
|
||||
logger.info(`Deploying Bot Storage...`);
|
||||
const administratorLogin = `sa${GBAdminService.getRndReadableIdentifier()}`;
|
||||
const administratorPassword = GBAdminService.getRndPassword();
|
||||
const storageServer = `${name.toLowerCase()}-storage-server`;
|
||||
const storageName = `${name}-storage`;
|
||||
await this.createStorageServer(
|
||||
name,
|
||||
storageServer,
|
||||
administratorLogin,
|
||||
administratorPassword,
|
||||
storageServer,
|
||||
instance.cloudLocation
|
||||
);
|
||||
await this.createStorage(
|
||||
name,
|
||||
storageServer,
|
||||
storageName,
|
||||
instance.cloudLocation
|
||||
);
|
||||
instance.storageUsername = administratorLogin;
|
||||
instance.storagePassword = administratorPassword;
|
||||
instance.storageName = storageName;
|
||||
instance.storageDialect = 'mssql';
|
||||
instance.storageServer = storageServer;
|
||||
|
||||
logger.info(`Deploying Search...`);
|
||||
const searchName = `${name}-search`.toLowerCase();
|
||||
await this.createSearch(name, searchName, instance.cloudLocation);
|
||||
const searchKeys = await this.searchClient.adminKeys.get(
|
||||
name,
|
||||
searchName
|
||||
);
|
||||
instance.searchHost = `${searchName}.search.windows.net`;
|
||||
instance.searchIndex = 'azuresql-index';
|
||||
instance.searchIndexer = 'azuresql-indexer';
|
||||
instance.searchKey = searchKeys.primaryKey;
|
||||
this.deployer.rebuildIndex(instance);
|
||||
|
||||
logger.info(`Deploying Speech...`);
|
||||
const speech = await this.createSpeech(
|
||||
name,
|
||||
`${name}-speech`,
|
||||
instance.cloudLocation
|
||||
);
|
||||
keys = await this.cognitiveClient.accounts.listKeys(name, speech.name);
|
||||
instance.speechKeyEndpoint = speech.endpoint;
|
||||
instance.speechKey = keys.key1;
|
||||
|
||||
logger.info(`Deploying SpellChecker...`);
|
||||
const spellChecker = await this.createSpellChecker(
|
||||
name,
|
||||
`${name}-spellchecker`,
|
||||
instance.cloudLocation
|
||||
);
|
||||
keys = await this.cognitiveClient.accounts.listKeys(
|
||||
name,
|
||||
spellChecker.name
|
||||
);
|
||||
instance.spellCheckerKey = keys.key1;
|
||||
instance.spellCheckerEndpoint = spellChecker.endpoint;
|
||||
|
||||
logger.info(`Deploying Text Analytics...`);
|
||||
const textAnalytics = await this.createTextAnalytics(
|
||||
name,
|
||||
`${name}-textanalytics`,
|
||||
instance.cloudLocation
|
||||
);
|
||||
keys = await this.cognitiveClient.accounts.listKeys(
|
||||
name,
|
||||
textAnalytics.name
|
||||
);
|
||||
instance.textAnalyticsEndpoint = textAnalytics.endpoint;
|
||||
instance.textAnalyticsKey = keys.key1;
|
||||
|
||||
logger.info(`Deploying NLP...`);
|
||||
const nlp = await this.createNLP(name, `${name}-nlp`, instance.cloudLocation);
|
||||
keys = await this.cognitiveClient.accounts.listKeys(name, nlp.name);
|
||||
const nlpAppId = await this.createLUISApp(
|
||||
name,
|
||||
name,
|
||||
instance.cloudLocation,
|
||||
culture,
|
||||
instance.nlpAuthoringKey
|
||||
);
|
||||
|
||||
instance.nlpEndpoint = nlp.endpoint;
|
||||
instance.nlpKey = keys.key1;
|
||||
instance.nlpAppId = nlpAppId;
|
||||
|
||||
logger.info(`Deploying Bot...`);
|
||||
|
||||
// TODO: Default endpoint, will be updated when it runs in production.
|
||||
|
||||
instance.botEndpoint = 'http://localhost:4242';
|
||||
|
||||
instance = await this.deployBootBot(
|
||||
instance,
|
||||
name,
|
||||
`${proxyAddress}/api/messages/${name}`,
|
||||
instance.nlpAppId,
|
||||
instance.nlpKey,
|
||||
instance.cloudSubscriptionId
|
||||
);
|
||||
|
||||
spinner.stop();
|
||||
return instance;
|
||||
}
|
||||
|
||||
public async openStorageFirewall(groupName, serverName) {
|
||||
const username = GBConfigService.get('CLOUD_USERNAME');
|
||||
const password = GBConfigService.get('CLOUD_PASSWORD');
|
||||
const subscriptionId = GBConfigService.get('CLOUD_SUBSCRIPTIONID');
|
||||
|
||||
const credentials = await GBAdminService.getADALCredentialsFromUsername(
|
||||
username,
|
||||
password
|
||||
);
|
||||
const storageClient = new SqlManagementClient(credentials, subscriptionId);
|
||||
|
||||
const ip = await publicIp.v4();
|
||||
const params = {
|
||||
startIpAddress: ip,
|
||||
endIpAddress: ip
|
||||
};
|
||||
|
||||
await storageClient.firewallRules.createOrUpdate(
|
||||
groupName,
|
||||
serverName,
|
||||
'gb',
|
||||
params
|
||||
);
|
||||
}
|
||||
|
||||
public async deployBootBot(
|
||||
instance,
|
||||
botId,
|
||||
endpoint,
|
||||
nlpAppId,
|
||||
nlpKey,
|
||||
subscriptionId
|
||||
) {
|
||||
let appId = GBConfigService.get('MARKETPLACE_ID');
|
||||
let appPassword = GBConfigService.get('MARKETPLACE_SECRET');
|
||||
|
||||
if (!appId || !appPassword) {
|
||||
process.stdout.write(
|
||||
'Sorry, this part cannot be automated yet due to Microsoft schedule, please go to https://apps.dev.microsoft.com/portal/register-app to generate manually an App ID and App Secret.\n'
|
||||
);
|
||||
}
|
||||
|
||||
const retriveAppId = () => {
|
||||
if (!appId) {
|
||||
process.stdout.write('Generated Application Id (MARKETPLACE_ID):');
|
||||
appId = scanf('%s').replace(/(\n|\r)+$/, '');
|
||||
}
|
||||
};
|
||||
|
||||
const retriveAppPassword = () => {
|
||||
if (!appPassword) {
|
||||
process.stdout.write('Generated Password (MARKETPLACE_SECRET):');
|
||||
appPassword = scanf('%s').replace(/(\n|\r)+$/, '');
|
||||
}
|
||||
};
|
||||
|
||||
retriveAppId();
|
||||
retriveAppPassword();
|
||||
|
||||
await this.internalDeployBot(
|
||||
instance,
|
||||
this.accessToken,
|
||||
botId,
|
||||
botId,
|
||||
botId,
|
||||
'General BootBot',
|
||||
endpoint,
|
||||
'global',
|
||||
nlpAppId,
|
||||
nlpKey,
|
||||
appId,
|
||||
appPassword,
|
||||
subscriptionId
|
||||
);
|
||||
instance.marketplaceId = appId;
|
||||
instance.marketplacePassword = appPassword;
|
||||
instance.botId = botId;
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
public async updateBotProxy(botId, group, endpoint) {
|
||||
public static async updateBotProxy(botId, group, endpoint) {
|
||||
const baseUrl = `https://management.azure.com/`;
|
||||
const username = GBConfigService.get('CLOUD_USERNAME');
|
||||
const password = GBConfigService.get('CLOUD_PASSWORD');
|
||||
|
@ -445,144 +222,193 @@ export class AzureDeployerService extends GBService {
|
|||
logger.info(`Bot proxy updated at: ${endpoint}.`);
|
||||
}
|
||||
|
||||
public async deployGeneralBotsToAzure() {
|
||||
const status = await git.status();
|
||||
// TODO: Copy github to webapp.
|
||||
public static async openStorageFirewall(groupName, serverName) {
|
||||
const username = GBConfigService.get('CLOUD_USERNAME');
|
||||
const password = GBConfigService.get('CLOUD_PASSWORD');
|
||||
const subscriptionId = GBConfigService.get('CLOUD_SUBSCRIPTIONID');
|
||||
|
||||
const credentials = await GBAdminService.getADALCredentialsFromUsername(username, password);
|
||||
const storageClient = new SqlManagementClient(credentials, subscriptionId);
|
||||
|
||||
const ip = await publicIp.v4();
|
||||
const params = {
|
||||
startIpAddress: ip,
|
||||
endIpAddress: ip
|
||||
};
|
||||
|
||||
await storageClient.firewallRules.createOrUpdate(groupName, serverName, 'gb', params);
|
||||
}
|
||||
|
||||
private async ensureConfiguration(instance: IGBInstance) {
|
||||
let username = GBConfigService.get('CLOUD_USERNAME');
|
||||
let password = GBConfigService.get('CLOUD_PASSWORD');
|
||||
let subscriptionId = GBConfigService.get('CLOUD_SUBSCRIPTIONID');
|
||||
let location = GBConfigService.get('CLOUD_LOCATION');
|
||||
let botId = GBConfigService.get('BOT_ID');
|
||||
public static createRequestObject(url: string, accessToken: string, verb: HttpMethods, body: string) {
|
||||
const req = new WebResource();
|
||||
req.method = verb;
|
||||
req.url = url;
|
||||
req.headers = {};
|
||||
req.headers['Content-Type'] = 'application/json';
|
||||
req.headers['accept-language'] = '*';
|
||||
req.headers.Authorization = 'Bearer ' + accessToken;
|
||||
req.body = body;
|
||||
|
||||
// No .env so asks for cloud credentials to start a new farm.
|
||||
if (!username || !password || !subscriptionId || !location || !botId) {
|
||||
process.stdout.write(
|
||||
'A empty enviroment is detected. To start automatic deploy, please enter some information:\n'
|
||||
);
|
||||
}
|
||||
const retriveUsername = () => {
|
||||
if (!username) {
|
||||
process.stdout.write(`${GBAdminService.GB_PROMPT}CLOUD_USERNAME:`);
|
||||
username = scanf('%s').replace(/(\n|\r)+$/, '');
|
||||
}
|
||||
};
|
||||
const retrivePassword = () => {
|
||||
if (!password) {
|
||||
process.stdout.write(`${GBAdminService.GB_PROMPT}CLOUD_PASSWORD:`);
|
||||
password = scanf('%s').replace(/(\n|\r)+$/, '');
|
||||
}
|
||||
};
|
||||
const retrieveBotId = () => {
|
||||
if (!botId) {
|
||||
process.stdout.write(
|
||||
`${GBAdminService.GB_PROMPT}Choose a unique bot Id containing lowercase letters, digits or dashes (cannot use dash as the first two or last one characters), cannot start or end with or contain consecutive dashes and having 4 to 42 characters long.\n`
|
||||
);
|
||||
process.stdout.write(`${GBAdminService.GB_PROMPT}BOT_ID:`);
|
||||
botId = scanf('%s').replace(/(\n|\r)+$/, ''); // TODO: Update this regexp to match description of it.
|
||||
}
|
||||
};
|
||||
let authoringKey = GBConfigService.get('NLP_AUTHORING_KEY');
|
||||
const retriveAuthoringKey = () => {
|
||||
if (!authoringKey) {
|
||||
process.stdout.write(
|
||||
`${GBAdminService.GB_PROMPT}Due to this opened issue: https://github.com/Microsoft/botbuilder-tools/issues/550\n`
|
||||
);
|
||||
process.stdout.write(`${GBAdminService.GB_PROMPT}Please enter your LUIS Authoring Key:`);
|
||||
authoringKey = scanf('%s').replace(/(\n|\r)+$/, '');
|
||||
}
|
||||
};
|
||||
while (!authoringKey) {
|
||||
retriveAuthoringKey();
|
||||
}
|
||||
while (!botId) {
|
||||
retrieveBotId();
|
||||
}
|
||||
while (!username) {
|
||||
retriveUsername();
|
||||
}
|
||||
while (!password) {
|
||||
retrivePassword();
|
||||
}
|
||||
return req;
|
||||
}
|
||||
|
||||
// Connects to the cloud and retrives subscriptions.
|
||||
public async deployFarm(
|
||||
proxyAddress: string,
|
||||
instance: IGBInstance,
|
||||
credentials,
|
||||
subscriptionId: string
|
||||
): Promise<IGBInstance> {
|
||||
const culture = 'en-us';
|
||||
|
||||
const credentials = await GBAdminService.getADALCredentialsFromUsername(
|
||||
username,
|
||||
password
|
||||
this.initServices(credentials, subscriptionId);
|
||||
|
||||
const spinner = new Spinner('%s');
|
||||
spinner.start();
|
||||
spinner.setSpinnerString('|/-\\');
|
||||
|
||||
let keys: any;
|
||||
const name = instance.botId;
|
||||
|
||||
logger.info(`Deploying Deploy Group (It may take a few minutes)...`);
|
||||
await this.createDeployGroup(name, instance.cloudLocation);
|
||||
|
||||
logger.info(`Deploying Bot Server...`);
|
||||
const serverFarm = await this.createHostingPlan(name, `${name}-server-plan`, instance.cloudLocation);
|
||||
await this.createServer(serverFarm.id, name, `${name}-server`, instance.cloudLocation);
|
||||
|
||||
logger.info(`Deploying Bot Storage...`);
|
||||
const administratorLogin = `sa${GBAdminService.getRndReadableIdentifier()}`;
|
||||
const administratorPassword = GBAdminService.getRndPassword();
|
||||
const storageServer = `${name.toLowerCase()}-storage-server`;
|
||||
const storageName = `${name}-storage`;
|
||||
await this.createStorageServer(
|
||||
name,
|
||||
storageServer,
|
||||
administratorLogin,
|
||||
administratorPassword,
|
||||
storageServer,
|
||||
instance.cloudLocation
|
||||
);
|
||||
if (!subscriptionId) {
|
||||
const map = {};
|
||||
let index = 1;
|
||||
const list = await AzureDeployerService.getSubscriptions(credentials);
|
||||
list.forEach(element => {
|
||||
console.log(
|
||||
`${index}: ${element.displayName} (${element.subscriptionId})`
|
||||
);
|
||||
map[index++] = element;
|
||||
});
|
||||
let subscriptionIndex;
|
||||
const retrieveSubscription = () => {
|
||||
if (!subscriptionIndex) {
|
||||
process.stdout.write('CLOUD_SUBSCRIPTIONID (type a number):');
|
||||
subscriptionIndex = scanf('%d');
|
||||
}
|
||||
};
|
||||
while (!subscriptionIndex) {
|
||||
retrieveSubscription();
|
||||
}
|
||||
subscriptionId = map[subscriptionIndex].subscriptionId;
|
||||
}
|
||||
const retriveLocation = () => {
|
||||
if (!location) {
|
||||
process.stdout.write('CLOUD_LOCATION (eg. \'westus\'):');
|
||||
location = scanf('%s');
|
||||
}
|
||||
};
|
||||
while (!location) {
|
||||
retriveLocation();
|
||||
}
|
||||
await this.createStorage(name, storageServer, storageName, instance.cloudLocation);
|
||||
instance.storageUsername = administratorLogin;
|
||||
instance.storagePassword = administratorPassword;
|
||||
instance.storageName = storageName;
|
||||
instance.storageDialect = 'mssql';
|
||||
instance.storageServer = storageServer;
|
||||
|
||||
// Prepares the first instance on bot farm.
|
||||
logger.info(`Deploying Search...`);
|
||||
const searchName = `${name}-search`.toLowerCase();
|
||||
await this.createSearch(name, searchName, instance.cloudLocation);
|
||||
const searchKeys = await this.searchClient.adminKeys.get(name, searchName);
|
||||
instance.searchHost = `${searchName}.search.windows.net`;
|
||||
instance.searchIndex = 'azuresql-index';
|
||||
instance.searchIndexer = 'azuresql-indexer';
|
||||
instance.searchKey = searchKeys.primaryKey;
|
||||
this.deployer.rebuildIndex(instance);
|
||||
|
||||
instance.botId = botId;
|
||||
instance.cloudUsername = username;
|
||||
instance.cloudPassword = password;
|
||||
instance.cloudSubscriptionId = subscriptionId;
|
||||
instance.cloudLocation = location;
|
||||
instance.nlpAuthoringKey = authoringKey;
|
||||
instance.adminPass = GBAdminService.getRndPassword();
|
||||
logger.info(`Deploying Speech...`);
|
||||
const speech = await this.createSpeech(name, `${name}-speech`, instance.cloudLocation);
|
||||
keys = await this.cognitiveClient.accounts.listKeys(name, speech.name);
|
||||
instance.speechKeyEndpoint = speech.endpoint;
|
||||
instance.speechKey = keys.key1;
|
||||
|
||||
this.resourceClient = new ResourceManagementClient.default(
|
||||
credentials,
|
||||
subscriptionId
|
||||
);
|
||||
this.webSiteClient = new WebSiteManagementClient(
|
||||
credentials,
|
||||
subscriptionId
|
||||
);
|
||||
this.storageClient = new SqlManagementClient(credentials, subscriptionId);
|
||||
this.cognitiveClient = new CognitiveServicesManagementClient(
|
||||
credentials,
|
||||
subscriptionId
|
||||
logger.info(`Deploying SpellChecker...`);
|
||||
const spellChecker = await this.createSpellChecker(name, `${name}-spellchecker`, instance.cloudLocation);
|
||||
keys = await this.cognitiveClient.accounts.listKeys(name, spellChecker.name);
|
||||
instance.spellCheckerKey = keys.key1;
|
||||
instance.spellCheckerEndpoint = spellChecker.endpoint;
|
||||
|
||||
logger.info(`Deploying Text Analytics...`);
|
||||
const textAnalytics = await this.createTextAnalytics(name, `${name}-textanalytics`, instance.cloudLocation);
|
||||
keys = await this.cognitiveClient.accounts.listKeys(name, textAnalytics.name);
|
||||
instance.textAnalyticsEndpoint = textAnalytics.endpoint;
|
||||
instance.textAnalyticsKey = keys.key1;
|
||||
|
||||
logger.info(`Deploying NLP...`);
|
||||
const nlp = await this.createNLP(name, `${name}-nlp`, instance.cloudLocation);
|
||||
keys = await this.cognitiveClient.accounts.listKeys(name, nlp.name);
|
||||
const nlpAppId = await this.createNLPService(name, name, instance.cloudLocation, culture, instance.nlpAuthoringKey);
|
||||
|
||||
instance.nlpEndpoint = nlp.endpoint;
|
||||
instance.nlpKey = keys.key1;
|
||||
instance.nlpAppId = nlpAppId;
|
||||
|
||||
logger.info(`Deploying Bot...`);
|
||||
instance.botEndpoint = AzureDeployerService.defaultEndPoint;
|
||||
|
||||
instance = await this.internalDeployBot(
|
||||
instance,
|
||||
this.accessToken,
|
||||
name,
|
||||
name,
|
||||
name,
|
||||
'General BootBot',
|
||||
`${proxyAddress}/api/messages/${name}`,
|
||||
'global',
|
||||
instance.nlpAppId,
|
||||
instance.nlpKey,
|
||||
instance.appId,
|
||||
instance.appPassword,
|
||||
instance.cloudSubscriptionId
|
||||
);
|
||||
|
||||
this.searchClient = new SearchManagementClient(credentials, subscriptionId);
|
||||
this.accessToken = credentials.tokenCache._entries[0].accessToken;
|
||||
|
||||
spinner.stop();
|
||||
return instance;
|
||||
}
|
||||
|
||||
private async createStorageServer(
|
||||
group,
|
||||
name,
|
||||
administratorLogin,
|
||||
administratorPassword,
|
||||
serverName,
|
||||
location
|
||||
public async deployToCloud(
|
||||
title,
|
||||
username,
|
||||
password,
|
||||
cloudLocation,
|
||||
authoringKey,
|
||||
appId,
|
||||
appPassword,
|
||||
subscriptionId
|
||||
) {
|
||||
|
||||
const instance = new GuaribasInstance();
|
||||
|
||||
instance.botId = title;
|
||||
instance.cloudUsername = username;
|
||||
instance.cloudPassword = password;
|
||||
instance.cloudSubscriptionId = subscriptionId;
|
||||
instance.cloudLocation = cloudLocation;
|
||||
instance.nlpAuthoringKey = authoringKey;
|
||||
instance.marketplaceId = appId;
|
||||
instance.marketplacePassword = appPassword;
|
||||
instance.adminPass = GBAdminService.getRndPassword();
|
||||
|
||||
const credentials = await GBAdminService.getADALCredentialsFromUsername(username, password);
|
||||
this.deployFarm(`http://${instance.botId}.azurewebsites.net`, instance, credentials, subscriptionId);
|
||||
|
||||
// TODO: Copy github to webapp.
|
||||
//const status = await git.status();
|
||||
}
|
||||
|
||||
private initServices(credentials: any, subscriptionId: string) {
|
||||
this.resourceClient = new ResourceManagementClient.default(credentials, subscriptionId);
|
||||
this.webSiteClient = new WebSiteManagementClient(credentials, subscriptionId);
|
||||
this.storageClient = new SqlManagementClient(credentials, subscriptionId);
|
||||
this.cognitiveClient = new CognitiveServicesManagementClient(credentials, subscriptionId);
|
||||
this.searchClient = new SearchManagementClient(credentials, subscriptionId);
|
||||
this.accessToken = credentials.tokenCache._entries[0].accessToken;
|
||||
}
|
||||
|
||||
private async updateWebisteConfig(group, serverFarmId, name, location) {
|
||||
const siteConfig = {
|
||||
location: location,
|
||||
serverFarmId: serverFarmId,
|
||||
numberOfWorkers: 1,
|
||||
phpVersion: '5.5'
|
||||
};
|
||||
|
||||
// TODO: Copy .env to app settings.
|
||||
|
||||
return this.webSiteClient.webApps.createOrUpdateConfiguration(group, name, siteConfig);
|
||||
}
|
||||
|
||||
private async createStorageServer(group, name, administratorLogin, administratorPassword, serverName, location) {
|
||||
const params = {
|
||||
location: location,
|
||||
administratorLogin: administratorLogin,
|
||||
|
@ -595,7 +421,7 @@ export class AzureDeployerService extends GBService {
|
|||
|
||||
private async registerProviders(subscriptionId, baseUrl, accessToken) {
|
||||
const query = `subscriptions/${subscriptionId}/providers/${
|
||||
this.provider
|
||||
AzureDeployerService.provider
|
||||
}/register?api-version=2018-02-01`;
|
||||
const requestUrl = UrlJoin(baseUrl, query);
|
||||
|
||||
|
@ -611,6 +437,7 @@ export class AzureDeployerService extends GBService {
|
|||
const res = await httpClient.sendRequest(req);
|
||||
// TODO: Check res for error.
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://github.com/Azure/azure-rest-api-specs/blob/master/specification/botservice/resource-manager/Microsoft.BotService/preview/2017-12-01/botservice.json
|
||||
*/
|
||||
|
@ -660,18 +487,14 @@ export class AzureDeployerService extends GBService {
|
|||
|
||||
const httpClient = new ServiceClient();
|
||||
let query = `subscriptions/${subscriptionId}/resourceGroups/${group}/providers/${
|
||||
this.provider
|
||||
AzureDeployerService.provider
|
||||
}/botServices/${botId}?api-version=${AzureDeployerService.apiVersion}`;
|
||||
let url = UrlJoin(baseUrl, query);
|
||||
let req = this.createRequestObject(
|
||||
url,
|
||||
accessToken,
|
||||
'PUT',
|
||||
JSON.stringify(parameters)
|
||||
);
|
||||
let req = AzureDeployerService.createRequestObject(url, accessToken, 'PUT', JSON.stringify(parameters));
|
||||
const res = await httpClient.sendRequest(req);
|
||||
if (!(res.bodyAsJson as any).id) {
|
||||
reject(res.bodyAsText);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -681,42 +504,19 @@ export class AzureDeployerService extends GBService {
|
|||
AzureDeployerService.apiVersion
|
||||
}`;
|
||||
url = UrlJoin(baseUrl, query);
|
||||
req = this.createRequestObject(
|
||||
url,
|
||||
accessToken,
|
||||
'GET',
|
||||
JSON.stringify(parameters)
|
||||
);
|
||||
req = AzureDeployerService.createRequestObject(url, accessToken, 'GET', JSON.stringify(parameters));
|
||||
const resChannel = await httpClient.sendRequest(req);
|
||||
const key = (resChannel.bodyAsJson as any).properties.properties
|
||||
.sites[0].key;
|
||||
const key = (resChannel.bodyAsJson as any).properties.properties.sites[0].key;
|
||||
instance.webchatKey = key;
|
||||
resolve(instance);
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
}, 20000);
|
||||
}, 20000);
|
||||
});
|
||||
}
|
||||
|
||||
private createRequestObject(
|
||||
url: string,
|
||||
accessToken: string,
|
||||
verb: HttpMethods,
|
||||
body: string
|
||||
) {
|
||||
const req = new WebResource();
|
||||
req.method = verb;
|
||||
req.url = url;
|
||||
req.headers = {};
|
||||
req.headers['Content-Type'] = 'application/json';
|
||||
req.headers['accept-language'] = '*';
|
||||
req.headers.Authorization = 'Bearer ' + accessToken;
|
||||
req.body = body;
|
||||
return req;
|
||||
}
|
||||
|
||||
private async createLUISApp(
|
||||
private async createNLPService(
|
||||
name: string,
|
||||
description: string,
|
||||
location: string,
|
||||
|
@ -730,23 +530,11 @@ export class AzureDeployerService extends GBService {
|
|||
};
|
||||
|
||||
const body = JSON.stringify(parameters);
|
||||
const apps = await this.makeNlpRequest(
|
||||
location,
|
||||
authoringKey,
|
||||
null,
|
||||
'GET',
|
||||
'apps'
|
||||
);
|
||||
const apps = await this.makeNlpRequest(location, authoringKey, null, 'GET', 'apps');
|
||||
const app = (apps.bodyAsJson as any).filter(x => x.name == name)[0];
|
||||
let id: string;
|
||||
if (!app) {
|
||||
const res = await this.makeNlpRequest(
|
||||
location,
|
||||
authoringKey,
|
||||
body,
|
||||
'POST',
|
||||
'apps'
|
||||
);
|
||||
const res = await this.makeNlpRequest(location, authoringKey, body, 'POST', 'apps');
|
||||
id = res.bodyAsText;
|
||||
} else {
|
||||
id = app.id;
|
||||
|
@ -771,8 +559,8 @@ export class AzureDeployerService extends GBService {
|
|||
req.headers['Ocp-Apim-Subscription-Key'] = authoringKey;
|
||||
req.body = body;
|
||||
const httpClient = new ServiceClient();
|
||||
const res = await httpClient.sendRequest(req);
|
||||
return res;
|
||||
|
||||
return await httpClient.sendRequest(req);
|
||||
}
|
||||
|
||||
private async createSearch(group, name, location) {
|
||||
|
@ -791,20 +579,10 @@ export class AzureDeployerService extends GBService {
|
|||
location: location
|
||||
};
|
||||
|
||||
return this.storageClient.databases.createOrUpdate(
|
||||
group,
|
||||
serverName,
|
||||
name,
|
||||
params
|
||||
);
|
||||
return this.storageClient.databases.createOrUpdate(group, serverName, name, params);
|
||||
}
|
||||
|
||||
private async createCognitiveServices(
|
||||
group,
|
||||
name,
|
||||
location,
|
||||
kind
|
||||
): Promise<CognitiveServicesAccount> {
|
||||
private async createCognitiveServices(group, name, location, kind): Promise<CognitiveServicesAccount> {
|
||||
const params = {
|
||||
sku: { name: 'F0' },
|
||||
createMode: 'Default',
|
||||
|
@ -816,51 +594,20 @@ export class AzureDeployerService extends GBService {
|
|||
return await this.cognitiveClient.accounts.create(group, name, params);
|
||||
}
|
||||
|
||||
private async createSpeech(
|
||||
group,
|
||||
name,
|
||||
location
|
||||
): Promise<CognitiveServicesAccount> {
|
||||
return await this.createCognitiveServices(
|
||||
group,
|
||||
name,
|
||||
location,
|
||||
'SpeechServices'
|
||||
);
|
||||
private async createSpeech(group, name, location): Promise<CognitiveServicesAccount> {
|
||||
return await this.createCognitiveServices(group, name, location, 'SpeechServices');
|
||||
}
|
||||
|
||||
private async createNLP(
|
||||
group,
|
||||
name,
|
||||
location
|
||||
): Promise<CognitiveServicesAccount> {
|
||||
private async createNLP(group, name, location): Promise<CognitiveServicesAccount> {
|
||||
return await this.createCognitiveServices(group, name, location, 'LUIS');
|
||||
}
|
||||
|
||||
private async createSpellChecker(
|
||||
group,
|
||||
name,
|
||||
location
|
||||
): Promise<CognitiveServicesAccount> {
|
||||
return await this.createCognitiveServices(
|
||||
group,
|
||||
name,
|
||||
'global',
|
||||
'Bing.SpellCheck.v7'
|
||||
);
|
||||
private async createSpellChecker(group, name, location): Promise<CognitiveServicesAccount> {
|
||||
return await this.createCognitiveServices(group, name, 'global', 'Bing.SpellCheck.v7');
|
||||
}
|
||||
|
||||
private async createTextAnalytics(
|
||||
group,
|
||||
name,
|
||||
location
|
||||
): Promise<CognitiveServicesAccount> {
|
||||
return await this.createCognitiveServices(
|
||||
group,
|
||||
name,
|
||||
location,
|
||||
'TextAnalytics'
|
||||
);
|
||||
private async createTextAnalytics(group, name, location): Promise<CognitiveServicesAccount> {
|
||||
return await this.createCognitiveServices(group, name, location, 'TextAnalytics');
|
||||
}
|
||||
|
||||
private async createDeployGroup(name, location) {
|
||||
|
@ -868,11 +615,7 @@ export class AzureDeployerService extends GBService {
|
|||
return this.resourceClient.resourceGroups.createOrUpdate(name, params);
|
||||
}
|
||||
|
||||
private async createHostingPlan(
|
||||
group,
|
||||
name,
|
||||
location
|
||||
): Promise<AppServicePlan> {
|
||||
private async createHostingPlan(group, name, location): Promise<AppServicePlan> {
|
||||
const params = {
|
||||
serverFarmWithRichSkuName: name,
|
||||
location: location,
|
||||
|
@ -883,11 +626,7 @@ export class AzureDeployerService extends GBService {
|
|||
}
|
||||
};
|
||||
|
||||
return this.webSiteClient.appServicePlans.createOrUpdate(
|
||||
group,
|
||||
name,
|
||||
params
|
||||
);
|
||||
return this.webSiteClient.appServicePlans.createOrUpdate(group, name, params);
|
||||
}
|
||||
|
||||
private async createServer(farmId, group, name, location) {
|
||||
|
@ -897,21 +636,5 @@ export class AzureDeployerService extends GBService {
|
|||
};
|
||||
return this.webSiteClient.webApps.createOrUpdate(group, name, parameters);
|
||||
}
|
||||
|
||||
private async updateWebisteConfig(group, serverFarmId, name, location) {
|
||||
const siteConfig = {
|
||||
location: location,
|
||||
serverFarmId: serverFarmId,
|
||||
numberOfWorkers: 1,
|
||||
phpVersion: '5.5'
|
||||
};
|
||||
|
||||
// TODO: Copy .env to app settings.
|
||||
|
||||
return this.webSiteClient.webApps.createOrUpdateConfiguration(
|
||||
group,
|
||||
name,
|
||||
siteConfig
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -36,8 +36,12 @@ import { TurnContext } from 'botbuilder';
|
|||
import { WaterfallStepContext } from 'botbuilder-dialogs';
|
||||
import { GBMinInstance } from 'botlib';
|
||||
import { GBAdminService } from '../../admin.gbapp/services/GBAdminService';
|
||||
const WaitUntil = require('wait-until');
|
||||
import { AzureDeployerService } from '../../azuredeployer.gbapp/services/AzureDeployerService';
|
||||
|
||||
|
||||
/**
|
||||
* BASIC system class for extra manipulation of bot behaviour.
|
||||
*/
|
||||
class SysClass {
|
||||
public min: GBMinInstance;
|
||||
|
||||
|
@ -45,20 +49,36 @@ class SysClass {
|
|||
this.min = min;
|
||||
}
|
||||
|
||||
public generatePassword(){
|
||||
public async wait(seconds: number) {
|
||||
const timeout = ms => new Promise(resolve => setTimeout(resolve, ms));
|
||||
await timeout(seconds * 1000);
|
||||
}
|
||||
|
||||
public generatePassword() {
|
||||
return GBAdminService.getRndPassword();
|
||||
}
|
||||
|
||||
public async createABotFarmUsing(
|
||||
botId,
|
||||
description,
|
||||
username,
|
||||
password,
|
||||
location,
|
||||
nlpAuthoringKey,
|
||||
appId,
|
||||
appPassword,
|
||||
subscriptionId
|
||||
) {
|
||||
|
||||
const service = new AzureDeployerService(this.min.deployer);
|
||||
await service.deployToCloud(
|
||||
botId,
|
||||
username,
|
||||
password,
|
||||
location,
|
||||
nlpAuthoringKey,
|
||||
appId,
|
||||
appPassword,
|
||||
subscriptionId
|
||||
);
|
||||
}
|
||||
}
|
||||
/**
|
||||
|
@ -66,6 +86,7 @@ class SysClass {
|
|||
*/
|
||||
|
||||
export default class DialogClass {
|
||||
|
||||
public min: GBMinInstance;
|
||||
public context: TurnContext;
|
||||
public step: WaterfallStepContext;
|
||||
|
@ -73,16 +94,17 @@ export default class DialogClass {
|
|||
|
||||
constructor(min: GBMinInstance) {
|
||||
this.min = min;
|
||||
this.internalSys = new SysClass(min);
|
||||
}
|
||||
|
||||
public async sys() {
|
||||
public sys(): SysClass {
|
||||
return this.internalSys;
|
||||
}
|
||||
|
||||
public async hear(cb) {
|
||||
const idCallback = Math.floor(Math.random() * 1000000000000);
|
||||
this.min.cbMap[idCallback] = cb;
|
||||
await this.step.beginDialog('/hear', { id: idCallback});
|
||||
await this.step.beginDialog('/hear', { id: idCallback });
|
||||
}
|
||||
|
||||
public async talk(text: string) {
|
||||
|
|
|
@ -50,7 +50,7 @@ import { GBSecurityPackage } from '../../security.gblib';
|
|||
import { GBWhatsappPackage } from '../../whatsapp.gblib/index';
|
||||
import { GuaribasInstance } from '../models/GBModel';
|
||||
import { GBConfigService } from './GBConfigService';
|
||||
import { GBImporter } from './GBImporterService';
|
||||
import { StartDialog } from '../../azuredeployer.gbapp/dialogs/StartDialog';
|
||||
|
||||
const logger = require('../../../src/logger');
|
||||
const opn = require('opn');
|
||||
|
@ -274,7 +274,7 @@ STORAGE_SYNC=true
|
|||
const instance = instances[0];
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
logger.info(`Updating bot endpoint to local reverse proxy (ngrok)...`);
|
||||
await azureDeployer.updateBotProxy(
|
||||
await AzureDeployerService.updateBotProxy(
|
||||
instance.botId,
|
||||
instance.botId,
|
||||
`${proxyAddress}/api/messages/${instance.botId}`
|
||||
|
@ -347,22 +347,22 @@ STORAGE_SYNC=true
|
|||
}
|
||||
|
||||
public async createBootInstance(core: GBCoreService, azureDeployer: AzureDeployerService, proxyAddress: string) {
|
||||
let instance: IGBInstance;
|
||||
logger.info(`Deploying cognitive infrastructure (on the cloud / on premises)...`);
|
||||
try {
|
||||
instance = await azureDeployer.deployFarm(proxyAddress);
|
||||
let { instance, credentials, subscriptionId } = await StartDialog.createBaseInstance();
|
||||
instance = await azureDeployer.deployFarm(proxyAddress, instance, credentials, subscriptionId);
|
||||
core.writeEnv(instance);
|
||||
logger.info(`File .env written, starting General Bots...`);
|
||||
GBConfigService.init();
|
||||
|
||||
return instance;
|
||||
} catch (error) {
|
||||
logger.warn(
|
||||
`In case of error, please cleanup any infrastructure objects
|
||||
`In case of error, please cleanup any infrastructure objects
|
||||
created during this procedure and .env before running again.`
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
core.writeEnv(instance);
|
||||
logger.info(`File .env written, starting General Bots...`);
|
||||
GBConfigService.init();
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
public openBrowserInDevelopment() {
|
||||
|
@ -407,7 +407,7 @@ STORAGE_SYNC=true
|
|||
const fkcols = args[0];
|
||||
let fkname = table;
|
||||
let matches = re4.exec(fkcols);
|
||||
while (matches != null) {
|
||||
while (matches != undefined) {
|
||||
fkname += '_' + matches[1];
|
||||
matches = re4.exec(fkcols);
|
||||
}
|
||||
|
@ -440,7 +440,7 @@ STORAGE_SYNC=true
|
|||
const fkcols = args[2];
|
||||
let fkname = table;
|
||||
let matches = re3.exec(fkcols);
|
||||
while (matches != null) {
|
||||
while (matches != undefined) {
|
||||
fkname += '_' + matches[1];
|
||||
matches = re3.exec(fkcols);
|
||||
}
|
||||
|
@ -459,6 +459,6 @@ STORAGE_SYNC=true
|
|||
private async openStorageFrontier(deployer: AzureDeployerService) {
|
||||
const group = GBConfigService.get('CLOUD_GROUP');
|
||||
const serverName = GBConfigService.get('STORAGE_SERVER').split('.database.windows.net')[0];
|
||||
await deployer.openStorageFirewall(group, serverName);
|
||||
await AzureDeployerService.openStorageFirewall(group, serverName);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -175,30 +175,42 @@ export class GBMinService {
|
|||
throw new Error(msg);
|
||||
}
|
||||
const authenticationContext = new AuthenticationContext(
|
||||
UrlJoin(min.instance.authenticatorAuthorityHostUrl, min.instance.authenticatorTenant));
|
||||
UrlJoin(min.instance.authenticatorAuthorityHostUrl, min.instance.authenticatorTenant)
|
||||
);
|
||||
const resource = 'https://graph.microsoft.com';
|
||||
authenticationContext.acquireTokenWithAuthorizationCode(
|
||||
req.query.code, UrlJoin(instance.botEndpoint, min.instance.botId, '/token'),
|
||||
resource, instance.authenticatorClientId, instance.authenticatorClientSecret, async (err, token) => {
|
||||
if (err) {
|
||||
const msg = `Error acquiring token: ${err}`;
|
||||
logger.error(msg);
|
||||
res.send(msg);
|
||||
} else {
|
||||
await this.adminService.setValue(instance.instanceId, 'refreshToken', token.refreshToken);
|
||||
await this.adminService.setValue(instance.instanceId, 'accessToken', token.accessToken);
|
||||
await this.adminService.setValue(instance.instanceId, 'expiresOn', token.expiresOn.toString());
|
||||
await this.adminService.setValue(instance.instanceId, 'AntiCSRFAttackState', null);
|
||||
res.redirect(min.instance.botEndpoint);
|
||||
req.query.code,
|
||||
UrlJoin(instance.botEndpoint, min.instance.botId, '/token'),
|
||||
resource,
|
||||
instance.authenticatorClientId,
|
||||
instance.authenticatorClientSecret,
|
||||
async (err, token) => {
|
||||
if (err) {
|
||||
const msg = `Error acquiring token: ${err}`;
|
||||
logger.error(msg);
|
||||
res.send(msg);
|
||||
} else {
|
||||
await this.adminService.setValue(instance.instanceId, 'refreshToken', token.refreshToken);
|
||||
await this.adminService.setValue(instance.instanceId, 'accessToken', token.accessToken);
|
||||
await this.adminService.setValue(instance.instanceId, 'expiresOn', token.expiresOn.toString());
|
||||
await this.adminService.setValue(instance.instanceId, 'AntiCSRFAttackState', null);
|
||||
res.redirect(min.instance.botEndpoint);
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private handleOAuthRequests(server: any, min: GBMinInstance) {
|
||||
server.get(`/${min.instance.botId}/auth`, function (req, res) {
|
||||
let authorizationUrl = UrlJoin(min.instance.authenticatorAuthorityHostUrl, min.instance.authenticatorTenant, '/oauth2/authorize');
|
||||
authorizationUrl = `${authorizationUrl}?response_type=code&client_id=${min.instance.authenticatorClientId}&redirect_uri=${UrlJoin(min.instance.botEndpoint, min.instance.botId, 'token')}`;
|
||||
server.get(`/${min.instance.botId}/auth`, function(req, res) {
|
||||
let authorizationUrl = UrlJoin(
|
||||
min.instance.authenticatorAuthorityHostUrl,
|
||||
min.instance.authenticatorTenant,
|
||||
'/oauth2/authorize'
|
||||
);
|
||||
authorizationUrl = `${authorizationUrl}?response_type=code&client_id=${
|
||||
min.instance.authenticatorClientId
|
||||
}&redirect_uri=${UrlJoin(min.instance.botEndpoint, min.instance.botId, 'token')}`;
|
||||
res.redirect(authorizationUrl);
|
||||
});
|
||||
}
|
||||
|
@ -218,16 +230,18 @@ export class GBMinService {
|
|||
if (!theme) {
|
||||
theme = 'default.gbtheme';
|
||||
}
|
||||
res.send(JSON.stringify({
|
||||
instanceId: instance.instanceId,
|
||||
botId: botId,
|
||||
theme: theme,
|
||||
secret: instance.webchatKey,
|
||||
speechToken: speechToken,
|
||||
conversationId: webchatToken.conversationId,
|
||||
authenticatorTenant: instance.authenticatorTenant,
|
||||
authenticatorClientId: instance.authenticatorClientId
|
||||
}));
|
||||
res.send(
|
||||
JSON.stringify({
|
||||
instanceId: instance.instanceId,
|
||||
botId: botId,
|
||||
theme: theme,
|
||||
secret: instance.webchatKey,
|
||||
speechToken: speechToken,
|
||||
conversationId: webchatToken.conversationId,
|
||||
authenticatorTenant: instance.authenticatorTenant,
|
||||
authenticatorClientId: instance.authenticatorClientId
|
||||
})
|
||||
);
|
||||
} else {
|
||||
const error = `Instance not found: ${botId}.`;
|
||||
res.sendStatus(error);
|
||||
|
@ -308,6 +322,7 @@ export class GBMinService {
|
|||
min.adminService = this.adminService;
|
||||
min.instance = await this.core.loadInstance(min.botId);
|
||||
min.cbMap = {};
|
||||
min.scriptMap = {};
|
||||
min.userProfile = conversationState.createProperty('userProfile');
|
||||
const dialogState = conversationState.createProperty('dialogState');
|
||||
|
||||
|
@ -339,12 +354,12 @@ export class GBMinService {
|
|||
p.channel.received(req, res);
|
||||
});
|
||||
}
|
||||
}, this);
|
||||
}, this);
|
||||
|
||||
appPackages.forEach(e => {
|
||||
e.sysPackages = sysPackages;
|
||||
e.loadBot(min);
|
||||
}, this);
|
||||
}, this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -359,9 +374,7 @@ export class GBMinService {
|
|||
instance: any,
|
||||
appPackages: any[]
|
||||
) {
|
||||
|
||||
await adapter.processActivity(req, res, async context => {
|
||||
|
||||
// Get loaded user state
|
||||
const state = await conversationState.get(context);
|
||||
const step = await min.dialogs.createContext(context, state);
|
||||
|
@ -439,15 +452,15 @@ export class GBMinService {
|
|||
await step.beginDialog('/faq');
|
||||
} else if (context.activity.name === 'answerEvent') {
|
||||
await step.beginDialog('/answerEvent', {
|
||||
questionId: (context.activity).data,
|
||||
questionId: context.activity.data,
|
||||
fromFaq: true
|
||||
});
|
||||
} else if (context.activity.name === 'quality') {
|
||||
await step.beginDialog('/quality', {
|
||||
score: (context.activity).data
|
||||
score: context.activity.data
|
||||
});
|
||||
} else if (context.activity.name === 'updateToken') {
|
||||
const token = (context.activity).data;
|
||||
const token = context.activity.data;
|
||||
await step.beginDialog('/adminUpdateToken', { token: token });
|
||||
} else {
|
||||
await step.continueDialog();
|
||||
|
@ -455,30 +468,28 @@ export class GBMinService {
|
|||
}
|
||||
|
||||
private async processMessageActivity(context, min: GBMinInstance, step: any) {
|
||||
|
||||
// Direct script invoking by itent name.
|
||||
|
||||
let mainMethod = min.scriptMap[context.activity.text];
|
||||
if (mainMethod != undefined) {
|
||||
let isVMCall = Object.keys(min.scriptMap).find(key => min.scriptMap[key] === context.activity.text) !== undefined;
|
||||
|
||||
if (isVMCall) {
|
||||
|
||||
let mainMethod = context.activity.text;
|
||||
|
||||
min.sandbox.context = context;
|
||||
min.sandbox.step = step;
|
||||
min.sandbox[mainMethod].bind(min.sandbox);
|
||||
await min.sandbox[mainMethod]();
|
||||
|
||||
}else if (context.activity.text === 'admin') {
|
||||
|
||||
} else if (context.activity.text === 'admin') {
|
||||
await step.beginDialog('/admin');
|
||||
|
||||
// Checks for /menu JSON signature.
|
||||
// Checks for /menu JSON signature.
|
||||
} else if (context.activity.text.startsWith('{"title"')) {
|
||||
|
||||
await step.beginDialog('/menu', {
|
||||
data: JSON.parse(context.activity.text)
|
||||
});
|
||||
// Otherwise, continue to the active dialog in the stack.
|
||||
|
||||
} else {
|
||||
|
||||
const user = await min.userProfile.get(context, {});
|
||||
if (step.activeDialog) {
|
||||
await step.continueDialog();
|
||||
|
@ -487,7 +498,6 @@ export class GBMinService {
|
|||
query: context.activity.text
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,8 +37,8 @@ import { GBMinInstance, IGBCoreService } from 'botlib';
|
|||
import * as fs from 'fs';
|
||||
import { GBDeployer } from './GBDeployer';
|
||||
import { TSCompiler } from './TSCompiler';
|
||||
import GBAPIService from './GBAPIService';
|
||||
import DialogClass from './GBAPIService';
|
||||
|
||||
const walkPromise = require('walk-promise');
|
||||
const logger = require('../../../src/logger');
|
||||
const vm = require('vm');
|
||||
|
@ -59,7 +59,9 @@ export class GBVMService implements IGBCoreService {
|
|||
private readonly script = new vm.Script();
|
||||
|
||||
public async loadDialogPackage(folder: string, min: GBMinInstance, core: IGBCoreService, deployer: GBDeployer) {
|
||||
|
||||
const files = await walkPromise(folder);
|
||||
this.addHearDialog(min);
|
||||
|
||||
return Promise.all(
|
||||
files.map(async file => {
|
||||
|
@ -70,14 +72,14 @@ export class GBVMService implements IGBCoreService {
|
|||
file.name.endsWith('.bas')
|
||||
) {
|
||||
const mainName = file.name.replace(/\-|\./g, '');
|
||||
// min.scriptMap[file.name] = ;
|
||||
min.scriptMap[file.name] = mainName;
|
||||
|
||||
const filename = UrlJoin(folder, file.name);
|
||||
fs.watchFile(filename, async () => {
|
||||
await this.run(filename, min, deployer, mainName);
|
||||
});
|
||||
|
||||
await this.run(filename, min, deployer, mainName);
|
||||
this.addHearDialog(min);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
|
|
@ -7,25 +7,24 @@ talk "If you tell me your username/password, I can show service subscription lis
|
|||
talk "What is your Username (eg.: human@domain.bot)"
|
||||
hear email
|
||||
|
||||
talk "What is your Password"
|
||||
hear password
|
||||
|
||||
talk "Your password? (Will be discarded after sigining process)"
|
||||
talk "Let's generate a very dificult to guess password for the new bot:"
|
||||
generate a password
|
||||
talk "Your password is *" + password + "*. Keep it on a safe place only acessible to you."
|
||||
talk "Can you describe in a few words what the bot is about?"
|
||||
hear description
|
||||
|
||||
talk "Please, choose what subscription would you like to connect to:"
|
||||
|
||||
subscriptionId = ""
|
||||
talk "Please, paste the Subscription ID (Azure):"
|
||||
hear subscriptionId
|
||||
|
||||
talk "Please, provide the cloud location just like 'westus'?"
|
||||
hear cloudLocation
|
||||
hear location
|
||||
|
||||
talk "Please, provide the Authoring Key for NLP service (LUIS)?"
|
||||
hear nlpKey
|
||||
hear authoringKey
|
||||
|
||||
talk "Sorry, this part cannot be automated yet due to Microsoft schedule, please go to https://apps.dev.microsoft.com/portal/register-app to generate manually an App ID and App Secret."
|
||||
wait 1
|
||||
wait 5
|
||||
|
||||
talk "Please, provide the App ID you just generated:"
|
||||
hear appId
|
||||
|
@ -35,4 +34,4 @@ hear appPassword
|
|||
|
||||
talk "Now, I am going to create a Bot farm... Wait 5 minutes or more..."
|
||||
|
||||
create a bot farm using title, username, password, description, cloudLocation, nlpKey, appId, appPassword, subscriptionId
|
||||
create a bot farm using title, email, password, location, authoringKey, appId, appPassword, subscriptionId
|
||||
|
|
14
src/app.ts
14
src/app.ts
|
@ -103,9 +103,9 @@ export class GBServer {
|
|||
|
||||
logger.info(`Establishing a development local proxy (ngrok)...`);
|
||||
const proxyAddress: string = await core.ensureProxy(port);
|
||||
|
||||
|
||||
// Creates a boot instance or load it frmo storage.
|
||||
|
||||
|
||||
let bootInstance: IGBInstance = null;
|
||||
try {
|
||||
await core.initStorage();
|
||||
|
@ -117,11 +117,10 @@ export class GBServer {
|
|||
// Deploys system and user packages.
|
||||
|
||||
logger.info(`Deploying packages...`);
|
||||
await core.loadSysPackages(core);
|
||||
core.loadSysPackages(core);
|
||||
await core.checkStorage(azureDeployer);
|
||||
await deployer.deployPackages(core, server, appPackages);
|
||||
|
||||
|
||||
// Loads all bot instances.
|
||||
|
||||
logger.info(`Publishing instances...`);
|
||||
|
@ -153,8 +152,6 @@ export class GBServer {
|
|||
|
||||
core.openBrowserInDevelopment();
|
||||
|
||||
return core;
|
||||
|
||||
} catch (err) {
|
||||
logger.error(`STOP: ${err} ${err.stack ? err.stack : ''}`);
|
||||
process.exit(1);
|
||||
|
@ -164,9 +161,6 @@ export class GBServer {
|
|||
}
|
||||
}
|
||||
|
||||
let service:GBVMService = new GBVMService ();
|
||||
service.loadDialogPackage('C:\\Sources\\opensource\\BotServer\\packages\\default.gbdialog',null,null,null);
|
||||
|
||||
// First line to run.
|
||||
|
||||
// GBServer.run();
|
||||
GBServer.run();
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
],
|
||||
"jsRules": {},
|
||||
"rules": {
|
||||
"no-floating-promises": false,
|
||||
"no-var-requires":false,
|
||||
"typedef":false,
|
||||
"variable-name": false,
|
||||
|
|
Loading…
Add table
Reference in a new issue