fix(all): TRUE multicloud.
This commit is contained in:
parent
d5e47de73e
commit
a98323dfd1
9 changed files with 437 additions and 430 deletions
|
@ -32,7 +32,7 @@
|
||||||
|
|
||||||
import { GBMinInstance, GBService, IGBCoreService, GBLog } from 'botlib';
|
import { GBMinInstance, GBService, IGBCoreService, GBLog } from 'botlib';
|
||||||
import * as Fs from 'fs';
|
import * as Fs from 'fs';
|
||||||
import * as ji from 'just-indent'
|
import * as ji from 'just-indent';
|
||||||
import { GBServer } from '../../../src/app.js';
|
import { GBServer } from '../../../src/app.js';
|
||||||
import { GBDeployer } from '../../core.gbapp/services/GBDeployer.js';
|
import { GBDeployer } from '../../core.gbapp/services/GBDeployer.js';
|
||||||
import { CollectionUtil } from 'pragmatismo-io-framework';
|
import { CollectionUtil } from 'pragmatismo-io-framework';
|
||||||
|
@ -52,8 +52,8 @@ import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js';
|
||||||
import { GuaribasUser } from '../../security.gbapp/models/index.js';
|
import { GuaribasUser } from '../../security.gbapp/models/index.js';
|
||||||
import { SystemKeywords } from './SystemKeywords.js';
|
import { SystemKeywords } from './SystemKeywords.js';
|
||||||
import { Sequelize, QueryTypes } from '@sequelize/core';
|
import { Sequelize, QueryTypes } from '@sequelize/core';
|
||||||
import { z } from "zod";
|
import { z } from 'zod';
|
||||||
import { zodToJsonSchema } from "zod-to-json-schema";
|
import { zodToJsonSchema } from 'zod-to-json-schema';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fileoverview Decision was to priorize security(isolation) and debugging,
|
* @fileoverview Decision was to priorize security(isolation) and debugging,
|
||||||
|
@ -68,7 +68,8 @@ export class GBVMService extends GBService {
|
||||||
public static API_PORT = 1111;
|
public static API_PORT = 1111;
|
||||||
|
|
||||||
public async loadDialogPackage(folder: string, min: GBMinInstance, core: IGBCoreService, deployer: GBDeployer) {
|
public async loadDialogPackage(folder: string, min: GBMinInstance, core: IGBCoreService, deployer: GBDeployer) {
|
||||||
const files = await walkPromise(folder);
|
const ignore = Path.join('work', DialogKeywords.getGBAIPath(min.botId, 'gbdialog'), 'node_modules');
|
||||||
|
const files = await walkPromise(folder, { ignore: [ignore] });
|
||||||
|
|
||||||
await CollectionUtil.asyncForEach(files, async file => {
|
await CollectionUtil.asyncForEach(files, async file => {
|
||||||
if (!file) {
|
if (!file) {
|
||||||
|
@ -77,9 +78,7 @@ export class GBVMService extends GBService {
|
||||||
|
|
||||||
let filename: string = file.name;
|
let filename: string = file.name;
|
||||||
|
|
||||||
if (filename.endsWith('.docx')) {
|
filename = await this.loadDialog(filename, folder, min);
|
||||||
filename = await this.loadDialog(filename, folder, min);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,14 +90,11 @@ export class GBVMService extends GBService {
|
||||||
|
|
||||||
//check every key for being same
|
//check every key for being same
|
||||||
return Object.keys(obj1).every(function (key) {
|
return Object.keys(obj1).every(function (key) {
|
||||||
|
|
||||||
//if object
|
//if object
|
||||||
if ((typeof obj1[key] == "object") && (typeof obj2[key] == "object")) {
|
if (typeof obj1[key] == 'object' && typeof obj2[key] == 'object') {
|
||||||
|
|
||||||
//recursively check
|
//recursively check
|
||||||
return GBVMService.compare(obj1[key], obj2[key]);
|
return GBVMService.compare(obj1[key], obj2[key]);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
//do the normal compare
|
//do the normal compare
|
||||||
return obj1[key] === obj2[key];
|
return obj1[key] === obj2[key];
|
||||||
}
|
}
|
||||||
|
@ -106,9 +102,22 @@ export class GBVMService extends GBService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async loadDialog(filename: string, folder: string, min: GBMinInstance) {
|
public async loadDialog(filename: string, folder: string, min: GBMinInstance) {
|
||||||
|
const isWord = filename.endsWith('.docx');
|
||||||
|
if (
|
||||||
|
!(
|
||||||
|
isWord ||
|
||||||
|
filename.endsWith('.vbs') ||
|
||||||
|
filename.endsWith('.vb') ||
|
||||||
|
filename.endsWith('.vba') ||
|
||||||
|
filename.endsWith('.bas') ||
|
||||||
|
filename.endsWith('.basic')
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const wordFile = filename;
|
const wordFile = filename;
|
||||||
const vbsFile = filename.substr(0, filename.indexOf('docx')) + 'vbs';
|
const vbsFile = isWord ? filename.substr(0, filename.indexOf('docx')) + 'vbs' : filename;
|
||||||
const fullVbsFile = urlJoin(folder, vbsFile);
|
const fullVbsFile = urlJoin(folder, vbsFile);
|
||||||
const docxStat = Fs.statSync(urlJoin(folder, wordFile));
|
const docxStat = Fs.statSync(urlJoin(folder, wordFile));
|
||||||
const interval = 3000; // If compiled is older 30 seconds, then recompile.
|
const interval = 3000; // If compiled is older 30 seconds, then recompile.
|
||||||
|
@ -129,7 +138,6 @@ export class GBVMService extends GBService {
|
||||||
// await client.api('/subscriptions')
|
// await client.api('/subscriptions')
|
||||||
// .post(subscription);
|
// .post(subscription);
|
||||||
|
|
||||||
|
|
||||||
if (Fs.existsSync(fullVbsFile)) {
|
if (Fs.existsSync(fullVbsFile)) {
|
||||||
const vbsStat = Fs.statSync(fullVbsFile);
|
const vbsStat = Fs.statSync(fullVbsFile);
|
||||||
if (docxStat['mtimeMs'] < vbsStat['mtimeMs'] + interval) {
|
if (docxStat['mtimeMs'] < vbsStat['mtimeMs'] + interval) {
|
||||||
|
@ -184,7 +192,6 @@ export class GBVMService extends GBService {
|
||||||
min.sandBoxMap[mainName.toLowerCase().trim()] = parsedCode;
|
min.sandBoxMap[mainName.toLowerCase().trim()] = parsedCode;
|
||||||
return filename;
|
return filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
private processNodeModules(folder: string, min: GBMinInstance) {
|
private processNodeModules(folder: string, min: GBMinInstance) {
|
||||||
const node_modules = urlJoin(process.env.PWD, folder, 'node_modules');
|
const node_modules = urlJoin(process.env.PWD, folder, 'node_modules');
|
||||||
if (!Fs.existsSync(node_modules)) {
|
if (!Fs.existsSync(node_modules)) {
|
||||||
|
@ -215,7 +222,6 @@ export class GBVMService extends GBService {
|
||||||
}
|
}
|
||||||
|
|
||||||
private syncStorageFromTABLE(folder: string, filename: string, min: GBMinInstance, mainName: string) {
|
private syncStorageFromTABLE(folder: string, filename: string, min: GBMinInstance, mainName: string) {
|
||||||
|
|
||||||
const tablesFile = urlJoin(folder, `${filename}.tables.json`);
|
const tablesFile = urlJoin(folder, `${filename}.tables.json`);
|
||||||
let sync = false;
|
let sync = false;
|
||||||
|
|
||||||
|
@ -225,7 +231,6 @@ export class GBVMService extends GBService {
|
||||||
const tableDef = JSON.parse(Fs.readFileSync(tablesFile, 'utf8')) as any;
|
const tableDef = JSON.parse(Fs.readFileSync(tablesFile, 'utf8')) as any;
|
||||||
|
|
||||||
const getTypeBasedOnCondition = (t, size) => {
|
const getTypeBasedOnCondition = (t, size) => {
|
||||||
|
|
||||||
if (1) {
|
if (1) {
|
||||||
switch (t) {
|
switch (t) {
|
||||||
case 'string':
|
case 'string':
|
||||||
|
@ -249,7 +254,6 @@ export class GBVMService extends GBService {
|
||||||
default:
|
default:
|
||||||
return { type: 'TABLE', name: t };
|
return { type: 'TABLE', name: t };
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
switch (t) {
|
switch (t) {
|
||||||
case 'string':
|
case 'string':
|
||||||
|
@ -273,7 +277,6 @@ export class GBVMService extends GBService {
|
||||||
default:
|
default:
|
||||||
return { key: 'TABLE', name: t };
|
return { key: 'TABLE', name: t };
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -286,22 +289,17 @@ export class GBVMService extends GBService {
|
||||||
if (Fs.existsSync(filePath)) {
|
if (Fs.existsSync(filePath)) {
|
||||||
connections = JSON.parse(Fs.readFileSync(filePath, 'utf8'));
|
connections = JSON.parse(Fs.readFileSync(filePath, 'utf8'));
|
||||||
}
|
}
|
||||||
const shouldSync = min.core.getParam<boolean>(
|
const shouldSync = min.core.getParam<boolean>(min.instance, 'Synchronize Database', false);
|
||||||
min.instance,
|
|
||||||
'Synchronize Database',
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
tableDef.forEach(async (t) => {
|
|
||||||
|
|
||||||
|
tableDef.forEach(async t => {
|
||||||
const tableName = t.name.trim();
|
const tableName = t.name.trim();
|
||||||
|
|
||||||
// Determines autorelationship.
|
// Determines autorelationship.
|
||||||
Object.keys(t.fields).forEach(key => {
|
Object.keys(t.fields).forEach(key => {
|
||||||
let obj = t.fields[key];
|
let obj = t.fields[key];
|
||||||
obj.type = getTypeBasedOnCondition(obj.type, obj.size);
|
obj.type = getTypeBasedOnCondition(obj.type, obj.size);
|
||||||
if (obj.type.key === "TABLE") {
|
if (obj.type.key === 'TABLE') {
|
||||||
obj.type.key = "BIGINT";
|
obj.type.key = 'BIGINT';
|
||||||
associations.push({ from: tableName, to: obj.type.name });
|
associations.push({ from: tableName, to: obj.type.name });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -320,11 +318,12 @@ export class GBVMService extends GBService {
|
||||||
const username = con['storageUsername'];
|
const username = con['storageUsername'];
|
||||||
const password = con['storagePassword'];
|
const password = con['storagePassword'];
|
||||||
|
|
||||||
const logging: boolean | Function = GBConfigService.get('STORAGE_LOGGING') === 'true'
|
const logging: boolean | Function =
|
||||||
? (str: string): void => {
|
GBConfigService.get('STORAGE_LOGGING') === 'true'
|
||||||
GBLogEx.info(min, str);
|
? (str: string): void => {
|
||||||
}
|
GBLogEx.info(min, str);
|
||||||
: false;
|
}
|
||||||
|
: false;
|
||||||
|
|
||||||
const encrypt: boolean = GBConfigService.get('STORAGE_ENCRYPT') === 'true';
|
const encrypt: boolean = GBConfigService.get('STORAGE_ENCRYPT') === 'true';
|
||||||
const acquire = parseInt(GBConfigService.get('STORAGE_ACQUIRE_TIMEOUT'));
|
const acquire = parseInt(GBConfigService.get('STORAGE_ACQUIRE_TIMEOUT'));
|
||||||
|
@ -362,9 +361,9 @@ export class GBVMService extends GBService {
|
||||||
min[`llmconnection`] = {
|
min[`llmconnection`] = {
|
||||||
type: dialect,
|
type: dialect,
|
||||||
username,
|
username,
|
||||||
database: storageName, password
|
database: storageName,
|
||||||
|
password
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -373,11 +372,9 @@ export class GBVMService extends GBService {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Field checking, syncs if there is any difference.
|
// Field checking, syncs if there is any difference.
|
||||||
const seq = min[connectionName] ? min[connectionName]
|
const seq = min[connectionName] ? min[connectionName] : minBoot.core.sequelize;
|
||||||
: minBoot.core.sequelize;
|
|
||||||
|
|
||||||
if (seq) {
|
if (seq) {
|
||||||
|
|
||||||
const model = seq.models[tableName];
|
const model = seq.models[tableName];
|
||||||
if (model) {
|
if (model) {
|
||||||
// Except Id, checks if has same number of fields.
|
// Except Id, checks if has same number of fields.
|
||||||
|
@ -386,12 +383,11 @@ export class GBVMService extends GBService {
|
||||||
let obj1 = t.fields[key];
|
let obj1 = t.fields[key];
|
||||||
let obj2 = model['fieldRawAttributesMap'][key];
|
let obj2 = model['fieldRawAttributesMap'][key];
|
||||||
|
|
||||||
if (key !== "id") {
|
if (key !== 'id') {
|
||||||
if (obj1 && obj2) {
|
if (obj1 && obj2) {
|
||||||
equals++;
|
equals++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (equals != Object.keys(t.fields).length) {
|
if (equals != Object.keys(t.fields).length) {
|
||||||
|
@ -405,19 +401,21 @@ export class GBVMService extends GBService {
|
||||||
let tables;
|
let tables;
|
||||||
|
|
||||||
if (con.storageDriver === 'mssql') {
|
if (con.storageDriver === 'mssql') {
|
||||||
tables = await seq.query(`SELECT table_name, table_schema
|
tables = await seq.query(
|
||||||
|
`SELECT table_name, table_schema
|
||||||
FROM information_schema.tables
|
FROM information_schema.tables
|
||||||
WHERE table_type = 'BASE TABLE'
|
WHERE table_type = 'BASE TABLE'
|
||||||
ORDER BY table_name ASC`, {
|
ORDER BY table_name ASC`,
|
||||||
type: QueryTypes.RAW
|
{
|
||||||
})[0];
|
type: QueryTypes.RAW
|
||||||
}
|
}
|
||||||
else if (con.storageDriver === 'mariadb') {
|
)[0];
|
||||||
|
} else if (con.storageDriver === 'mariadb') {
|
||||||
tables = await seq.getQueryInterface().showAllTables();
|
tables = await seq.getQueryInterface().showAllTables();
|
||||||
}
|
}
|
||||||
|
|
||||||
let found = false;
|
let found = false;
|
||||||
tables.forEach((storageTable) => {
|
tables.forEach(storageTable => {
|
||||||
if (storageTable['table_name'] === tableName) {
|
if (storageTable['table_name'] === tableName) {
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
|
@ -432,15 +430,17 @@ export class GBVMService extends GBService {
|
||||||
try {
|
try {
|
||||||
to.hasMany(from);
|
to.hasMany(from);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error(`BASIC: Invalid relationship in ${mainName}: from ${e.from} to ${e.to} (${min.botId})... ${error.message}`);
|
throw new Error(
|
||||||
|
`BASIC: Invalid relationship in ${mainName}: from ${e.from} to ${e.to} (${min.botId})... ${error.message}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
if (sync && shouldSync) {
|
if (sync && shouldSync) {
|
||||||
|
GBLogEx.info(
|
||||||
GBLogEx.info(min, `BASIC: Syncing changes for TABLE ${connectionName} ${tableName} keyword (${min.botId})...`);
|
min,
|
||||||
|
`BASIC: Syncing changes for TABLE ${connectionName} ${tableName} keyword (${min.botId})...`
|
||||||
|
);
|
||||||
|
|
||||||
await seq.sync({
|
await seq.sync({
|
||||||
alter: true,
|
alter: true,
|
||||||
|
@ -454,7 +454,6 @@ export class GBVMService extends GBService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async translateBASIC(mainName, filename: any, min: GBMinInstance) {
|
public async translateBASIC(mainName, filename: any, min: GBMinInstance) {
|
||||||
|
|
||||||
// Converts General Bots BASIC into regular VBS
|
// Converts General Bots BASIC into regular VBS
|
||||||
|
|
||||||
let basicCode: string = Fs.readFileSync(filename, 'utf8');
|
let basicCode: string = Fs.readFileSync(filename, 'utf8');
|
||||||
|
@ -467,17 +466,14 @@ export class GBVMService extends GBService {
|
||||||
await s.deleteScheduleIfAny(min, mainName);
|
await s.deleteScheduleIfAny(min, mainName);
|
||||||
|
|
||||||
let i = 1;
|
let i = 1;
|
||||||
await CollectionUtil.asyncForEach(schedules, async (syntax) => {
|
await CollectionUtil.asyncForEach(schedules, async syntax => {
|
||||||
|
|
||||||
if (s) {
|
if (s) {
|
||||||
await s.createOrUpdateSchedule(min, syntax, `${mainName};${i++}`);
|
await s.createOrUpdateSchedule(min, syntax, `${mainName};${i++}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
basicCode = basicCode.replace(/^\s*SET SCHEDULE (.*)/gim, '');
|
basicCode = basicCode.replace(/^\s*SET SCHEDULE (.*)/gim, '');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Process INCLUDE keyword to include another
|
// Process INCLUDE keyword to include another
|
||||||
// dialog inside the dialog.
|
// dialog inside the dialog.
|
||||||
|
|
||||||
|
@ -718,7 +714,6 @@ export class GBVMService extends GBService {
|
||||||
|
|
||||||
Fs.writeFileSync(jsfile, code);
|
Fs.writeFileSync(jsfile, code);
|
||||||
GBLogEx.info(min, `[GBVMService] Finished loading of ${filename}, JavaScript from Word: \n ${code}`);
|
GBLogEx.info(min, `[GBVMService] Finished loading of ${filename}, JavaScript from Word: \n ${code}`);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async executeTasks(min, tasks) {
|
private async executeTasks(min, tasks) {
|
||||||
|
@ -726,12 +721,10 @@ export class GBVMService extends GBService {
|
||||||
const task = tasks[i];
|
const task = tasks[i];
|
||||||
|
|
||||||
if (task.kind === 'writeTableDefinition') {
|
if (task.kind === 'writeTableDefinition') {
|
||||||
|
|
||||||
// Creates an empty object that will receive Sequelize fields.
|
// Creates an empty object that will receive Sequelize fields.
|
||||||
|
|
||||||
const tablesFile = `${task.file}.tables.json`;
|
const tablesFile = `${task.file}.tables.json`;
|
||||||
Fs.writeFileSync(tablesFile, JSON.stringify(task.tables));
|
Fs.writeFileSync(tablesFile, JSON.stringify(task.tables));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -750,10 +743,10 @@ export class GBVMService extends GBService {
|
||||||
lines.forEach(line => {
|
lines.forEach(line => {
|
||||||
if (line.trim()) {
|
if (line.trim()) {
|
||||||
console.log(line);
|
console.log(line);
|
||||||
const keyword = /\s*SET SCHEDULE (.*)/gi;
|
const keyword = /^\s*SET SCHEDULE (.*)/gi;
|
||||||
let result: any = keyword.exec(line);
|
let result: any = keyword.exec(line);
|
||||||
if (result) {
|
if (result) {
|
||||||
result = result[1].replace(/\`|\"|\'/, '')
|
result = result[1].replace(/\`|\"|\'/, '');
|
||||||
result = result.trim();
|
result = result.trim();
|
||||||
results.push(result);
|
results.push(result);
|
||||||
}
|
}
|
||||||
|
@ -784,7 +777,6 @@ export class GBVMService extends GBService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static normalizeQuotes(text: any) {
|
public static normalizeQuotes(text: any) {
|
||||||
|
|
||||||
text = text.replace(/\"/gm, '`');
|
text = text.replace(/\"/gm, '`');
|
||||||
text = text.replace(/\¨/gm, '`');
|
text = text.replace(/\¨/gm, '`');
|
||||||
text = text.replace(/\“/gm, '`');
|
text = text.replace(/\“/gm, '`');
|
||||||
|
@ -798,27 +790,22 @@ export class GBVMService extends GBService {
|
||||||
public static getMetadata(mainName: string, propertiesText, description) {
|
public static getMetadata(mainName: string, propertiesText, description) {
|
||||||
let properties = {};
|
let properties = {};
|
||||||
if (!propertiesText || !description) {
|
if (!propertiesText || !description) {
|
||||||
|
return {};
|
||||||
return {}
|
|
||||||
}
|
}
|
||||||
const getType = asClause => {
|
const getType = asClause => {
|
||||||
|
|
||||||
asClause = asClause.trim().toUpperCase();
|
asClause = asClause.trim().toUpperCase();
|
||||||
|
|
||||||
if (asClause.indexOf('STRING') !== -1) {
|
if (asClause.indexOf('STRING') !== -1) {
|
||||||
return 'string';
|
return 'string';
|
||||||
}
|
} else if (asClause.indexOf('OBJECT') !== -1) {
|
||||||
else if (asClause.indexOf('OBJECT') !== -1) {
|
|
||||||
return 'object';
|
return 'object';
|
||||||
}
|
} else if (asClause.indexOf('INTEGER') !== -1 || asClause.indexOf('NUMBER') !== -1) {
|
||||||
else if (asClause.indexOf('INTEGER') !== -1 || asClause.indexOf('NUMBER') !== -1) {
|
|
||||||
return 'number';
|
return 'number';
|
||||||
} else {
|
} else {
|
||||||
return 'enum';
|
return 'enum';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
for (let i = 0; i < propertiesText.length; i++) {
|
for (let i = 0; i < propertiesText.length; i++) {
|
||||||
const propertiesExp = propertiesText[i];
|
const propertiesExp = propertiesText[i];
|
||||||
const t = getType(propertiesExp[2]);
|
const t = getType(propertiesExp[2]);
|
||||||
|
@ -841,21 +828,19 @@ export class GBVMService extends GBService {
|
||||||
properties[propertiesExp[1].trim()] = element;
|
properties[propertiesExp[1].trim()] = element;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let json = {
|
let json = {
|
||||||
type: "function",
|
type: 'function',
|
||||||
function: {
|
function: {
|
||||||
name: `${mainName}`,
|
name: `${mainName}`,
|
||||||
description: description ? description : '',
|
description: description ? description : '',
|
||||||
parameters: zodToJsonSchema(z.object(properties))
|
parameters: zodToJsonSchema(z.object(properties))
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async parseField(line) {
|
public async parseField(line) {
|
||||||
|
|
||||||
let required = line.indexOf('*') !== -1;
|
let required = line.indexOf('*') !== -1;
|
||||||
let unique = /\bunique\b/gi.test(line);
|
let unique = /\bunique\b/gi.test(line);
|
||||||
let primaryKey = /\bkey\b/gi.test(line);
|
let primaryKey = /\bkey\b/gi.test(line);
|
||||||
|
@ -877,7 +862,8 @@ export class GBVMService extends GBService {
|
||||||
|
|
||||||
let definition = {
|
let definition = {
|
||||||
allowNull: !required,
|
allowNull: !required,
|
||||||
unique: unique, primaryKey: primaryKey,
|
unique: unique,
|
||||||
|
primaryKey: primaryKey,
|
||||||
autoIncrement: autoIncrement
|
autoIncrement: autoIncrement
|
||||||
};
|
};
|
||||||
definition['type'] = t;
|
definition['type'] = t;
|
||||||
|
@ -896,7 +882,6 @@ export class GBVMService extends GBService {
|
||||||
* @param code General Bots BASIC
|
* @param code General Bots BASIC
|
||||||
*/
|
*/
|
||||||
public async convert(filename: string, mainName: string, code: string) {
|
public async convert(filename: string, mainName: string, code: string) {
|
||||||
|
|
||||||
// Start and End of VB2TS tags of processing.
|
// Start and End of VB2TS tags of processing.
|
||||||
|
|
||||||
code = process.env.ENABLE_AUTH ? `hear GBLogExin as login\n${code}` : code;
|
code = process.env.ENABLE_AUTH ? `hear GBLogExin as login\n${code}` : code;
|
||||||
|
@ -917,7 +902,6 @@ export class GBVMService extends GBService {
|
||||||
const outputLines = [];
|
const outputLines = [];
|
||||||
let emmitIndex = 1;
|
let emmitIndex = 1;
|
||||||
for (let i = 1; i <= lines.length; i++) {
|
for (let i = 1; i <= lines.length; i++) {
|
||||||
|
|
||||||
let line = lines[i - 1];
|
let line = lines[i - 1];
|
||||||
|
|
||||||
// Remove lines before statements.
|
// Remove lines before statements.
|
||||||
|
@ -968,12 +952,12 @@ export class GBVMService extends GBService {
|
||||||
const endTableKeyword = /^\s*END TABLE\s*/gim;
|
const endTableKeyword = /^\s*END TABLE\s*/gim;
|
||||||
let endTableReg = endTableKeyword.exec(line);
|
let endTableReg = endTableKeyword.exec(line);
|
||||||
if (endTableReg && table) {
|
if (endTableReg && table) {
|
||||||
|
|
||||||
tables.push({
|
tables.push({
|
||||||
name: table, fields: fields, connection: connection
|
name: table,
|
||||||
|
fields: fields,
|
||||||
|
connection: connection
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
fields = {};
|
fields = {};
|
||||||
table = null;
|
table = null;
|
||||||
connection = null;
|
connection = null;
|
||||||
|
@ -1013,14 +997,14 @@ export class GBVMService extends GBService {
|
||||||
const talkKeyword = /^\s*BEGIN TALK\s*/gim;
|
const talkKeyword = /^\s*BEGIN TALK\s*/gim;
|
||||||
let talkReg = talkKeyword.exec(line);
|
let talkReg = talkKeyword.exec(line);
|
||||||
if (talkReg && !talk) {
|
if (talkReg && !talk) {
|
||||||
talk = "await dk.talk ({pid: pid, text: `";
|
talk = 'await dk.talk ({pid: pid, text: `';
|
||||||
emmit = false;
|
emmit = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const systemPromptKeyword = /^\s*BEGIN SYSTEM PROMPT\s*/gim;
|
const systemPromptKeyword = /^\s*BEGIN SYSTEM PROMPT\s*/gim;
|
||||||
let systemPromptReg = systemPromptKeyword.exec(line);
|
let systemPromptReg = systemPromptKeyword.exec(line);
|
||||||
if (systemPromptReg && !systemPrompt) {
|
if (systemPromptReg && !systemPrompt) {
|
||||||
systemPrompt = "await sys.setSystemPrompt ({pid: pid, text: `";
|
systemPrompt = 'await sys.setSystemPrompt ({pid: pid, text: `';
|
||||||
emmit = false;
|
emmit = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1038,9 +1022,10 @@ export class GBVMService extends GBService {
|
||||||
|
|
||||||
if (tables) {
|
if (tables) {
|
||||||
tasks.push({
|
tasks.push({
|
||||||
kind: 'writeTableDefinition', file: filename, tables
|
kind: 'writeTableDefinition',
|
||||||
|
file: filename,
|
||||||
|
tables
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
code = `${outputLines.join('\n')}\n`;
|
code = `${outputLines.join('\n')}\n`;
|
||||||
|
@ -1053,14 +1038,7 @@ export class GBVMService extends GBService {
|
||||||
/**
|
/**
|
||||||
* Executes the converted JavaScript from BASIC code inside execution context.
|
* Executes the converted JavaScript from BASIC code inside execution context.
|
||||||
*/
|
*/
|
||||||
public static async callVM(
|
public static async callVM(text: string, min: GBMinInstance, step, pid, debug: boolean = false, params = []) {
|
||||||
text: string,
|
|
||||||
min: GBMinInstance,
|
|
||||||
step,
|
|
||||||
pid,
|
|
||||||
debug: boolean = false,
|
|
||||||
params = []
|
|
||||||
) {
|
|
||||||
// Creates a class DialogKeywords which is the *this* pointer
|
// Creates a class DialogKeywords which is the *this* pointer
|
||||||
// in BASIC.
|
// in BASIC.
|
||||||
|
|
||||||
|
@ -1076,8 +1054,7 @@ export class GBVMService extends GBService {
|
||||||
// These variables will be automatically be available as normal BASIC variables.
|
// These variables will be automatically be available as normal BASIC variables.
|
||||||
|
|
||||||
try {
|
try {
|
||||||
variables['aadToken'] = await (min.adminService as any)['acquireElevatedToken']
|
variables['aadToken'] = await (min.adminService as any)['acquireElevatedToken'](min.instance.instanceId, false);
|
||||||
(min.instance.instanceId, false);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
variables['aadToken'] = 'ERROR: Configure /setupSecurity before using aadToken variable.';
|
variables['aadToken'] = 'ERROR: Configure /setupSecurity before using aadToken variable.';
|
||||||
}
|
}
|
||||||
|
@ -1118,12 +1095,10 @@ export class GBVMService extends GBService {
|
||||||
let code = min.sandBoxMap[text];
|
let code = min.sandBoxMap[text];
|
||||||
const channel = step ? step.context.activity.channelId : 'web';
|
const channel = step ? step.context.activity.channelId : 'web';
|
||||||
|
|
||||||
|
|
||||||
const dk = new DialogKeywords();
|
const dk = new DialogKeywords();
|
||||||
const sys = new SystemKeywords();
|
const sys = new SystemKeywords();
|
||||||
await dk.setFilter({ pid: pid, value: null });
|
await dk.setFilter({ pid: pid, value: null });
|
||||||
|
|
||||||
|
|
||||||
// Find all tokens in .gbot Config.
|
// Find all tokens in .gbot Config.
|
||||||
|
|
||||||
const strFind = ' Client ID';
|
const strFind = ' Client ID';
|
||||||
|
@ -1159,7 +1134,7 @@ export class GBVMService extends GBService {
|
||||||
return await new Promise((resolve, reject) => {
|
return await new Promise((resolve, reject) => {
|
||||||
sandbox['resolve'] = resolve;
|
sandbox['resolve'] = resolve;
|
||||||
// TODO: #411 sandbox['reject'] = reject;
|
// TODO: #411 sandbox['reject'] = reject;
|
||||||
sandbox['reject'] = ()=>{};
|
sandbox['reject'] = () => {};
|
||||||
|
|
||||||
const vm1 = new NodeVM({
|
const vm1 = new NodeVM({
|
||||||
allowAsync: true,
|
allowAsync: true,
|
||||||
|
@ -1176,7 +1151,6 @@ export class GBVMService extends GBService {
|
||||||
const s = new VMScript(code, { filename: scriptPath });
|
const s = new VMScript(code, { filename: scriptPath });
|
||||||
result = vm1.run(s);
|
result = vm1.run(s);
|
||||||
});
|
});
|
||||||
|
|
||||||
})();
|
})();
|
||||||
} else {
|
} else {
|
||||||
const runnerPath = urlJoin(
|
const runnerPath = urlJoin(
|
||||||
|
@ -1207,10 +1181,15 @@ export class GBVMService extends GBService {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error(`BASIC RUNTIME ERR: ${error.message ? error.message : error}\n Stack:${error.stack}`);
|
throw new Error(`BASIC RUNTIME ERR: ${error.message ? error.message : error}\n Stack:${error.stack}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static createProcessInfo(user: GuaribasUser, min: GBMinInstance, channel: any, executable: string, step = null) {
|
public static createProcessInfo(
|
||||||
|
user: GuaribasUser,
|
||||||
|
min: GBMinInstance,
|
||||||
|
channel: any,
|
||||||
|
executable: string,
|
||||||
|
step = null
|
||||||
|
) {
|
||||||
const pid = GBAdminService.getNumberIdentifier();
|
const pid = GBAdminService.getNumberIdentifier();
|
||||||
GBServer.globals.processes[pid] = {
|
GBServer.globals.processes[pid] = {
|
||||||
pid: pid,
|
pid: pid,
|
||||||
|
|
|
@ -47,33 +47,30 @@ import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js';
|
||||||
* Basic services for BASIC manipulation.
|
* Basic services for BASIC manipulation.
|
||||||
*/
|
*/
|
||||||
export class ScheduleServices extends GBService {
|
export class ScheduleServices extends GBService {
|
||||||
|
|
||||||
public async deleteScheduleIfAny(min: GBMinInstance, name: string) {
|
public async deleteScheduleIfAny(min: GBMinInstance, name: string) {
|
||||||
|
|
||||||
let i = 1;
|
let i = 1;
|
||||||
while (i <= 10) {
|
while (i <= 10) {
|
||||||
const task = min['scheduleMap'] ? min['scheduleMap'][name + i] : null;
|
const task = min['scheduleMap'] ? min['scheduleMap'][name + i] : null;
|
||||||
|
|
||||||
if (task) {
|
if (task) {
|
||||||
task.destroy();
|
task.destroy();
|
||||||
const id = `${name};${i}`;
|
|
||||||
|
|
||||||
delete min['scheduleMap'][id];
|
|
||||||
const count = await GuaribasSchedule.destroy({
|
|
||||||
where: {
|
|
||||||
instanceId: min.instance.instanceId,
|
|
||||||
name: id
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (count > 0) {
|
|
||||||
GBLogEx.info(min, `BASIC: Removed ${name} SET SCHEDULE and ${count} rows from storage on: ${min.botId}...`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
const id = `${name};${i}`;
|
||||||
|
|
||||||
|
delete min['scheduleMap'][id];
|
||||||
|
const count = await GuaribasSchedule.destroy({
|
||||||
|
where: {
|
||||||
|
instanceId: min.instance.instanceId,
|
||||||
|
name: id
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (count > 0) {
|
||||||
|
GBLogEx.info(min, `BASIC: Removed ${name} SET SCHEDULE and ${count} rows from storage on: ${min.botId}...`);
|
||||||
|
}
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -113,12 +110,10 @@ export class ScheduleServices extends GBService {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
let lastName = '';
|
let lastName = '';
|
||||||
|
|
||||||
await CollectionUtil.asyncForEach(schedules, async (item) => {
|
await CollectionUtil.asyncForEach(schedules, async item => {
|
||||||
|
|
||||||
if (item.name === lastName) {
|
if (item.name === lastName) {
|
||||||
item.name = item.name + ++i;
|
item.name = item.name + ++i;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
i = 0;
|
i = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,7 +164,6 @@ export class ScheduleServices extends GBService {
|
||||||
},
|
},
|
||||||
options
|
options
|
||||||
);
|
);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
GBLogEx.error(min, `Running .gbdialog word ${item.name} : ${error}...`);
|
GBLogEx.error(min, `Running .gbdialog word ${item.name} : ${error}...`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,8 +79,11 @@ export class GBConfigService {
|
||||||
public static get(key: string): string | undefined {
|
public static get(key: string): string | undefined {
|
||||||
let value = GBConfigService.tryGet(key);
|
let value = GBConfigService.tryGet(key);
|
||||||
|
|
||||||
if (value === undefined) {
|
if (!value) {
|
||||||
switch (key) {
|
switch (key) {
|
||||||
|
case 'STORAGE_NAME':
|
||||||
|
value = null;
|
||||||
|
break;
|
||||||
case 'CLOUD_USERNAME':
|
case 'CLOUD_USERNAME':
|
||||||
value = undefined;
|
value = undefined;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -242,7 +242,7 @@ export class GBCoreService implements IGBCoreService {
|
||||||
* Loads all items to start several listeners.
|
* Loads all items to start several listeners.
|
||||||
*/
|
*/
|
||||||
public async loadInstances(): Promise<IGBInstance[]> {
|
public async loadInstances(): Promise<IGBInstance[]> {
|
||||||
if (process.env.LOAD_ONLY !== undefined) {
|
if (process.env.LOAD_ONLY) {
|
||||||
const bots = process.env.LOAD_ONLY.split(`;`);
|
const bots = process.env.LOAD_ONLY.split(`;`);
|
||||||
const and = [];
|
const and = [];
|
||||||
await CollectionUtil.asyncForEach(bots, async e => {
|
await CollectionUtil.asyncForEach(bots, async e => {
|
||||||
|
@ -814,8 +814,6 @@ ENDPOINT_UPDATE=true
|
||||||
mkdirp.sync(libraryPath);
|
mkdirp.sync(libraryPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
await this.syncBotStorage(instances, 'default', deployer, libraryPath);
|
await this.syncBotStorage(instances, 'default', deployer, libraryPath);
|
||||||
|
|
||||||
const files = Fs.readdirSync(libraryPath);
|
const files = Fs.readdirSync(libraryPath);
|
||||||
|
|
|
@ -254,6 +254,11 @@ export class GBDeployer implements IGBDeployer {
|
||||||
if (GBConfigService.get('STORAGE_NAME')) {
|
if (GBConfigService.get('STORAGE_NAME')) {
|
||||||
await this.deployBotOnAzure(instance, GBServer.globals.publicAddress);
|
await this.deployBotOnAzure(instance, GBServer.globals.publicAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Makes available bot to the channels and .gbui interfaces.
|
||||||
|
|
||||||
|
await GBServer.globals.minService.mountBot(instance);
|
||||||
|
|
||||||
// Creates remaining objects on the cloud and updates instance information.
|
// Creates remaining objects on the cloud and updates instance information.
|
||||||
|
|
||||||
return instance;
|
return instance;
|
||||||
|
@ -310,10 +315,6 @@ export class GBDeployer implements IGBDeployer {
|
||||||
subscriptionId
|
subscriptionId
|
||||||
);
|
);
|
||||||
|
|
||||||
// Makes available bot to the channels and .gbui interfaces.
|
|
||||||
|
|
||||||
await GBServer.globals.minService.mountBot(instance);
|
|
||||||
await GBServer.globals.minService.ensureAPI();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Saves final instance object and returns it.
|
// Saves final instance object and returns it.
|
||||||
|
|
|
@ -167,9 +167,6 @@ export class GBMinService {
|
||||||
|
|
||||||
let i = 1;
|
let i = 1;
|
||||||
|
|
||||||
if (instances.length > 1) {
|
|
||||||
}
|
|
||||||
|
|
||||||
await CollectionUtil.asyncForEach(
|
await CollectionUtil.asyncForEach(
|
||||||
instances,
|
instances,
|
||||||
(async instance => {
|
(async instance => {
|
||||||
|
@ -184,12 +181,9 @@ export class GBMinService {
|
||||||
GBLog.error(`Error mounting bot ${instance.botId}: ${error.message}\n${error.stack}`);
|
GBLog.error(`Error mounting bot ${instance.botId}: ${error.message}\n${error.stack}`);
|
||||||
}
|
}
|
||||||
}).bind(this)
|
}).bind(this)
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Loads API.
|
|
||||||
|
|
||||||
await this.ensureAPI();
|
|
||||||
|
|
||||||
// Loads schedules.
|
// Loads schedules.
|
||||||
|
|
||||||
GBLogEx.info(0, `Loading SET SCHEDULE entries...`);
|
GBLogEx.info(0, `Loading SET SCHEDULE entries...`);
|
||||||
|
@ -199,6 +193,37 @@ export class GBMinService {
|
||||||
GBLogEx.info(0, `All Bot instances loaded.`);
|
GBLogEx.info(0, `All Bot instances loaded.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async startSimpleTest(min) {
|
||||||
|
if (process.env.TEST_MESSAGE && min['isDefault']) {
|
||||||
|
GBLogEx.info(min, `Starting auto test with '${process.env.TEST_MESSAGE}'.`);
|
||||||
|
|
||||||
|
const client = await GBUtil.getDirectLineClient(min);
|
||||||
|
|
||||||
|
const response = await client.apis.Conversations.Conversations_StartConversation();
|
||||||
|
const conversationId = response.obj.conversationId;
|
||||||
|
GBServer.globals.debugConversationId = conversationId;
|
||||||
|
|
||||||
|
const steps = process.env.TEST_MESSAGE.split(';');
|
||||||
|
|
||||||
|
await CollectionUtil.asyncForEach(steps, async (step) => {
|
||||||
|
client.apis.Conversations.Conversations_PostActivity({
|
||||||
|
conversationId: conversationId,
|
||||||
|
activity: {
|
||||||
|
textFormat: 'plain',
|
||||||
|
text: step,
|
||||||
|
type: 'message',
|
||||||
|
from: {
|
||||||
|
id: 'test',
|
||||||
|
name: 'test'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await GBUtil.sleep(3000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes bot endpoint from web listeners and remove bot instance
|
* Removes bot endpoint from web listeners and remove bot instance
|
||||||
* from list of global server bot instances.
|
* from list of global server bot instances.
|
||||||
|
@ -256,6 +281,8 @@ export class GBMinService {
|
||||||
// https://github.com/GeneralBots/BotServer/issues/286
|
// https://github.com/GeneralBots/BotServer/issues/286
|
||||||
// min['groupCache'] = await KBService.getGroupReplies(instance.instanceId);
|
// min['groupCache'] = await KBService.getGroupReplies(instance.instanceId);
|
||||||
|
|
||||||
|
min['isDefault'] = GBServer.globals.minInstances.length === 0;
|
||||||
|
|
||||||
GBServer.globals.minInstances.push(min);
|
GBServer.globals.minInstances.push(min);
|
||||||
const user = null; // No user context.
|
const user = null; // No user context.
|
||||||
|
|
||||||
|
@ -330,9 +357,6 @@ export class GBMinService {
|
||||||
GBLogEx.info(1, `WebDav for ${botId} loaded.`);
|
GBLogEx.info(1, `WebDav for ${botId} loaded.`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// Loads Named Entity data for this bot.
|
|
||||||
|
|
||||||
// TODO: await KBService.RefreshNER(min);
|
|
||||||
|
|
||||||
// Calls the loadBot context.activity for all packages.
|
// Calls the loadBot context.activity for all packages.
|
||||||
|
|
||||||
|
@ -356,34 +380,6 @@ export class GBMinService {
|
||||||
});
|
});
|
||||||
GBLog.verbose(`GeneralBots(${instance.engineName}) listening on: ${url}.`);
|
GBLog.verbose(`GeneralBots(${instance.engineName}) listening on: ${url}.`);
|
||||||
|
|
||||||
// Test code.
|
|
||||||
if (process.env.TEST_MESSAGE) {
|
|
||||||
GBLogEx.info(min, `Starting auto test with '${process.env.TEST_MESSAGE}'.`);
|
|
||||||
|
|
||||||
const client = await GBUtil.getDirectLineClient(min);
|
|
||||||
|
|
||||||
const response = await client.apis.Conversations.Conversations_StartConversation();
|
|
||||||
const conversationId = response.obj.conversationId;
|
|
||||||
GBServer.globals.debugConversationId = conversationId;
|
|
||||||
|
|
||||||
const steps = process.env.TEST_MESSAGE.split(';');
|
|
||||||
|
|
||||||
await CollectionUtil.asyncForEach(steps, async step => {
|
|
||||||
client.apis.Conversations.Conversations_PostActivity({
|
|
||||||
conversationId: conversationId,
|
|
||||||
activity: {
|
|
||||||
textFormat: 'plain',
|
|
||||||
text: step,
|
|
||||||
type: 'message',
|
|
||||||
from: {
|
|
||||||
id: 'test',
|
|
||||||
name: 'test'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await GBUtil.sleep(3000);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Generates MS Teams manifest.
|
// Generates MS Teams manifest.
|
||||||
|
|
||||||
|
@ -394,7 +390,6 @@ export class GBMinService {
|
||||||
const data = await this.deployer.getBotManifest(instance);
|
const data = await this.deployer.getBotManifest(instance);
|
||||||
Fs.writeFileSync(packageTeams, data);
|
Fs.writeFileSync(packageTeams, data);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Serves individual URL for each bot user interface.
|
// Serves individual URL for each bot user interface.
|
||||||
|
|
||||||
|
@ -463,6 +458,11 @@ export class GBMinService {
|
||||||
.bind(min);
|
.bind(min);
|
||||||
|
|
||||||
GBDeployer.mountGBKBAssets(`${botId}.gbkb`, botId, `${botId}.gbkb`);
|
GBDeployer.mountGBKBAssets(`${botId}.gbkb`, botId, `${botId}.gbkb`);
|
||||||
|
|
||||||
|
// Loads API.
|
||||||
|
|
||||||
|
await this.ensureAPI();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static getProviderName(req: any, res: any) {
|
public static getProviderName(req: any, res: any) {
|
||||||
|
@ -839,6 +839,8 @@ export class GBMinService {
|
||||||
|
|
||||||
let url = `/api/messages/${instance.botId}`;
|
let url = `/api/messages/${instance.botId}`;
|
||||||
GBServer.globals.server.post(url, receiver);
|
GBServer.globals.server.post(url, receiver);
|
||||||
|
url = `/api/messages`;
|
||||||
|
GBServer.globals.server.post(url, receiver);
|
||||||
|
|
||||||
// NLP Manager.
|
// NLP Manager.
|
||||||
|
|
||||||
|
@ -849,9 +851,6 @@ export class GBMinService {
|
||||||
GBServer.globals.minBoot = min;
|
GBServer.globals.minBoot = min;
|
||||||
GBServer.globals.minBoot.instance.marketplaceId = GBConfigService.get('MARKETPLACE_ID');
|
GBServer.globals.minBoot.instance.marketplaceId = GBConfigService.get('MARKETPLACE_ID');
|
||||||
GBServer.globals.minBoot.instance.marketplacePassword = GBConfigService.get('MARKETPLACE_SECRET');
|
GBServer.globals.minBoot.instance.marketplacePassword = GBConfigService.get('MARKETPLACE_SECRET');
|
||||||
} else {
|
|
||||||
url = `/api/messages`;
|
|
||||||
GBServer.globals.server.post(url, receiver);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (min.instance.facebookWorkplaceVerifyToken) {
|
if (min.instance.facebookWorkplaceVerifyToken) {
|
||||||
|
|
|
@ -12,197 +12,214 @@ const conversationsCleanupInterval = 10000;
|
||||||
const conversations: { [key: string]: IConversation } = {};
|
const conversations: { [key: string]: IConversation } = {};
|
||||||
const botDataStore: { [key: string]: IBotData } = {};
|
const botDataStore: { [key: string]: IBotData } = {};
|
||||||
|
|
||||||
export const getRouter = (serviceUrl: string, botUrl: string, conversationInitRequired = true, botId): express.Router => {
|
export const getRouter = (
|
||||||
const router = express.Router();
|
serviceUrl: string,
|
||||||
|
botUrl: string,
|
||||||
|
conversationInitRequired = true,
|
||||||
|
botId
|
||||||
|
): express.Router => {
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
router.use(bodyParser.json()); // for parsing application/json
|
router.use(bodyParser.json()); // for parsing application/json
|
||||||
router.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded
|
router.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded
|
||||||
router.use((req, res, next) => {
|
router.use((req, res, next) => {
|
||||||
res.header('Access-Control-Allow-Origin', '*');
|
res.header('Access-Control-Allow-Origin', '*');
|
||||||
res.header('Access-Control-Allow-Methods', 'GET, PUT, POST, DELETE, PATCH, OPTIONS');
|
res.header('Access-Control-Allow-Methods', 'GET, PUT, POST, DELETE, PATCH, OPTIONS');
|
||||||
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization, x-ms-bot-agent');
|
res.header(
|
||||||
next();
|
'Access-Control-Allow-Headers',
|
||||||
});
|
'Origin, X-Requested-With, Content-Type, Accept, Authorization, x-ms-bot-agent'
|
||||||
|
);
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
// CLIENT ENDPOINT
|
// CLIENT ENDPOINT
|
||||||
router.options(`/directline/${botId}/`, (req, res) => {
|
router.options(`/directline/${botId}/`, (req, res) => {
|
||||||
res.status(200).end();
|
res.status(200).end();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Creates a conversation
|
// Creates a conversation
|
||||||
const reqs = (req, res) => {
|
const reqs = (req, res) => {
|
||||||
|
const conversationId: string = uuidv4.v4().toString();
|
||||||
const conversationId: string = uuidv4.v4().toString();
|
conversations[conversationId] = {
|
||||||
conversations[conversationId] = {
|
conversationId,
|
||||||
conversationId,
|
history: []
|
||||||
history: [],
|
|
||||||
};
|
|
||||||
console.log('Created conversation with conversationId: ' + conversationId);
|
|
||||||
|
|
||||||
const activity = createConversationUpdateActivity(serviceUrl, conversationId);
|
|
||||||
fetch(botUrl, {
|
|
||||||
method: 'POST',
|
|
||||||
body: JSON.stringify(activity),
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
}).then((response) => {
|
|
||||||
res.status(response.status).send({
|
|
||||||
conversationId,
|
|
||||||
expiresIn,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
console.log('Created conversation with conversationId: ' + conversationId);
|
||||||
|
|
||||||
router.post('/v3/directline/conversations',reqs );
|
const activity = createConversationUpdateActivity(serviceUrl, conversationId);
|
||||||
router.post(`/directline/${botId}/conversations`,reqs );
|
fetch(botUrl, {
|
||||||
router.post(`/directline/conversations`,reqs );
|
method: 'POST',
|
||||||
|
body: JSON.stringify(activity),
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
}).then(response => {
|
||||||
|
res.status(response.status).send({
|
||||||
|
conversationId,
|
||||||
|
expiresIn
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// Reconnect API
|
router.post('/v3/directline/conversations', reqs);
|
||||||
router.get('/v3/directline/conversations/:conversationId', (req, res) => {
|
router.post(`/directline/${botId}/conversations`, reqs);
|
||||||
const conversation = getConversation(req.params.conversationId, conversationInitRequired);
|
router.post(`/directline/conversations`, reqs);
|
||||||
if (conversation) {
|
|
||||||
res.status(200).send(conversation);
|
// Reconnect API
|
||||||
} else {
|
router.get('/v3/directline/conversations/:conversationId', (req, res) => {
|
||||||
// Conversation was never initialized
|
const conversation = getConversation(req.params.conversationId, conversationInitRequired);
|
||||||
res.status(400).send();
|
if (conversation) {
|
||||||
|
res.status(200).send(conversation);
|
||||||
|
} else {
|
||||||
|
// Conversation was never initialized
|
||||||
|
res.status(400).send();
|
||||||
|
}
|
||||||
|
|
||||||
|
console.warn('/v3/directline/conversations/:conversationId not implemented');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Gets activities from store (local history array for now)
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (conversation) {
|
||||||
|
// If the bot has pushed anything into the history array
|
||||||
|
if (conversation.history.length > watermark) {
|
||||||
|
const activities = conversation.history.slice(watermark);
|
||||||
|
res.status(200).json({
|
||||||
|
activities,
|
||||||
|
watermark: watermark + activities.length
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
res.status(200).send({
|
||||||
|
activities: [],
|
||||||
|
watermark
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Conversation was never initialized
|
||||||
|
res.status(400).send();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Sends message to bot. Assumes message activities
|
||||||
|
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);
|
||||||
|
|
||||||
|
const conversation = getConversation(req.params.conversationId, conversationInitRequired);
|
||||||
|
|
||||||
|
if (conversation) {
|
||||||
|
conversation.history.push(activity);
|
||||||
|
fetch(botUrl, {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify(activity),
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
}
|
}
|
||||||
|
}).then(response => {
|
||||||
|
res.status(response.status).json({ id: activity.id });
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Conversation was never initialized
|
||||||
|
res.status(400).send();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
console.warn('/v3/directline/conversations/:conversationId not implemented');
|
router.post('/v3/directline/conversations/:conversationId/upload', (req, res) => {
|
||||||
});
|
console.warn('/v3/directline/conversations/:conversationId/upload not implemented');
|
||||||
|
});
|
||||||
|
router.get('/v3/directline/conversations/:conversationId/stream', (req, res) => {
|
||||||
|
console.warn('/v3/directline/conversations/:conversationId/stream not implemented');
|
||||||
|
});
|
||||||
|
|
||||||
// Gets activities from store (local history array for now)
|
// BOT CONVERSATION ENDPOINT
|
||||||
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);
|
router.post('/v3/conversations', (req, res) => {
|
||||||
|
console.warn('/v3/conversations not implemented');
|
||||||
|
});
|
||||||
|
|
||||||
if (conversation) {
|
router.post('/v3/conversations/:conversationId/activities', (req, res) => {
|
||||||
// If the bot has pushed anything into the history array
|
let activity: IActivity;
|
||||||
if (conversation.history.length > watermark) {
|
|
||||||
const activities = conversation.history.slice(watermark);
|
|
||||||
res.status(200).json({
|
|
||||||
activities,
|
|
||||||
watermark: watermark + activities.length,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
res.status(200).send({
|
|
||||||
activities: [],
|
|
||||||
watermark,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Conversation was never initialized
|
|
||||||
res.status(400).send();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Sends message to bot. Assumes message activities
|
activity = req.body;
|
||||||
router.post(`/directline/${botId}/conversations/:conversationId/activities`, (req, res) => {
|
activity.id = uuidv4.v4();
|
||||||
const incomingActivity = req.body;
|
activity.from = { id: 'id', name: 'Bot' };
|
||||||
// Make copy of activity. Add required fields
|
|
||||||
const activity = createMessageActivity(incomingActivity, serviceUrl, req.params.conversationId);
|
|
||||||
|
|
||||||
const conversation = getConversation(req.params.conversationId, conversationInitRequired);
|
const conversation = getConversation(req.params.conversationId, conversationInitRequired);
|
||||||
|
if (conversation) {
|
||||||
|
conversation.history.push(activity);
|
||||||
|
res.status(200).send();
|
||||||
|
} else {
|
||||||
|
// Conversation was never initialized
|
||||||
|
res.status(400).send();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if (conversation) {
|
router.post('/v3/conversations/:conversationId/activities/:activityId', (req, res) => {
|
||||||
conversation.history.push(activity);
|
let activity: IActivity;
|
||||||
fetch(botUrl, {
|
|
||||||
method: 'POST',
|
|
||||||
body: JSON.stringify(activity),
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
}).then((response) => {
|
|
||||||
res.status(response.status).json({ id: activity.id });
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// Conversation was never initialized
|
|
||||||
res.status(400).send();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
router.post('/v3/directline/conversations/:conversationId/upload', (req, res) => { console.warn('/v3/directline/conversations/:conversationId/upload not implemented'); });
|
activity = req.body;
|
||||||
router.get('/v3/directline/conversations/:conversationId/stream', (req, res) => { console.warn('/v3/directline/conversations/:conversationId/stream not implemented'); });
|
activity.id = uuidv4.v4();
|
||||||
|
activity.from = { id: 'id', name: 'Bot' };
|
||||||
|
|
||||||
// BOT CONVERSATION ENDPOINT
|
const conversation = getConversation(req.params.conversationId, conversationInitRequired);
|
||||||
|
if (conversation) {
|
||||||
|
conversation.history.push(activity);
|
||||||
|
res.status(200).send();
|
||||||
|
} else {
|
||||||
|
// Conversation was never initialized
|
||||||
|
res.status(400).send();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
router.post('/v3/conversations', (req, res) => { console.warn('/v3/conversations not implemented'); });
|
router.get('/v3/conversations/:conversationId/members', (req, res) => {
|
||||||
|
console.warn('/v3/conversations/:conversationId/members not implemented');
|
||||||
|
});
|
||||||
|
router.get('/v3/conversations/:conversationId/activities/:activityId/members', (req, res) => {
|
||||||
|
console.warn('/v3/conversations/:conversationId/activities/:activityId/members');
|
||||||
|
});
|
||||||
|
|
||||||
router.post('/v3/conversations/:conversationId/activities', (req, res) => {
|
// BOTSTATE ENDPOINT
|
||||||
let activity: IActivity;
|
|
||||||
|
|
||||||
activity = req.body;
|
router.get('/v3/botstate/:channelId/users/:userId', (req, res) => {
|
||||||
activity.id = uuidv4.v4();
|
console.log('Called GET user data');
|
||||||
activity.from = { id: 'id', name: 'Bot' };
|
getBotData(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
const conversation = getConversation(req.params.conversationId, conversationInitRequired);
|
router.get('/v3/botstate/:channelId/conversations/:conversationId', (req, res) => {
|
||||||
if (conversation) {
|
console.log('Called GET conversation data');
|
||||||
conversation.history.push(activity);
|
getBotData(req, res);
|
||||||
res.status(200).send();
|
});
|
||||||
} else {
|
|
||||||
// Conversation was never initialized
|
|
||||||
res.status(400).send();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
router.post('/v3/conversations/:conversationId/activities/:activityId', (req, res) => {
|
router.get('/v3/botstate/:channelId/conversations/:conversationId/users/:userId', (req, res) => {
|
||||||
let activity: IActivity;
|
console.log('Called GET private conversation data');
|
||||||
|
getBotData(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
activity = req.body;
|
router.post('/v3/botstate/:channelId/users/:userId', (req, res) => {
|
||||||
activity.id = uuidv4.v4();
|
console.log('Called POST setUserData');
|
||||||
activity.from = { id: 'id', name: 'Bot' };
|
setUserData(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
const conversation = getConversation(req.params.conversationId, conversationInitRequired);
|
router.post('/v3/botstate/:channelId/conversations/:conversationId', (req, res) => {
|
||||||
if (conversation) {
|
console.log('Called POST setConversationData');
|
||||||
conversation.history.push(activity);
|
setConversationData(req, res);
|
||||||
res.status(200).send();
|
});
|
||||||
} else {
|
|
||||||
// Conversation was never initialized
|
|
||||||
res.status(400).send();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
router.get('/v3/conversations/:conversationId/members', (req, res) => { console.warn('/v3/conversations/:conversationId/members not implemented'); });
|
router.post('/v3/botstate/:channelId/conversations/:conversationId/users/:userId', (req, res) => {
|
||||||
router.get('/v3/conversations/:conversationId/activities/:activityId/members', (req, res) => { console.warn('/v3/conversations/:conversationId/activities/:activityId/members'); });
|
setPrivateConversationData(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
// BOTSTATE ENDPOINT
|
router.delete('/v3/botstate/:channelId/users/:userId', (req, res) => {
|
||||||
|
console.log('Called DELETE deleteStateForUser');
|
||||||
|
deleteStateForUser(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
router.get('/v3/botstate/:channelId/users/:userId', (req, res) => {
|
return router;
|
||||||
console.log('Called GET user data');
|
|
||||||
getBotData(req, res);
|
|
||||||
});
|
|
||||||
|
|
||||||
router.get('/v3/botstate/:channelId/conversations/:conversationId', (req, res) => {
|
|
||||||
console.log(('Called GET conversation data'));
|
|
||||||
getBotData(req, res);
|
|
||||||
});
|
|
||||||
|
|
||||||
router.get('/v3/botstate/:channelId/conversations/:conversationId/users/:userId', (req, res) => {
|
|
||||||
console.log('Called GET private conversation data');
|
|
||||||
getBotData(req, res);
|
|
||||||
});
|
|
||||||
|
|
||||||
router.post('/v3/botstate/:channelId/users/:userId', (req, res) => {
|
|
||||||
console.log('Called POST setUserData');
|
|
||||||
setUserData(req, res);
|
|
||||||
});
|
|
||||||
|
|
||||||
router.post('/v3/botstate/:channelId/conversations/:conversationId', (req, res) => {
|
|
||||||
console.log('Called POST setConversationData');
|
|
||||||
setConversationData(req, res);
|
|
||||||
});
|
|
||||||
|
|
||||||
router.post('/v3/botstate/:channelId/conversations/:conversationId/users/:userId', (req, res) => {
|
|
||||||
setPrivateConversationData(req, res);
|
|
||||||
});
|
|
||||||
|
|
||||||
router.delete('/v3/botstate/:channelId/users/:userId', (req, res) => {
|
|
||||||
console.log('Called DELETE deleteStateForUser');
|
|
||||||
deleteStateForUser(req, res);
|
|
||||||
});
|
|
||||||
|
|
||||||
return router;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -212,114 +229,132 @@ export const getRouter = (serviceUrl: string, botUrl: string, conversationInitRe
|
||||||
* @param conversationInitRequired Requires that a conversation is initialized before it is accessed, returning a 400
|
* @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.
|
* 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, botId) => {
|
export const initializeRoutes = (
|
||||||
conversationsCleanup();
|
app: express.Express,
|
||||||
|
port: number,
|
||||||
|
botUrl: string,
|
||||||
|
conversationInitRequired = true,
|
||||||
|
botId
|
||||||
|
) => {
|
||||||
|
conversationsCleanup();
|
||||||
|
|
||||||
const directLineEndpoint = `http://127.0.0.1:${port}`;
|
const directLineEndpoint = `http://127.0.0.1:${port}`;
|
||||||
const router = getRouter(directLineEndpoint, botUrl, conversationInitRequired, botId);
|
const router = getRouter(directLineEndpoint, botUrl, conversationInitRequired, botId);
|
||||||
|
|
||||||
app.use(router);
|
|
||||||
console.log(`Routing messages to bot on ${botUrl}`);
|
|
||||||
|
|
||||||
|
app.use(router);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getConversation = (conversationId: string, conversationInitRequired: boolean) => {
|
const getConversation = (conversationId: string, conversationInitRequired: boolean) => {
|
||||||
|
// Create conversation on the fly when needed and init not required
|
||||||
// Create conversation on the fly when needed and init not required
|
if (!conversations[conversationId] && !conversationInitRequired) {
|
||||||
if (!conversations[conversationId] && !conversationInitRequired) {
|
conversations[conversationId] = {
|
||||||
conversations[conversationId] = {
|
conversationId,
|
||||||
conversationId,
|
history: []
|
||||||
history: [],
|
};
|
||||||
};
|
}
|
||||||
}
|
return conversations[conversationId];
|
||||||
return conversations[conversationId];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const getBotDataKey = (channelId: string, conversationId: string, userId: string) => {
|
const getBotDataKey = (channelId: string, conversationId: string, userId: string) => {
|
||||||
return `$${channelId || '*'}!${conversationId || '*'}!${userId || '*'}`;
|
return `$${channelId || '*'}!${conversationId || '*'}!${userId || '*'}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const setBotData = (channelId: string, conversationId: string, userId: string, incomingData: IBotData): IBotData => {
|
const setBotData = (channelId: string, conversationId: string, userId: string, incomingData: IBotData): IBotData => {
|
||||||
const key = getBotDataKey(channelId, conversationId, userId);
|
const key = getBotDataKey(channelId, conversationId, userId);
|
||||||
const newData: IBotData = {
|
const newData: IBotData = {
|
||||||
eTag: new Date().getTime().toString(),
|
eTag: new Date().getTime().toString(),
|
||||||
data: incomingData.data,
|
data: incomingData.data
|
||||||
};
|
};
|
||||||
|
|
||||||
if (incomingData) {
|
if (incomingData) {
|
||||||
botDataStore[key] = newData;
|
botDataStore[key] = newData;
|
||||||
} else {
|
} else {
|
||||||
delete botDataStore[key];
|
delete botDataStore[key];
|
||||||
newData.eTag = '*';
|
newData.eTag = '*';
|
||||||
}
|
}
|
||||||
|
|
||||||
return newData;
|
return newData;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getBotData = (req: express.Request, res: express.Response) => {
|
const getBotData = (req: express.Request, res: express.Response) => {
|
||||||
const key = getBotDataKey(req.params.channelId, req.params.conversationId, req.params.userId);
|
const key = getBotDataKey(req.params.channelId, req.params.conversationId, req.params.userId);
|
||||||
console.log('Data key: ' + key);
|
console.log('Data key: ' + key);
|
||||||
|
|
||||||
res.status(200).send(botDataStore[key] || { data: null, eTag: '*' });
|
res.status(200).send(botDataStore[key] || { data: null, eTag: '*' });
|
||||||
};
|
};
|
||||||
|
|
||||||
const setUserData = (req: express.Request, res: express.Response) => {
|
const setUserData = (req: express.Request, res: express.Response) => {
|
||||||
res.status(200).send(setBotData(req.params.channelId, req.params.conversationId, req.params.userId, req.body));
|
res.status(200).send(setBotData(req.params.channelId, req.params.conversationId, req.params.userId, req.body));
|
||||||
};
|
};
|
||||||
|
|
||||||
const setConversationData = (req: express.Request, res: express.Response) => {
|
const setConversationData = (req: express.Request, res: express.Response) => {
|
||||||
res.status(200).send(setBotData(req.params.channelId, req.params.conversationId, req.params.userId, req.body));
|
res.status(200).send(setBotData(req.params.channelId, req.params.conversationId, req.params.userId, req.body));
|
||||||
};
|
};
|
||||||
|
|
||||||
const setPrivateConversationData = (req: express.Request, res: express.Response) => {
|
const setPrivateConversationData = (req: express.Request, res: express.Response) => {
|
||||||
res.status(200).send(setBotData(req.params.channelId, req.params.conversationId, req.params.userId, req.body));
|
res.status(200).send(setBotData(req.params.channelId, req.params.conversationId, req.params.userId, req.body));
|
||||||
};
|
};
|
||||||
|
|
||||||
export const start = (server, botId)=>{
|
export const start = (server, botId) => {
|
||||||
const port = GBConfigService.getServerPort();
|
const port = GBConfigService.getServerPort();
|
||||||
initializeRoutes(server, Number(port), `http://127.0.0.1:${port}/api/messages/${botId}`, null, botId);
|
initializeRoutes(server, Number(port), `http://127.0.0.1:${port}/api/messages/${botId}`, null, botId);
|
||||||
}
|
|
||||||
|
if (botId === 'default') {
|
||||||
|
initializeRoutes(server, Number(port), `http://127.0.0.1:${port}/api/messages`, null, botId);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const deleteStateForUser = (req: express.Request, res: express.Response) => {
|
const deleteStateForUser = (req: express.Request, res: express.Response) => {
|
||||||
Object.keys(botDataStore)
|
Object.keys(botDataStore).forEach(key => {
|
||||||
.forEach((key) => {
|
if (key.endsWith(`!{req.query.userId}`)) {
|
||||||
if (key.endsWith(`!{req.query.userId}`)) {
|
delete botDataStore[key];
|
||||||
delete botDataStore[key];
|
}
|
||||||
}
|
});
|
||||||
});
|
res.status(200).send();
|
||||||
res.status(200).send();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// CLIENT ENDPOINT HELPERS
|
// CLIENT ENDPOINT HELPERS
|
||||||
const createMessageActivity = (incomingActivity: IMessageActivity, serviceUrl: string, conversationId: string): IMessageActivity => {
|
const createMessageActivity = (
|
||||||
return { ...incomingActivity, channelId: 'emulator', serviceUrl, conversation: { id: conversationId }, id: uuidv4.v4() };
|
incomingActivity: IMessageActivity,
|
||||||
|
serviceUrl: string,
|
||||||
|
conversationId: string
|
||||||
|
): IMessageActivity => {
|
||||||
|
return {
|
||||||
|
...incomingActivity,
|
||||||
|
channelId: 'emulator',
|
||||||
|
serviceUrl,
|
||||||
|
conversation: { id: conversationId },
|
||||||
|
id: uuidv4.v4()
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const createConversationUpdateActivity = (serviceUrl: string, conversationId: string): IConversationUpdateActivity => {
|
const createConversationUpdateActivity = (serviceUrl: string, conversationId: string): IConversationUpdateActivity => {
|
||||||
const activity: IConversationUpdateActivity = {
|
const activity: IConversationUpdateActivity = {
|
||||||
type: 'conversationUpdate',
|
type: 'conversationUpdate',
|
||||||
channelId: 'emulator',
|
channelId: 'emulator',
|
||||||
serviceUrl,
|
serviceUrl,
|
||||||
conversation: { id: conversationId },
|
conversation: { id: conversationId },
|
||||||
id: uuidv4.v4(),
|
id: uuidv4.v4(),
|
||||||
membersAdded: [],
|
membersAdded: [],
|
||||||
membersRemoved: [],
|
membersRemoved: [],
|
||||||
from: { id: 'offline-directline', name: 'Offline Directline Server' },
|
from: { id: 'offline-directline', name: 'Offline Directline Server' }
|
||||||
};
|
};
|
||||||
return activity;
|
return activity;
|
||||||
};
|
};
|
||||||
|
|
||||||
const conversationsCleanup = () => {
|
const conversationsCleanup = () => {
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
const expiresTime = moment().subtract(expiresIn, 'seconds');
|
const expiresTime = moment().subtract(expiresIn, 'seconds');
|
||||||
Object.keys(conversations).forEach((conversationId) => {
|
Object.keys(conversations).forEach(conversationId => {
|
||||||
if (conversations[conversationId].history.length > 0) {
|
if (conversations[conversationId].history.length > 0) {
|
||||||
const lastTime = moment(conversations[conversationId].history[conversations[conversationId].history.length - 1].localTimestamp);
|
const lastTime = moment(
|
||||||
if (lastTime < expiresTime) {
|
conversations[conversationId].history[conversations[conversationId].history.length - 1].localTimestamp
|
||||||
delete conversations[conversationId];
|
);
|
||||||
console.log('deleted cId: ' + conversationId);
|
if (lastTime < expiresTime) {
|
||||||
}
|
delete conversations[conversationId];
|
||||||
}
|
console.log('deleted cId: ' + conversationId);
|
||||||
});
|
}
|
||||||
}, conversationsCleanupInterval);
|
}
|
||||||
|
});
|
||||||
|
}, conversationsCleanupInterval);
|
||||||
};
|
};
|
||||||
|
|
26
src/app.ts
26
src/app.ts
|
@ -122,10 +122,7 @@ export class GBServer {
|
||||||
});
|
});
|
||||||
|
|
||||||
process.on('uncaughtException', (err, p) => {
|
process.on('uncaughtException', (err, p) => {
|
||||||
GBLogEx.error(
|
GBLogEx.error(0, `GBEXCEPTION: ${GBUtil.toYAML(err)}`);
|
||||||
0,
|
|
||||||
`GBEXCEPTION: ${GBUtil.toYAML(err)}`
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
process.on('unhandledRejection', (err, p) => {
|
process.on('unhandledRejection', (err, p) => {
|
||||||
|
@ -138,10 +135,7 @@ export class GBServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bypass) {
|
if (!bypass) {
|
||||||
GBLogEx.error(
|
GBLogEx.error(0, `GBREJECTION: ${GBUtil.toYAML(err)}`);
|
||||||
0,
|
|
||||||
`GBREJECTION: ${GBUtil.toYAML(err)}`
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -186,7 +180,6 @@ export class GBServer {
|
||||||
|
|
||||||
// Creates a boot instance or load it from storage.
|
// Creates a boot instance or load it from storage.
|
||||||
|
|
||||||
|
|
||||||
if (GBConfigService.get('STORAGE_SERVER')) {
|
if (GBConfigService.get('STORAGE_SERVER')) {
|
||||||
azureDeployer = await AzureDeployerService.createInstance(deployer);
|
azureDeployer = await AzureDeployerService.createInstance(deployer);
|
||||||
await core.initStorage();
|
await core.initStorage();
|
||||||
|
@ -245,17 +238,20 @@ export class GBServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!GBConfigService.get('STORAGE_NAME')) {
|
const conversationalService: GBConversationalService = new GBConversationalService(core);
|
||||||
|
const adminService: GBAdminService = new GBAdminService(core);
|
||||||
|
const minService: GBMinService = new GBMinService(core, conversationalService, adminService, deployer);
|
||||||
|
GBServer.globals.minService = minService;
|
||||||
|
|
||||||
|
// Just sync if not using LOAD_ONLY.
|
||||||
|
|
||||||
|
if (!GBConfigService.get('STORAGE_NAME') && !process.env.LOAD_ONLY) {
|
||||||
await core['ensureFolders'](instances, deployer);
|
await core['ensureFolders'](instances, deployer);
|
||||||
}
|
}
|
||||||
GBServer.globals.bootInstance = instances[0];
|
GBServer.globals.bootInstance = instances[0];
|
||||||
|
|
||||||
// Builds minimal service infrastructure.
|
// Builds minimal service infrastructure.
|
||||||
|
|
||||||
const conversationalService: GBConversationalService = new GBConversationalService(core);
|
|
||||||
const adminService: GBAdminService = new GBAdminService(core);
|
|
||||||
const minService: GBMinService = new GBMinService(core, conversationalService, adminService, deployer);
|
|
||||||
GBServer.globals.minService = minService;
|
|
||||||
await minService.buildMin(instances);
|
await minService.buildMin(instances);
|
||||||
|
|
||||||
server.all('*', async (req, res, next) => {
|
server.all('*', async (req, res, next) => {
|
||||||
|
@ -291,6 +287,8 @@ export class GBServer {
|
||||||
|
|
||||||
GBLogEx.info(0, `The Bot Server is in RUNNING mode...`);
|
GBLogEx.info(0, `The Bot Server is in RUNNING mode...`);
|
||||||
|
|
||||||
|
await minService.startSimpleTest(GBServer.globals.minBoot);
|
||||||
|
|
||||||
// Opens Navigator.
|
// Opens Navigator.
|
||||||
|
|
||||||
if (process.env.DEV_OPEN_BROWSER) {
|
if (process.env.DEV_OPEN_BROWSER) {
|
||||||
|
|
|
@ -76,8 +76,8 @@ export class GBUtil {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (!GBConfigService.get('STORAGE_NAME')) {
|
if (!GBConfigService.get('STORAGE_NAME')) {
|
||||||
config['spec'].url = `http://127.0.0.1:${GBConfigService.getServerPort()}/api/messages`,
|
config['spec'].url = `http://127.0.0.1:${GBConfigService.getServerPort()}/api/messages/${min.botId}`,
|
||||||
config['spec'].servers = [{ url: `http://127.0.0.1:${GBConfigService.getServerPort()}/api/messages` }];
|
config['spec'].servers = [{ url: `http://127.0.0.1:${GBConfigService.getServerPort()}/api/messages/${min.botId}` }];
|
||||||
config['spec'].openapi = '3.0.0';
|
config['spec'].openapi = '3.0.0';
|
||||||
delete config['spec'].host;
|
delete config['spec'].host;
|
||||||
delete config['spec'].swagger;
|
delete config['spec'].swagger;
|
||||||
|
|
Loading…
Add table
Reference in a new issue