vulcain-corejs
Version:
Vulcain micro-service framework
271 lines (269 loc) • 10.8 kB
JavaScript
"use strict";
const expressAuthentication_1 = require('./servers/expressAuthentication');
const apiKeyService_1 = require('./auth/apiKeyService');
const preloader_1 = require('./preloader');
const hystrixSSEStream_1 = require('./commands/http/hystrixSSEStream');
const localAdapter_1 = require('./bus/localAdapter');
const Path = require('path');
const schema_1 = require('./schemas/schema');
const containers_1 = require('./di/containers');
const files_1 = require('./utils/files');
const expressAdapter_1 = require('./servers/expressAdapter');
require('reflect-metadata');
const annotations_1 = require('./di/annotations');
const conventions_1 = require('./utils/conventions');
const provider_1 = require("./providers/memory/provider");
const requestContext_1 = require('./servers/requestContext');
require('./defaults/serviceExplorer'); // Don't remove (auto register)
require('./defaults/dependencyExplorer'); // Don't remove (auto register)
require('./pipeline/scopeDescriptors'); // Don't remove (auto register)
const system_1 = require('./configurations/globals/system');
/**
* Application base class
*
* @export
* @abstract
* @class Application
*/
class Application {
/**
* Create new application
* @param path Files base path for components discovery
* @param container Global component container
* @param app (optional)Server adapter
*/
constructor(domainName, container) {
domainName = domainName;
if (!domainName) {
throw new Error("Domain name is required.");
}
system_1.System.defaultDomainName = domainName;
system_1.System.log.info(null, "Starting application");
this._executablePath = Path.dirname(module.filename);
this._basePath = this.findBasePath();
// Ensure initializing this first
const test = system_1.System.isDevelopment;
this._container = container || new containers_1.Container();
this._container.injectTransient(provider_1.MemoryProvider, annotations_1.DefaultServiceNames.Provider);
this._container.injectInstance(this, annotations_1.DefaultServiceNames.Application);
this._container.injectSingleton(expressAuthentication_1.Authentication, annotations_1.DefaultServiceNames.Authentication);
this._domain = new schema_1.Domain(domainName, this._container);
this._container.injectInstance(this.domain, annotations_1.DefaultServiceNames.Domain);
}
/**
* Enable api key authentication
*
* @param {string} apiKeyServiceName Vulcain service name
* @param {string} [version="1.0"] Service version
*
* @memberOf Application
*/
enableApiKeyAuthentication(apiKeyServiceName, version = "1.0") {
this.container.injectInstance(new apiKeyService_1.ApiKeyService(this.container, apiKeyServiceName, version), annotations_1.DefaultServiceNames.ApiKeyService);
}
/**
* Set the user to use in local development
*
* @param {UserContext} user
* @returns
*/
setTestUser(user) {
user = user || requestContext_1.RequestContext.TestUser;
if (!user.id || !user.name || !user.scopes) {
throw new Error("Invalid test user - Properties must be set.");
}
if (!system_1.System.isTestEnvironnment) {
system_1.System.log.info(null, "Warning : TestUser ignored");
return;
}
this._container.injectInstance(user, annotations_1.DefaultServiceNames.TestUser);
}
/**
* Called when the server adapter is started
*
* @param {*} server
*/
onServerStarted(server, adapter) { }
/**
* Current component container
* @returns {Container}
*/
get container() { return this._container; }
/**
* Get the current domain model
* @returns {Domain}
*/
get domain() {
return this._domain;
}
findBasePath() {
let parent = module.parent;
while (parent.parent) {
parent = parent.parent;
}
return Path.dirname(parent.filename);
}
startHystrixStream() {
if (!this.enableHystrixStream) {
return;
}
this.adapter.useMiddleware("get", conventions_1.Conventions.instance.defaultHystrixPath, (request, response) => {
response.append('Content-Type', 'text/event-stream;charset=UTF-8');
response.append('Cache-Control', 'no-cache, no-store, max-age=0, must-revalidate');
response.append('Pragma', 'no-cache');
system_1.System.log.info(null, "get hystrix.stream");
let subscription = hystrixSSEStream_1.HystrixSSEStream.toObservable().subscribe(function onNext(sseData) {
response.write('data: ' + sseData + '\n\n');
}, function onError(error) {
system_1.System.log.info(null, "hystrixstream: error");
}, function onComplete() {
system_1.System.log.info(null, "end hystrix.stream");
return response.end();
});
request.on("close", () => {
system_1.System.log.info(null, "close hystrix.stream");
subscription.dispose();
});
return subscription;
});
}
defineScopes(scopes) {
}
/**
* Override this method to initialize default containers
*
* @protected
* @param {IContainer} container
*/
initializeDefaultServices(container) {
}
/**
* Override this method to add your custom services
*
* @protected
* @param {IContainer} container
*/
initializeServices(container) {
}
/**
* Called before the server adapter is started
*
* @protected
* @param {AbstractAdapter} abstractAdapter
*/
initializeServerAdapter(abstractAdapter) {
}
/**
* Initialize and start application
*
* @param {number} port
*/
start(port) {
this.initializeDefaultServices(this.container);
let local = new localAdapter_1.LocalAdapter();
let eventBus = this.container.get(annotations_1.DefaultServiceNames.EventBusAdapter, true);
if (!eventBus) {
this.container.injectInstance(local, annotations_1.DefaultServiceNames.EventBusAdapter);
eventBus = local;
}
let commandBus = this.container.get(annotations_1.DefaultServiceNames.ActionBusAdapter, true);
if (!commandBus) {
this.container.injectInstance(local, annotations_1.DefaultServiceNames.ActionBusAdapter);
commandBus = local;
}
eventBus.startAsync().then(() => {
commandBus.startAsync().then(() => {
try {
this.registerModelsInternal();
this.registerServicesInternal();
this.registerHandlersInternal();
this.initializeServices(this.container);
preloader_1.Preloader.instance.runPreloads(this.container, this._domain);
let scopes = this.container.get(annotations_1.DefaultServiceNames.ScopesDescriptor);
this.defineScopes(scopes);
let descriptors = this.container.get(annotations_1.DefaultServiceNames.ServiceDescriptors);
descriptors.createHandlersTable();
this.adapter = this.container.get(annotations_1.DefaultServiceNames.ServerAdapter, true);
if (!this.adapter) {
this.adapter = new expressAdapter_1.ExpressAdapter(this.domain.name, this._container, this);
this.container.injectInstance(this.adapter, annotations_1.DefaultServiceNames.ServerAdapter);
this.initializeServerAdapter(this.adapter);
this.adapter.initialize();
}
this.startHystrixStream();
this.adapter.start(port);
}
catch (err) {
system_1.System.log.error(null, err);
}
});
});
}
registerModelsInternal() {
this.registerModels(Path.join(this._executablePath, "defaults/models"));
let path = conventions_1.Conventions.instance.defaultModelsFolderPattern.replace("${base}", conventions_1.Conventions.instance.defaultApplicationFolder);
this.registerModels(Path.join(this._basePath, path));
}
/**
* Inject all components from a specific folder (relative to the current folder)
*
* @protected
* @param {string} path Folder path
* @returns The current container
*/
injectFrom(path) {
if (!Path.isAbsolute(path)) {
path = Path.join(this._basePath, path);
}
this._container.injectFrom(path);
return this._container;
}
/**
* Discover models components
* @param path Where to find models component relative to base path (default=/api/models)
* @returns {Container}
*/
registerModels(path) {
if (!Path.isAbsolute(path)) {
path = Path.join(this._basePath, path);
}
files_1.Files.traverse(path);
return this._container;
}
registerHandlersInternal() {
this.registerHandlers(Path.join(this._executablePath, "defaults/handlers"));
let path = conventions_1.Conventions.instance.defaultHandlersFolderPattern.replace("${base}", conventions_1.Conventions.instance.defaultApplicationFolder);
this.registerHandlers(Path.join(this._basePath, path));
}
/**
* Discover models components
* @param path Where to find models component relative to base path (default=/api/models)
* @returns {Container}
*/
registerHandlers(path) {
if (!Path.isAbsolute(path)) {
path = Path.join(this._basePath, path);
}
files_1.Files.traverse(path);
return this._container;
}
registerServicesInternal() {
this.registerServices(Path.join(this._executablePath, "defaults/services"));
let path = conventions_1.Conventions.instance.defaultServicesFolderPattern.replace("${base}", conventions_1.Conventions.instance.defaultApplicationFolder);
this.registerServices(Path.join(this._basePath, path));
}
/**
* Discover service components
* @param path Where to find services component relative to base path (default=/core/services)
* @returns {Container}
*/
registerServices(path) {
if (!Path.isAbsolute(path)) {
path = Path.join(this._basePath, path);
}
files_1.Files.traverse(path);
return this._container;
}
}
exports.Application = Application;
//# sourceMappingURL=application.js.map