public/lib/presence.js (87 lines of code) (raw):

import _ from "lodash" import { wfPresenceIndicatorsDirective } from 'components/presence-indicator/presence-indicators'; import { wfPresenceCurrentState } from 'components/presence-indicator/presence-status'; var module = angular.module('wfPresenceService', []); module.factory('wfPresenceService', ['$rootScope', '$log', 'config', 'wfUser', function($rootScope, $log, config, wfUser) { function presenceError(msg, loggingFields) { var err = new Error(msg); err.name = "PresenceError"; $log.error(["Presence error: ", JSON.stringify(msg)].join(' '), loggingFields); $rootScope.$apply(function () { throw err }); broadcast("presence.connection.error", msg); } var self = {}; self.whenEnabled = Promise.resolve(true); self.endpoint = config.presenceUrl; var currentArticleIds = []; function broadcast(name, data) { /* use apply to make it take effect straight away */ $rootScope.$apply(function () { $rootScope.$broadcast(name, data); }); } var messageHandlers = { "visitor-list-subscribe": function(msg) { broadcast("presence.subscribed", msg.data); }, "visitor-list-updated": function(msg) { broadcast("presence.status", msg); } }; function addHandlers(presence, handlers) { _.forEach(_.keys(handlers), (eventName) => { presence.register(eventName, handlers[eventName]); }); } // this is required, and passed to the presence client // library, and should return a promise which points to the // current user var person = { firstName : wfUser.firstName, lastName : wfUser.lastName, email : wfUser.email }; // INITIATE the connection if presence is enabled var presence = new Promise(function(presenceResolve, presenceReject) { // call normal error procedure for presence, and then // additionally reject this promise function promisePresenceError(msg) { presenceError(msg); presenceReject(msg); } self.whenEnabled.then( // 1. Is presence enabled? ()=>window.presenceClient, ()=>promisePresenceError("presence is disabled") ).then( // 2. Have we loaded the client library? (presenceClient) => { var p = presenceClient(self.endpoint, person); var loggingFields = {'sessionId':p.connectionId, 'userEmail': person.email} // for all successful connections, trigger a subscribe // (this will happen on initial connection, but also if we // lose connection and then it is restored) p.on('connection.open', () => { $log.info('Presence connection open', loggingFields); broadcast("presence.connection.open"); p.subscribe(currentArticleIds).catch((err) => $log.error(['error subscribing ', err].join(' '))); }); // the 'error' event gets triggered for each of the // three retries, but 'connection.error' will only get // triggered if we finally give up. p.on('connection.error', msg => { presenceError(msg, loggingFields); }); p.on('connectionRetry', () => { broadcast("presence.connection.retry"); $log.warn("Presence connection lost, retrying",loggingFields); }); p.on('connectionLog', msg => { $log.debug(["Presence logging: ", JSON.stringify(msg)].join(' '), loggingFields); }) addHandlers(p, messageHandlers); // startConnection() will return a promise that will be // resolved once the conection has been successfully // established. So we return a chained promise that // replaces the return value with our presenceClient object return p.startConnection().then(() => presenceResolve(p), () => promisePresenceError("unable to establish connection to presence")); }, (err) => { promisePresenceError("Could not get access to the client library: " + err); }).catch((err)=>{ promisePresenceError("error starting presence " + err); }); }); self.subscribe = function (articleIds) { currentArticleIds = articleIds; presence.then((p) => p.subscribe(articleIds), (msg) => { $log.error("could not subscribe to presence " + msg); }); }; return self; }]); module.factory('wfPresenceCurrentState', ['$rootScope', wfPresenceCurrentState]); module.directive('wfPresenceIndicators', ['$rootScope', 'wfPresenceService', 'wfPresenceCurrentState','$log', wfPresenceIndicatorsDirective]);