new(all): TRUE multicloud.

This commit is contained in:
Rodrigo Rodriguez 2024-08-19 23:03:58 -03:00
parent 3ebf79c7b5
commit b004f8b4b5
76 changed files with 219 additions and 121 deletions

View file

@ -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}`;
}

View file

@ -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));

View file

@ -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);

View file

@ -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;

View file

@ -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
});
}
}
}
}

View file

@ -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);
}
/**

View file

@ -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);

View file

@ -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) => {

View file

@ -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));

View file

@ -65,4 +65,5 @@ export class RootData {
public dbg;
public img;
indexSemaphore: any;
public webDavServer;
}

View file

@ -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.

View file

@ -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);

View file

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View file

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View file

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View file

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View file

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

View file

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

View file

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View file

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View file

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

View file

Before

Width:  |  Height:  |  Size: 2 KiB

After

Width:  |  Height:  |  Size: 2 KiB

View file

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View file

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View file

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View file

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View file

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 70 KiB

View file

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View file

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View file

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View file

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View file

Before

Width:  |  Height:  |  Size: 958 B

After

Width:  |  Height:  |  Size: 958 B

View file

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View file

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View file

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

View file

Before

Width:  |  Height:  |  Size: 247 KiB

After

Width:  |  Height:  |  Size: 247 KiB

View file

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 64 KiB

View file

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 79 KiB

View file

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB