@fabrix/spool-broadcast
Version:
Spool: broadcast for Fabrix to implement CQRS and Event Sourcing
256 lines • 10.3 kB
JavaScript
"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