Skip to content

Commit

Permalink
feat(platform/messaging): support sending retained intents
Browse files Browse the repository at this point in the history
Similar to a retained message, a retained intent helps newly subscribed clients receive the last intent published for a capability. The platform supports the sending of retained intents and requests.

closes #142

BREAKING CHANGE: The `IntentClient` now uses the same `options` object as the `MessageClient` to control how to send a message or request. The content of the `options` object has not changed, only its name, i.e., migration is only required if assigning it to a typed variable or decorating the `IntentClient`.

Note that the communication protocol between host and client has NOT changed, i.e., host and clients can be migrated independently.

To migrate:
 - options for sending an intent was changed from `IntentOptions` to `PublishOptions` (`IntentClient#publish`)
 - options for requesting data was changed from `IntentOptions` to `RequestOptions` (`IntentClient#request`)
  • Loading branch information
danielwiehl authored and Marcarrian committed Nov 8, 2022
1 parent 4bdbc82 commit 08afb72
Show file tree
Hide file tree
Showing 26 changed files with 2,570 additions and 265 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-2020 Swiss Federal Railways
* Copyright (c) 2018-2022 Swiss Federal Railways
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
Expand All @@ -9,7 +9,7 @@
*/

import {BeanDecorator} from '@scion/toolkit/bean-manager';
import {Intent, IntentClient, IntentMessage, IntentOptions, IntentSelector, MessageClient, PublishOptions, RequestOptions, TopicMessage} from '@scion/microfrontend-platform';
import {Intent, IntentClient, IntentMessage, IntentSelector, MessageClient, PublishOptions, RequestOptions, TopicMessage} from '@scion/microfrontend-platform';
import {Injectable, NgZone} from '@angular/core';
import {MonoTypeOperatorFunction, Observable, pipe, Subscription} from 'rxjs';
import {observeInside, subscribeInside} from '@scion/toolkit/operators';
Expand Down Expand Up @@ -63,11 +63,11 @@ export class NgZoneIntentClientDecorator implements BeanDecorator<IntentClient>
const zone = this._zone;
return new class implements IntentClient {

public publish<T = any>(intent: Intent, body?: T, options?: IntentOptions): Promise<void> {
public publish<T = any>(intent: Intent, body?: T, options?: PublishOptions): Promise<void> {
return delegate.publish(intent, body, options);
}

public request$<T>(intent: Intent, body?: any, options?: IntentOptions): Observable<TopicMessage<T>> {
public request$<T>(intent: Intent, body?: any, options?: RequestOptions): Observable<TopicMessage<T>> {
return delegate.request$<T>(intent, body, options).pipe(synchronizeWithAngular(zone));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<sci-checkbox [formControlName]="REQUEST_REPLY" class="e2e-request-reply"></sci-checkbox>
</sci-form-field>

<sci-form-field label="Retain" *ngIf="isTopicFlavor()">
<sci-form-field label="Retain">
<sci-checkbox [formControlName]="RETAIN" class="e2e-retain"></sci-checkbox>
</sci-form-field>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-2020 Swiss Federal Railways
* Copyright (c) 2018-2022 Swiss Federal Railways
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
Expand Down Expand Up @@ -182,15 +182,15 @@ export class PublishMessageComponent implements OnDestroy {
this.publishError = null;
try {
if (requestReply) {
this._requestResponseSubscription = this._intentClient.request$({type, qualifier}, message, {headers: headers})
this._requestResponseSubscription = this._intentClient.request$({type, qualifier}, message, {retain: this.form.get(RETAIN).value, headers})
.pipe(finalize(() => this.markPublishing(false)))
.subscribe({
next: reply => this.replies.push(reply),
error: error => this.publishError = error,
});
}
else {
this._intentClient.publish({type, qualifier, params}, message, {headers: headers})
this._intentClient.publish({type, qualifier, params}, message, {retain: this.form.get(RETAIN).value, headers})
.catch(error => {
this.publishError = error?.message ?? `${error}`;
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-2020 Swiss Federal Railways
* Copyright (c) 2018-2022 Swiss Federal Railways
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
Expand All @@ -9,7 +9,7 @@
*/

import {BeanDecorator} from '@scion/toolkit/bean-manager';
import {Intent, IntentClient, IntentMessage, IntentOptions, IntentSelector, MessageClient, PublishOptions, RequestOptions, TopicMessage} from '@scion/microfrontend-platform';
import {Intent, IntentClient, IntentMessage, IntentSelector, MessageClient, PublishOptions, RequestOptions, TopicMessage} from '@scion/microfrontend-platform';
import {Injectable, NgZone} from '@angular/core';
import {MonoTypeOperatorFunction, Observable, pipe, Subscription} from 'rxjs';
import {observeInside, subscribeInside} from '@scion/toolkit/operators';
Expand Down Expand Up @@ -63,11 +63,11 @@ export class NgZoneIntentClientDecorator implements BeanDecorator<IntentClient>
const zone = this._zone;
return new class implements IntentClient {

public publish<T = any>(intent: Intent, body?: T, options?: IntentOptions): Promise<void> {
public publish<T = any>(intent: Intent, body?: T, options?: PublishOptions): Promise<void> {
return intentClient.publish(intent, body, options);
}

public request$<T>(intent: Intent, body?: any, options?: IntentOptions): Observable<TopicMessage<T>> {
public request$<T>(intent: Intent, body?: any, options?: RequestOptions): Observable<TopicMessage<T>> {
return intentClient.request$<T>(intent, body, options).pipe(synchronizeWithAngular(zone));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ In this Chapter
An activator allows a micro application to initialize and connect to the platform upon host application's startup, i.e., when the user loads the web application into the browser. An activator is a startup hook for micro applications to initialize or register message or intent handlers. In the broadest sense, an activator is a kind of microfrontend, i.e. an HTML page that runs in an iframe. In contrast to regular microfrontends, however, at platform startup, the platform loads activator microfrontends into hidden iframes for the entire platform lifecycle, thus, providing a stateful session to the micro application on the client-side.

====
An activator is loaded into the browser exactly once, for the entire lifecycle of the application. Some typical use cases for activators include <<chapter:intent-based-messaging:handling-intents,handling intents>> and <<chapter:topic-based-messaging:receiving-messages,messages>>, preloading data, or <<chapter:intention-api:capability-registration,flexibly providing capabilities>>. If implementing single sign-on authentication, you could, for example, obtain the user's access token and preemptively refresh it before its expected expiration.
An activator is loaded into the browser exactly once, for the entire lifecycle of the application. Some typical use cases for activators include <<chapter:intent-based-messaging:receiving-intents,handling intents>> and <<chapter:topic-based-messaging:receiving-messages,messages>>, preloading data, or <<chapter:intention-api:capability-registration,flexibly providing capabilities>>. If implementing single sign-on authentication, you could, for example, obtain the user's access token and preemptively refresh it before its expected expiration.
====

A micro application registers an activator as public _activator_ capability in its manifest, as follows:
Expand Down
Loading

0 comments on commit 08afb72

Please sign in to comment.