publisher-subscriber-ts
Version:
Publisher subscriber library for javascript
189 lines (184 loc) • 6.68 kB
JavaScript
import { v4 } from 'uuid';
/**
* @author Harsh A. Mistry
*
* Subscriber class to start listening to any topic
*/
var Subscriber = /** @class */ (function () {
function Subscriber(callBack, topicName) {
this._callBack = callBack;
this._id = v4();
this._topicName = topicName;
}
Object.defineProperty(Subscriber.prototype, "callBack", {
/**
* Getter for callback
*
* @returns {Function} callback function provided while subscribing
*/
get: function () {
return this._callBack;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Subscriber.prototype, "id", {
/**
* Getter for subscrber ID. Used for unsubscription.
*
* @returns {string} subscription ID
*/
get: function () {
return this._id;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Subscriber.prototype, "topicName", {
/**
* Getter for topic name. Used for unsubscription.
*
* @returns {string} topic name
*/
get: function () {
return this._topicName;
},
enumerable: false,
configurable: true
});
return Subscriber;
}());
/**
* @author Harsh A. Mistry
*
* Topic class for creating new topic. Topic is a medium for communicating between publisher and subscriber. A publisher will create topic and subscriber will
* subscribe to topic/topics
*/
var Topic = /** @class */ (function () {
function Topic(topicName) {
this._topicName = topicName;
this._subscriberList = new Array();
}
/**
* Publish any event for current topic. Once event is published all active subscribers will get a notification in callback function.
* @param {any} event
*/
Topic.prototype.publish = function (event) {
this._currentValue = event;
for (var _i = 0, _a = this._subscriberList; _i < _a.length; _i++) {
var subscriber = _a[_i];
this.emitValueToSubscriber(subscriber);
}
};
/**
* Once topic is created, it can be subscribed using this method
* @param {Function} callback
* @param {SubscribeOption} option Different option can be passed while subscribing.
* e.g. If topic has already emitted some value and then a subscriber comes, then it can pass option to re-emit last emitted value only for this new subscriber.
*
* @returns {Subscriber} Final subscriber object once successfully subscribed
*/
Topic.prototype.subscribe = function (callback, option) {
var subscriber = new Subscriber(callback, this._topicName);
if (option.getLastValue && this._currentValue) {
this.emitValueToSubscriber(subscriber);
}
this._subscriberList.push(subscriber);
return subscriber;
};
/**
* Method to unsubscribe/remove a listener of this topic
* @param {Subscriber} subscription Subscriber of this topic
*/
Topic.prototype.unsubscribe = function (subscription) {
if (subscription && subscription.id) {
var removeAtIndex = this._subscriberList.findIndex(function (subscriber) {
return subscriber.id === subscription.id;
});
if (removeAtIndex > -1) {
this._subscriberList.splice(removeAtIndex, 1);
}
}
};
Object.defineProperty(Topic.prototype, "topicName", {
/**
* Returns topic name
*
* @returns {string}
*/
get: function () {
return this._topicName;
},
enumerable: false,
configurable: true
});
/**
* Broadcast value to given subscriber
* @param {Subscriber} subscriber
*/
Topic.prototype.emitValueToSubscriber = function (subscriber) {
if (this._currentValue) {
subscriber.callBack.call(this, this._currentValue);
}
};
return Topic;
}());
/**
* @author Harsh A. Mistry
*
* Publisher class to publish new topics and emit values
*/
var Publisher = /** @class */ (function () {
function Publisher() {
}
/**
* Creates new topic for given topic name
* @param {string} topicName Name for topic to be created
*
* @returns {Topic} New created topic
*/
Publisher.createTopic = function (topicName) {
var topic = new Topic(topicName);
this._topicMap.set(topicName, topic);
return topic;
};
/**
* Subscribe to a particular topic by providing option and a callback function.
* @param {SubscribeOption} option
* @param {Function} callback
* @throws {Topic name cannot be empty or null while subscribing} Error if topic name passed is null or empty
* @throws {'Cannot find topic with name: ' ${topic_name} '. Please create one and then subscribe.'} If given topic name does not exist
*
* @returns {Subscriber}
*/
Publisher.subscribeTopic = function (option, callback) {
var _a, _b;
if (!option.topicName) {
throw new Error('Topic name cannot be empty or null while subscribing');
}
else if (!this._topicMap.has(option.topicName)) {
throw new Error('Cannot find topic with name: ' + option.topicName + '. Please create one and then subscribe.');
}
else if (this._topicMap) {
return (_b = (_a = this._topicMap) === null || _a === void 0 ? void 0 : _a.get(option.topicName)) === null || _b === void 0 ? void 0 : _b.subscribe(callback, option);
}
};
/**
* Unsubscribe any topic for given subscriber
* @param {string} topicName
* @throws {'Cannot find topic with name: ' ${topicName}} Thrown when given topic name is not found
* @param {Subscriber} subscriber Subscriber of this topic
*/
Publisher.unsubscribeTopic = function (subscriber) {
var _a, _b;
if (!this._topicMap.has(subscriber.topicName)) {
throw new Error('Cannot find topic with name: ' + subscriber.topicName);
}
else {
(_b = (_a = this._topicMap) === null || _a === void 0 ? void 0 : _a.get(subscriber.topicName)) === null || _b === void 0 ? void 0 : _b.unsubscribe(subscriber);
}
};
Publisher._topicMap = new Map();
return Publisher;
}());
export { Publisher };