@mashroom/mashroom-messaging
v2.7.1
Published
Adds a Service plugin for server-side messaging and comes with a WebSocket interface that allows sending messages across clients (and browser tabs)
Downloads
118
Readme
Mashroom Messaging
Plugin for Mashroom Server, a Microfrontend Integration Platform.
This plugin adds server side messaging support to Mashroom Server. If an external provider plugin (e.g. MQTT) is configured the messages can also be sent across multiple nodes (cluster support!) and to 3rd party systems.
Optionally it supports sending and receiving messages via WebSocket (Requires mashroom-websocket).
Usage
If node_modules/@mashroom is configured as plugin path just add @mashroom/mashroom-messaging as dependency.
And you can use the messaging service like this:
import type {MashroomMessagingService} from '@mashroom/mashroom-messaging/type-definitions';
export default async (req: Request, res: Response) => {
const messagingService: MashroomMessagingService = req.pluginContext.services.messaging.service;
// Subscribe
await messagingService.subscribe(req, 'my/topic', (data) => {
// Do something with data
});
// Publish
await messagingService.publish(req, 'other/topic', {
item: 'Beer',
quantity: 1,
});
// ...
}
You can override the default config in your Mashroom config file like this:
{
"plugins": {
"Mashroom Messaging Services": {
"externalProvider": null,
"externalTopics": [],
"userPrivateBaseTopic": "user",
"enableWebSockets": true,
"topicACL": "./topicACL.json"
}
}
}
- externalProvider: A plugin that connects to an external messaging system. Allows to receive messages from other systems and to send messages "out" (Default: null)
- externalTopics: A list of topic roots that should be considered as external. E.g. if the list contains other-system topics published to other-system/foo or other-system/bar would be sent via externalProvider. (Default: [])
- userPrivateBaseTopic: The base for private user topics. If the prefix is something/user the user john would only be able to subscribe to user/john/something and not to something/user/thomas/weather-update (Default: user).
- enableWebSockets: Enable WebSocket support when mashroom-websocket is present (Default: true)
- topicACL: Access control list to restrict the use of certain topic patterns to specific roles (Default: ./topicACL.json)
With a config like that you can place a file topic_acl.json in your server config with a content like this:
{
"$schema": "https://www.mashroom-server.com/schemas/mashroom-security-topic-acl.json",
"my/topic": {
"allow": ["Role1"]
},
"foo/bar/#": {
"allow": "any"
"deny": ["NotSoTrustedRole"]
}
}
The general structure is:
"/my/+/topic/#": {
"allow": "any"|<array of roles>
"deny": "any"|<array of roles>
}
You can use here + or * as a wildcard for a single level and # for multiple levels.
WebSocket interface
If enableWebSockets is true you can connect to the messaging system on <websocket_base_path>/messaging which is by default /websocket/messaging. The server expects and sends serialized JSON.
After a successful connection you can use the following commands:
Subscribe
{
messageId: 'ABCD',
command: 'subscribe',
topic: 'foo/bar',
}
The messageId should be unique. You will get a response message like this when the operation succeeds:
{
messageId: 'ABCD',
success: true,
}
Otherwise a error message like this:
{
messageId: 'ABCD',
error: true,
message: 'The error message'
}
Unsubscribe
{
messageId: 'ABCD',
command: 'unsubscribe',
topic: 'foo/bar',
}
Success and error response messages are the same as above.
Publish
{
messageId: 'ABCD',
command: 'publish',
topic: 'foo/bar',
message: {
foo: 'bar'
}
}
Success and error response messages are the same as above.
And the server will push the following if a message for a subscribed topic arrives:
{
remoteMessage: true,
topic: 'foo/bar',
message: {
what: 'ever'
}
}
Services
MashroomMessagingService
The exposed service is accessible through pluginContext.services.messaging.service
Interface:
export interface MashroomMessagingService {
/**
* Subscribe to given topic.
* Topics can be hierarchical and also can contain wildcards. Supported wildcards are + for a single level
* and # for multiple levels. E.g. foo/+/bar or foo/#
*
* Throws an exception if there is no authenticated user
*/
subscribe(req: Request, topic: string, callback: MashroomMessagingSubscriberCallback): Promise<void>;
/**
* Unsubscribe from topic
*/
unsubscribe(topic: string, callback: MashroomMessagingSubscriberCallback): Promise<void>;
/**
* Publish to a specific topic
*
* Throws an exception if there is no authenticated user
*/
publish(req: Request, topic: string, data: any): Promise<void>;
/**
* The private topic only the current user can access.
* E.g. if the value is user/john the user john can access to user/john/whatever
* but not to user/otheruser/foo
*
* Throws an exception if there is no authenticated user
*/
getUserPrivateTopic(req: Request): string;
/**
* The connect path to send publish or subscribe via WebSocket.
* Only available if enableWebSockets is true and mashroom-websocket is preset.
*/
getWebSocketConnectPath(req: Request): string | null | undefined;
}
Plugin Types
external-messaging-provider
This plugin type connects the messaging system to an external message broker. It also adds cluster support to the messaging system.
To register your custom external-messaging-provider plugin add this to package.json:
{
"mashroom": {
"plugins": [
{
"name": "My Custom External Messaging Provider",
"type": "external-messaging-provider",
"bootstrap": "./dist/mashroom-bootstrap",
"defaultConfig": {
"myProperty": "foo"
}
}
]
}
}
The bootstrap returns the provider:
import type {MashroomExternalMessagingProviderPluginBootstrapFunction} from '@mashroom/mashroom-messaging/type-definitions';
const bootstrap: MashroomExternalMessagingProviderPluginBootstrapFunction = async (pluginName, pluginConfig, pluginContextHolder) => {
return new MyExternalMessagingProvider(/* ... */);
};
export default bootstrap;
The provider has to implement the following interface:
export interface MashroomMessagingExternalProvider {
/**
* Add a message listener
* The message must be a JSON object.
*/
addMessageListener(listener: MashroomExternalMessageListener): void;
/**
* Remove an existing listener
*/
removeMessageListener(listener: MashroomExternalMessageListener): void;
/**
* Send a message to given internal topic.
* Used to broadcast message between Mashroom instances.
*
* The passed topic must be prefixed with the topic the provider is listening to.
* E.g. if the passed topic is foo/bar and the provider is listening to mashroom/# the message must be
* sent to mashroom/foo/bars.
*
* The message will be a JSON object.
*/
sendInternalMessage(topic: string, message: any): Promise<void>;
/**
* Send a message to given external topic.
* Used to send messages to 3rd party systems.
*
* The message will be a JSON object.
*/
sendExternalMessage(topic: string, message: any): Promise<void>;
}