diff --git a/HISTORY.MD b/HISTORY.MD index 9a0ea71..25a9133 100644 --- a/HISTORY.MD +++ b/HISTORY.MD @@ -1,3 +1,7 @@ +0.4.3 /2020-03-17 +================= +* Updated code to avoid duplicated subscriptions by adding a hash to subscription object + 0.4.2 / 2020-02-16 ================== diff --git a/logic/observer.js b/logic/observer.js index ab4ac2d..6e7c53b 100644 --- a/logic/observer.js +++ b/logic/observer.js @@ -1,4 +1,5 @@ -const errors = require('../util/errors'), + const crypto = require ('crypto') + const errors = require('../util/errors'), TransactionWatcher = require('./transaction-watcher'), Notifier = require('./notifier'), storage = require('./storage'), @@ -38,10 +39,21 @@ class Observer { } subscribe(subscriptionParams, user) { - //TODO: prevent duplicate subscriptions by checking subscription hash (fields "account", "asset_type" etc.) - //https://www.npmjs.com/package/farmhash return this.loadSubscriptions() .then(() => { + // Create hash in the subscription to avoid duplication + + let hashData = `${subscriptionParams.reaction_url} ${subscriptionParams.account} ${subscriptionParams.memo} ${subscriptionParams.operation_types} ${subscriptionParams.asset_code} ${subscriptionParams.asset_issuer} ${subscriptionParams.expires}` + let hash = crypto.createHash('md5').update(hashData).digest("hex").toString(); + subscriptionParams.hash = hash + + let subscription = this.subscriptions.find(s => s.hash == hash) + + if(subscription){ + + return subscription + } + if (this.getActiveSubscriptionsCount() >= config.maxActiveSubscriptions) { return Promise.reject(errors.forbidden('Max active subscriptions exceeded.')) } diff --git a/logic/storage.js b/logic/storage.js index 77e49cc..4367406 100644 --- a/logic/storage.js +++ b/logic/storage.js @@ -58,6 +58,19 @@ class Storage { }) } + /** + * + * @param {*} hash - the hash of the subscription + */ + + async fetchSubscriptioHash(hash){ + this.provider.fetchSubscriptioHash(hash) + .then(subscription =>{ + return subscription + }) + } + + /** * Load next notification from db * @param {*} subscriptionId - subscription id @@ -208,6 +221,8 @@ class Storage { subscription.expires = expirationDate } + subscription.hash = subscriptionParams.hash + return this.provider.saveSubscription(subscription) } diff --git a/models/subscription-model.js b/models/subscription-model.js index 524ee3d..86e35c5 100644 --- a/models/subscription-model.js +++ b/models/subscription-model.js @@ -67,6 +67,12 @@ class SubscriptionModel extends Model { * Cached notifications, associated with the subscription */ notifications + + /** + * Subscription hash to avoid duplicated subscriptions + */ + hash + } module.exports = SubscriptionModel \ No newline at end of file diff --git a/package.json b/package.json index abb6b43..4cbd53c 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "@stellar-expert/operations-notifier", "license": "MIT", "private": true, - "version": "0.4.2", + "version": "0.4.3", "author": "orbitlens", "description": "Stellar operations observer and notifier.", "main": "app.js", diff --git a/persistence-layer/mongodb-storage-provider/index.js b/persistence-layer/mongodb-storage-provider/index.js index 6bc48e1..0d198c6 100644 --- a/persistence-layer/mongodb-storage-provider/index.js +++ b/persistence-layer/mongodb-storage-provider/index.js @@ -41,6 +41,10 @@ class MongoDBStorageProvider extends StorageProvider { return Subscription.findById(id) } + fetchSubscriptioHash(hash){ + return Subscription.findOne({hash}) + } + fetchNextNotification(subscriptionId) { return Notification.findOne({subscriptions: toObjectId(subscriptionId)}) } diff --git a/persistence-layer/mongodb-storage-provider/models/subscription-db-model.js b/persistence-layer/mongodb-storage-provider/models/subscription-db-model.js index c80d336..29d48d6 100644 --- a/persistence-layer/mongodb-storage-provider/models/subscription-db-model.js +++ b/persistence-layer/mongodb-storage-provider/models/subscription-db-model.js @@ -13,7 +13,8 @@ const subscriptionSchema = new Schema({ reaction_url: {type: String}, delivery_failures: {type: Number, default: 0}, sent: {type: Number, default: 0}, - expires: {type: Date} + expires: {type: Date}, + hash:{type:String} }, { timestamps: {createdAt: 'created', updatedAt: 'updated'}