111 lines
3.2 KiB
Markdown
111 lines
3.2 KiB
Markdown
|
|
# Pub sub
|
|||
|
|
|
|||
|
|
## Overview
|
|||
|
|
Publish–subscribe pattern is a messaging pattern that is one of the fundamentals patterns used in reusable software components.
|
|||
|
|
|
|||
|
|
In short, services that implements this pattern, can have listeners subscribed to their broadcasted events. After the event is fired, the corresponding listener will execute the function that is registered.
|
|||
|
|
|
|||
|
|
You can read more about this design pattern [here](https://cloud.google.com/pubsub/docs/overview).
|
|||
|
|
|
|||
|
|
|
|||
|
|
## Example: Default Initialization
|
|||
|
|
In `Mode.jsx` we have a default initialization that demonstrates
|
|||
|
|
a series of subscriptions to various events.
|
|||
|
|
|
|||
|
|
|
|||
|
|
```js
|
|||
|
|
async function defaultRouteInit({
|
|||
|
|
servicesManager,
|
|||
|
|
studyInstanceUIDs,
|
|||
|
|
dataSource,
|
|||
|
|
}) {
|
|||
|
|
const {
|
|||
|
|
DisplaySetService,
|
|||
|
|
HangingProtocolService,
|
|||
|
|
} = servicesManager.services;
|
|||
|
|
|
|||
|
|
const unsubscriptions = [];
|
|||
|
|
|
|||
|
|
const {
|
|||
|
|
unsubscribe: instanceAddedUnsubscribe,
|
|||
|
|
} = DicomMetadataStore.subscribe(
|
|||
|
|
DicomMetadataStore.EVENTS.INSTANCES_ADDED,
|
|||
|
|
({ StudyInstanceUID, SeriesInstanceUID, madeInClient = false }) => {
|
|||
|
|
const seriesMetadata = DicomMetadataStore.getSeries(
|
|||
|
|
StudyInstanceUID,
|
|||
|
|
SeriesInstanceUID
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
DisplaySetService.makeDisplaySets(seriesMetadata.instances, madeInClient);
|
|||
|
|
}
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
unsubscriptions.push(instanceAddedUnsubscribe);
|
|||
|
|
|
|||
|
|
studyInstanceUIDs.forEach(StudyInstanceUID => {
|
|||
|
|
dataSource.retrieveSeriesMetadata({ StudyInstanceUID });
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
const { unsubscribe: seriesAddedUnsubscribe } = DicomMetadataStore.subscribe(
|
|||
|
|
DicomMetadataStore.EVENTS.SERIES_ADDED,
|
|||
|
|
({ StudyInstanceUID }) => {
|
|||
|
|
const studyMetadata = DicomMetadataStore.getStudy(StudyInstanceUID);
|
|||
|
|
HangingProtocolService.run(studyMetadata);
|
|||
|
|
}
|
|||
|
|
);
|
|||
|
|
unsubscriptions.push(seriesAddedUnsubscribe);
|
|||
|
|
|
|||
|
|
return unsubscriptions;
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Unsubscription
|
|||
|
|
You need to be careful if you are adding custom subscriptions to the app. Each subscription will return a unsubscription function that needs to be executed on component destruction to avoid adding multiple subscriptions to the same observer.
|
|||
|
|
|
|||
|
|
Below, we can see `simplified` `Mode.jsx` and the corresponding `useEffect` where the unsubscription functions are executed upon destruction.
|
|||
|
|
|
|||
|
|
```js
|
|||
|
|
// platform/viewer/src/routes/Mode/Mode.jsx
|
|||
|
|
export default function ModeRoute(/**..**/) {
|
|||
|
|
/**...**/
|
|||
|
|
useEffect(
|
|||
|
|
() => {
|
|||
|
|
/**...**/
|
|||
|
|
|
|||
|
|
DisplaySetService.init(extensionManager, sopClassHandlers)
|
|||
|
|
|
|||
|
|
extensionManager.onModeEnter()
|
|||
|
|
mode?.onModeEnter({ servicesManager, extensionManager })
|
|||
|
|
|
|||
|
|
hangingProtocols.forEach((extentionProtocols) => {
|
|||
|
|
const { protocols } =
|
|||
|
|
extensionManager.getModuleEntry(extentionProtocols)
|
|||
|
|
HangingProtocolService.addProtocols(protocols)
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
const setupRouteInit = async () => {
|
|||
|
|
if (route.init) {
|
|||
|
|
return await route.init(/**...**/)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return await defaultRouteInit(/**...**/)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
let unsubscriptions
|
|||
|
|
setupRouteInit().then((unsubs) => {
|
|||
|
|
unsubscriptions = unsubs
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
return () => {
|
|||
|
|
extensionManager.onModeExit()
|
|||
|
|
mode?.onModeExit({ servicesManager, extensionManager })
|
|||
|
|
unsubscriptions.forEach((unsub) => {
|
|||
|
|
unsub()
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
)
|
|||
|
|
return <> /**...**/ </>
|
|||
|
|
}
|
|||
|
|
```
|