lexica-dialog-core
Version:
Core server for Lexica dialog agent.
221 lines • 9.89 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const immutable_1 = require("immutable");
const Koa = require("koa");
const BodyParser = require("koa-bodyparser");
const Router = require("koa-router");
const mongoose = require("mongoose");
const AWS = require("aws-sdk");
const winston = require("winston");
const lodash_1 = require("lodash");
const redis_1 = require("redis");
const lexica_dialog_repository_1 = require("lexica-dialog-repository");
const middlewares = require("./middlewares");
const executors = require("./executors");
const preProcessors = require("./pre-processors");
const postProcessors = require("./post-processors");
const nlp_1 = require("./nlp");
const session_1 = require("./session");
const aws_1 = require("./aws");
class BotServer {
constructor(config) {
this.server = new Koa();
this.router = new Router();
this.config = config;
this.messengers = config.messengers;
this.middlewares = this.createDefaultMiddlewares().merge(config.middlewares);
this.preProcessors = this.createDefaultPreProcessor().merge(config.preProcessors);
this.postProcessors = this.createDefaultPostProcessor().merge(config.postProcessors);
this.executors = this.createDefaultExecutor().merge(config.executors);
}
init() {
const { mongo, redis } = this.config;
mongoose.connect(mongo.url, Object.assign({}, mongo.options));
mongoose.Promise = global.Promise;
this.mongoConnection = mongoose.connection;
const redisConfig = Object.assign({}, redis.options);
if (redis.url.trim()) {
redisConfig.url = redis.url;
}
else {
redisConfig.host = redis.host;
redisConfig.port = redis.port;
}
this.redisClient = redis_1.createClient(redisConfig);
AWS.config.update({
accessKeyId: this.config.aws.accessKeyId,
region: this.config.aws.region,
secretAccessKey: this.config.aws.secretAccessKey,
});
AWS.config.setPromisesDependency(Promise);
if (lodash_1.isNil(this.config.nlpService) && lodash_1.isNil(this.config.nlp)) {
this.nlpService = new nlp_1.DefaultNlpService();
}
else if (this.config.nlp) {
this.nlpService = new nlp_1.ExternalNlpService(this.config.nlp.url);
}
else if (this.config.nlpService) {
this.nlpService = this.config.nlpService;
}
else {
throw new Error('Unknown NLP error.');
}
if (lodash_1.isNil(this.config.aws.s3)) {
throw new Error('Please config aws.s3 or fileService');
}
else if (!lodash_1.isNil(this.config.aws.s3)) {
this.fileService = new aws_1.S3Service(this.config.aws.s3);
}
else if (!lodash_1.isNil(this.config.fileService)) {
this.fileService = this.config.fileService;
}
if (lodash_1.isNil(this.config.aws.transcoder) && lodash_1.isNil(this.config.transcodeService)) {
throw new Error('Please config aws.transcoder or transcodeService');
}
else if (!lodash_1.isNil(this.config.aws.transcoder)) {
this.transcodeService = new aws_1.ElasticTranscoderService(this.config.aws.transcoder);
}
else if (!lodash_1.isNil(this.config.transcodeService)) {
this.transcodeService = this.config.transcodeService;
}
this.intentRepository = this.getDefaultValue(lexica_dialog_repository_1.intentRepository, this.config.intentRepository);
this.sessionRepository = this.getDefaultValue(new session_1.RedisSessionRepository(this.redisClient), this.config.sessionRepository);
this.configRepository = this.getDefaultValue(lexica_dialog_repository_1.configRepository, this.config.configRepository);
this.messageRepository = this.getDefaultValue(lexica_dialog_repository_1.messageRepository, this.config.messageRepository);
this.issueRepository = this.getDefaultValue(lexica_dialog_repository_1.issueRepository, this.config.issueRepository);
this.senderInfoRepository = this.getDefaultValue(lexica_dialog_repository_1.senderInfoRepository, this.config.senderInfoRepository);
if (lodash_1.isNil(this.config.logger)) {
this.logger = new winston.Logger({
level: lodash_1.isString(this.config.logLevel) ? this.config.logLevel : 'info',
transports: [new winston.transports.Console()],
});
}
else {
this.logger = this.config.logger;
}
this.redisClient.on('error', err => {
this.logger.error(`Unable to connect Redis ${redis.host}:${redis.port}`);
});
this.setupKoa();
this.nodeServer = this.server.listen(this.config.port);
}
close() {
this.nodeServer.close();
this.redisClient.quit();
mongoose.connection.close();
}
getDefaultValue(defaultValue, value) {
if (lodash_1.isNil(value)) {
return defaultValue;
}
return value;
}
setupKoa() {
this.setupMessenger();
this.sortedMiddlewares = immutable_1.List(this.middlewares
.sortBy((value, key) => key, (a, b) => (!lodash_1.isNil(a) && !lodash_1.isNil(b) ? a - b : -1))
.toArray()
.map(value => value));
this.server.use(BodyParser());
this.server.use(this.router.routes());
}
createDefaultMiddlewares() {
return [
middlewares.globalConfigMiddleware,
middlewares.unitConfigMiddleware,
middlewares.messengerWhiteListMiddleware,
middlewares.responseMessageLoggingMiddleware,
middlewares.messengerMiddleware,
middlewares.senderInfoMiddleware,
middlewares.fallbackResponseMiddleware,
middlewares.fetchIssueMiddleware,
middlewares.fileRequestMiddleware,
middlewares.transcodeMiddleware,
middlewares.sessionMiddleware,
middlewares.requestMessageLoggingMiddleware,
middlewares.fileRequestResponseMiddleware,
middlewares.intentOptionMiddleware,
middlewares.continuousOptionsToTextMiddleware,
middlewares.nlpMiddleware,
middlewares.suspendAutoReplyMiddleware,
middlewares.additionalResponseMessageMiddleware,
middlewares.flattenResponsesMiddleware,
middlewares.conversationIntentMiddleware,
middlewares.startConversationMiddleware,
middlewares.newIntentMiddleware,
middlewares.commandsValidationMiddleware,
middlewares.intentPreProcessorMiddleware,
middlewares.memoriesFeatureMiddleware,
middlewares.intentDefaultFeatureMiddleware,
middlewares.intentRequiredFeatureMiddleware,
middlewares.intentPostProcessorMiddleware,
middlewares.intentResponseMiddleware,
middlewares.intentExecutorMiddleware,
].reduce((map, middleware, i) => map.set((i + 1) * 100, middleware), immutable_1.Map());
}
createDefaultPreProcessor() {
return immutable_1.Map({
SenderNamePreProcessor: preProcessors.senderNamePreProcessor,
});
}
createDefaultPostProcessor() {
return immutable_1.Map({
DatePostProcessor: postProcessors.datePostProcessor,
});
}
createDefaultExecutor() {
return immutable_1.Map({
CloseIssueExecutor: executors.closeIssueExecutor,
CreateIssueExecutor: executors.createIssueExecutor,
});
}
setupMessenger() {
this.messengers.forEach((messenger, path) => this.router.all(`/:uni${path}`, this.createMessengerHandler(messenger)));
}
createMessengerHandler(messenger) {
return async (serverContext) => {
const context = {
attributes: immutable_1.Map(),
commands: immutable_1.List(),
configRepository: this.configRepository,
executors: this.executors,
fileService: this.fileService,
intentRepository: this.intentRepository,
issueRepository: this.issueRepository,
logger: this.logger,
messageRepository: this.messageRepository,
messenger,
nlpService: this.nlpService,
postProcessors: this.postProcessors,
preProcessors: this.preProcessors,
rawRequest: serverContext.request.body,
responses: immutable_1.List(),
senderInfoRepository: this.senderInfoRepository,
serverContext,
sessionRepository: this.sessionRepository,
transcodeService: this.transcodeService,
uni: serverContext.params.uni,
uniConfigs: immutable_1.Map(),
};
const start = this.createMiddlewareStartPoint(context, this.sortedMiddlewares);
try {
await start();
if (lodash_1.isNil(serverContext.status)) {
serverContext.status = 200;
}
}
catch (err) {
this.logger.error('Unhandled error from middlewares', err);
serverContext.status = 200;
}
};
}
createMiddlewareStartPoint(botServiceContext, services, index = 0) {
if (index >= services.size) {
return () => Promise.resolve();
}
return async () => await services.get(index)(botServiceContext, this.createMiddlewareStartPoint(botServiceContext, services, index + 1));
}
}
exports.default = BotServer;
//# sourceMappingURL=BotServer.js.map