From 89d845e3d565156e7b0f88ce630b3980aa48c51a Mon Sep 17 00:00:00 2001 From: Alex Tymchenko Date: Fri, 13 Jan 2023 12:58:25 +0000 Subject: [PATCH 01/20] Bump the version. --- version.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.gradle.kts b/version.gradle.kts index b476a09a..211323c5 100644 --- a/version.gradle.kts +++ b/version.gradle.kts @@ -29,5 +29,5 @@ val spineTimeVersion: String by extra("1.9.0-SNAPSHOT.5") val spineCoreVersion: String by extra("1.9.0-SNAPSHOT.6") val spineVersion: String by extra(spineCoreVersion) -val versionToPublish: String by extra("1.9.0-SNAPSHOT.9") +val versionToPublish: String by extra("1.9.0-SNAPSHOT.10") val versionToPublishJs: String by extra(versionToPublish) From 9283f830ff7241f79ecf441b726d112837e5a7bb Mon Sep 17 00:00:00 2001 From: Alex Tymchenko Date: Fri, 13 Jan 2023 13:08:32 +0000 Subject: [PATCH 02/20] Remove an unused import. --- client-js/main/client/firebase-client.js | 1 - 1 file changed, 1 deletion(-) diff --git a/client-js/main/client/firebase-client.js b/client-js/main/client/firebase-client.js index 6a61d0e7..ad7f3eaf 100644 --- a/client-js/main/client/firebase-client.js +++ b/client-js/main/client/firebase-client.js @@ -35,7 +35,6 @@ import {ActorRequestFactory} from './actor-request-factory'; import {AbstractClientFactory} from './client-factory'; import {CommandingClient} from "./commanding-client"; import {CompositeClient} from "./composite-client"; -import {HttpClient} from './http-client'; import {HttpEndpoint} from './http-endpoint'; import {FirebaseDatabaseClient} from './firebase-database-client'; import {FirebaseSubscriptionService} from './firebase-subscription-service'; From e0b5bc61536957a25a3cee5995f60002f06f5b4a Mon Sep 17 00:00:00 2001 From: Alex Tymchenko Date: Fri, 13 Jan 2023 13:12:39 +0000 Subject: [PATCH 03/20] Fix another typo. --- client-js/main/client/firebase-client.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client-js/main/client/firebase-client.js b/client-js/main/client/firebase-client.js index ad7f3eaf..b4574cea 100644 --- a/client-js/main/client/firebase-client.js +++ b/client-js/main/client/firebase-client.js @@ -83,9 +83,9 @@ class SpineSubscription extends Subscription { class EntitySubscription extends SpineSubscription { /** - * @param {Function} unsubscribe the callbacks that allows to cancel the subscription + * @param {Function} unsubscribe the callback that allows to cancel the subscription * @param {{itemAdded: Observable, itemChanged: Observable, itemRemoved: Observable}} observables - * the observables for entity changes + * the observables for entity change * @param {SubscriptionObject} subscription the wrapped subscription object */ constructor({ From f0078324f829befcecaa8a78944c9af608ba74dd Mon Sep 17 00:00:00 2001 From: Alex Tymchenko Date: Fri, 13 Jan 2023 15:52:56 +0000 Subject: [PATCH 04/20] Introduce an API to cancel all active subscriptions. --- client-js/main/client/client.js | 10 ++++++++++ client-js/main/client/composite-client.js | 7 +++++++ client-js/main/client/firebase-client.js | 7 +++++++ .../main/client/firebase-subscription-service.js | 15 +++++++++++++++ client-js/main/client/subscribing-client.js | 16 ++++++++++++++++ 5 files changed, 55 insertions(+) diff --git a/client-js/main/client/client.js b/client-js/main/client/client.js index b027346f..53506fde 100644 --- a/client-js/main/client/client.js +++ b/client-js/main/client/client.js @@ -183,6 +183,16 @@ export class Client { throw new Error('Not implemented in abstract base.'); } + /** + * Immediately cancels all active subscriptions. + * + * This endpoint is handy to use when an end-user chooses to end her session + * with the web app. E.g. all subscriptions should be cancelled upon user sign-out. + */ + cancelAllSubscriptions() { + throw new Error('Not implemented in abstract base.'); + } + /** * Subscribes to the given `Topic` instance. * diff --git a/client-js/main/client/composite-client.js b/client-js/main/client/composite-client.js index bb219155..8de05fb2 100644 --- a/client-js/main/client/composite-client.js +++ b/client-js/main/client/composite-client.js @@ -90,6 +90,13 @@ export class CompositeClient extends Client { return this._subscribing.subscribeTo(entityType, this); } + /** + * @override + */ + cancelAllSubscriptions() { + this._subscribing.cancelAllSubscriptions(); + } + /** * @override */ diff --git a/client-js/main/client/firebase-client.js b/client-js/main/client/firebase-client.js index b4574cea..f7782ca0 100644 --- a/client-js/main/client/firebase-client.js +++ b/client-js/main/client/firebase-client.js @@ -268,6 +268,13 @@ class FirebaseSubscribingClient extends SubscribingClient { }); } + /** + * @override + */ + cancelAllSubscriptions() { + this._subscriptionService.cancelAllSubscriptions(); + } + /** * Unsubscribes the provided Firebase subscriptions. * diff --git a/client-js/main/client/firebase-subscription-service.js b/client-js/main/client/firebase-subscription-service.js index 44b80c66..f6c83e14 100644 --- a/client-js/main/client/firebase-subscription-service.js +++ b/client-js/main/client/firebase-subscription-service.js @@ -84,6 +84,21 @@ export class FirebaseSubscriptionService { } } + /** + * Immediately cancels all active subscriptions previously created through this service. + */ + cancelAllSubscriptions() { + const activeSubscriptions = this._subscriptions.filter(s => !s.closed); + if (activeSubscriptions.length > 0) { + const subscriptionMessages = activeSubscriptions.map(s => s.internal()) + this._endpoint.cancelAll(subscriptionMessages); + activeSubscriptions.forEach(s => { + s.unsubscribe() /* Calling RxJS's `unsubscribe` to stop propagating the updates. */ + this._removeSubscription(s) + }) + } + } + /** * Indicates whether this service is running keeping up subscriptions. * diff --git a/client-js/main/client/subscribing-client.js b/client-js/main/client/subscribing-client.js index 62d5856d..6ad02d71 100644 --- a/client-js/main/client/subscribing-client.js +++ b/client-js/main/client/subscribing-client.js @@ -85,6 +85,13 @@ export class SubscribingClient { throw new Error('Not implemented in abstract base.'); } + /** + * Cancels all subscriptions, which were created through this instance of subscribing client. + */ + cancelAllSubscriptions() { + throw new Error('Not implemented in abstract base.'); + } + /** * Returns a new topic factory instance which can be further used for the `Topic` creation. * @@ -123,4 +130,13 @@ export class NoOpSubscribingClient extends SubscribingClient { subscribeToEvents(topic) { throw new Error(SUBSCRIPTIONS_NOT_SUPPORTED); } + + /** + * Always throws an error. + * + * @override + */ + cancelAllSubscriptions() { + throw new Error(SUBSCRIPTIONS_NOT_SUPPORTED); + } } From ed5bab51558282761156887429d2cafbf5145306 Mon Sep 17 00:00:00 2001 From: Alex Tymchenko Date: Fri, 13 Jan 2023 15:53:19 +0000 Subject: [PATCH 05/20] Update the reports and `package.json`. --- client-js/package.json | 2 +- integration-tests/js-tests/package.json | 2 +- license-report.md | 32 ++++++++++++------------- pom.xml | 2 +- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/client-js/package.json b/client-js/package.json index 8d5ff85f..73446ec2 100644 --- a/client-js/package.json +++ b/client-js/package.json @@ -1,6 +1,6 @@ { "name": "spine-web", - "version": "1.9.0-SNAPSHOT.9", + "version": "1.9.0-SNAPSHOT.10", "license": "Apache-2.0", "description": "A JS client for interacting with Spine applications.", "homepage": "https://spine.io", diff --git a/integration-tests/js-tests/package.json b/integration-tests/js-tests/package.json index 8143d89e..b43dd0c1 100644 --- a/integration-tests/js-tests/package.json +++ b/integration-tests/js-tests/package.json @@ -1,6 +1,6 @@ { "name": "client-js-tests", - "version": "1.9.0-SNAPSHOT.9", + "version": "1.9.0-SNAPSHOT.10", "license": "Apache-2.0", "description": "Tests of a `spine-web` JS library against the Spine-based application.", "scripts": { diff --git a/license-report.md b/license-report.md index 324379a7..b5b6cfb0 100644 --- a/license-report.md +++ b/license-report.md @@ -1,6 +1,6 @@ -# Dependencies of `io.spine:spine-client-js:1.9.0-SNAPSHOT.9` +# Dependencies of `io.spine:spine-client-js:1.9.0-SNAPSHOT.10` ## Runtime 1. **Group:** com.google.code.findbugs **Name:** jsr305 **Version:** 3.0.2 @@ -368,10 +368,10 @@ The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Jan 12 13:42:53 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Fri Jan 13 13:41:27 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -#NPM dependencies of `spine-web@1.9.0-SNAPSHOT.9` +#NPM dependencies of `spine-web@1.9.0-SNAPSHOT.10` ## `Production` dependencies: @@ -405,7 +405,7 @@ This report was generated on **Thu Jan 12 13:42:53 WET 2023** using [Gradle-Lice 1. **rxjs@6.5.5** * Licenses: Apache-2.0 * Repository: [https://github.com/reactivex/rxjs](https://github.com/reactivex/rxjs) -1. **spine-web@1.9.0-SNAPSHOT.9** +1. **spine-web@1.9.0-SNAPSHOT.10** * Licenses: Apache-2.0 * Repository: [https://github.com/SpineEventEngine/web](https://github.com/SpineEventEngine/web) 1. **tr46@0.0.3** @@ -1958,7 +1958,7 @@ This report was generated on **Thu Jan 12 13:42:53 WET 2023** using [Gradle-Lice 1. **spdx-satisfies@4.0.1** * Licenses: MIT * Repository: [https://github.com/kemitchell/spdx-satisfies.js](https://github.com/kemitchell/spdx-satisfies.js) -1. **spine-web@1.9.0-SNAPSHOT.9** +1. **spine-web@1.9.0-SNAPSHOT.10** * Licenses: Apache-2.0 * Repository: [https://github.com/SpineEventEngine/web](https://github.com/SpineEventEngine/web) 1. **sprintf-js@1.0.3** @@ -2140,12 +2140,12 @@ This report was generated on **Thu Jan 12 13:42:53 WET 2023** using [Gradle-Lice * Repository: [https://github.com/sindresorhus/yocto-queue](https://github.com/sindresorhus/yocto-queue) -This report was generated on **Thu Jan 12 2023 13:42:54 GMT+0000 (Western European Standard Time)** using [NPM License Checker](https://github.com/davglass/license-checker) library. +This report was generated on **Fri Jan 13 2023 13:41:28 GMT+0000 (Western European Standard Time)** using [NPM License Checker](https://github.com/davglass/license-checker) library. -# Dependencies of `io.spine.gcloud:spine-firebase-web:1.9.0-SNAPSHOT.9` +# Dependencies of `io.spine.gcloud:spine-firebase-web:1.9.0-SNAPSHOT.10` ## Runtime 1. **Group:** com.fasterxml.jackson.core **Name:** jackson-annotations **Version:** 2.9.10 @@ -2932,12 +2932,12 @@ This report was generated on **Thu Jan 12 2023 13:42:54 GMT+0000 (Western Europe The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Jan 12 13:42:59 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Fri Jan 13 13:41:35 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine:spine-js-tests:1.9.0-SNAPSHOT.9` +# Dependencies of `io.spine:spine-js-tests:1.9.0-SNAPSHOT.10` ## Runtime 1. **Group:** com.google.code.findbugs **Name:** jsr305 **Version:** 3.0.2 @@ -3327,12 +3327,12 @@ This report was generated on **Thu Jan 12 13:42:59 WET 2023** using [Gradle-Lice The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Jan 12 13:43:04 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Fri Jan 13 13:41:40 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine:spine-test-app:1.9.0-SNAPSHOT.9` +# Dependencies of `io.spine:spine-test-app:1.9.0-SNAPSHOT.10` ## Runtime 1. **Group:** com.fasterxml.jackson.core **Name:** jackson-annotations **Version:** 2.9.10 @@ -4906,12 +4906,12 @@ This report was generated on **Thu Jan 12 13:43:04 WET 2023** using [Gradle-Lice The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Jan 12 13:43:06 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Fri Jan 13 13:41:43 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine:spine-testutil-web:1.9.0-SNAPSHOT.9` +# Dependencies of `io.spine:spine-testutil-web:1.9.0-SNAPSHOT.10` ## Runtime 1. **Group:** com.google.android **Name:** annotations **Version:** 4.1.1.4 @@ -5370,12 +5370,12 @@ This report was generated on **Thu Jan 12 13:43:06 WET 2023** using [Gradle-Lice The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Jan 12 13:43:08 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Fri Jan 13 13:41:45 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine:spine-web:1.9.0-SNAPSHOT.9` +# Dependencies of `io.spine:spine-web:1.9.0-SNAPSHOT.10` ## Runtime 1. **Group:** com.google.android **Name:** annotations **Version:** 4.1.1.4 @@ -5873,4 +5873,4 @@ This report was generated on **Thu Jan 12 13:43:08 WET 2023** using [Gradle-Lice The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Thu Jan 12 13:43:11 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file +This report was generated on **Fri Jan 13 13:41:48 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file diff --git a/pom.xml b/pom.xml index 40a93f8e..52255002 100644 --- a/pom.xml +++ b/pom.xml @@ -12,7 +12,7 @@ all modules and does not describe the project structure per-subproject. io.spine spine-web -1.9.0-SNAPSHOT.9 +1.9.0-SNAPSHOT.10 2015 From b53d9d7decf96be9debc9069eebd6f7b4ebb8e9c Mon Sep 17 00:00:00 2001 From: Alex Tymchenko Date: Mon, 16 Jan 2023 17:39:27 +0000 Subject: [PATCH 06/20] Fix wording. --- integration-tests/js-tests/test/test-helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/js-tests/test/test-helpers.js b/integration-tests/js-tests/test/test-helpers.js index f92e9e2d..803a5bef 100644 --- a/integration-tests/js-tests/test/test-helpers.js +++ b/integration-tests/js-tests/test/test-helpers.js @@ -139,7 +139,7 @@ function arraysEqualDeep(arr1, arr2, compare) { * @param {EntitySubscriptionObject} subscription a subscription to retrieve values * @param {(o1: T, o2: T) => boolean} compare a function that compares objects of `T` type; * returns `true` if objects are considered equal, `false` otherwise - * @return {Observable} an observable that emits a list of values, composed from the given + * @return {Observable} an observable that emits a list of values, composed of the given * subscription object * * @template a class of a subscription target entities From f374c80d5dc5ef9815245d23ab053a5cbe241b02 Mon Sep 17 00:00:00 2001 From: Alex Tymchenko Date: Tue, 17 Jan 2023 13:50:26 +0000 Subject: [PATCH 07/20] Test cancelling all known subscriptions. --- .../test/firebase-client/subscribe-test.js | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/integration-tests/js-tests/test/firebase-client/subscribe-test.js b/integration-tests/js-tests/test/firebase-client/subscribe-test.js index eb566942..f0406f76 100644 --- a/integration-tests/js-tests/test/firebase-client/subscribe-test.js +++ b/integration-tests/js-tests/test/firebase-client/subscribe-test.js @@ -221,6 +221,120 @@ describe('FirebaseClient subscription', function () { .catch(fail(done)); }); + /** + * This test creates two tasks, one after another, and then creates two subscriptions + * to changes of the created tasks. Prior to sending the renaming commands, + * the test code cancels all known subscriptions, and verifies that no `itemChanged` + * promises are resolved when the renaming commands are sent. + */ + it('may be cancelled along with all other subscriptions in a bulk', done => { + const prefix = 'spine-web-test-bulk-cancellation'; + const createFirst = TestEnvironment.createTaskCommand({ + withPrefix: prefix, + named: "first task" + }); + const createSecond = TestEnvironment.createTaskCommand({ + withPrefix: prefix, + named: "second task" + }); + + const firstId = createFirst.getId(); + const secondId = createSecond.getId(); + + function createFirstTask() { + client.command(createFirst) + .onOk(() => console.log(`1st task '${firstId.getValue()}' created.`)) + .onError(fail(done, 'Unexpected error while creating the 1st task.')) + .onImmediateRejection(fail(done, + 'Unexpected rejection while creating the 1st task.')) + .post(); + } + + function createSecondTask() { + client.command(createSecond) + .onOk(() => console.log(`2nd task '${secondId.getValue()}' created.`)) + .onError(fail(done, 'Unexpected error while creating the 2nd task.')) + .onImmediateRejection(fail(done, + 'Unexpected rejection while creating the 2nd task.')) + .post(); + } + + function renameFirstTask() { + const renameFirst = TestEnvironment.renameTaskCommand({ + withId: firstId.getValue(), + to: "first updated" + }); + + client.command(renameFirst) + .onOk(() => console.log(`1st task '${firstId.getValue()}' was renamed.`)) + .onError(fail(done, 'Unexpected error while renaming the 1st task.')) + .onImmediateRejection(fail(done, + 'Unexpected rejection while renaming the 1st task.')) + .post(); + } + + function renameSecondTask() { + const renameSecond = TestEnvironment.renameTaskCommand({ + withId: secondId.getValue(), + to: "second updated" + }); + client.command(renameSecond) + .onOk(() => console.log(`2nd task '${secondId.getValue()}' was renamed.`)) + .onError(fail(done, 'Unexpected error while renaming the 2nd task.')) + .onImmediateRejection(fail(done, + 'Unexpected rejection while renaming the 2nd task.')) + .post(); + } + + client.subscribeTo(Task) + .byId(firstId) + .post() + .then(({itemAdded, itemChanged, itemRemoved, unsubscribe}) => { + itemAdded.subscribe({ + next: () => { + createSecondTask(); + } + }); + itemChanged.subscribe({ + next: () => { fail(done, 'Unexpected 1st task change received, ' + + 'while the corresponding subscription had to be cancelled by now.'); } + }); + + client.subscribeTo(Task) + .byId(secondId) + .post() + .then(({itemAdded, itemChanged, itemRemoved, unsubscribe}) => { + itemChanged.subscribe({ + next: () => { fail(done, 'Unexpected 2nd task change received, ' + + 'while the corresponding subscription had to be cancelled by now.'); } + }); + itemAdded.subscribe({ + next: async () => { + client.cancelAllSubscriptions(); + renameFirstTask(); + renameSecondTask(); + + await oneHundredMs(); + + done(); + } + }); + }) + }) + .catch(fail(done)); + createFirstTask(); + }); + + /** + * Returns a promise to be resolved after 100 ms. + * + * @returns {Promise} + */ + function oneHundredMs() { + return new Promise(resolve => + setTimeout(() => resolve(), 100)) + } + it('is notified when the entity no longer matches the subscription criteria', done => { const initialTaskName = 'Initial task name'; const nameAfterRenamed = 'Renamed task'; From b25ca7c23df115a9343f0f7c5f46112bd1f13234 Mon Sep 17 00:00:00 2001 From: Alex Tymchenko Date: Tue, 17 Jan 2023 15:52:14 +0000 Subject: [PATCH 08/20] Fix a typo. --- .../spine/web/firebase/subscription/SubscriptionRepository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firebase-web/src/main/java/io/spine/web/firebase/subscription/SubscriptionRepository.java b/firebase-web/src/main/java/io/spine/web/firebase/subscription/SubscriptionRepository.java index 32eee4e9..3500683b 100644 --- a/firebase-web/src/main/java/io/spine/web/firebase/subscription/SubscriptionRepository.java +++ b/firebase-web/src/main/java/io/spine/web/firebase/subscription/SubscriptionRepository.java @@ -81,7 +81,7 @@ final class SubscriptionRepository { /** * Fetches all the existing subscriptions from the Firebase and activates them. * - *

After calling this method, all the new subscriptions are automatically activates on this + *

After calling this method, all the new subscriptions are automatically activated on this * server instance. */ void subscribeToAll() { From 1a3261c8fc88f95eefa45b9deea547122c250411 Mon Sep 17 00:00:00 2001 From: Alex Tymchenko Date: Wed, 18 Jan 2023 17:52:21 +0000 Subject: [PATCH 09/20] Allow to cancel subscriptions immediately (in progress). --- client-js/main/client/firebase-client.js | 9 +++++++++ .../main/client/firebase-subscription-service.js | 11 +++++++++++ 2 files changed, 20 insertions(+) diff --git a/client-js/main/client/firebase-client.js b/client-js/main/client/firebase-client.js index f7782ca0..b308ea2d 100644 --- a/client-js/main/client/firebase-client.js +++ b/client-js/main/client/firebase-client.js @@ -242,6 +242,15 @@ class FirebaseSubscribingClient extends SubscribingClient { return new EntitySubscription({ unsubscribedBy: () => { FirebaseSubscribingClient._unsubscribe(pathSubscriptions); + // TODO:alex.tymchenko:2023-01-17: find out how to report `Promise` errors, and where. + this._subscriptionService.cancelSubscription(subscription) + .then( + (result) => { + console.log("Subscription successfully cancelled: " + JSON.stringify(result)) + }, + () => console.warn("Error sending the subscription" + + " cancellation request to the server-side.") + ); }, withObservables: { itemAdded: ObjectToProto.map(itemAdded.asObservable(), typeUrl), diff --git a/client-js/main/client/firebase-subscription-service.js b/client-js/main/client/firebase-subscription-service.js index f6c83e14..3ea7261b 100644 --- a/client-js/main/client/firebase-subscription-service.js +++ b/client-js/main/client/firebase-subscription-service.js @@ -99,6 +99,17 @@ export class FirebaseSubscriptionService { } } + /** + * Immediately cancels the given subscription, including cancelling it on the server-side. + * + * @param {SubscriptionObject} subscription the subscription to cancel + * @return {Promise} a promise of a successful server response, rejected if + * an error occurs + */ + cancelSubscription(subscription) { + return this._endpoint.cancelSubscription(subscription); + } + /** * Indicates whether this service is running keeping up subscriptions. * From e633640c74ae2041557aaed36be8f481d2585a1c Mon Sep 17 00:00:00 2001 From: Alex Tymchenko Date: Thu, 26 Jan 2023 14:29:41 +0000 Subject: [PATCH 10/20] Fix the Javadoc syntax problem. --- .../main/java/io/spine/web/firebase/subscription/HealthLog.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firebase-web/src/main/java/io/spine/web/firebase/subscription/HealthLog.java b/firebase-web/src/main/java/io/spine/web/firebase/subscription/HealthLog.java index 458a33b8..f97ce73c 100644 --- a/firebase-web/src/main/java/io/spine/web/firebase/subscription/HealthLog.java +++ b/firebase-web/src/main/java/io/spine/web/firebase/subscription/HealthLog.java @@ -47,7 +47,7 @@ *

To understand whether a client is still listening to the {@code Topic} updates, she * periodically sends a {@link FirebaseSubscriptionBridge#keepUp(Subscription) keepUp(Subscription)} * request. The server records the timestamps of these requests in this log and counts the client - * alive, as long as the {@linkplain #withTimeout(Duration)} configured} timeout does not pass + * alive, as long as the {@linkplain #withTimeout(Duration) configured} timeout does not pass * since the last request. */ final class HealthLog { From 23cb5bb494c6c56d55eccd8234fc55b2de5ea48a Mon Sep 17 00:00:00 2001 From: Alex Tymchenko Date: Thu, 26 Jan 2023 14:43:19 +0000 Subject: [PATCH 11/20] Remove the topic from the `HealthLog` upon cancellation. --- .../io/spine/web/firebase/subscription/HealthLog.java | 11 +++++++++++ .../firebase/subscription/SubscriptionRepository.java | 1 + 2 files changed, 12 insertions(+) diff --git a/firebase-web/src/main/java/io/spine/web/firebase/subscription/HealthLog.java b/firebase-web/src/main/java/io/spine/web/firebase/subscription/HealthLog.java index f97ce73c..b8d1129f 100644 --- a/firebase-web/src/main/java/io/spine/web/firebase/subscription/HealthLog.java +++ b/firebase-web/src/main/java/io/spine/web/firebase/subscription/HealthLog.java @@ -113,4 +113,15 @@ boolean isStale(Topic topic) { Duration elapsed = between(lastUpdate, now); return compare(elapsed, expirationTimeout) > 0; } + + /** + * Removes the given {@code Topic} from this health log. + * + *

In case this topic is not known to this registry, does nothing, allowing + * to safely clear the health log from stale topics potentially residing in storage + * on either client- or server-sides. + */ + void remove(Topic topic) { + updateTimes.remove(topic.getId()); + } } diff --git a/firebase-web/src/main/java/io/spine/web/firebase/subscription/SubscriptionRepository.java b/firebase-web/src/main/java/io/spine/web/firebase/subscription/SubscriptionRepository.java index 3500683b..25e23499 100644 --- a/firebase-web/src/main/java/io/spine/web/firebase/subscription/SubscriptionRepository.java +++ b/firebase-web/src/main/java/io/spine/web/firebase/subscription/SubscriptionRepository.java @@ -152,6 +152,7 @@ private void delete(Topic topic) { checkNotNull(topic); NodePath path = pathForSubscription(topic); firebase.delete(path); + healthLog.remove(topic); } private static NodePath pathForSubscription(Topic topic) { From 48040c37ae82ab4b8279a695b5b991ede426e216 Mon Sep 17 00:00:00 2001 From: Alex Tymchenko Date: Fri, 27 Jan 2023 16:41:01 +0000 Subject: [PATCH 12/20] Remove the topic from the repository if the corresponding node is removed at Firebase RDB side. --- .../web/firebase/subscription/SubscriptionRepository.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/firebase-web/src/main/java/io/spine/web/firebase/subscription/SubscriptionRepository.java b/firebase-web/src/main/java/io/spine/web/firebase/subscription/SubscriptionRepository.java index 25e23499..62896176 100644 --- a/firebase-web/src/main/java/io/spine/web/firebase/subscription/SubscriptionRepository.java +++ b/firebase-web/src/main/java/io/spine/web/firebase/subscription/SubscriptionRepository.java @@ -217,7 +217,12 @@ private void deleteOrActivate(Topic topic) { @Override public void onChildRemoved(DataSnapshot snapshot) { - // NOP. + String json = asJson(snapshot); + Topic topic = loadTopic(json); + HealthLog healthLog = repository.healthLog; + if (healthLog.isKnown(topic)) { + repository.delete(topic); + } } @Override From 5bc0c07657ec94a1ba5ead2293e1656fc7013bf0 Mon Sep 17 00:00:00 2001 From: Alex Tymchenko Date: Fri, 27 Jan 2023 17:46:09 +0000 Subject: [PATCH 13/20] Parse the `Topic` instance safely. --- .../subscription/SubscriptionRepository.java | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/firebase-web/src/main/java/io/spine/web/firebase/subscription/SubscriptionRepository.java b/firebase-web/src/main/java/io/spine/web/firebase/subscription/SubscriptionRepository.java index 62896176..48c1c471 100644 --- a/firebase-web/src/main/java/io/spine/web/firebase/subscription/SubscriptionRepository.java +++ b/firebase-web/src/main/java/io/spine/web/firebase/subscription/SubscriptionRepository.java @@ -34,7 +34,6 @@ import com.google.protobuf.Duration; import io.spine.client.Subscription; import io.spine.client.Topic; -import io.spine.json.Json; import io.spine.web.firebase.FirebaseClient; import io.spine.web.firebase.NodePath; import io.spine.web.firebase.NodePaths; @@ -44,6 +43,7 @@ import java.util.Optional; import static com.google.common.base.Preconditions.checkNotNull; +import static io.spine.json.Json.fromJson; import static io.spine.util.Exceptions.illegalStateWithCauseOf; import static io.spine.web.firebase.subscription.LazyRepository.lazy; @@ -201,7 +201,7 @@ private static String asJson(DataSnapshot snapshot) { } private Topic loadTopic(String json) { - Topic topic = Json.fromJson(json, Topic.class); + Topic topic = fromJson(json, Topic.class); repository.healthLog.put(topic); return topic; } @@ -218,10 +218,29 @@ private void deleteOrActivate(Topic topic) { @Override public void onChildRemoved(DataSnapshot snapshot) { String json = asJson(snapshot); - Topic topic = loadTopic(json); - HealthLog healthLog = repository.healthLog; - if (healthLog.isKnown(topic)) { - repository.delete(topic); + Optional topic = parseTopic(json); + topic.ifPresent(t -> { + HealthLog healthLog = repository.healthLog; + if (healthLog.isKnown(t)) { + repository.delete(t); + } + }); + } + + /** + * Safely parses the {@code Topic} from the passed JSON. + * + * @param json + * JSON to parse + * @return parsed {@code Topic} wrapped as {@code Optional}, + * or {@code Optional.empty()} if there was a parsing error + */ + private static Optional parseTopic(String json) { + try { + Topic topic = fromJson(json, Topic.class); + return Optional.of(topic); + } catch (RuntimeException e) { + return Optional.empty(); } } From ace9b9d6f71cff0c676712aaf3ad1e77ddd5dbea Mon Sep 17 00:00:00 2001 From: Alex Tymchenko Date: Fri, 27 Jan 2023 17:46:27 +0000 Subject: [PATCH 14/20] Improve the docs. --- .../main/java/io/spine/web/firebase/FirebaseCredentials.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/firebase-web/src/main/java/io/spine/web/firebase/FirebaseCredentials.java b/firebase-web/src/main/java/io/spine/web/firebase/FirebaseCredentials.java index bbec849e..c00292a7 100644 --- a/firebase-web/src/main/java/io/spine/web/firebase/FirebaseCredentials.java +++ b/firebase-web/src/main/java/io/spine/web/firebase/FirebaseCredentials.java @@ -50,8 +50,7 @@ * *

See Firebase REST docs. */ -@SuppressWarnings("deprecation") -// Use deprecated `GoogleCredential` to retain backward compatibility. +@SuppressWarnings("deprecation" /*`GoogleCredential` is used to retain backward compatibility.*/) public final class FirebaseCredentials implements HttpRequestInitializer { private static final String AUTH_DATABASE = "https://www.googleapis.com/auth/firebase.database"; From 42c0be055a3ce4f8118a89191bca4139b4aa9197 Mon Sep 17 00:00:00 2001 From: Alex Tymchenko Date: Fri, 27 Jan 2023 17:48:08 +0000 Subject: [PATCH 15/20] Improve cancelling subscriptions by removing them from the list of known subscriptions. Remove debug logging as well. --- client-js/main/client/firebase-client.js | 27 +++++++++++-------- .../client/firebase-subscription-service.js | 7 ++--- .../test/firebase-client/subscribe-test.js | 10 +++---- 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/client-js/main/client/firebase-client.js b/client-js/main/client/firebase-client.js index b308ea2d..af8071c8 100644 --- a/client-js/main/client/firebase-client.js +++ b/client-js/main/client/firebase-client.js @@ -101,7 +101,13 @@ class EntitySubscription extends SpineSubscription { * @return {EntitySubscriptionObject} a plain object with observables and unsubscribe method */ toObject() { - return Object.assign({}, this._observables, {unsubscribe: () => this.unsubscribe()}); + return Object.assign({}, + this._observables, + { + unsubscribe: () => { + return this.unsubscribe(); + } + }); } } @@ -129,7 +135,13 @@ class EventSubscription extends SpineSubscription { */ toObject() { return Object.assign( - {}, {eventEmitted: this._observable}, {unsubscribe: () => this.unsubscribe()} + {}, + {eventEmitted: this._observable}, + { + unsubscribe: () => { + return this.unsubscribe(); + } + } ); } } @@ -242,15 +254,7 @@ class FirebaseSubscribingClient extends SubscribingClient { return new EntitySubscription({ unsubscribedBy: () => { FirebaseSubscribingClient._unsubscribe(pathSubscriptions); - // TODO:alex.tymchenko:2023-01-17: find out how to report `Promise` errors, and where. - this._subscriptionService.cancelSubscription(subscription) - .then( - (result) => { - console.log("Subscription successfully cancelled: " + JSON.stringify(result)) - }, - () => console.warn("Error sending the subscription" + - " cancellation request to the server-side.") - ); + this._subscriptionService.cancelSubscription(subscription); }, withObservables: { itemAdded: ObjectToProto.map(itemAdded.asObservable(), typeUrl), @@ -271,6 +275,7 @@ class FirebaseSubscribingClient extends SubscribingClient { return new EventSubscription({ unsubscribedBy: () => { FirebaseSubscribingClient._unsubscribe([pathSubscription]); + return this._subscriptionService.cancelSubscription(subscription); }, withObservable: ObjectToProto.map(itemAdded.asObservable(), EVENT_TYPE_URL), forInternal: subscription diff --git a/client-js/main/client/firebase-subscription-service.js b/client-js/main/client/firebase-subscription-service.js index 3ea7261b..f789fdc0 100644 --- a/client-js/main/client/firebase-subscription-service.js +++ b/client-js/main/client/firebase-subscription-service.js @@ -103,11 +103,12 @@ export class FirebaseSubscriptionService { * Immediately cancels the given subscription, including cancelling it on the server-side. * * @param {SubscriptionObject} subscription the subscription to cancel - * @return {Promise} a promise of a successful server response, rejected if - * an error occurs */ cancelSubscription(subscription) { - return this._endpoint.cancelSubscription(subscription); + this._endpoint.cancelSubscription(subscription) + .then(() => { + this._removeSubscription(subscription) + }); } /** diff --git a/integration-tests/js-tests/test/firebase-client/subscribe-test.js b/integration-tests/js-tests/test/firebase-client/subscribe-test.js index f0406f76..82f2fd20 100644 --- a/integration-tests/js-tests/test/firebase-client/subscribe-test.js +++ b/integration-tests/js-tests/test/firebase-client/subscribe-test.js @@ -539,15 +539,13 @@ describe('FirebaseClient subscription', function () { }); }); - it('and canceled on the next keep up interval if unsubscribed', done => { + it('and cancel subscription immediately if unsubscribed', done => { const cancelEndpoint = cancelEndpointSpy(); - subscribeToAllTasks().then(async ({itemAdded, itemChanged, itemRemoved, unsubscribe}) => { assert.ok(cancelEndpoint.notCalled); unsubscribe(); - await nextInterval(); assert.ok(cancelEndpoint.calledOnce); - const subscriptionMessage = cancelEndpoint.getCall(0).args[0][0]; + const subscriptionMessage = cancelEndpoint.getCall(0).args[0]; checkAllTasks(subscriptionMessage); done(); }); @@ -564,10 +562,10 @@ describe('FirebaseClient subscription', function () { assert.ok(keepUpEndpoint.calledOnce); assert.ok(cancelEndpoint.notCalled); unsubscribe(); + assert.ok(cancelEndpoint.calledOnce); await nextInterval(); assert.ok(keepUpEndpoint.calledOnce); - assert.ok(cancelEndpoint.calledOnce); await nextInterval(); assert.ok(keepUpEndpoint.calledOnce); @@ -618,7 +616,7 @@ describe('FirebaseClient subscription', function () { function cancelEndpointSpy() { const httpEndpoint = client._subscribing._endpoint; - return sandbox.spy(httpEndpoint, 'cancelAll'); + return sandbox.spy(httpEndpoint, 'cancelSubscription'); } /** From 28fd794d047df62bff8f257a306ca29feba490ce Mon Sep 17 00:00:00 2001 From: Alex Tymchenko Date: Fri, 27 Jan 2023 17:48:23 +0000 Subject: [PATCH 16/20] Update the reports. --- license-report.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/license-report.md b/license-report.md index b5b6cfb0..ab2ceed5 100644 --- a/license-report.md +++ b/license-report.md @@ -368,7 +368,7 @@ The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri Jan 13 13:41:27 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Fri Jan 27 17:43:52 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). #NPM dependencies of `spine-web@1.9.0-SNAPSHOT.10` @@ -2140,7 +2140,7 @@ This report was generated on **Fri Jan 13 13:41:27 WET 2023** using [Gradle-Lice * Repository: [https://github.com/sindresorhus/yocto-queue](https://github.com/sindresorhus/yocto-queue) -This report was generated on **Fri Jan 13 2023 13:41:28 GMT+0000 (Western European Standard Time)** using [NPM License Checker](https://github.com/davglass/license-checker) library. +This report was generated on **Fri Jan 27 2023 17:43:53 GMT+0000 (Western European Standard Time)** using [NPM License Checker](https://github.com/davglass/license-checker) library. @@ -2932,7 +2932,7 @@ This report was generated on **Fri Jan 13 2023 13:41:28 GMT+0000 (Western Europe The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri Jan 13 13:41:35 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Fri Jan 27 17:43:59 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -3327,7 +3327,7 @@ This report was generated on **Fri Jan 13 13:41:35 WET 2023** using [Gradle-Lice The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri Jan 13 13:41:40 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Fri Jan 27 17:44:03 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -4906,7 +4906,7 @@ This report was generated on **Fri Jan 13 13:41:40 WET 2023** using [Gradle-Lice The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri Jan 13 13:41:43 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Fri Jan 27 17:44:05 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -5370,7 +5370,7 @@ This report was generated on **Fri Jan 13 13:41:43 WET 2023** using [Gradle-Lice The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri Jan 13 13:41:45 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Fri Jan 27 17:44:07 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). @@ -5873,4 +5873,4 @@ This report was generated on **Fri Jan 13 13:41:45 WET 2023** using [Gradle-Lice The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri Jan 13 13:41:48 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file +This report was generated on **Fri Jan 27 17:44:10 WET 2023** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file From 1c184ab8764e019473563c561a7c2e34a7be7208 Mon Sep 17 00:00:00 2001 From: Alex Tymchenko Date: Mon, 30 Jan 2023 12:01:37 +0000 Subject: [PATCH 17/20] Improve the documentation and error messages. --- .../subscription/FirebaseSubscriptionBridge.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/firebase-web/src/main/java/io/spine/web/firebase/subscription/FirebaseSubscriptionBridge.java b/firebase-web/src/main/java/io/spine/web/firebase/subscription/FirebaseSubscriptionBridge.java index 56eaac34..83f06c12 100644 --- a/firebase-web/src/main/java/io/spine/web/firebase/subscription/FirebaseSubscriptionBridge.java +++ b/firebase-web/src/main/java/io/spine/web/firebase/subscription/FirebaseSubscriptionBridge.java @@ -209,13 +209,18 @@ public Builder setSubscriptionLifeSpan(Duration subscriptionLifeSpan) { /** * Creates a new instance of {@code FirebaseQueryBridge}. * + *

Mandatory fields are {@link #setFirebaseClient(FirebaseClient) firebaseClient} + * and {@link #setSubscriptionService(SubscriptionServiceImplBase) subscriptionService}. + * * @return new instance of {@code FirebaseQueryBridge} */ public FirebaseSubscriptionBridge build() { checkState(firebaseClient != null, - "Firebase database client is not set to FirebaseSubscriptionBridge."); + "Mandatory Firebase database client" + + " is not specified for `FirebaseSubscriptionBridge`."); checkState(subscriptionService != null, - "Subscription Service is not set to FirebaseSubscriptionBridge."); + "Mandatory Subscription Service is not specified" + + " for `FirebaseSubscriptionBridge`."); return new FirebaseSubscriptionBridge(this); } } From bd1f9590c052a2b7c8a31a2f7ee0fa697feec5b4 Mon Sep 17 00:00:00 2001 From: Alex Tymchenko Date: Mon, 30 Jan 2023 14:15:25 +0000 Subject: [PATCH 18/20] Remove the outdated `return` statement. --- client-js/main/client/firebase-client.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client-js/main/client/firebase-client.js b/client-js/main/client/firebase-client.js index af8071c8..b1c0df0a 100644 --- a/client-js/main/client/firebase-client.js +++ b/client-js/main/client/firebase-client.js @@ -275,7 +275,7 @@ class FirebaseSubscribingClient extends SubscribingClient { return new EventSubscription({ unsubscribedBy: () => { FirebaseSubscribingClient._unsubscribe([pathSubscription]); - return this._subscriptionService.cancelSubscription(subscription); + this._subscriptionService.cancelSubscription(subscription); }, withObservable: ObjectToProto.map(itemAdded.asObservable(), EVENT_TYPE_URL), forInternal: subscription From 951bcd2bae9f5d33c415f148e6b7f84a46796f1b Mon Sep 17 00:00:00 2001 From: Alex Tymchenko Date: Mon, 30 Jan 2023 14:35:30 +0000 Subject: [PATCH 19/20] Improve the formatting of error message. --- .../spine/web/subscription/BlockingSubscriptionService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/src/main/java/io/spine/web/subscription/BlockingSubscriptionService.java b/web/src/main/java/io/spine/web/subscription/BlockingSubscriptionService.java index 9eb8df91..57da98f6 100644 --- a/web/src/main/java/io/spine/web/subscription/BlockingSubscriptionService.java +++ b/web/src/main/java/io/spine/web/subscription/BlockingSubscriptionService.java @@ -94,8 +94,8 @@ private void checkObserver(MemoizingObserver observer) { throw illegalStateWithCauseOf(error); } else { checkState(observer.isCompleted(), - "Provided SubscriptionService implementation (`%s`) must complete `%s`" + - " procedure at once.", + "Provided `SubscriptionService` implementation (`%s`)" + + " must complete `%s` procedure at once.", subscriptionService, SUBSCRIBE_METHOD_NAME); } From f75bd3af55241f531dafbc7be8722107b7e76756 Mon Sep 17 00:00:00 2001 From: Alex Tymchenko Date: Mon, 30 Jan 2023 15:37:57 +0000 Subject: [PATCH 20/20] Cancel the subscriptions of both `SpineSubscription` and Proto `Subscription` types by using their IDs. Improve the formatting of type-level docs. --- .../client/firebase-subscription-service.js | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/client-js/main/client/firebase-subscription-service.js b/client-js/main/client/firebase-subscription-service.js index f789fdc0..19ea4d89 100644 --- a/client-js/main/client/firebase-subscription-service.js +++ b/client-js/main/client/firebase-subscription-service.js @@ -38,8 +38,8 @@ import {Status} from '../proto/spine/core/response_pb'; const DEFAULT_KEEP_UP_INTERVAL = new Duration({minutes: 2}); /** - * A service that manages the active subscriptions periodically sending requests to keep them - * running. + * A service that manages the active subscriptions periodically sending requests + * to keep them running. */ export class FirebaseSubscriptionService { @@ -177,10 +177,22 @@ export class FirebaseSubscriptionService { * Removes the provided subscription from subscriptions list, which stops any attempts * to update it. In case no more subscriptions are left, stops this service. * + * In case the passed subscription is not known to this service, does nothing. + * + * @param subscription a subscription to cancel; + * this method accepts values of both `SpineSubscription` + * and Proto `Subscription` types, + * and operates based on the subscription ID * @private */ _removeSubscription(subscription) { - const index = this._subscriptions.indexOf(subscription); + let id; + if (typeof subscription.id === 'function') { + id = subscription.id(); + } else { + id = subscription.getId().getValue(); + } + const index = this._subscriptions.findIndex(item => item.id() === id); this._subscriptions.splice(index, 1); if (this._subscriptions.length === 0) {