A frontend package which adds websocket and pubSub logic from high-templar to mobx-spine.
The functionality of this package includes:
- Websocket creation
- Keepalive
- Automatic reconnection
- Subscriptions
- Handlers for the publishes happening for a subscription
- Subscription refreshing after a socket disconnect => reconnect
spine-high-templar offers a Socket model. It is recommended to create this socket in the viewStore and save it in the api instance.
In the store/View
constructor:
this.fetchBootstrap().then(() => {
if (this.bootstrapCode === 200) {
api.socket = new Socket({
url: process.env.CY_FRONTEND_WEBSOCKET_URL,
});
}
});
It is important that the bootstrap has actually succeeded, the high-templar instance will use the headers provided in the socket-open-request to authenticate the user against the binder instance.
The frontend subscribes to a room (in the form of an object). onPublish
will be called with every message published in that room.
Don't forget to unsubscribe when a view will unmount.
View example:
componentDidMount() {
this.subscription = this.props.store.api.socket.subscribe({
onPublish: this.handlePublish.bind(this),
room: {
tenant: 16,
driver: this.props.screenProps.viewStore.currentUser.id,
},
});
}
handlePublish(msg) {
this.props.store.add(msg.data);
}
componentWillUnmount() {
this.props.store.api.socket.unsubscribe(this.subscription);
}
The websocket may disconnect. This can be a client side reason (loss of internet) or a server side reason (deployment). When the websocket has been disconnected, the frontend might be outdated, as publishes may have been missed.
For this reason the subscribe action has a onReconnect callback, where the frontend can refetch/do whatever to make sure it's up to date.
componentDidMount() {
this.subscription = this.props.store.api.socket.subscribe({
onPublish: this.handlePublish.bind(this),
onReconnect: this.handleReconnect.bind(this),
room: {
tenant: 16,
driver: this.props.screenProps.viewStore.currentUser.id,
},
});
}
handlePublish(msg) {
this.props.store.add(msg.data);
}
handleReconnect() {
this.props.store.fetch();
}
componentWillUnmount() {
this.props.store.api.socket.unsubscribe(this.subscription);
}
If the app doesn't use session auth but an Authorization token, one can pass the token under the token
key in the Socket constructor options. Due to a limitation of the WebSocket available in browsers, it's not possible to add custom headers to a websocket open request, so we handle this in high-templar.
The high-templar instance will add a header Authorization: Token ${token}
when authenticating against the binder instance.
api.socket = new Socket({
url: WEBSOCKET_URL,
token: this.authToken.value,
});