@talema/graphql-azure-servicebus-subscriptions
Version:
A GraphQL subscription library using Azure Service Bus topics as PubSub server
129 lines • 6.26 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
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) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ServiceBusPubSub = void 0;
const graphql_subscriptions_1 = require("graphql-subscriptions");
const service_bus_1 = require("@azure/service-bus");
const rxjs_1 = require("rxjs");
const debug_1 = __importDefault(require("debug"));
const MessageProcessor_1 = require("./MessageProcessor");
/**
* An override for the in-memory PubSubEngine which connects to the Azure ServiceBus.
*/
class ServiceBusPubSub extends graphql_subscriptions_1.PubSubEngine {
constructor(options, logger, messageProcessor, client) {
super();
this.subscriptions = new Map();
this.debugger = (0, debug_1.default)("graphql:servicebus");
this.eventNameKey = "sub.eventName";
this.options = options;
this.client = client || new service_bus_1.ServiceBusClient(this.options.connectionString);
this.sender = this.client.createSender(this.options.topicName);
this.reciever = this.client.createReceiver(this.options.topicName, this.options.subscriptionName);
this.logger = logger;
this.messageProcessor = messageProcessor || new MessageProcessor_1.MessageProcessor(logger);
this.subject = new rxjs_1.Subject();
}
createSubscription() {
return this.reciever.subscribe({
processMessage: (message) => __awaiter(this, void 0, void 0, function* () {
yield this.messageProcessor.process(this.subject, message);
}),
processError: (args) => __awaiter(this, void 0, void 0, function* () {
yield this.messageProcessor.onError(args, (error) => __awaiter(this, void 0, void 0, function* () {
var _a;
if (error.code === "UnauthorizedAccess") {
yield ((_a = this.subscription) === null || _a === void 0 ? void 0 : _a.close());
}
}));
}),
});
}
publish(eventName, payload) {
return __awaiter(this, void 0, void 0, function* () {
try {
let event = {
body: {
name: eventName,
payload: payload,
},
};
event = this.enrichMessage(new Map([[this.eventNameKey, eventName]]), event);
return this.sender.sendMessages(event);
}
catch (error) {
this.logger.error(error);
}
});
}
/**
* Subscribe to a specific event updates. The subscribe method would create a ServiceBusReceiver to listen to all the published events.
* The method internally would filter out all the received events that are not meant for this subscriber.
* @property {eventName | string} - published event name
* @property {onMessage | Function} - client handler for processing received events.
* @returns {Promise<number>} - returns the created identifier for the created subscription. It would be used to dispose/close any resources while unsubscribing.
*/
subscribe(eventName, onMessage, options = {}) {
return __awaiter(this, void 0, void 0, function* () {
const id = Date.now() * Math.random();
this.debugger("sub metadata: ", eventName, onMessage, options);
if (this.subscriptions.size <= 0) {
this.subscription = this.createSubscription();
}
this.subscriptions.set(id, this.subject
.pipe((0, rxjs_1.filter)((e) => (eventName && e.body.name === eventName) ||
!eventName ||
eventName === "*"), (0, rxjs_1.map)((e) => e.body.payload), (0, rxjs_1.tap)((e) => e))
.subscribe((event) => {
this.debugger("returned event: ", event);
onMessage(event);
}));
return id;
});
}
/**
* Unsubscribe method would close open connection with the ServiceBus for a specific event handler.
* @property {subId} - It's a unique identifier for each subscribed client.
*/
unsubscribe(subId) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const subscription = this.subscriptions.get(subId) || undefined;
if (!subscription)
return false;
if (!subscription.closed) {
subscription.unsubscribe();
this.subscriptions.delete(subId);
}
if (this.subscriptions.size <= 0)
yield ((_a = this.subscription) === null || _a === void 0 ? void 0 : _a.close());
return true;
});
}
enrichMessage(attributes, message) {
const enrichedMessage = Object.assign({}, message);
if (enrichedMessage.applicationProperties == undefined)
enrichedMessage.applicationProperties = {};
attributes.forEach((value, key) => {
var _a;
if (enrichedMessage.applicationProperties !== undefined &&
((_a = enrichedMessage.applicationProperties) === null || _a === void 0 ? void 0 : _a[key]) === undefined) {
enrichedMessage.applicationProperties[key] = value;
}
});
return enrichedMessage;
}
}
exports.ServiceBusPubSub = ServiceBusPubSub;
//# sourceMappingURL=ServiceBusPubSub.js.map