UNPKG

@fabrix/spool-broadcast

Version:

Spool: broadcast for Fabrix to implement CQRS and Event Sourcing

256 lines 10.3 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); const common_1 = require("@fabrix/fabrix/dist/common"); const bluebird_1 = require("bluebird"); const BroadcastEntity_1 = require("./BroadcastEntity"); const lodash_1 = require("lodash"); const errors_1 = require("@fabrix/spool-errors/dist/errors"); class BroadcastProject extends common_1.FabrixGeneric { constructor(app, { event, options, consistency, message, manager, broadcaster }) { super(app); this.consistency = 'strong'; this.isAcknowledged = false; this.isRedelivered = false; this.retries = 0; this.event = event; if (manager && manager.options) { this.options = Object.assign({}, options, manager.options); } else { this.options = options; } this.manager = manager; this.consistency = consistency || this.consistency; this.broadcaster = broadcaster; this.id = this.event.event_uuid; this.message = message; if (this.message && this.message.fields) { this.isRedelivered = this.message.fields.redelivered; } } get saveOptions() { let fields = this.event.changes(); if (this.projectorModel && this.fields.length > 0) { fields = lodash_1.intersection(this.event.changes(), this.fields); } else if (this.event.object && this.event.object.resolver && this.event.object.resolver.schema) { fields = lodash_1.intersection(this.event.changes(), Object.keys(this.event.object.resolver.schema)); } return { transaction: this.options.transaction, useMaster: this.options.useMaster, fields: fields }; } get id() { return this._id; } set id(id) { this._id = id; } get name() { return this.constructor.name; } get projectorModel() { return this._projectorModel; } get fields() { if (this.projectorModel && this.projectorModel.resolver && this.projectorModel.resolver.schema) { return Object.keys(this.projectorModel.resolver.schema); } else { return []; } } set projectorModel(model) { if (typeof model === 'string') { if (this.app.models[model]) { this._projectorModel = this.app.models[model]; } else { throw new errors_1.GenericError('E_NOT_VALID', `${model} is not in app.models`); } } else { if (this.app.models[model.constructor.name]) { this._projectorModel = model; } else { throw new errors_1.GenericError('E_NOT_VALID', `${model.constructor.name} is not in app.models`); } } } run() { return __awaiter(this, void 0, void 0, function* () { throw new Error('Subclasses must override BroadcastProject.run'); }); } ack() { return __awaiter(this, void 0, void 0, function* () { if (!this.isAcknowledged && this.message) { this.isAcknowledged = true; return new bluebird_1.Promise((resolve, reject) => { return resolve(this.message.ack()); }) .then(() => { return [this.event, this.options]; }) .catch((err) => { this.app.log.error(`Projector ${this.name} failed on ack`, err); return [this.event, this.options]; }); } else if (!this.isAcknowledged && !this.message) { this.isAcknowledged = true; return bluebird_1.Promise.resolve([this.event, this.options]); } else { this.app.log.warn(`Projector ${this.name} attempting to ack a message that already responded`); return bluebird_1.Promise.resolve([this.event, this.options]); } }); } nack() { return __awaiter(this, void 0, void 0, function* () { if (!this.isAcknowledged && this.message) { this.app.log.debug(`Nacking ${this.name}`); this.isAcknowledged = true; return new bluebird_1.Promise((resolve, reject) => { return resolve(this.message.nack()); }) .then(() => { return [this.event, this.options]; }) .catch((err) => { this.app.log.error(`${this.name} failed on nack`, err); return [this.event, this.options]; }); } else if (!this.isAcknowledged && !this.message) { this.app.log.debug(`Can not nack empty message for Projector ${this.name}`); this.isAcknowledged = true; return bluebird_1.Promise.resolve([this.event, this.options]); } else if (this.isAcknowledged && this.message) { this.app.log.debug(`Can not nack acknowledged message for Projector ${this.name}`); this.isAcknowledged = true; return bluebird_1.Promise.resolve([this.event, this.options]); } else { this.app.log.warn(`Projector ${this.name} attempting to nack a message that already responded`); return bluebird_1.Promise.resolve([this.event, this.options]); } }); } reject() { return __awaiter(this, void 0, void 0, function* () { if (!this.isAcknowledged && this.message) { this.app.log.debug(`Projector Rejecting ${this.name}`); this.isAcknowledged = true; return new bluebird_1.Promise((resolve, reject) => { return resolve(this.message.reject()); }) .then(() => { return [this.event, this.options]; }) .catch((err) => { this.app.log.error(`${this.name} failed on reject`, err); return [this.event, this.options]; }); } else if (!this.isAcknowledged && !this.message) { this.app.log.debug(`Can not reject empty message for Projector ${this.name}`); this.isAcknowledged = true; return bluebird_1.Promise.resolve([this.event, this.options]); } else if (this.isAcknowledged && this.message) { this.app.log.debug(`Can not reject acknowledged message for Projector ${this.name}`); return bluebird_1.Promise.resolve([this.event, this.options]); } else { this.app.log.warn(`${this.name} attempting to reject a message that already responded`); return bluebird_1.Promise.resolve([this.event, this.options]); } }); } interrupt(msg) { return __awaiter(this, void 0, void 0, function* () { this.app.log.debug(`${this.name} Interrupt:`, msg); }); } reply(msg) { return __awaiter(this, void 0, void 0, function* () { this.app.log.debug(`${this.name} Reply:`, msg); }); } finalize() { return __awaiter(this, void 0, void 0, function* () { this.app.log.debug(`${this.name} Finalize:`, this.event.event_type); }); } entries(name) { if (!this.app.spools.broadcast) { throw new Error('Spool-broadcast is not loaded!'); } return this.app.spools.broadcast.entries(name); } Sequelize() { if (!this.app.spools.sequelize) { throw new Error('Spool-sequelize is not loaded!'); } return this.app.spools.sequelize._datastore; } mapSeries(...args) { return this.app.broadcastSeries(...args); } get metadata() { const channel = { channel_uuid: this.event.metadata.req_channel_uuid || null }; const channel_session = { session_uuid: this.event.metadata.req_session_uuid || null }; const user = { user_uuid: this.event.metadata.req_user_uuid }; const device = { device_uuid: this.event.metadata.req_device_uuid || null }; const application = { application_uuid: this.event.metadata.req_application_uuid || null }; const causation_uuid = this.event.event_uuid || null; const correlation_uuid = this.event.correlation_uuid || null; const correlation_type = this.event.correlation_type || null; const explain = this.event.explain || {}; const ip = { ip: this.event.metadata.req_ip || null }; return { channel, channel_session, user, device, application, causation_uuid, correlation_uuid, correlation_type, explain, ip }; } } exports.BroadcastProject = BroadcastProject; class BroadcastProjector extends BroadcastEntity_1.BroadcastEntity { constructor(app) { super(app, 'projectors'); this._managers = new Map(); } newProjector(func, vals) { return new func(this.app, vals); } get managers() { return this._managers; } hasManager(name) { return this._managers.has(name); } } exports.BroadcastProjector = BroadcastProjector; //# sourceMappingURL=BroadcastProjector.js.map