Skip to main content

BFF-WS-EXT

General

This extension provides ability to consume messages from BE via WebSockets. On server connection provided over RabbitMQ in future probably another MQ will be added.

Backend part

Installation

$ npm install @invent/bff-ws-ext

Configuration

On first place you have to describe configuration params.

import { ExtInitConfig } from '@invent/bff-ws-ext';

export const bffWsExt: ExtInitConfig = {
messages: [],
extHost: `${process.env.MY_HOST}:443`,
qOptions: {
qName: 'my-tenant-prefix',
qHost: process.env.RMQ_HOST
}
};

type ExtInitConfig = {
pathOverride?: {
root: string;
schema: string;
channel: string;
};
messages: SchemaMessagesT<unknown>[];
qOptions: QOptionsT;
};

Path override

  • this is optional config key
  • this key provides ability to override endpoints for this extension
pathOverride?: {
root: string;
schema: string;
channel: string;
};

Default values are:

/ext/ws/schema
/ext/ws/channel

QOptions

  • for now implemented support only for rabbitMq
  • this is mandatory config key
  • if port not setted up default rabbitmq port will be used
type QOptionsT = {
qName: string;
qPort?: number;
qHost: string;
}

Example:

{
qName: 'wlabel',
qPort: '101107',
qHost: 'amqp://0.0.0.0'
}

Messages

TO BE IMPLEMENTED

Connection mapping

  • all connections of user will be binded to user ID provided in JWT (the sub claim).
  • messages from rabbitMq will be sent to all user connections in all browser tabs.

Init & expose

import { bffWsExt } from './src/extentions/ws-extention';
import { initBffWsExt } from '@invent/bff-ws-ext';

....
app.use(
validateRequestTokenMiddlewareFabric([
'/images',
'/templates/assets/fonts',
'/theme',
'/theme/my-default-theme',
'/tenent',
'/ext/ws/channel/.websocket'
])
);
overrideRoutes();
let extentions = [];
extensions = await initBffWsExt(app, bffWsExt, extentions);
exposeExtensions(extentions);
endpointConfig.forEach((domain) => hydrate(app, domain));

Exposed extensions in this example

[
{
"author":"Nameless invent developer",
"name":"@invent/bff-ws-ext",
"version":"1.0.12",
"module":"./BffWssCompanion",
"scope":"companion_bff_ws_ext",
"extHost":"https://fe-be.dev.clic.apptrium.cloud:443",
"companion":"https://inventwidgetextensions.z19.web.core.windows.net/271/remoteEntry.js",
"pathList":[
{
"method":"get",
"path":"/ext/ws/schema"
},
{
"method":"ws",
"path":"/ext/ws/channel"
}
]
}
]
  • The order of function calls is important
  • extensions is list of mounted extenstions. In case you use more then one installed extension, pass this var to another iniAnotherExt function.
  • The part /ext/ws/channel/.websocket exposes connection. Also please keep in mind that .websocket is mandatory.
  • exposeExtnsions used to expose list of installed extensions. If you want to add customization or override some params, you can do it on extenstions before pass to exposeExtensions function.

Companion

Subscribe

In place where you whan to subscribe on WebSocket.

// In case you are in host application area
import { getExtension, getExtensionsList } from '@/lib/module-federation/use-extensions';

// In case you are accessing websocket extension in widget
const { getExtension, getExtensionsList } = props;

// mySubscriptionId should be placed outside the component
const mySubscriptionId = v4();

useEffect(() => {
const wss = getExtension('@invent/bff-ws-ext');
if (wss && wss.subscribe) {
// (entity: string, id: string, callback: (message: unknown) => void) => void
wss.subscribe('Notification', mySubscriptionId, (message: unknown) => console.log(message));
/*
`entity` refers to `headers.entity` in websocket message.
So you subscribing to specific entity events.

`id` is unique string id.

`callback` is handler function.
*/
}
}, [getExtension('@invent/bff-ws-ext')]);
  • you can wrap handler with React-Query or another wrapper.

Unsubscribe

import { getExtencion } from '@/lib/module-federation/use-extensions';
import { useUnmount } from 'react-use';

useUnmount(() => {
const wss = getExtencion('@invent/bff-ws-ext');
if (wss) {
// mySubscriptionId same value as in subscribe
wss.unsubscribe('Notification', mySubscriptionId);
}
});

Common websocket messages shape

{
"message": {
"downloadId":"cbe1894e44984b74b9f829f8ddeb9c50",
"userId":"00000",
"type":1,
"name":"contacts-grid_08-21-2021_19-23",
"uri":"https://clicqacudata.blob.core.windows.net/files/downloads/cbe1894e44984b74b9f829f8ddeb9c50?sv=2020-08-04&se=2021-09-21T13%3A23%3A19Z&sr=b&sp=r&rscd=attachment%3B+filename%3Dcontacts-grid_08-21-2021_19-23&sig=2tNFPCOMJR1rkyGgBLuP5MIlV4IetsC6afMjSXUuBb0%3D",
"status":2,
"expiresAt":"2021-09-21T13:23:16.516Z",
"createdAt":"2021-09-21T12:23:19.0470019Z",
"scope":3
},
"headers": {
"x-datadog-trace-id":"7247253089438860160",
"x-datadog-parent-id":"7380314150188049681",
"x-datadog-sampling-priority":"1",
"CausationId":"541750d3-1c93-4656-a40b-237c8c3da2c0",
"CausedBy":"DCore.FinTech.Messages.Downloads.Commands+V1+SetDownloadAvailable",
"CorrelationId":"25df0318-ab3a-5087-b345-681753ee5ed5",
"TenantId":"CIR",
"entity":"Download",
"recipientId":"00000",
"deliveryMethod":"Direct"
}
}