vulcain-corejs
Version:
Vulcain micro-service framework
291 lines (289 loc) • 12.8 kB
JavaScript
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
const schema_1 = require('./../schemas/schema');
const annotations_1 = require('../di/annotations');
const annotations_2 = require('./../schemas/annotations');
const runtimeError_1 = require('./../errors/runtimeError');
const system_1 = require('./../configurations/globals/system');
class PropertyDescription {
}
exports.PropertyDescription = PropertyDescription;
class SchemaDescription {
}
exports.SchemaDescription = SchemaDescription;
class ActionDescription {
}
exports.ActionDescription = ActionDescription;
let ServiceDescription = class ServiceDescription {
};
ServiceDescription = __decorate([
annotations_2.Model(),
__metadata('design:paramtypes', [])
], ServiceDescription);
exports.ServiceDescription = ServiceDescription;
class ServiceDescriptors {
constructor(container, domain) {
this.container = container;
this.domain = domain;
this.handlers = new Array();
this.routes = new Map();
this.monoSchema = true;
}
getDescriptions() {
this.createHandlersTable();
return this.descriptions;
}
getHandlerInfo(container, schema, action, optional) {
this.createHandlersTable();
let a = action && action.toLowerCase();
let item;
if (this.monoSchema || !schema) {
item = this.routes.get(a);
}
else {
let s = schema && schema.toLowerCase();
item = this.routes.get(s + "." + a);
}
if (!item) {
if (optional)
return null;
else
throw new runtimeError_1.RuntimeError(`no handler method founded for action ${action}, schema ${schema}`);
}
try {
let handler = container && container.resolve(item.handler);
return { handler: handler, metadata: item.metadata, method: item.methodName, kind: item.kind };
}
catch (e) {
system_1.System.log.error(null, e, `Unable to create handler action ${action}, schema ${schema}`);
throw new Error(`Unable to create handler for action ${action}, schema ${schema}`);
}
}
createHandlersTable() {
if (!this.handlers)
return;
let scopes = this.container.get(annotations_1.DefaultServiceNames.ScopesDescriptor);
let schemas = new Map();
// Check if there is only one Schema
let lastSchema;
this.handlers.forEach(item => {
if (!item.metadata.schema)
return;
if (!lastSchema)
lastSchema = item.metadata.schema;
else if (item.metadata.schema !== lastSchema) {
this.monoSchema = false;
}
});
this.descriptions = {
services: [],
schemas: new Array(),
domain: this.domain.name,
serviceName: system_1.System.serviceName,
serviceVersion: system_1.System.serviceVersion,
alternateAddress: null,
hasAsyncTasks: false,
scopes: scopes.getScopes().map(d => { return { name: d.name, description: d.description }; })
};
for (let item of this.handlers.filter(h => h.kind === "action")) {
let schema = this.getSchemaDescription(schemas, item.metadata.schema);
let verb = !item.metadata.schema || this.monoSchema
? item.metadata.action
: schema + "." + item.metadata.action;
verb = verb.toLowerCase();
if (this.routes.has(verb))
throw new Error(`*** Duplicate handler for action ${item.metadata.action} for handler ${item.handler.name}`);
system_1.System.log.info(null, "Handler registered for action verb %s", verb);
this.routes.set(verb, item);
let metadata = item.metadata;
metadata.scope = this.checkScopes(scopes, metadata.scope, verb);
metadata.inputSchema = this.getSchemaDescription(schemas, metadata.inputSchema, schema);
metadata.outputSchema = !metadata.async && this.getSchemaDescription(schemas, metadata.outputSchema, schema);
let desc = {
schema: schema,
kind: "action",
async: metadata.async,
verb: verb,
description: metadata.description,
action: metadata.action,
scope: metadata.scope,
inputSchema: metadata.inputSchema,
outputSchema: metadata.outputSchema
};
if (metadata.async)
this.descriptions.hasAsyncTasks = true;
this.descriptions.services.push(desc);
}
for (let item of this.handlers.filter(h => h.kind === "query")) {
let schema = item.metadata.schema && this.getSchemaDescription(schemas, item.metadata.schema);
let verb = !item.metadata.schema || this.monoSchema
? item.metadata.action
: schema + "." + item.metadata.action;
verb = verb.toLowerCase();
if (this.routes.has(verb))
throw new Error(`*** Duplicate handler for query ${item.metadata.action} for handler ${item.handler.name}`);
system_1.System.log.info(null, "Handler registered for query verb %s", verb);
this.routes.set(verb, item);
if (item.metadata.action.startsWith("_service"))
continue;
let metadata = item.metadata;
metadata.inputSchema = this.getSchemaDescription(schemas, metadata.inputSchema);
metadata.outputSchema = this.getSchemaDescription(schemas, metadata.outputSchema, schema);
metadata.scope = this.checkScopes(scopes, metadata.scope, verb);
let desc = {
schema: schema,
kind: metadata.action === "get" ? "get" : "query",
verb: verb,
description: metadata.description,
action: metadata.action,
scope: metadata.scope,
async: false,
inputSchema: metadata.inputSchema,
outputSchema: metadata.outputSchema
};
if (desc.action === "get" && !desc.inputSchema)
desc.inputSchema = "string";
if (desc.action !== "get")
desc.outputSchema = desc.outputSchema;
this.descriptions.services.push(desc);
}
this.sortSchemasDependencies();
this.handlers = null;
}
checkScopes(scopes, scope, verb) {
if (!scope || scope === "?" || scope === "*")
return scope;
let parts = scope.split(',');
let result = [];
for (let sc of parts) {
sc = system_1.System.domainName + ":" + sc.trim();
if (!scopes.getScopes().find(s => s.name === sc))
throw new Error(`${sc} not found in scopes descriptor for ${verb}. You must define it in (Startup)application.defineScopes.`);
result.push(sc);
}
return result.join(',');
}
getSchemaDescription(schemas, schemaName, defaultValue) {
if (schemaName === "none")
return;
if (!schemaName)
return defaultValue;
let schema;
if (typeof schemaName === "string") {
if (ServiceDescriptors.nativeTypes.indexOf(schemaName) >= 0)
return schemaName;
let type = this.getPropertyType(schemaName);
if (type)
return type.name;
}
schema = this.domain.getSchema(schemaName);
if (!schema)
throw new Error("Unknow schema " + schemaName);
let desc = schemas.get(schema.name);
if (desc)
return desc.name;
desc = { name: schema.name, properties: [], dependencies: new Set() };
schemas.set(schema.name, desc);
this.descriptions.schemas.push(desc);
for (let k of Object.keys(schema.description.properties)) {
const p = schema.description.properties[k];
let type = this.getPropertyType(p.item || p.type);
if (type) {
let metadata = { type: p.type, item: p.item, values: p.values, required: p.required, description: p.description };
let pdesc = { name: k, type: p.item ? type.name + "[]" : type.name, required: p.required, description: p.description, metadata: metadata };
// Insert required at the beginning
if (!pdesc.required)
desc.properties.push(pdesc);
else
desc.properties.unshift(pdesc);
}
}
for (let k of Object.keys(schema.description.references)) {
const r = schema.description.references[k];
if (schemas.has(k))
return k;
this.getSchemaDescription(schemas, r.item);
let metadata = { item: r.item, cardinality: r.cardinality, required: r.required, description: r.description };
let pdesc = {
name: k,
reference: r.cardinality,
type: r.cardinality === "many" ? r.item + "[]" : r.item,
required: false,
description: r.description,
metadata: metadata
};
if (r.item !== "any")
desc.dependencies.add(r.item);
// Insert required at the beginning
if (!pdesc.required)
desc.properties.push(pdesc);
else
desc.properties.unshift(pdesc);
}
return desc.name;
}
getPropertyType(name) {
while (true) {
let type = this.domain._findType(name);
if (!type) {
name = name.toLowerCase();
type = this.domain._findType(name);
}
if (!type || (!type.type && !type.item)) {
if (type)
type.name = name;
return type;
}
name = type.type || type.item;
}
}
sortSchemasDependencies() {
this.descriptions.schemas = this.descriptions.schemas.sort((a, b) => {
if (a.dependencies.has(b.name))
return 1;
return -1;
});
this.descriptions.schemas.forEach((s) => delete s.dependencies);
}
register(container, domain, target, actions, handlerMetadata, kind) {
handlerMetadata = handlerMetadata || { scope: "*" };
if (handlerMetadata.schema) {
// test if exists
let tmp = domain.getSchema(handlerMetadata.schema);
handlerMetadata.schema = tmp.name;
}
container.inject(handlerMetadata.serviceName || target.name, target, handlerMetadata.serviceLifeTime || annotations_1.LifeTime.Scoped);
for (const action in actions) {
let actionMetadata = actions[action];
actionMetadata = actionMetadata || {};
actionMetadata.action = actionMetadata.action || action;
// Merge metadata
let item = {
kind: kind,
methodName: action,
metadata: Object.assign({}, handlerMetadata, actionMetadata),
handler: target
};
this.handlers.push(item);
}
}
}
ServiceDescriptors.nativeTypes = ["string", "String", "boolean", "Boolean", "number", "Number", "any", "Object"];
ServiceDescriptors = __decorate([
__param(0, annotations_1.Inject(annotations_1.DefaultServiceNames.Container)),
__param(1, annotations_1.Inject(annotations_1.DefaultServiceNames.Domain)),
__metadata('design:paramtypes', [Object, schema_1.Domain])
], ServiceDescriptors);
exports.ServiceDescriptors = ServiceDescriptors;
//# sourceMappingURL=serviceDescriptions.js.map