UNPKG

lml-main

Version:

This is now a mono repository published into many standalone packages.

87 lines (77 loc) 3.54 kB
import * as Pusher from 'pusher-js' import { get } from 'lodash' import { Observable } from 'rxjs' import { combineEpics, ActionsObservable } from 'redux-observable' import { Store } from 'redux' import { AUTHENTICATED } from '@lml/cosmo-ui-auth' import { RootState } from '../reducers' import { Pusher as PusherInterface } from 'pusher-js' import { formatChannelName } from '../utils' import { PusherMetadataModel } from '../interfaces' import { setMetadata, pusherHealthcheckError, PUSHER_CONNECT, SUBSCRIBE_CHANNEL, pusherConnectionSuccess, pusherConnectionError, PusherConnectAction, PusherSubscribeChannelAction, } from '../actions' // not exactly functional but lets expose it anyway // use at your own risk - no guarantees export let pusherClient: PusherInterface export const connectToPusher = (action$: ActionsObservable<PusherConnectAction>, store: Store<RootState>): Observable<any> => action$.ofType(PUSHER_CONNECT) .mergeMap((action: PusherConnectAction) => Observable.create((observer: any) => { const options = { cluster: action.cluster, ...action.options, } pusherClient = new Pusher(action.key, options) pusherClient.connection.bind('connected', (result: any) => { observer.next(pusherConnectionSuccess(pusherClient, result)) }); pusherClient.connection.bind('error', (error: any) => { observer.next(pusherConnectionError(error)) }); })) /** * An epic to subscribe to a channel * * @param action$ * @param store */ export const subscribeToChannel = (action$: ActionsObservable<PusherSubscribeChannelAction>, store: Store<RootState>) => action$.ofType(SUBSCRIBE_CHANNEL) .mergeMap((action: PusherSubscribeChannelAction) => Observable.create((observer: any) => { const { events } = action const channel = pusherClient.subscribe(formatChannelName(action.channel)) if (Array.isArray(events)) { events.forEach(e => { channel.bind(e, (message: any) => { observer.next(action.callback(message)) }) }) } else { channel.bind(events, (message: any) => { observer.next(action.callback(message)) }) } // always bind to metadata regardless of channel // the backend team should be providing this as a health check on all channels channel.bind('METADATA', (message: PusherMetadataModel) => { const { items } = message const errors = Object.keys(items) .filter((event: string) => items[event].error > 0) if (errors) { errors.forEach((event: string) => { observer.next(pusherHealthcheckError(action.channel, event, message)) }) } observer.next(setMetadata(action.channel, message)) }) }))