new(all): TRUE multicloud.
This commit is contained in:
parent
3299683268
commit
5880355349
14 changed files with 518 additions and 1358 deletions
File diff suppressed because one or more lines are too long
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"swagger": "2.0",
|
"openapi": "3.0.0",
|
||||||
"info": {
|
"info": {
|
||||||
"version": "v3",
|
"version": "v3",
|
||||||
"title": "Bot Connector - Direct Line API - v3.0",
|
"title": "Bot Connector - Direct Line API - v3.0",
|
||||||
|
@ -15,7 +15,7 @@
|
||||||
"url": "https://opensource.org/licenses/MIT"
|
"url": "https://opensource.org/licenses/MIT"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"host": "directline.botframework.com",
|
"servers": [{"url": "http://127.0.0.1:4242"}],
|
||||||
"schemes": [
|
"schemes": [
|
||||||
"https"
|
"https"
|
||||||
],
|
],
|
||||||
|
|
10
package.json
10
package.json
|
@ -76,7 +76,7 @@
|
||||||
"@azure/keyvault-keys": "4.8.0",
|
"@azure/keyvault-keys": "4.8.0",
|
||||||
"@azure/ms-rest-js": "2.7.0",
|
"@azure/ms-rest-js": "2.7.0",
|
||||||
"@azure/msal-node": "2.8.1",
|
"@azure/msal-node": "2.8.1",
|
||||||
"@azure/openai": "^2.0.0-beta.1",
|
"@azure/openai": "2.0.0-beta.1",
|
||||||
"@azure/search-documents": "12.0.0",
|
"@azure/search-documents": "12.0.0",
|
||||||
"@azure/storage-blob": "12.18.0",
|
"@azure/storage-blob": "12.18.0",
|
||||||
"@google-cloud/pubsub": "4.4.0",
|
"@google-cloud/pubsub": "4.4.0",
|
||||||
|
@ -137,11 +137,12 @@
|
||||||
"google-libphonenumber": "3.2.34",
|
"google-libphonenumber": "3.2.34",
|
||||||
"googleapis": "126.0.1",
|
"googleapis": "126.0.1",
|
||||||
"hnswlib-node": "3.0.0",
|
"hnswlib-node": "3.0.0",
|
||||||
"html-to-md": "^0.8.5",
|
"html-to-md": "0.8.5",
|
||||||
"http-proxy": "1.18.1",
|
"http-proxy": "1.18.1",
|
||||||
"ibm-watson": "9.1.0",
|
"ibm-watson": "9.1.0",
|
||||||
"instagram-private-api": "^1.46.1",
|
"instagram-private-api": "1.46.1",
|
||||||
"iso-639-1": "3.1.2",
|
"iso-639-1": "3.1.2",
|
||||||
|
"isomorphic-fetch": "3.0.0",
|
||||||
"join-images-updated": "1.1.11",
|
"join-images-updated": "1.1.11",
|
||||||
"js-md5": "0.8.3",
|
"js-md5": "0.8.3",
|
||||||
"json-schema-to-zod": "2.1.0",
|
"json-schema-to-zod": "2.1.0",
|
||||||
|
@ -210,7 +211,7 @@
|
||||||
"textract": "2.5.0",
|
"textract": "2.5.0",
|
||||||
"twilio": "5.1.0",
|
"twilio": "5.1.0",
|
||||||
"twitter-api-v2": "1.17.0",
|
"twitter-api-v2": "1.17.0",
|
||||||
"typeorm": "^0.3.20",
|
"typeorm": "0.3.20",
|
||||||
"typescript": "5.4.5",
|
"typescript": "5.4.5",
|
||||||
"url-join": "5.0.0",
|
"url-join": "5.0.0",
|
||||||
"vhost": "3.0.2",
|
"vhost": "3.0.2",
|
||||||
|
@ -218,6 +219,7 @@
|
||||||
"vm2-process": "2.1.5",
|
"vm2-process": "2.1.5",
|
||||||
"walk-promise": "0.2.0",
|
"walk-promise": "0.2.0",
|
||||||
"washyourmouthoutwithsoap": "1.0.2",
|
"washyourmouthoutwithsoap": "1.0.2",
|
||||||
|
"webdav-server": "2.6.2",
|
||||||
"whatsapp-cloud-api": "0.3.1",
|
"whatsapp-cloud-api": "0.3.1",
|
||||||
"whatsapp-web.js": "https://github.com/Julzk/whatsapp-web.js/tarball/jkr_hotfix_7",
|
"whatsapp-web.js": "https://github.com/Julzk/whatsapp-web.js/tarball/jkr_hotfix_7",
|
||||||
"winston": "3.13.0",
|
"winston": "3.13.0",
|
||||||
|
|
|
@ -37,6 +37,7 @@ import SwaggerClient from 'swagger-client';
|
||||||
import { spawn } from 'child_process';
|
import { spawn } from 'child_process';
|
||||||
import { CodeServices } from '../../gpt.gblib/services/CodeServices.js';
|
import { CodeServices } from '../../gpt.gblib/services/CodeServices.js';
|
||||||
import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js';
|
import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js';
|
||||||
|
import { GBUtil } from '../../../src/util.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Web Automation services of conversation to be called by BASIC.
|
* Web Automation services of conversation to be called by BASIC.
|
||||||
|
@ -154,12 +155,8 @@ export class DebuggerService {
|
||||||
|
|
||||||
let min: GBMinInstance = GBServer.globals.minInstances.filter(p => p.instance.botId === botId)[0];
|
let min: GBMinInstance = GBServer.globals.minInstances.filter(p => p.instance.botId === botId)[0];
|
||||||
|
|
||||||
const client = await new SwaggerClient({
|
const client = await GBUtil.getDirectLineClient(min);
|
||||||
spec: JSON.parse(Fs.readFileSync('directline-3.0.json', 'utf8')),
|
|
||||||
requestInterceptor: req => {
|
|
||||||
req.headers['Authorization'] = `Bearer ${min.instance.webchatKey}`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
GBServer.globals.debuggers[botId].client = client;
|
GBServer.globals.debuggers[botId].client = client;
|
||||||
const response = await client.apis.Conversations.Conversations_StartConversation();
|
const response = await client.apis.Conversations.Conversations_StartConversation();
|
||||||
const conversationId = response.obj.conversationId;
|
const conversationId = response.obj.conversationId;
|
||||||
|
|
|
@ -1348,12 +1348,7 @@ export class DialogKeywords {
|
||||||
|
|
||||||
const conversation = min['apiConversations'][pid];
|
const conversation = min['apiConversations'][pid];
|
||||||
|
|
||||||
const client = await new SwaggerClient({
|
const client = await GBUtil.getDirectLineClient(min);
|
||||||
spec: JSON.parse(Fs.readFileSync('directline-3.0.json', 'utf8')),
|
|
||||||
requestInterceptor: req => {
|
|
||||||
req.headers['Authorization'] = `Bearer ${min.instance.webchatKey}`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
conversation.client = client;
|
conversation.client = client;
|
||||||
const response = await client.apis.Conversations.Conversations_StartConversation();
|
const response = await client.apis.Conversations.Conversations_StartConversation();
|
||||||
conversation.conversationId = response.obj.conversationId;
|
conversation.conversationId = response.obj.conversationId;
|
||||||
|
|
|
@ -106,7 +106,7 @@ export class GBConfigService {
|
||||||
value = undefined;
|
value = undefined;
|
||||||
break;
|
break;
|
||||||
case 'STORAGE_FILE':
|
case 'STORAGE_FILE':
|
||||||
value = './guaribas.sqlite';
|
value = './data.db';
|
||||||
break;
|
break;
|
||||||
case 'GBKB_AUTO_DEPLOY':
|
case 'GBKB_AUTO_DEPLOY':
|
||||||
value = false;
|
value = false;
|
||||||
|
|
|
@ -42,6 +42,7 @@ import { FacebookAdapter } from 'botbuilder-adapter-facebook';
|
||||||
import mkdirp from 'mkdirp';
|
import mkdirp from 'mkdirp';
|
||||||
import Fs from 'fs';
|
import Fs from 'fs';
|
||||||
import arrayBufferToBuffer from 'arraybuffer-to-buffer';
|
import arrayBufferToBuffer from 'arraybuffer-to-buffer';
|
||||||
|
import { v2 as webdav } from 'webdav-server';
|
||||||
import { NlpManager } from 'node-nlp';
|
import { NlpManager } from 'node-nlp';
|
||||||
import Koa from 'koa';
|
import Koa from 'koa';
|
||||||
import { createRpcServer } from '@push-rpc/core';
|
import { createRpcServer } from '@push-rpc/core';
|
||||||
|
@ -253,6 +254,8 @@ export class GBMinService {
|
||||||
GBServer.globals.minInstances.push(min);
|
GBServer.globals.minInstances.push(min);
|
||||||
const user = null; // No user context.
|
const user = null; // No user context.
|
||||||
|
|
||||||
|
// Serves individual URL for each bot conversational interface.
|
||||||
|
|
||||||
await this.deployer['deployPackage2'](min, user, 'packages/default.gbtheme');
|
await this.deployer['deployPackage2'](min, user, 'packages/default.gbtheme');
|
||||||
|
|
||||||
// Install per bot deployed packages.
|
// Install per bot deployed packages.
|
||||||
|
@ -314,6 +317,14 @@ export class GBMinService {
|
||||||
mkdirp.sync(dir);
|
mkdirp.sync(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dir = Path.join(process.env.PWD, 'work', gbai);
|
||||||
|
|
||||||
|
const server = new webdav.WebDAVServer();
|
||||||
|
server.setFileSystem(`/${botId}`,
|
||||||
|
new webdav.PhysicalFileSystem(dir), (success) => {
|
||||||
|
server.start(() => console.log('WEBDAV READY'));
|
||||||
|
})
|
||||||
|
|
||||||
// Loads Named Entity data for this bot.
|
// Loads Named Entity data for this bot.
|
||||||
|
|
||||||
// TODO: await KBService.RefreshNER(min);
|
// TODO: await KBService.RefreshNER(min);
|
||||||
|
@ -321,16 +332,11 @@ export class GBMinService {
|
||||||
// Calls the loadBot context.activity for all packages.
|
// Calls the loadBot context.activity for all packages.
|
||||||
|
|
||||||
await this.invokeLoadBot(min.appPackages, GBServer.globals.sysPackages, min);
|
await this.invokeLoadBot(min.appPackages, GBServer.globals.sysPackages, min);
|
||||||
|
|
||||||
// Serves individual URL for each bot conversational interface.
|
|
||||||
|
|
||||||
const receiver = async (req, res) => {
|
const receiver = async (req, res) => {
|
||||||
await this.receiver(req, res, conversationState, min, instance, GBServer.globals.appPackages);
|
await this.receiver(req, res, conversationState, min, instance, GBServer.globals.appPackages);
|
||||||
};
|
};
|
||||||
let url = `/api/messages/${instance.botId}`;
|
let url = `/api/messages/${instance.botId}`;
|
||||||
GBServer.globals.server.post(url, receiver);
|
|
||||||
url = `/api/messages`;
|
|
||||||
GBServer.globals.server.post(url, receiver);
|
|
||||||
GBServer.globals.server.get(url, (req, res) => {
|
GBServer.globals.server.get(url, (req, res) => {
|
||||||
if (req.query['hub.mode'] === 'subscribe') {
|
if (req.query['hub.mode'] === 'subscribe') {
|
||||||
if (req.query['hub.verify_token'] === process.env.FACEBOOK_VERIFY_TOKEN) {
|
if (req.query['hub.verify_token'] === process.env.FACEBOOK_VERIFY_TOKEN) {
|
||||||
|
@ -349,12 +355,7 @@ export class GBMinService {
|
||||||
if (process.env.TEST_MESSAGE) {
|
if (process.env.TEST_MESSAGE) {
|
||||||
GBLogEx.info(min, `Starting auto test with '${process.env.TEST_MESSAGE}'.`);
|
GBLogEx.info(min, `Starting auto test with '${process.env.TEST_MESSAGE}'.`);
|
||||||
|
|
||||||
const client = await new SwaggerClient({
|
const client = await GBUtil.getDirectLineClient(min);
|
||||||
spec: JSON.parse(Fs.readFileSync('directline-3.0.json', 'utf8')),
|
|
||||||
requestInterceptor: req => {
|
|
||||||
req.headers['Authorization'] = `Bearer ${min.instance.webchatKey}`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await client.apis.Conversations.Conversations_StartConversation();
|
const response = await client.apis.Conversations.Conversations_StartConversation();
|
||||||
const conversationId = response.obj.conversationId;
|
const conversationId = response.obj.conversationId;
|
||||||
|
@ -450,7 +451,9 @@ export class GBMinService {
|
||||||
whatsAppDirectLine = WhatsappDirectLine.botsByNumber[to];
|
whatsAppDirectLine = WhatsappDirectLine.botsByNumber[to];
|
||||||
}
|
}
|
||||||
|
|
||||||
await whatsAppDirectLine.WhatsAppCallback(req, res, whatsAppDirectLine.botId);
|
if (whatsAppDirectLine) {
|
||||||
|
await whatsAppDirectLine.WhatsAppCallback(req, res, whatsAppDirectLine.botId);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.bind(min);
|
.bind(min);
|
||||||
|
|
||||||
|
@ -672,27 +675,31 @@ export class GBMinService {
|
||||||
theme = `default.gbtheme`;
|
theme = `default.gbtheme`;
|
||||||
}
|
}
|
||||||
|
|
||||||
res.send(
|
let config = {
|
||||||
JSON.stringify({
|
instanceId: instance.instanceId,
|
||||||
instanceId: instance.instanceId,
|
botId: botId,
|
||||||
botId: botId,
|
theme: theme,
|
||||||
theme: theme,
|
speechToken: speechToken,
|
||||||
//webchatToken: webchatTokenContainer.token,
|
conversationId: webchatTokenContainer.conversationId,
|
||||||
domain: 'http://localhost:3978/directline',
|
authenticatorTenant: instance.authenticatorTenant,
|
||||||
speechToken: speechToken,
|
authenticatorClientId: instance.marketplaceId,
|
||||||
conversationId: webchatTokenContainer.conversationId,
|
paramLogoImageUrl: this.core.getParam(instance, 'Logo Image Url', null),
|
||||||
authenticatorTenant: instance.authenticatorTenant,
|
paramLogoImageAlt: this.core.getParam(instance, 'Logo Image Alt', null),
|
||||||
authenticatorClientId: instance.marketplaceId,
|
paramLogoImageWidth: this.core.getParam(instance, 'Logo Image Width', null),
|
||||||
paramLogoImageUrl: this.core.getParam(instance, 'Logo Image Url', null),
|
paramLogoImageHeight: this.core.getParam(instance, 'Logo Image Height', null),
|
||||||
paramLogoImageAlt: this.core.getParam(instance, 'Logo Image Alt', null),
|
paramLogoImageType: this.core.getParam(instance, 'Logo Image Type', null),
|
||||||
paramLogoImageWidth: this.core.getParam(instance, 'Logo Image Width', null),
|
logo: this.core.getParam(instance, 'Logo', null),
|
||||||
paramLogoImageHeight: this.core.getParam(instance, 'Logo Image Height', null),
|
color1: this.core.getParam(instance, 'Color1', null),
|
||||||
paramLogoImageType: this.core.getParam(instance, 'Logo Image Type', null),
|
color2: this.core.getParam(instance, 'Color2', null)
|
||||||
logo: this.core.getParam(instance, 'Logo', null),
|
};
|
||||||
color1: this.core.getParam(instance, 'Color1', null),
|
|
||||||
color2: this.core.getParam(instance, 'Color2', null)
|
if (process.env.STORAGE_FILE) {
|
||||||
})
|
config['domain'] = `http://localhost:${process.env.PORT}/directline`;
|
||||||
);
|
} else {
|
||||||
|
config['webchatToken'] = webchatTokenContainer.token;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.send(JSON.stringify(config));
|
||||||
} else {
|
} else {
|
||||||
const error = `Instance not found while retrieving from .gbui web client: ${botId}.`;
|
const error = `Instance not found while retrieving from .gbui web client: ${botId}.`;
|
||||||
res.sendStatus(error);
|
res.sendStatus(error);
|
||||||
|
@ -749,15 +756,18 @@ export class GBMinService {
|
||||||
*/
|
*/
|
||||||
private async buildBotAdapter(instance: any, sysPackages: IGBPackage[], appPackages: IGBPackage[]) {
|
private async buildBotAdapter(instance: any, sysPackages: IGBPackage[], appPackages: IGBPackage[]) {
|
||||||
// MSFT stuff.
|
// MSFT stuff.
|
||||||
const uri = 'http://localhost:3978';
|
|
||||||
|
|
||||||
const adapter = new BotFrameworkAdapter({
|
let config = {
|
||||||
clientOptions: { baseUri: uri },
|
|
||||||
appId: instance.marketplaceId ? instance.marketplaceId : GBConfigService.get('MARKETPLACE_ID'),
|
appId: instance.marketplaceId ? instance.marketplaceId : GBConfigService.get('MARKETPLACE_ID'),
|
||||||
appPassword: instance.marketplacePassword
|
appPassword: instance.marketplacePassword
|
||||||
? instance.marketplacePassword
|
? instance.marketplacePassword
|
||||||
: GBConfigService.get('MARKETPLACE_SECRET')
|
: GBConfigService.get('MARKETPLACE_SECRET')
|
||||||
});
|
};
|
||||||
|
if (process.env.STORAGE_FILE) {
|
||||||
|
config['clientOptions'] = { baseUri: `http://localhost:${process.env.PORT}` };
|
||||||
|
}
|
||||||
|
|
||||||
|
const adapter = new BotFrameworkAdapter(config);
|
||||||
const storage = new MemoryStorage();
|
const storage = new MemoryStorage();
|
||||||
const conversationState = new ConversationState(storage);
|
const conversationState = new ConversationState(storage);
|
||||||
const userState = new UserState(storage);
|
const userState = new UserState(storage);
|
||||||
|
@ -770,6 +780,28 @@ export class GBMinService {
|
||||||
// The minimal bot is built here.
|
// The minimal bot is built here.
|
||||||
|
|
||||||
const min = new GBMinInstance();
|
const min = new GBMinInstance();
|
||||||
|
|
||||||
|
// Setups default BOT Framework dialogs.
|
||||||
|
|
||||||
|
min.userProfile = conversationState.createProperty('userProfile');
|
||||||
|
const dialogState = conversationState.createProperty('dialogState');
|
||||||
|
|
||||||
|
min.dialogs = new DialogSet(dialogState);
|
||||||
|
min.dialogs.add(new TextPrompt('textPrompt'));
|
||||||
|
min.dialogs.add(new AttachmentPrompt('attachmentPrompt'));
|
||||||
|
|
||||||
|
min.dialogs.add(new ConfirmPrompt('confirmPrompt'));
|
||||||
|
if (process.env.ENABLE_AUTH) {
|
||||||
|
min.dialogs.add(
|
||||||
|
new OAuthPrompt('oAuthPrompt', {
|
||||||
|
connectionName: 'OAuth2',
|
||||||
|
text: 'Please sign in to General Bots.',
|
||||||
|
title: 'Sign in',
|
||||||
|
timeout: 300000
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
min.botId = instance.botId;
|
min.botId = instance.botId;
|
||||||
min.bot = adapter;
|
min.bot = adapter;
|
||||||
min.userState = userState;
|
min.userState = userState;
|
||||||
|
@ -792,6 +824,15 @@ export class GBMinService {
|
||||||
min['apiConversations'] = {};
|
min['apiConversations'] = {};
|
||||||
min.packages = sysPackages;
|
min.packages = sysPackages;
|
||||||
|
|
||||||
|
const receiver = async (req, res) => {
|
||||||
|
await this.receiver(req, res, conversationState, min, instance, GBServer.globals.appPackages);
|
||||||
|
};
|
||||||
|
|
||||||
|
let url = `/api/messages/${instance.botId}`;
|
||||||
|
GBServer.globals.server.post(url, receiver);
|
||||||
|
url = `/api/messages`;
|
||||||
|
GBServer.globals.server.post(url, receiver);
|
||||||
|
|
||||||
// NLP Manager.
|
// NLP Manager.
|
||||||
|
|
||||||
const manager = new NlpManager({ languages: ['pt'], forceNER: true });
|
const manager = new NlpManager({ languages: ['pt'], forceNER: true });
|
||||||
|
@ -879,26 +920,6 @@ export class GBMinService {
|
||||||
WhatsappDirectLine.botsByNumber[botNumber] = min.whatsAppDirectLine;
|
WhatsappDirectLine.botsByNumber[botNumber] = min.whatsAppDirectLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setups default BOT Framework dialogs.
|
|
||||||
|
|
||||||
min.userProfile = conversationState.createProperty('userProfile');
|
|
||||||
const dialogState = conversationState.createProperty('dialogState');
|
|
||||||
|
|
||||||
min.dialogs = new DialogSet(dialogState);
|
|
||||||
min.dialogs.add(new TextPrompt('textPrompt'));
|
|
||||||
min.dialogs.add(new AttachmentPrompt('attachmentPrompt'));
|
|
||||||
|
|
||||||
min.dialogs.add(new ConfirmPrompt('confirmPrompt'));
|
|
||||||
if (process.env.ENABLE_AUTH) {
|
|
||||||
min.dialogs.add(
|
|
||||||
new OAuthPrompt('oAuthPrompt', {
|
|
||||||
connectionName: 'OAuth2',
|
|
||||||
text: 'Please sign in to General Bots.',
|
|
||||||
title: 'Sign in',
|
|
||||||
timeout: 300000
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return { min, adapter, conversationState };
|
return { min, adapter, conversationState };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1376,7 +1397,7 @@ export class GBMinService {
|
||||||
context.activity.text = context.activity.text.trim();
|
context.activity.text = context.activity.text.trim();
|
||||||
|
|
||||||
const member = context.activity.from;
|
const member = context.activity.from;
|
||||||
let memberId, email;
|
let memberId = null, email = null;
|
||||||
|
|
||||||
// Processes e-mail from id in case of Teams messages.
|
// Processes e-mail from id in case of Teams messages.
|
||||||
|
|
||||||
|
@ -1648,12 +1669,7 @@ export class GBMinService {
|
||||||
if (script === 'start') {
|
if (script === 'start') {
|
||||||
pid = GBVMService.createProcessInfo(user, min, 'api', null);
|
pid = GBVMService.createProcessInfo(user, min, 'api', null);
|
||||||
|
|
||||||
const client = await new SwaggerClient({
|
const client = await GBUtil.getDirectLineClient(min);
|
||||||
spec: JSON.parse(Fs.readFileSync('directline-3.0.json', 'utf8')),
|
|
||||||
requestInterceptor: req => {
|
|
||||||
req.headers['Authorization'] = `Bearer ${min.instance.webchatKey}`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const response = await client.apis.Conversations.Conversations_StartConversation();
|
const response = await client.apis.Conversations.Conversations_StartConversation();
|
||||||
|
|
||||||
min['apiConversations'][pid] = { conversation: response.obj, client: client };
|
min['apiConversations'][pid] = { conversation: response.obj, client: client };
|
||||||
|
|
322
packages/core.gbapp/services/router/bridge.ts
Normal file
322
packages/core.gbapp/services/router/bridge.ts
Normal file
|
@ -0,0 +1,322 @@
|
||||||
|
import bodyParser from 'body-parser';
|
||||||
|
import express from 'express';
|
||||||
|
import fetch from 'isomorphic-fetch';
|
||||||
|
import moment from 'moment';
|
||||||
|
import * as uuidv4 from 'uuid';
|
||||||
|
|
||||||
|
import { IActivity, IBotData, IConversation, IConversationUpdateActivity, IMessageActivity } from './types';
|
||||||
|
|
||||||
|
const expiresIn = 1800;
|
||||||
|
const conversationsCleanupInterval = 10000;
|
||||||
|
const conversations: { [key: string]: IConversation } = {};
|
||||||
|
const botDataStore: { [key: string]: IBotData } = {};
|
||||||
|
|
||||||
|
export const getRouter = (serviceUrl: string, botUrl: string, conversationInitRequired = true): express.Router => {
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
router.use(bodyParser.json()); // for parsing application/json
|
||||||
|
router.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded
|
||||||
|
router.use((req, res, next) => {
|
||||||
|
res.header('Access-Control-Allow-Origin', '*');
|
||||||
|
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');
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
// CLIENT ENDPOINT
|
||||||
|
router.options('/directline', (req, res) => {
|
||||||
|
res.status(200).end();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Creates a conversation
|
||||||
|
const reqs = (req, res) => {
|
||||||
|
|
||||||
|
const conversationId: string = uuidv4.v4().toString();
|
||||||
|
conversations[conversationId] = {
|
||||||
|
conversationId,
|
||||||
|
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,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
router.post('/v3/directline/conversations',reqs );
|
||||||
|
router.post('/directline/conversations',reqs );
|
||||||
|
|
||||||
|
// Reconnect API
|
||||||
|
router.get('/v3/directline/conversations/:conversationId', (req, res) => {
|
||||||
|
const conversation = getConversation(req.params.conversationId, conversationInitRequired);
|
||||||
|
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/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/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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
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'); });
|
||||||
|
|
||||||
|
// BOT CONVERSATION ENDPOINT
|
||||||
|
|
||||||
|
router.post('/v3/conversations', (req, res) => { console.warn('/v3/conversations not implemented'); });
|
||||||
|
|
||||||
|
router.post('/v3/conversations/:conversationId/activities', (req, res) => {
|
||||||
|
let activity: IActivity;
|
||||||
|
|
||||||
|
activity = req.body;
|
||||||
|
activity.id = uuidv4.v4();
|
||||||
|
activity.from = { id: 'id', name: 'Bot' };
|
||||||
|
|
||||||
|
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/:conversationId/activities/:activityId', (req, res) => {
|
||||||
|
let activity: IActivity;
|
||||||
|
|
||||||
|
activity = req.body;
|
||||||
|
activity.id = uuidv4.v4();
|
||||||
|
activity.from = { id: 'id', name: 'Bot' };
|
||||||
|
|
||||||
|
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.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'); });
|
||||||
|
|
||||||
|
// BOTSTATE ENDPOINT
|
||||||
|
|
||||||
|
router.get('/v3/botstate/:channelId/users/:userId', (req, res) => {
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param app The express app where your offline-directline endpoint will live
|
||||||
|
* @param port The port where your offline-directline will be hosted
|
||||||
|
* @param botUrl The url of the bot (e.g. http://127.0.0.1:3978/api/messages)
|
||||||
|
* @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) => {
|
||||||
|
conversationsCleanup();
|
||||||
|
|
||||||
|
const directLineEndpoint = `http://127.0.0.1:${port}`;
|
||||||
|
const router = getRouter(directLineEndpoint, botUrl, conversationInitRequired);
|
||||||
|
|
||||||
|
app.use(router);
|
||||||
|
console.log(`Routing messages to bot on ${botUrl}`);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const getConversation = (conversationId: string, conversationInitRequired: boolean) => {
|
||||||
|
|
||||||
|
// Create conversation on the fly when needed and init not required
|
||||||
|
if (!conversations[conversationId] && !conversationInitRequired) {
|
||||||
|
conversations[conversationId] = {
|
||||||
|
conversationId,
|
||||||
|
history: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return conversations[conversationId];
|
||||||
|
};
|
||||||
|
|
||||||
|
const getBotDataKey = (channelId: string, conversationId: string, userId: string) => {
|
||||||
|
return `$${channelId || '*'}!${conversationId || '*'}!${userId || '*'}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const setBotData = (channelId: string, conversationId: string, userId: string, incomingData: IBotData): IBotData => {
|
||||||
|
const key = getBotDataKey(channelId, conversationId, userId);
|
||||||
|
const newData: IBotData = {
|
||||||
|
eTag: new Date().getTime().toString(),
|
||||||
|
data: incomingData.data,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (incomingData) {
|
||||||
|
botDataStore[key] = newData;
|
||||||
|
} else {
|
||||||
|
delete botDataStore[key];
|
||||||
|
newData.eTag = '*';
|
||||||
|
}
|
||||||
|
|
||||||
|
return newData;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getBotData = (req: express.Request, res: express.Response) => {
|
||||||
|
const key = getBotDataKey(req.params.channelId, req.params.conversationId, req.params.userId);
|
||||||
|
console.log('Data key: ' + key);
|
||||||
|
|
||||||
|
res.status(200).send(botDataStore[key] || { data: null, eTag: '*' });
|
||||||
|
};
|
||||||
|
|
||||||
|
const setUserData = (req: express.Request, res: express.Response) => {
|
||||||
|
res.status(200).send(setBotData(req.params.channelId, req.params.conversationId, req.params.userId, req.body));
|
||||||
|
};
|
||||||
|
|
||||||
|
const setConversationData = (req: express.Request, res: express.Response) => {
|
||||||
|
res.status(200).send(setBotData(req.params.channelId, req.params.conversationId, req.params.userId, req.body));
|
||||||
|
};
|
||||||
|
|
||||||
|
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)=>{
|
||||||
|
|
||||||
|
initializeRoutes(server, Number(process.env.PORT), `http://127.0.0.1:${process.env.PORT}/api/messages`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteStateForUser = (req: express.Request, res: express.Response) => {
|
||||||
|
Object.keys(botDataStore)
|
||||||
|
.forEach((key) => {
|
||||||
|
if (key.endsWith(`!{req.query.userId}`)) {
|
||||||
|
delete botDataStore[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
res.status(200).send();
|
||||||
|
};
|
||||||
|
|
||||||
|
// CLIENT ENDPOINT HELPERS
|
||||||
|
const createMessageActivity = (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 activity: IConversationUpdateActivity = {
|
||||||
|
type: 'conversationUpdate',
|
||||||
|
channelId: 'emulator',
|
||||||
|
serviceUrl,
|
||||||
|
conversation: { id: conversationId },
|
||||||
|
id: uuidv4.v4(),
|
||||||
|
membersAdded: [],
|
||||||
|
membersRemoved: [],
|
||||||
|
from: { id: 'offline-directline', name: 'Offline Directline Server' },
|
||||||
|
};
|
||||||
|
return activity;
|
||||||
|
};
|
||||||
|
|
||||||
|
const conversationsCleanup = () => {
|
||||||
|
setInterval(() => {
|
||||||
|
const expiresTime = moment().subtract(expiresIn, 'seconds');
|
||||||
|
Object.keys(conversations).forEach((conversationId) => {
|
||||||
|
if (conversations[conversationId].history.length > 0) {
|
||||||
|
const lastTime = moment(conversations[conversationId].history[conversations[conversationId].history.length - 1].localTimestamp);
|
||||||
|
if (lastTime < expiresTime) {
|
||||||
|
delete conversations[conversationId];
|
||||||
|
console.log('deleted cId: ' + conversationId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, conversationsCleanupInterval);
|
||||||
|
};
|
66
packages/core.gbapp/services/router/types.ts
Normal file
66
packages/core.gbapp/services/router/types.ts
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
export interface IUser {
|
||||||
|
id: string,
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IChannelAccount {
|
||||||
|
id?: string,
|
||||||
|
name?: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IConversationAccount extends IChannelAccount {
|
||||||
|
isGroup?: boolean,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IAttachment {
|
||||||
|
contentType?: string,
|
||||||
|
contentUrl?: string,
|
||||||
|
content?: any,
|
||||||
|
name?: string,
|
||||||
|
thumbnailUrl?: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IEntity {
|
||||||
|
type?: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IActivity {
|
||||||
|
type?: string,
|
||||||
|
id?: string,
|
||||||
|
serviceUrl?: string,
|
||||||
|
timestamp?: string,
|
||||||
|
localTimestamp?: string,
|
||||||
|
channelId?: string,
|
||||||
|
from?: IChannelAccount,
|
||||||
|
conversation?: IConversationAccount,
|
||||||
|
recipient?: IChannelAccount,
|
||||||
|
replyToId?: string,
|
||||||
|
channelData?: any,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IMessageActivity extends IActivity {
|
||||||
|
locale?: string,
|
||||||
|
text?: string,
|
||||||
|
summary?: string,
|
||||||
|
textFormat?: string,
|
||||||
|
attachmentLayout?: string,
|
||||||
|
attachments?: IAttachment[],
|
||||||
|
entities?: IEntity[],
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IBotData {
|
||||||
|
eTag: string;
|
||||||
|
data: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IConversation {
|
||||||
|
conversationId: string,
|
||||||
|
history?: IActivity[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IConversationUpdateActivity extends IActivity {
|
||||||
|
membersAdded?: IChannelAccount[],
|
||||||
|
membersRemoved?: IChannelAccount[],
|
||||||
|
topicName?: string,
|
||||||
|
historyDisclosed?: boolean,
|
||||||
|
}
|
|
@ -36,6 +36,7 @@ import { GBLog, GBMinInstance, GBService } from 'botlib';
|
||||||
import { GBServer } from '../../../src/app.js';
|
import { GBServer } from '../../../src/app.js';
|
||||||
import { SecService } from '../../security.gbapp/services/SecService.js';
|
import { SecService } from '../../security.gbapp/services/SecService.js';
|
||||||
import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js';
|
import { GBLogEx } from '../../core.gbapp/services/GBLogEx.js';
|
||||||
|
import { GBUtil } from '../../../src/util.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Support for Google Chat.
|
* Support for Google Chat.
|
||||||
|
@ -90,10 +91,7 @@ export class GoogleChatDirectLine extends GBService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async setup (setUrl) {
|
public async setup (setUrl) {
|
||||||
this.directLineClient = new Swagger({
|
this.directLineClient = await GBUtil.getDirectLineClient(this.min);
|
||||||
spec: JSON.parse(Fs.readFileSync('directline-3.0.json', 'utf8')),
|
|
||||||
usePromise: true
|
|
||||||
});
|
|
||||||
const client = await this.directLineClient;
|
const client = await this.directLineClient;
|
||||||
|
|
||||||
client.clientAuthorizations.add(
|
client.clientAuthorizations.add(
|
||||||
|
|
|
@ -54,8 +54,10 @@ export class SecService extends GBService {
|
||||||
user.email = email;
|
user.email = email;
|
||||||
user.defaultChannel = channelName;
|
user.defaultChannel = channelName;
|
||||||
GBServer.globals.users [user.userId] = user;
|
GBServer.globals.users [user.userId] = user;
|
||||||
|
if(user.changed()){
|
||||||
return await user.save();
|
await user.save();
|
||||||
|
}
|
||||||
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -30,7 +30,6 @@
|
||||||
|
|
||||||
import mime from 'mime-types';
|
import mime from 'mime-types';
|
||||||
import urlJoin from 'url-join';
|
import urlJoin from 'url-join';
|
||||||
import SwaggerClient from 'swagger-client';
|
|
||||||
import Path from 'path';
|
import Path from 'path';
|
||||||
import Fs from 'fs';
|
import Fs from 'fs';
|
||||||
import { GBLog, GBMinInstance, GBService, IGBPackage } from 'botlib';
|
import { GBLog, GBMinInstance, GBService, IGBPackage } from 'botlib';
|
||||||
|
@ -46,7 +45,7 @@ import qrcode from 'qrcode-terminal';
|
||||||
import express from 'express';
|
import express from 'express';
|
||||||
import { GBSSR } from '../../core.gbapp/services/GBSSR.js';
|
import { GBSSR } from '../../core.gbapp/services/GBSSR.js';
|
||||||
import pkg from 'whatsapp-web.js';
|
import pkg from 'whatsapp-web.js';
|
||||||
import fetch, { Response } from 'node-fetch';
|
import fetch from 'node-fetch';
|
||||||
import { DialogKeywords } from '../../basic.gblib/services/DialogKeywords.js';
|
import { DialogKeywords } from '../../basic.gblib/services/DialogKeywords.js';
|
||||||
import { ChatServices } from '../../gpt.gblib/services/ChatServices.js';
|
import { ChatServices } from '../../gpt.gblib/services/ChatServices.js';
|
||||||
import { GBAdminService } from '../../admin.gbapp/services/GBAdminService.js';
|
import { GBAdminService } from '../../admin.gbapp/services/GBAdminService.js';
|
||||||
|
@ -117,19 +116,8 @@ export class WhatsappDirectLine extends GBService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async setup(setUrl: boolean) {
|
public async setup(setUrl: boolean) {
|
||||||
const client = await new SwaggerClient({
|
|
||||||
url: 'http://127.0.0.1:3978/api/messages', // TODO:
|
|
||||||
spec: JSON.parse(Fs.readFileSync('directline-3.0.json', 'utf8')),
|
|
||||||
requestInterceptor: req => {
|
|
||||||
req.headers['Authorization'] = `Bearer ${this.min.instance.webchatKey}`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.directLineClient = client;
|
this.directLineClient = GBUtil.getDirectLineClient(this.min);
|
||||||
|
|
||||||
// Warms up MSBF.
|
|
||||||
|
|
||||||
await client.apis.Conversations.Conversations_StartConversation();
|
|
||||||
|
|
||||||
let url: string;
|
let url: string;
|
||||||
let options: any;
|
let options: any;
|
||||||
|
|
10
src/app.ts
10
src/app.ts
|
@ -40,6 +40,8 @@ import bodyParser from 'body-parser';
|
||||||
import { GBLog, GBMinInstance, IGBCoreService, IGBInstance } from 'botlib';
|
import { GBLog, GBMinInstance, IGBCoreService, IGBInstance } from 'botlib';
|
||||||
import child_process from 'child_process';
|
import child_process from 'child_process';
|
||||||
import express from 'express';
|
import express from 'express';
|
||||||
|
import {start as startRouter} from '../packages/core.gbapp/services/router/bridge.js'
|
||||||
|
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import http from 'http';
|
import http from 'http';
|
||||||
import httpProxy from 'http-proxy';
|
import httpProxy from 'http-proxy';
|
||||||
|
@ -87,8 +89,9 @@ export class GBServer {
|
||||||
|
|
||||||
const server = express();
|
const server = express();
|
||||||
this.initEndpointsDocs(server);
|
this.initEndpointsDocs(server);
|
||||||
|
startRouter(server);
|
||||||
GBServer.globals.server = server;
|
GBServer.globals.server = server;
|
||||||
|
|
||||||
GBServer.globals.httpsServer = null;
|
GBServer.globals.httpsServer = null;
|
||||||
GBServer.globals.webSessions = {};
|
GBServer.globals.webSessions = {};
|
||||||
GBServer.globals.processes = {};
|
GBServer.globals.processes = {};
|
||||||
|
@ -118,7 +121,7 @@ export class GBServer {
|
||||||
});
|
});
|
||||||
|
|
||||||
process.on('uncaughtException', (err, p) => {
|
process.on('uncaughtException', (err, p) => {
|
||||||
GBLogEx.error(0, `GBEXCEPTION: ${GBUtil.toYAML(err)} ${GBUtil.toYAML(p)}`);
|
GBLogEx.error(0, `GBEXCEPTION: ${GBUtil.toYAML(JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))))}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
process.on('unhandledRejection', (err, p) => {
|
process.on('unhandledRejection', (err, p) => {
|
||||||
|
@ -131,7 +134,7 @@ export class GBServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bypass) {
|
if (!bypass) {
|
||||||
GBLogEx.error(0, `GBREJECTION: ${GBUtil.toYAML(err)} ${GBUtil.toYAML(p)}`);
|
GBLogEx.error(0,`GBREJECTION: ${GBUtil.toYAML(JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))))}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -147,6 +150,7 @@ export class GBServer {
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
GBLogEx.info(0, `Now accepting connections on ${port}...`);
|
GBLogEx.info(0, `Now accepting connections on ${port}...`);
|
||||||
|
|
||||||
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
|
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
|
||||||
|
|
||||||
// Reads basic configuration, initialize minimal services.
|
// Reads basic configuration, initialize minimal services.
|
||||||
|
|
18
src/util.ts
18
src/util.ts
|
@ -34,6 +34,8 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
import * as YAML from 'yaml';
|
import * as YAML from 'yaml';
|
||||||
|
import SwaggerClient from 'swagger-client';
|
||||||
|
import Fs from 'fs';
|
||||||
|
|
||||||
export class GBUtil {
|
export class GBUtil {
|
||||||
public static repeat(chr, count) {
|
public static repeat(chr, count) {
|
||||||
|
@ -64,6 +66,22 @@ export class GBUtil {
|
||||||
return (value + GBUtil.repeat(pad, length)).substr(0, width);
|
return (value + GBUtil.repeat(pad, length)).substr(0, width);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async getDirectLineClient(min) {
|
||||||
|
|
||||||
|
let config = {
|
||||||
|
url: `http://127.0.0.1:${process.env.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` }];
|
||||||
|
config['openapi'] = '3.0.0';
|
||||||
|
}
|
||||||
|
return await new SwaggerClient(config);
|
||||||
|
}
|
||||||
|
|
||||||
public static toYAML(json) {
|
public static toYAML(json) {
|
||||||
const doc = new YAML.Document();
|
const doc = new YAML.Document();
|
||||||
doc.contents = json;
|
doc.contents = json;
|
||||||
|
|
Loading…
Add table
Reference in a new issue