@webex/internal-plugin-presence 3.0.0-beta.13 → 3.0.0-beta.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -3
- package/dist/config.js.map +1 -1
- package/dist/constants.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/presence-batcher.js.map +1 -1
- package/dist/presence-worker.js.map +1 -1
- package/dist/presence.js +3 -3
- package/dist/presence.js.map +1 -1
- package/package.json +9 -9
- package/src/config.js +2 -2
- package/src/constants.js +2 -4
- package/src/index.js +6 -6
- package/src/presence-batcher.js +13 -12
- package/src/presence-worker.js +43 -51
- package/src/presence.js +50 -45
- package/test/integration/spec/presence.js +112 -76
- package/test/unit/spec/presence-worker.js +33 -37
- package/test/unit/spec/presence.js +18 -9
package/README.md
CHANGED
|
@@ -21,14 +21,12 @@ npm install --save @webex/internal-plugin-presence
|
|
|
21
21
|
## Usage
|
|
22
22
|
|
|
23
23
|
```js
|
|
24
|
-
|
|
25
24
|
import '@webex/internal-plugin-presence';
|
|
26
25
|
|
|
27
26
|
import WebexCore from '@webex/webex-core';
|
|
28
27
|
|
|
29
28
|
const webex = new WebexCore();
|
|
30
|
-
webex.internal.presence.WHATEVER
|
|
31
|
-
|
|
29
|
+
webex.internal.presence.WHATEVER;
|
|
32
30
|
```
|
|
33
31
|
|
|
34
32
|
## Maintainers
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["presence","batcherWait","batcherMaxCalls","batcherMaxWait"],"sources":["config.js"],"sourcesContent":["/*!\n * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.\n */\n\nexport default {\n presence: {\n batcherWait: 50,\n batcherMaxCalls: 50,\n batcherMaxWait: 150
|
|
1
|
+
{"version":3,"names":["presence","batcherWait","batcherMaxCalls","batcherMaxWait"],"sources":["config.js"],"sourcesContent":["/*!\n * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.\n */\n\nexport default {\n presence: {\n batcherWait: 50,\n batcherMaxCalls: 50,\n batcherMaxWait: 150,\n },\n};\n"],"mappings":";;;;;;;;;;AAAA;AACA;AACA;eAEe;EACbA,QAAQ,EAAE;IACRC,WAAW,EAAE,EADL;IAERC,eAAe,EAAE,EAFT;IAGRC,cAAc,EAAE;EAHR;AADG,C"}
|
package/dist/constants.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["GROUNDSKEEPER_INTERVAL","FETCH_DELAY","UPDATE_PRESENCE_DELAY","EXPIRED_PRESENCE_TIME","SUBSCRIPTION_DELAY","PREMATURE_EXPIRATION_SUBSCRIPTION_TIME","DEFAULT_SUBSCRIPTION_TTL","APHELEIA_SUBSCRIPTION_UPDATE","PRESENCE_UPDATE","ENVELOPE_TYPE","SUBSCRIPTION","PRESENCE","DELETE"],"sources":["constants.js"],"sourcesContent":["
|
|
1
|
+
{"version":3,"names":["GROUNDSKEEPER_INTERVAL","FETCH_DELAY","UPDATE_PRESENCE_DELAY","EXPIRED_PRESENCE_TIME","SUBSCRIPTION_DELAY","PREMATURE_EXPIRATION_SUBSCRIPTION_TIME","DEFAULT_SUBSCRIPTION_TTL","APHELEIA_SUBSCRIPTION_UPDATE","PRESENCE_UPDATE","ENVELOPE_TYPE","SUBSCRIPTION","PRESENCE","DELETE"],"sources":["constants.js"],"sourcesContent":["export const GROUNDSKEEPER_INTERVAL = 20 * 1000; // 20 seconds in ms\n\nexport const FETCH_DELAY = 300; // ms\n\nexport const UPDATE_PRESENCE_DELAY = 60 * 1000; // 1 minute in ms\nexport const EXPIRED_PRESENCE_TIME = 10 * 60 * 1000; // 10 minutes in ms\n\nexport const SUBSCRIPTION_DELAY = 60 * 1000; // 1 minute in ms\nexport const PREMATURE_EXPIRATION_SUBSCRIPTION_TIME = 60 * 1000; // 1 minute in ms\nexport const DEFAULT_SUBSCRIPTION_TTL = 10 * 60 * 1000; // 10 minutes in ms\n\nexport const APHELEIA_SUBSCRIPTION_UPDATE = 'event:apheleia.subscription_update';\nexport const PRESENCE_UPDATE = 'updated';\n\nexport const ENVELOPE_TYPE = {\n SUBSCRIPTION: 'subscription',\n PRESENCE: 'presence',\n DELETE: 'delete',\n};\n"],"mappings":";;;;;;;;;AAAO,IAAMA,sBAAsB,GAAG,KAAK,IAApC,C,CAA0C;;;AAE1C,IAAMC,WAAW,GAAG,GAApB,C,CAAyB;;;AAEzB,IAAMC,qBAAqB,GAAG,KAAK,IAAnC,C,CAAyC;;;AACzC,IAAMC,qBAAqB,GAAG,KAAK,EAAL,GAAU,IAAxC,C,CAA8C;;;AAE9C,IAAMC,kBAAkB,GAAG,KAAK,IAAhC,C,CAAsC;;;AACtC,IAAMC,sCAAsC,GAAG,KAAK,IAApD,C,CAA0D;;;AAC1D,IAAMC,wBAAwB,GAAG,KAAK,EAAL,GAAU,IAA3C,C,CAAiD;;;AAEjD,IAAMC,4BAA4B,GAAG,oCAArC;;AACA,IAAMC,eAAe,GAAG,SAAxB;;AAEA,IAAMC,aAAa,GAAG;EAC3BC,YAAY,EAAE,cADa;EAE3BC,QAAQ,EAAE,UAFiB;EAG3BC,MAAM,EAAE;AAHmB,CAAtB"}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["registerInternalPlugin","Presence","payloadTransformer","predicates","name","direction","test","ctx","response","resolve","extract","transforms","fn","body","status","eventType","config"],"sources":["index.js"],"sourcesContent":["/*!\n * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.\n */\n\nimport '@webex/internal-plugin-device';\n\nimport {registerInternalPlugin} from '@webex/webex-core';\nimport {has} from 'lodash';\n\nimport Presence from './presence';\nimport config from './config';\n\nregisterInternalPlugin('presence', Presence, {\n payloadTransformer: {\n predicates: [\n {\n name: 'normalizeSingleStatusResponse',\n direction: 'inbound',\n test(ctx, response) {\n // POST to /apheleia/api/v1/events\n return Promise.resolve(has(response, 'body.eventType') && has(response, 'body.subject'));\n },\n extract(response) {\n return Promise.resolve(response);\n }
|
|
1
|
+
{"version":3,"names":["registerInternalPlugin","Presence","payloadTransformer","predicates","name","direction","test","ctx","response","resolve","extract","transforms","fn","body","status","eventType","config"],"sources":["index.js"],"sourcesContent":["/*!\n * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.\n */\n\nimport '@webex/internal-plugin-device';\n\nimport {registerInternalPlugin} from '@webex/webex-core';\nimport {has} from 'lodash';\n\nimport Presence from './presence';\nimport config from './config';\n\nregisterInternalPlugin('presence', Presence, {\n payloadTransformer: {\n predicates: [\n {\n name: 'normalizeSingleStatusResponse',\n direction: 'inbound',\n test(ctx, response) {\n // POST to /apheleia/api/v1/events\n return Promise.resolve(has(response, 'body.eventType') && has(response, 'body.subject'));\n },\n extract(response) {\n return Promise.resolve(response);\n },\n },\n ],\n transforms: [\n {\n name: 'normalizeSingleStatusResponse',\n direction: 'inbound',\n fn(ctx, response) {\n response.body.status = response.body.eventType;\n },\n },\n ],\n },\n config,\n});\n\nexport {default} from './presence';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAIA;;AAEA;;AAGA;;AACA;;AAVA;AACA;AACA;AAUA,IAAAA,iCAAA,EAAuB,UAAvB,EAAmCC,iBAAnC,EAA6C;EAC3CC,kBAAkB,EAAE;IAClBC,UAAU,EAAE,CACV;MACEC,IAAI,EAAE,+BADR;MAEEC,SAAS,EAAE,SAFb;MAGEC,IAHF,gBAGOC,GAHP,EAGYC,QAHZ,EAGsB;QAClB;QACA,OAAO,iBAAQC,OAAR,CAAgB,mBAAID,QAAJ,EAAc,gBAAd,KAAmC,mBAAIA,QAAJ,EAAc,cAAd,CAAnD,CAAP;MACD,CANH;MAOEE,OAPF,mBAOUF,QAPV,EAOoB;QAChB,OAAO,iBAAQC,OAAR,CAAgBD,QAAhB,CAAP;MACD;IATH,CADU,CADM;IAclBG,UAAU,EAAE,CACV;MACEP,IAAI,EAAE,+BADR;MAEEC,SAAS,EAAE,SAFb;MAGEO,EAHF,cAGKL,GAHL,EAGUC,QAHV,EAGoB;QAChBA,QAAQ,CAACK,IAAT,CAAcC,MAAd,GAAuBN,QAAQ,CAACK,IAAT,CAAcE,SAArC;MACD;IALH,CADU;EAdM,CADuB;EAyB3CC,MAAM,EAANA;AAzB2C,CAA7C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["PresenceBatcher","Batcher","extend","namespace","handleHttpSuccess","res","all","body","statusList","map","presenceResponse","handleItemSuccess","subject","handleItemFailure","item","response","getDeferredForResponse","then","defer","reject","resolve","fingerprintRequest","id","fingerprintResponse","prepareRequest","ids","submitHttpRequest","subjects","webex","request","method","api","resource"],"sources":["presence-batcher.js"],"sourcesContent":["/*!\n * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.\n */\n\nimport {Batcher} from '@webex/webex-core';\n\n/**\n * @class\n * @ignore\n */\nconst PresenceBatcher = Batcher.extend({\n namespace: 'Presence',\n\n /**\n * @instance\n * @memberof PresenceBatcher\n * @param {HttpResponseObject} res\n * @returns {Promise}\n */\n handleHttpSuccess(res) {\n return Promise.all(res.body.statusList.map((presenceResponse) =>\n
|
|
1
|
+
{"version":3,"names":["PresenceBatcher","Batcher","extend","namespace","handleHttpSuccess","res","all","body","statusList","map","presenceResponse","handleItemSuccess","subject","handleItemFailure","item","response","getDeferredForResponse","then","defer","reject","resolve","fingerprintRequest","id","fingerprintResponse","prepareRequest","ids","submitHttpRequest","subjects","webex","request","method","api","resource"],"sources":["presence-batcher.js"],"sourcesContent":["/*!\n * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.\n */\n\nimport {Batcher} from '@webex/webex-core';\n\n/**\n * @class\n * @ignore\n */\nconst PresenceBatcher = Batcher.extend({\n namespace: 'Presence',\n\n /**\n * @instance\n * @memberof PresenceBatcher\n * @param {HttpResponseObject} res\n * @returns {Promise}\n */\n handleHttpSuccess(res) {\n return Promise.all(\n res.body.statusList.map((presenceResponse) =>\n this.handleItemSuccess(presenceResponse.subject, presenceResponse)\n )\n );\n },\n\n /**\n * @instance\n * @memberof PresenceBatcher\n * @param {string} item\n * @param {Object} response\n * @returns {Promise}\n */\n handleItemFailure(item, response) {\n return this.getDeferredForResponse(item).then((defer) => {\n defer.reject(response);\n });\n },\n\n /**\n * @instance\n * @memberof PresenceBatcher\n * @param {string} item\n * @param {Object} response\n * @returns {Promise}\n */\n handleItemSuccess(item, response) {\n return this.getDeferredForResponse(item).then((defer) => {\n defer.resolve(response);\n });\n },\n\n /**\n * @instance\n * @memberof PresenceBatcher\n * @param {string} id\n * @returns {Promise<string>}\n */\n fingerprintRequest(id) {\n return Promise.resolve(id);\n },\n\n /**\n * @instance\n * @memberof PresenceBatcher\n * @param {string} id\n * @returns {Promise<string>}\n */\n fingerprintResponse(id) {\n return Promise.resolve(id);\n },\n\n /**\n * @instance\n * @memberof PresenceBatcher\n * @param {Array} ids\n * @returns {Promise<Array>}\n */\n prepareRequest(ids) {\n return Promise.resolve(ids);\n },\n\n /**\n * @instance\n * @memberof PresenceBatcher\n * @param {Object} subjects\n * @returns {Promise<HttpResponseObject>}\n */\n submitHttpRequest(subjects) {\n return this.webex.request({\n method: 'POST',\n api: 'apheleia',\n resource: 'compositions',\n body: {subjects},\n });\n },\n});\n\nexport default PresenceBatcher;\n"],"mappings":";;;;;;;;;;;;;;AAIA;;AAJA;AACA;AACA;;AAIA;AACA;AACA;AACA;AACA,IAAMA,eAAe,GAAGC,kBAAA,CAAQC,MAAR,CAAe;EACrCC,SAAS,EAAE,UAD0B;;EAGrC;AACF;AACA;AACA;AACA;AACA;EACEC,iBATqC,6BASnBC,GATmB,EASd;IAAA;;IACrB,OAAO,iBAAQC,GAAR,CACLD,GAAG,CAACE,IAAJ,CAASC,UAAT,CAAoBC,GAApB,CAAwB,UAACC,gBAAD;MAAA,OACtB,KAAI,CAACC,iBAAL,CAAuBD,gBAAgB,CAACE,OAAxC,EAAiDF,gBAAjD,CADsB;IAAA,CAAxB,CADK,CAAP;EAKD,CAfoC;;EAiBrC;AACF;AACA;AACA;AACA;AACA;AACA;EACEG,iBAxBqC,6BAwBnBC,IAxBmB,EAwBbC,QAxBa,EAwBH;IAChC,OAAO,KAAKC,sBAAL,CAA4BF,IAA5B,EAAkCG,IAAlC,CAAuC,UAACC,KAAD,EAAW;MACvDA,KAAK,CAACC,MAAN,CAAaJ,QAAb;IACD,CAFM,CAAP;EAGD,CA5BoC;;EA8BrC;AACF;AACA;AACA;AACA;AACA;AACA;EACEJ,iBArCqC,6BAqCnBG,IArCmB,EAqCbC,QArCa,EAqCH;IAChC,OAAO,KAAKC,sBAAL,CAA4BF,IAA5B,EAAkCG,IAAlC,CAAuC,UAACC,KAAD,EAAW;MACvDA,KAAK,CAACE,OAAN,CAAcL,QAAd;IACD,CAFM,CAAP;EAGD,CAzCoC;;EA2CrC;AACF;AACA;AACA;AACA;AACA;EACEM,kBAjDqC,8BAiDlBC,EAjDkB,EAiDd;IACrB,OAAO,iBAAQF,OAAR,CAAgBE,EAAhB,CAAP;EACD,CAnDoC;;EAqDrC;AACF;AACA;AACA;AACA;AACA;EACEC,mBA3DqC,+BA2DjBD,EA3DiB,EA2Db;IACtB,OAAO,iBAAQF,OAAR,CAAgBE,EAAhB,CAAP;EACD,CA7DoC;;EA+DrC;AACF;AACA;AACA;AACA;AACA;EACEE,cArEqC,0BAqEtBC,GArEsB,EAqEjB;IAClB,OAAO,iBAAQL,OAAR,CAAgBK,GAAhB,CAAP;EACD,CAvEoC;;EAyErC;AACF;AACA;AACA;AACA;AACA;EACEC,iBA/EqC,6BA+EnBC,QA/EmB,EA+ET;IAC1B,OAAO,KAAKC,KAAL,CAAWC,OAAX,CAAmB;MACxBC,MAAM,EAAE,MADgB;MAExBC,GAAG,EAAE,UAFmB;MAGxBC,QAAQ,EAAE,cAHc;MAIxBzB,IAAI,EAAE;QAACoB,QAAQ,EAARA;MAAD;IAJkB,CAAnB,CAAP;EAMD;AAtFoC,CAAf,CAAxB;;eAyFe3B,e"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["PresenceWorker","checkFetchers","FETCH_DELAY","presences","watchers","fetchers","flights","campers","subscribers","webex","internal","Error","mercury","connected","resolve","connect","then","on","APHELEIA_SUBSCRIPTION_UPDATE","subscriptionUpdate","bind","setInterval","groundskeeper","GROUNDSKEEPER_INTERVAL","event","data","subject","Date","getTime","presence","emitEvent","PRESENCE_UPDATE","type","ENVELOPE_TYPE","SUBSCRIPTION","payload","id","now","UPDATE_PRESENCE_DELAY","debouncedFetch","boarding","list","response","statusList","forEach","PRESENCE","camper","time","SUBSCRIPTION_DELAY","push","renewIds","subscription","expiration","PREMATURE_EXPIRATION_SUBSCRIPTION_TIME","trash","tenMinutesAgo","EXPIRED_PRESENCE_TIME","lastUpdated","length","DELETE","checkCampers","renewSubscriptions","checkSubscriptions","ids","subscribe","body","responses","responseCode","ttl","subscriptionTtl","status","DEFAULT_SUBSCRIPTION_TTL","cleanPresences"],"sources":["presence-worker.js"],"sourcesContent":["\nimport {debounce} from 'lodash';\n\nimport {\n FETCH_DELAY,\n GROUNDSKEEPER_INTERVAL,\n SUBSCRIPTION_DELAY,\n UPDATE_PRESENCE_DELAY,\n EXPIRED_PRESENCE_TIME,\n PREMATURE_EXPIRATION_SUBSCRIPTION_TIME,\n DEFAULT_SUBSCRIPTION_TTL,\n APHELEIA_SUBSCRIPTION_UPDATE,\n PRESENCE_UPDATE,\n ENVELOPE_TYPE\n} from './constants';\n\n/**\n * Presence Worker\n * Manages fetches and subscriptions for presence\n * @class\n */\nexport default class PresenceWorker {\n /**\n * Constructs a presence worker to execute and\n * maintain tasks related to presence upkeep.\n * @returns {undefined}\n */\n constructor() {\n this.presences = {}; // current presence objects; updated time\n this.watchers = {}; // counter of visible presence-required objects\n this.fetchers = {}; // waiting to get presence object\n this.flights = {}; // in flight to get presence object\n this.campers = {}; // waiting to subscribe; updated time\n this.subscribers = {}; // current subscriptions; expiration time\n }\n\n /**\n * Connect to the mercury for presence and starts worker.\n * @param {object} webex\n * @returns {undefined}\n */\n initialize(webex) {\n if (!webex || !webex.internal) {\n throw new Error('Must initialize Presence Worker with webex!');\n }\n\n this.webex = webex;\n\n const mercury = this.webex.internal.mercury.connected ?\n Promise.resolve() : this.webex.internal.mercury.connect();\n\n mercury.then(() => {\n this.webex.internal.mercury.on(APHELEIA_SUBSCRIPTION_UPDATE,\n this.subscriptionUpdate.bind(this));\n });\n\n setInterval(this.groundskeeper.bind(this), GROUNDSKEEPER_INTERVAL);\n }\n\n /**\n * Trigger a subscription update event.\n * @param {string} event\n * @returns {undefined}\n */\n subscriptionUpdate(event) {\n this.presences[event.data.subject] = new Date().getTime();\n\n this.webex.internal.presence.emitEvent(PRESENCE_UPDATE, {\n type: ENVELOPE_TYPE.SUBSCRIPTION,\n payload: event.data\n });\n }\n\n /**\n * Retrieves and subscribes to a user's presence.\n * @param {string} id\n * @returns {undefined}\n */\n enqueue(id) {\n const now = new Date().getTime();\n\n if (this.watchers[id]) {\n this.watchers[id] += 1;\n }\n else {\n this.watchers[id] = 1;\n }\n\n if (this.subscribers[id]) {\n return;\n }\n\n if (!this.campers[id]) {\n this.campers[id] = now;\n }\n\n // Retrieve presence if:\n // not in flight or\n // don't already have the presence or\n // presence has gone stale\n if (!this.flights[id] &&\n (!this.presences[id] ||\n this.presences[id] < now - UPDATE_PRESENCE_DELAY)) {\n this.fetchers[id] = id;\n this.debouncedFetch();\n }\n }\n\n /**\n * Retract from subscribing to a user's presence.\n * @param {string} id\n * @returns {undefined}\n */\n dequeue(id) {\n if (this.watchers[id]) {\n this.watchers[id] -= 1;\n\n if (this.watchers[id] <= 0) {\n delete this.watchers[id];\n delete this.fetchers[id];\n delete this.campers[id];\n }\n }\n }\n\n /**\n * Retrieve users' presences.\n * @returns {undefined}\n */\n checkFetchers() {\n const boarding = this.fetchers;\n\n Object.assign(this.flights, boarding);\n this.fetchers = {};\n\n\n this.webex.internal.presence.list(Object.keys(boarding))\n .then((response) => {\n const now = new Date().getTime();\n\n response.statusList.forEach((presence) => {\n const id = presence.subject;\n\n delete this.flights[id];\n this.presences[id] = now;\n });\n\n this.webex.internal.presence.emitEvent(PRESENCE_UPDATE, {\n type: ENVELOPE_TYPE.PRESENCE,\n payload: response\n });\n });\n }\n\n debouncedFetch = debounce(this.checkFetchers, FETCH_DELAY);\n\n /**\n * Determine if we should subscribe to users' presences.\n * @returns {Array}: User ids to subscribe.\n */\n checkCampers() {\n const now = new Date().getTime();\n const subscribers = [];\n\n Object.entries(this.campers).forEach((camper) => {\n const id = camper[0];\n const time = camper[1];\n\n // Subscribe if they've been camping for a minute\n if (time < now - SUBSCRIPTION_DELAY) {\n delete this.campers[id];\n this.subscribers[id] = null;\n subscribers.push(id);\n }\n });\n\n return subscribers;\n }\n\n /**\n * Determine if we should re-subscribe or remove users' subscriptions.\n * @returns {Array}: User ids to re-subscribe.\n */\n checkSubscriptions() {\n const now = new Date().getTime();\n\n const renewIds = [];\n\n Object.entries(this.subscribers).forEach((subscription) => {\n const id = subscription[0];\n const expiration = subscription[1];\n\n if (expiration) {\n // Renew subscription if they're about to expire\n if (this.watchers[id] &&\n now > expiration - PREMATURE_EXPIRATION_SUBSCRIPTION_TIME) {\n renewIds.push(id);\n }\n else if (now > expiration) {\n delete this.subscribers[id];\n }\n }\n });\n\n return renewIds;\n }\n\n /**\n * Remove expired presence objects.\n * @returns {undefined}\n */\n cleanPresences() {\n const trash = [];\n const tenMinutesAgo = new Date().getTime() - EXPIRED_PRESENCE_TIME;\n\n Object.entries(this.presences).forEach((presence) => {\n const id = presence[0];\n const lastUpdated = presence[1];\n\n // Delete the object if it is stale\n if (lastUpdated < tenMinutesAgo) {\n delete this.presences[id];\n trash.push(id);\n }\n });\n\n // Tells client to delete it too\n if (trash.length) {\n this.webex.internal.presence.emitEvent(PRESENCE_UPDATE, {\n type: ENVELOPE_TYPE.DELETE,\n payload: trash\n });\n }\n }\n\n /**\n * Execute chores on an interval.\n * Checks if we should make new subscribe,\n * checks if we should re-subscribe,\n * removes expired subscriptions,\n * removes expired presence objects.\n * @returns {undefined}\n */\n groundskeeper() {\n const campers = this.checkCampers();\n const renewSubscriptions = this.checkSubscriptions();\n\n const ids = [\n ...campers,\n ...renewSubscriptions\n ];\n\n if (ids.length) {\n this.webex.internal.presence.subscribe(ids)\n .then((body) => {\n const now = new Date().getTime();\n\n body.responses.forEach((response) => {\n if (response.responseCode === 200) {\n const ttl = response.subscriptionTtl * 1000;\n\n this.subscribers[response.subject] = now + ttl;\n this.presences[response.status.subject] = now;\n }\n else {\n // If it errored for any reason, set the ttl so we clean it out eventually\n this.subscribers[response.subject] = now + DEFAULT_SUBSCRIPTION_TTL;\n }\n });\n });\n }\n\n this.cleanPresences();\n }\n}\n\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"names":["PresenceWorker","checkFetchers","FETCH_DELAY","presences","watchers","fetchers","flights","campers","subscribers","webex","internal","Error","mercury","connected","resolve","connect","then","on","APHELEIA_SUBSCRIPTION_UPDATE","subscriptionUpdate","bind","setInterval","groundskeeper","GROUNDSKEEPER_INTERVAL","event","data","subject","Date","getTime","presence","emitEvent","PRESENCE_UPDATE","type","ENVELOPE_TYPE","SUBSCRIPTION","payload","id","now","UPDATE_PRESENCE_DELAY","debouncedFetch","boarding","list","response","statusList","forEach","PRESENCE","camper","time","SUBSCRIPTION_DELAY","push","renewIds","subscription","expiration","PREMATURE_EXPIRATION_SUBSCRIPTION_TIME","trash","tenMinutesAgo","EXPIRED_PRESENCE_TIME","lastUpdated","length","DELETE","checkCampers","renewSubscriptions","checkSubscriptions","ids","subscribe","body","responses","responseCode","ttl","subscriptionTtl","status","DEFAULT_SUBSCRIPTION_TTL","cleanPresences"],"sources":["presence-worker.js"],"sourcesContent":["import {debounce} from 'lodash';\n\nimport {\n FETCH_DELAY,\n GROUNDSKEEPER_INTERVAL,\n SUBSCRIPTION_DELAY,\n UPDATE_PRESENCE_DELAY,\n EXPIRED_PRESENCE_TIME,\n PREMATURE_EXPIRATION_SUBSCRIPTION_TIME,\n DEFAULT_SUBSCRIPTION_TTL,\n APHELEIA_SUBSCRIPTION_UPDATE,\n PRESENCE_UPDATE,\n ENVELOPE_TYPE,\n} from './constants';\n\n/**\n * Presence Worker\n * Manages fetches and subscriptions for presence\n * @class\n */\nexport default class PresenceWorker {\n /**\n * Constructs a presence worker to execute and\n * maintain tasks related to presence upkeep.\n * @returns {undefined}\n */\n constructor() {\n this.presences = {}; // current presence objects; updated time\n this.watchers = {}; // counter of visible presence-required objects\n this.fetchers = {}; // waiting to get presence object\n this.flights = {}; // in flight to get presence object\n this.campers = {}; // waiting to subscribe; updated time\n this.subscribers = {}; // current subscriptions; expiration time\n }\n\n /**\n * Connect to the mercury for presence and starts worker.\n * @param {object} webex\n * @returns {undefined}\n */\n initialize(webex) {\n if (!webex || !webex.internal) {\n throw new Error('Must initialize Presence Worker with webex!');\n }\n\n this.webex = webex;\n\n const mercury = this.webex.internal.mercury.connected\n ? Promise.resolve()\n : this.webex.internal.mercury.connect();\n\n mercury.then(() => {\n this.webex.internal.mercury.on(\n APHELEIA_SUBSCRIPTION_UPDATE,\n this.subscriptionUpdate.bind(this)\n );\n });\n\n setInterval(this.groundskeeper.bind(this), GROUNDSKEEPER_INTERVAL);\n }\n\n /**\n * Trigger a subscription update event.\n * @param {string} event\n * @returns {undefined}\n */\n subscriptionUpdate(event) {\n this.presences[event.data.subject] = new Date().getTime();\n\n this.webex.internal.presence.emitEvent(PRESENCE_UPDATE, {\n type: ENVELOPE_TYPE.SUBSCRIPTION,\n payload: event.data,\n });\n }\n\n /**\n * Retrieves and subscribes to a user's presence.\n * @param {string} id\n * @returns {undefined}\n */\n enqueue(id) {\n const now = new Date().getTime();\n\n if (this.watchers[id]) {\n this.watchers[id] += 1;\n } else {\n this.watchers[id] = 1;\n }\n\n if (this.subscribers[id]) {\n return;\n }\n\n if (!this.campers[id]) {\n this.campers[id] = now;\n }\n\n // Retrieve presence if:\n // not in flight or\n // don't already have the presence or\n // presence has gone stale\n if (\n !this.flights[id] &&\n (!this.presences[id] || this.presences[id] < now - UPDATE_PRESENCE_DELAY)\n ) {\n this.fetchers[id] = id;\n this.debouncedFetch();\n }\n }\n\n /**\n * Retract from subscribing to a user's presence.\n * @param {string} id\n * @returns {undefined}\n */\n dequeue(id) {\n if (this.watchers[id]) {\n this.watchers[id] -= 1;\n\n if (this.watchers[id] <= 0) {\n delete this.watchers[id];\n delete this.fetchers[id];\n delete this.campers[id];\n }\n }\n }\n\n /**\n * Retrieve users' presences.\n * @returns {undefined}\n */\n checkFetchers() {\n const boarding = this.fetchers;\n\n Object.assign(this.flights, boarding);\n this.fetchers = {};\n\n this.webex.internal.presence.list(Object.keys(boarding)).then((response) => {\n const now = new Date().getTime();\n\n response.statusList.forEach((presence) => {\n const id = presence.subject;\n\n delete this.flights[id];\n this.presences[id] = now;\n });\n\n this.webex.internal.presence.emitEvent(PRESENCE_UPDATE, {\n type: ENVELOPE_TYPE.PRESENCE,\n payload: response,\n });\n });\n }\n\n debouncedFetch = debounce(this.checkFetchers, FETCH_DELAY);\n\n /**\n * Determine if we should subscribe to users' presences.\n * @returns {Array}: User ids to subscribe.\n */\n checkCampers() {\n const now = new Date().getTime();\n const subscribers = [];\n\n Object.entries(this.campers).forEach((camper) => {\n const id = camper[0];\n const time = camper[1];\n\n // Subscribe if they've been camping for a minute\n if (time < now - SUBSCRIPTION_DELAY) {\n delete this.campers[id];\n this.subscribers[id] = null;\n subscribers.push(id);\n }\n });\n\n return subscribers;\n }\n\n /**\n * Determine if we should re-subscribe or remove users' subscriptions.\n * @returns {Array}: User ids to re-subscribe.\n */\n checkSubscriptions() {\n const now = new Date().getTime();\n\n const renewIds = [];\n\n Object.entries(this.subscribers).forEach((subscription) => {\n const id = subscription[0];\n const expiration = subscription[1];\n\n if (expiration) {\n // Renew subscription if they're about to expire\n if (this.watchers[id] && now > expiration - PREMATURE_EXPIRATION_SUBSCRIPTION_TIME) {\n renewIds.push(id);\n } else if (now > expiration) {\n delete this.subscribers[id];\n }\n }\n });\n\n return renewIds;\n }\n\n /**\n * Remove expired presence objects.\n * @returns {undefined}\n */\n cleanPresences() {\n const trash = [];\n const tenMinutesAgo = new Date().getTime() - EXPIRED_PRESENCE_TIME;\n\n Object.entries(this.presences).forEach((presence) => {\n const id = presence[0];\n const lastUpdated = presence[1];\n\n // Delete the object if it is stale\n if (lastUpdated < tenMinutesAgo) {\n delete this.presences[id];\n trash.push(id);\n }\n });\n\n // Tells client to delete it too\n if (trash.length) {\n this.webex.internal.presence.emitEvent(PRESENCE_UPDATE, {\n type: ENVELOPE_TYPE.DELETE,\n payload: trash,\n });\n }\n }\n\n /**\n * Execute chores on an interval.\n * Checks if we should make new subscribe,\n * checks if we should re-subscribe,\n * removes expired subscriptions,\n * removes expired presence objects.\n * @returns {undefined}\n */\n groundskeeper() {\n const campers = this.checkCampers();\n const renewSubscriptions = this.checkSubscriptions();\n\n const ids = [...campers, ...renewSubscriptions];\n\n if (ids.length) {\n this.webex.internal.presence.subscribe(ids).then((body) => {\n const now = new Date().getTime();\n\n body.responses.forEach((response) => {\n if (response.responseCode === 200) {\n const ttl = response.subscriptionTtl * 1000;\n\n this.subscribers[response.subject] = now + ttl;\n this.presences[response.status.subject] = now;\n } else {\n // If it errored for any reason, set the ttl so we clean it out eventually\n this.subscribers[response.subject] = now + DEFAULT_SUBSCRIPTION_TTL;\n }\n });\n });\n }\n\n this.cleanPresences();\n }\n}\n"],"mappings":"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"}
|
package/dist/presence.js
CHANGED
|
@@ -143,8 +143,8 @@ var Presence = _webexCore.WebexPlugin.extend({
|
|
|
143
143
|
},
|
|
144
144
|
|
|
145
145
|
/**
|
|
146
|
-
|
|
147
|
-
|
|
146
|
+
* @typedef {Object} PresenceStatusesObject
|
|
147
|
+
* @property {Array.<PresenceStatusObject>} statusList
|
|
148
148
|
*/
|
|
149
149
|
|
|
150
150
|
/**
|
|
@@ -292,7 +292,7 @@ var Presence = _webexCore.WebexPlugin.extend({
|
|
|
292
292
|
dequeue: function dequeue(id) {
|
|
293
293
|
return this.worker.dequeue(id);
|
|
294
294
|
},
|
|
295
|
-
version: "3.0.0-beta.
|
|
295
|
+
version: "3.0.0-beta.15"
|
|
296
296
|
});
|
|
297
297
|
|
|
298
298
|
var _default2 = Presence;
|
package/dist/presence.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["defaultSubscriptionTtl","USER","USER_PRESENCE_ENABLED","Presence","WebexPlugin","extend","namespace","children","batcher","PresenceBatcher","session","worker","default","PresenceWorker","type","initialize","webex","once","config","initializeWorker","emitEvent","event","payload","trigger","enable","internal","feature","setFeature","then","response","value","disable","isEnabled","getFeature","get","personId","reject","Error","request","method","service","resource","body","list","personIds","all","map","id","presences","statusList","subscribe","subscriptionTtl","subjects","batches","batchLimit","i","length","push","slice","ids","api","includeStatus","responses","idBatches","concat","unsubscribe","setStatus","status","ttl","subject","device","userId","eventType","enqueue","dequeue"],"sources":["presence.js"],"sourcesContent":["/*!\n * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.\n */\n\nimport '@webex/internal-plugin-device';\n\nimport {WebexPlugin} from '@webex/webex-core';\n\nimport PresenceBatcher from './presence-batcher';\nimport PresenceWorker from './presence-worker';\n\nconst defaultSubscriptionTtl = 600;\nconst USER = 'user';\nconst USER_PRESENCE_ENABLED = 'user-presence-enabled';\n\n/**\n * @class\n * @extends WebexPlugin\n */\nconst Presence = WebexPlugin.extend({\n namespace: 'Presence',\n\n children: {\n batcher: PresenceBatcher\n },\n\n session: {\n worker: {\n default() {\n return new PresenceWorker();\n },\n type: 'any'\n }\n },\n\n /**\n * Initialize the presence worker for client\n * @returns {undefined}\n */\n initialize() {\n this.webex.once('ready', () => {\n if (this.config.initializeWorker) {\n this.worker.initialize(this.webex);\n }\n });\n },\n\n /**\n * Trigger an event.\n * @param {string} event\n * @param {string} payload\n * @returns {undefined}\n */\n emitEvent(event, payload) {\n if (payload.type && payload.payload) {\n this.trigger(event, payload);\n }\n },\n\n /**\n * Enables presence feature\n * @returns {Promise<boolean>} resolves with true, if successful\n */\n enable() {\n return this.webex.internal.feature.setFeature(USER, USER_PRESENCE_ENABLED, true)\n .then((response) => response.value);\n },\n\n /**\n * Disables presence feature\n * @returns {Promise<boolean>} resolves with false, if successful\n */\n disable() {\n return this.webex.internal.feature.setFeature(USER, USER_PRESENCE_ENABLED, false)\n .then((response) => response.value);\n },\n\n /**\n * Returns true if presence is enabled, false otherwise\n * @returns {Promise<boolean>} resolves with true if presence is enabled\n */\n isEnabled() {\n return this.webex.internal.feature.getFeature(USER, USER_PRESENCE_ENABLED);\n },\n\n /**\n * The status object\n * @typedef {Object} PresenceStatusObject\n * @property {string} url: Public resource identifier for presence\n * @property {string} subject: User ID for the user the returned composed presence represents\n * @property {string} status: Current composed presence state\n * @property {string} statusTime: DateTime in RFC3339 format that the current status began\n * @property {string} lastActive: DateTime in RFC3339 format that the service last saw activity from the user.\n * @property {string} expires: DEPRECATED - DateTime in RFC3339 format that represents when the current\n * status will expire. Will not exist if expiresTTL is -1.\n * @property {Number} expiresTTL: TTL in seconds until the status will expire. If TTL is -1 the current\n * status has no known expiration.\n * @property {string} expiresTime: DateTime in RFC3339 format that the current status will expire. Missing\n * field means no known expiration.\n * @property {Object} vectorCounters: Used for packet ordering and tracking.\n * @property {Boolean} suppressNotifications: Indicates if notification suppression is recommended for this status.\n * @property {string} lastSeenDeviceUrl: Resource Identifier of the last device to post presence activity for\n * this user.\n */\n\n /**\n * Gets the current presence status of a given person id\n * @param {string} personId\n * @returns {Promise<PresenceStatusObject>} resolves with status object of person\n */\n get(personId) {\n if (!personId) {\n return Promise.reject(new Error('A person id is required'));\n }\n\n return this.webex.request({\n method: 'GET',\n service: 'apheleia',\n resource: `compositions?userId=${personId}`\n })\n .then((response) => response.body);\n },\n\n /**\n * @typedef {Object} PresenceStatusesObject\n * @property {Array.<PresenceStatusObject>} statusList\n */\n /**\n * Gets the current presence statuses of an array of people ids\n * @param {Array} personIds\n * @returns {Promise<PresenceStatusesObject>} resolves with an object with key of `statusList` array\n */\n list(personIds) {\n if (!personIds || !Array.isArray(personIds)) {\n return Promise.reject(new Error('An array of person ids is required'));\n }\n\n return Promise.all(personIds.map((id) =>\n this.batcher.request(id)))\n .then((presences) => ({statusList: presences}));\n },\n\n /**\n * Subscribes to a person's presence status updates\n * Updates are sent via mercury events `apheleia.subscription_update`\n * @param {string | Array} personIds\n * @param {number} subscriptionTtl - Requested length of subscriptions in seconds.\n * @returns {Promise}\n */\n subscribe(personIds, subscriptionTtl = defaultSubscriptionTtl) {\n let subjects;\n const batches = [];\n const batchLimit = 50;\n\n if (!personIds) {\n return Promise.reject(new Error('A person id is required'));\n }\n if (Array.isArray(personIds)) {\n subjects = personIds;\n }\n else {\n subjects = [personIds];\n }\n // Limit batches to 50 ids per request\n for (let i = 0; i < subjects.length; i += batchLimit) {\n batches.push(subjects.slice(i, i + batchLimit));\n }\n\n return Promise.all(batches.map((ids) =>\n this.webex.request({\n method: 'POST',\n api: 'apheleia',\n resource: 'subscriptions',\n body: {\n subjects: ids,\n subscriptionTtl,\n includeStatus: true\n }\n })\n .then((response) => response.body.responses)))\n .then((idBatches) => ({responses: [].concat(...idBatches)}));\n },\n\n /**\n * Unsubscribes from a person or group of people's presence subscription\n * @param {string | Array} personIds\n * @returns {Promise}\n */\n unsubscribe(personIds) {\n let subjects;\n\n if (!personIds) {\n return Promise.reject(new Error('A person id is required'));\n }\n if (Array.isArray(personIds)) {\n subjects = personIds;\n }\n else {\n subjects = [personIds];\n }\n\n return this.webex.request({\n method: 'POST',\n api: 'apheleia',\n resource: 'subscriptions',\n body: {\n subjects,\n subscriptionTtl: 0,\n includeStatus: true\n }\n });\n },\n\n /**\n * Sets the status of the current user\n * @param {string} status - active | inactive | ooo | dnd\n * @param {number} ttl - Time To Live for the event in seconds.\n * @returns {Promise}\n */\n setStatus(status, ttl) {\n if (!status) {\n return Promise.reject(new Error('A status is required'));\n }\n\n return this.webex.request({\n method: 'POST',\n api: 'apheleia',\n resource: 'events',\n body: {\n subject: this.webex.internal.device.userId,\n eventType: status,\n ttl\n }\n })\n .then((response) => response.body);\n },\n\n /**\n * Retrieves and subscribes to a user's presence.\n * @param {string} id\n * @returns {undefined}\n */\n enqueue(id) {\n return this.worker.enqueue(id);\n },\n\n /**\n * Retract from subscribing to a user's presence.\n * @param {string} id\n * @returns {undefined}\n */\n dequeue(id) {\n return this.worker.dequeue(id);\n }\n});\n\nexport default Presence;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"names":["defaultSubscriptionTtl","USER","USER_PRESENCE_ENABLED","Presence","WebexPlugin","extend","namespace","children","batcher","PresenceBatcher","session","worker","default","PresenceWorker","type","initialize","webex","once","config","initializeWorker","emitEvent","event","payload","trigger","enable","internal","feature","setFeature","then","response","value","disable","isEnabled","getFeature","get","personId","reject","Error","request","method","service","resource","body","list","personIds","all","map","id","presences","statusList","subscribe","subscriptionTtl","subjects","batches","batchLimit","i","length","push","slice","ids","api","includeStatus","responses","idBatches","concat","unsubscribe","setStatus","status","ttl","subject","device","userId","eventType","enqueue","dequeue"],"sources":["presence.js"],"sourcesContent":["/*!\n * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.\n */\n\nimport '@webex/internal-plugin-device';\n\nimport {WebexPlugin} from '@webex/webex-core';\n\nimport PresenceBatcher from './presence-batcher';\nimport PresenceWorker from './presence-worker';\n\nconst defaultSubscriptionTtl = 600;\nconst USER = 'user';\nconst USER_PRESENCE_ENABLED = 'user-presence-enabled';\n\n/**\n * @class\n * @extends WebexPlugin\n */\nconst Presence = WebexPlugin.extend({\n namespace: 'Presence',\n\n children: {\n batcher: PresenceBatcher,\n },\n\n session: {\n worker: {\n default() {\n return new PresenceWorker();\n },\n type: 'any',\n },\n },\n\n /**\n * Initialize the presence worker for client\n * @returns {undefined}\n */\n initialize() {\n this.webex.once('ready', () => {\n if (this.config.initializeWorker) {\n this.worker.initialize(this.webex);\n }\n });\n },\n\n /**\n * Trigger an event.\n * @param {string} event\n * @param {string} payload\n * @returns {undefined}\n */\n emitEvent(event, payload) {\n if (payload.type && payload.payload) {\n this.trigger(event, payload);\n }\n },\n\n /**\n * Enables presence feature\n * @returns {Promise<boolean>} resolves with true, if successful\n */\n enable() {\n return this.webex.internal.feature\n .setFeature(USER, USER_PRESENCE_ENABLED, true)\n .then((response) => response.value);\n },\n\n /**\n * Disables presence feature\n * @returns {Promise<boolean>} resolves with false, if successful\n */\n disable() {\n return this.webex.internal.feature\n .setFeature(USER, USER_PRESENCE_ENABLED, false)\n .then((response) => response.value);\n },\n\n /**\n * Returns true if presence is enabled, false otherwise\n * @returns {Promise<boolean>} resolves with true if presence is enabled\n */\n isEnabled() {\n return this.webex.internal.feature.getFeature(USER, USER_PRESENCE_ENABLED);\n },\n\n /**\n * The status object\n * @typedef {Object} PresenceStatusObject\n * @property {string} url: Public resource identifier for presence\n * @property {string} subject: User ID for the user the returned composed presence represents\n * @property {string} status: Current composed presence state\n * @property {string} statusTime: DateTime in RFC3339 format that the current status began\n * @property {string} lastActive: DateTime in RFC3339 format that the service last saw activity from the user.\n * @property {string} expires: DEPRECATED - DateTime in RFC3339 format that represents when the current\n * status will expire. Will not exist if expiresTTL is -1.\n * @property {Number} expiresTTL: TTL in seconds until the status will expire. If TTL is -1 the current\n * status has no known expiration.\n * @property {string} expiresTime: DateTime in RFC3339 format that the current status will expire. Missing\n * field means no known expiration.\n * @property {Object} vectorCounters: Used for packet ordering and tracking.\n * @property {Boolean} suppressNotifications: Indicates if notification suppression is recommended for this status.\n * @property {string} lastSeenDeviceUrl: Resource Identifier of the last device to post presence activity for\n * this user.\n */\n\n /**\n * Gets the current presence status of a given person id\n * @param {string} personId\n * @returns {Promise<PresenceStatusObject>} resolves with status object of person\n */\n get(personId) {\n if (!personId) {\n return Promise.reject(new Error('A person id is required'));\n }\n\n return this.webex\n .request({\n method: 'GET',\n service: 'apheleia',\n resource: `compositions?userId=${personId}`,\n })\n .then((response) => response.body);\n },\n\n /**\n * @typedef {Object} PresenceStatusesObject\n * @property {Array.<PresenceStatusObject>} statusList\n */\n /**\n * Gets the current presence statuses of an array of people ids\n * @param {Array} personIds\n * @returns {Promise<PresenceStatusesObject>} resolves with an object with key of `statusList` array\n */\n list(personIds) {\n if (!personIds || !Array.isArray(personIds)) {\n return Promise.reject(new Error('An array of person ids is required'));\n }\n\n return Promise.all(personIds.map((id) => this.batcher.request(id))).then((presences) => ({\n statusList: presences,\n }));\n },\n\n /**\n * Subscribes to a person's presence status updates\n * Updates are sent via mercury events `apheleia.subscription_update`\n * @param {string | Array} personIds\n * @param {number} subscriptionTtl - Requested length of subscriptions in seconds.\n * @returns {Promise}\n */\n subscribe(personIds, subscriptionTtl = defaultSubscriptionTtl) {\n let subjects;\n const batches = [];\n const batchLimit = 50;\n\n if (!personIds) {\n return Promise.reject(new Error('A person id is required'));\n }\n if (Array.isArray(personIds)) {\n subjects = personIds;\n } else {\n subjects = [personIds];\n }\n // Limit batches to 50 ids per request\n for (let i = 0; i < subjects.length; i += batchLimit) {\n batches.push(subjects.slice(i, i + batchLimit));\n }\n\n return Promise.all(\n batches.map((ids) =>\n this.webex\n .request({\n method: 'POST',\n api: 'apheleia',\n resource: 'subscriptions',\n body: {\n subjects: ids,\n subscriptionTtl,\n includeStatus: true,\n },\n })\n .then((response) => response.body.responses)\n )\n ).then((idBatches) => ({responses: [].concat(...idBatches)}));\n },\n\n /**\n * Unsubscribes from a person or group of people's presence subscription\n * @param {string | Array} personIds\n * @returns {Promise}\n */\n unsubscribe(personIds) {\n let subjects;\n\n if (!personIds) {\n return Promise.reject(new Error('A person id is required'));\n }\n if (Array.isArray(personIds)) {\n subjects = personIds;\n } else {\n subjects = [personIds];\n }\n\n return this.webex.request({\n method: 'POST',\n api: 'apheleia',\n resource: 'subscriptions',\n body: {\n subjects,\n subscriptionTtl: 0,\n includeStatus: true,\n },\n });\n },\n\n /**\n * Sets the status of the current user\n * @param {string} status - active | inactive | ooo | dnd\n * @param {number} ttl - Time To Live for the event in seconds.\n * @returns {Promise}\n */\n setStatus(status, ttl) {\n if (!status) {\n return Promise.reject(new Error('A status is required'));\n }\n\n return this.webex\n .request({\n method: 'POST',\n api: 'apheleia',\n resource: 'events',\n body: {\n subject: this.webex.internal.device.userId,\n eventType: status,\n ttl,\n },\n })\n .then((response) => response.body);\n },\n\n /**\n * Retrieves and subscribes to a user's presence.\n * @param {string} id\n * @returns {undefined}\n */\n enqueue(id) {\n return this.worker.enqueue(id);\n },\n\n /**\n * Retract from subscribing to a user's presence.\n * @param {string} id\n * @returns {undefined}\n */\n dequeue(id) {\n return this.worker.dequeue(id);\n },\n});\n\nexport default Presence;\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webex/internal-plugin-presence",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.15",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -23,14 +23,14 @@
|
|
|
23
23
|
"sinon": "^9.2.4"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@webex/internal-plugin-device": "3.0.0-beta.
|
|
27
|
-
"@webex/internal-plugin-mercury": "3.0.0-beta.
|
|
28
|
-
"@webex/internal-plugin-presence": "3.0.0-beta.
|
|
29
|
-
"@webex/test-helper-chai": "3.0.0-beta.
|
|
30
|
-
"@webex/test-helper-mocha": "3.0.0-beta.
|
|
31
|
-
"@webex/test-helper-mock-webex": "3.0.0-beta.
|
|
32
|
-
"@webex/test-helper-test-users": "3.0.0-beta.
|
|
33
|
-
"@webex/webex-core": "3.0.0-beta.
|
|
26
|
+
"@webex/internal-plugin-device": "3.0.0-beta.15",
|
|
27
|
+
"@webex/internal-plugin-mercury": "3.0.0-beta.15",
|
|
28
|
+
"@webex/internal-plugin-presence": "3.0.0-beta.15",
|
|
29
|
+
"@webex/test-helper-chai": "3.0.0-beta.15",
|
|
30
|
+
"@webex/test-helper-mocha": "3.0.0-beta.15",
|
|
31
|
+
"@webex/test-helper-mock-webex": "3.0.0-beta.15",
|
|
32
|
+
"@webex/test-helper-test-users": "3.0.0-beta.15",
|
|
33
|
+
"@webex/webex-core": "3.0.0-beta.15",
|
|
34
34
|
"lodash": "^4.17.21"
|
|
35
35
|
}
|
|
36
36
|
}
|
package/src/config.js
CHANGED
package/src/constants.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
export const GROUNDSKEEPER_INTERVAL = 20 * 1000; // 20 seconds in ms
|
|
3
2
|
|
|
4
3
|
export const FETCH_DELAY = 300; // ms
|
|
@@ -10,12 +9,11 @@ export const SUBSCRIPTION_DELAY = 60 * 1000; // 1 minute in ms
|
|
|
10
9
|
export const PREMATURE_EXPIRATION_SUBSCRIPTION_TIME = 60 * 1000; // 1 minute in ms
|
|
11
10
|
export const DEFAULT_SUBSCRIPTION_TTL = 10 * 60 * 1000; // 10 minutes in ms
|
|
12
11
|
|
|
13
|
-
export const APHELEIA_SUBSCRIPTION_UPDATE =
|
|
14
|
-
'event:apheleia.subscription_update';
|
|
12
|
+
export const APHELEIA_SUBSCRIPTION_UPDATE = 'event:apheleia.subscription_update';
|
|
15
13
|
export const PRESENCE_UPDATE = 'updated';
|
|
16
14
|
|
|
17
15
|
export const ENVELOPE_TYPE = {
|
|
18
16
|
SUBSCRIPTION: 'subscription',
|
|
19
17
|
PRESENCE: 'presence',
|
|
20
|
-
DELETE: 'delete'
|
|
18
|
+
DELETE: 'delete',
|
|
21
19
|
};
|
package/src/index.js
CHANGED
|
@@ -22,8 +22,8 @@ registerInternalPlugin('presence', Presence, {
|
|
|
22
22
|
},
|
|
23
23
|
extract(response) {
|
|
24
24
|
return Promise.resolve(response);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
27
|
],
|
|
28
28
|
transforms: [
|
|
29
29
|
{
|
|
@@ -31,11 +31,11 @@ registerInternalPlugin('presence', Presence, {
|
|
|
31
31
|
direction: 'inbound',
|
|
32
32
|
fn(ctx, response) {
|
|
33
33
|
response.body.status = response.body.eventType;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
]
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
37
|
},
|
|
38
|
-
config
|
|
38
|
+
config,
|
|
39
39
|
});
|
|
40
40
|
|
|
41
41
|
export {default} from './presence';
|
package/src/presence-batcher.js
CHANGED
|
@@ -18,8 +18,11 @@ const PresenceBatcher = Batcher.extend({
|
|
|
18
18
|
* @returns {Promise}
|
|
19
19
|
*/
|
|
20
20
|
handleHttpSuccess(res) {
|
|
21
|
-
return Promise.all(
|
|
22
|
-
|
|
21
|
+
return Promise.all(
|
|
22
|
+
res.body.statusList.map((presenceResponse) =>
|
|
23
|
+
this.handleItemSuccess(presenceResponse.subject, presenceResponse)
|
|
24
|
+
)
|
|
25
|
+
);
|
|
23
26
|
},
|
|
24
27
|
|
|
25
28
|
/**
|
|
@@ -30,10 +33,9 @@ const PresenceBatcher = Batcher.extend({
|
|
|
30
33
|
* @returns {Promise}
|
|
31
34
|
*/
|
|
32
35
|
handleItemFailure(item, response) {
|
|
33
|
-
return this.getDeferredForResponse(item)
|
|
34
|
-
.
|
|
35
|
-
|
|
36
|
-
});
|
|
36
|
+
return this.getDeferredForResponse(item).then((defer) => {
|
|
37
|
+
defer.reject(response);
|
|
38
|
+
});
|
|
37
39
|
},
|
|
38
40
|
|
|
39
41
|
/**
|
|
@@ -44,10 +46,9 @@ const PresenceBatcher = Batcher.extend({
|
|
|
44
46
|
* @returns {Promise}
|
|
45
47
|
*/
|
|
46
48
|
handleItemSuccess(item, response) {
|
|
47
|
-
return this.getDeferredForResponse(item)
|
|
48
|
-
.
|
|
49
|
-
|
|
50
|
-
});
|
|
49
|
+
return this.getDeferredForResponse(item).then((defer) => {
|
|
50
|
+
defer.resolve(response);
|
|
51
|
+
});
|
|
51
52
|
},
|
|
52
53
|
|
|
53
54
|
/**
|
|
@@ -91,9 +92,9 @@ const PresenceBatcher = Batcher.extend({
|
|
|
91
92
|
method: 'POST',
|
|
92
93
|
api: 'apheleia',
|
|
93
94
|
resource: 'compositions',
|
|
94
|
-
body: {subjects}
|
|
95
|
+
body: {subjects},
|
|
95
96
|
});
|
|
96
|
-
}
|
|
97
|
+
},
|
|
97
98
|
});
|
|
98
99
|
|
|
99
100
|
export default PresenceBatcher;
|
package/src/presence-worker.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
import {debounce} from 'lodash';
|
|
3
2
|
|
|
4
3
|
import {
|
|
@@ -11,7 +10,7 @@ import {
|
|
|
11
10
|
DEFAULT_SUBSCRIPTION_TTL,
|
|
12
11
|
APHELEIA_SUBSCRIPTION_UPDATE,
|
|
13
12
|
PRESENCE_UPDATE,
|
|
14
|
-
ENVELOPE_TYPE
|
|
13
|
+
ENVELOPE_TYPE,
|
|
15
14
|
} from './constants';
|
|
16
15
|
|
|
17
16
|
/**
|
|
@@ -46,12 +45,15 @@ export default class PresenceWorker {
|
|
|
46
45
|
|
|
47
46
|
this.webex = webex;
|
|
48
47
|
|
|
49
|
-
const mercury = this.webex.internal.mercury.connected
|
|
50
|
-
Promise.resolve()
|
|
48
|
+
const mercury = this.webex.internal.mercury.connected
|
|
49
|
+
? Promise.resolve()
|
|
50
|
+
: this.webex.internal.mercury.connect();
|
|
51
51
|
|
|
52
52
|
mercury.then(() => {
|
|
53
|
-
this.webex.internal.mercury.on(
|
|
54
|
-
|
|
53
|
+
this.webex.internal.mercury.on(
|
|
54
|
+
APHELEIA_SUBSCRIPTION_UPDATE,
|
|
55
|
+
this.subscriptionUpdate.bind(this)
|
|
56
|
+
);
|
|
55
57
|
});
|
|
56
58
|
|
|
57
59
|
setInterval(this.groundskeeper.bind(this), GROUNDSKEEPER_INTERVAL);
|
|
@@ -67,7 +69,7 @@ export default class PresenceWorker {
|
|
|
67
69
|
|
|
68
70
|
this.webex.internal.presence.emitEvent(PRESENCE_UPDATE, {
|
|
69
71
|
type: ENVELOPE_TYPE.SUBSCRIPTION,
|
|
70
|
-
payload: event.data
|
|
72
|
+
payload: event.data,
|
|
71
73
|
});
|
|
72
74
|
}
|
|
73
75
|
|
|
@@ -81,8 +83,7 @@ export default class PresenceWorker {
|
|
|
81
83
|
|
|
82
84
|
if (this.watchers[id]) {
|
|
83
85
|
this.watchers[id] += 1;
|
|
84
|
-
}
|
|
85
|
-
else {
|
|
86
|
+
} else {
|
|
86
87
|
this.watchers[id] = 1;
|
|
87
88
|
}
|
|
88
89
|
|
|
@@ -98,9 +99,10 @@ export default class PresenceWorker {
|
|
|
98
99
|
// not in flight or
|
|
99
100
|
// don't already have the presence or
|
|
100
101
|
// presence has gone stale
|
|
101
|
-
if (
|
|
102
|
-
|
|
103
|
-
|
|
102
|
+
if (
|
|
103
|
+
!this.flights[id] &&
|
|
104
|
+
(!this.presences[id] || this.presences[id] < now - UPDATE_PRESENCE_DELAY)
|
|
105
|
+
) {
|
|
104
106
|
this.fetchers[id] = id;
|
|
105
107
|
this.debouncedFetch();
|
|
106
108
|
}
|
|
@@ -133,23 +135,21 @@ export default class PresenceWorker {
|
|
|
133
135
|
Object.assign(this.flights, boarding);
|
|
134
136
|
this.fetchers = {};
|
|
135
137
|
|
|
138
|
+
this.webex.internal.presence.list(Object.keys(boarding)).then((response) => {
|
|
139
|
+
const now = new Date().getTime();
|
|
136
140
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
const now = new Date().getTime();
|
|
140
|
-
|
|
141
|
-
response.statusList.forEach((presence) => {
|
|
142
|
-
const id = presence.subject;
|
|
141
|
+
response.statusList.forEach((presence) => {
|
|
142
|
+
const id = presence.subject;
|
|
143
143
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
144
|
+
delete this.flights[id];
|
|
145
|
+
this.presences[id] = now;
|
|
146
|
+
});
|
|
147
147
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
});
|
|
148
|
+
this.webex.internal.presence.emitEvent(PRESENCE_UPDATE, {
|
|
149
|
+
type: ENVELOPE_TYPE.PRESENCE,
|
|
150
|
+
payload: response,
|
|
152
151
|
});
|
|
152
|
+
});
|
|
153
153
|
}
|
|
154
154
|
|
|
155
155
|
debouncedFetch = debounce(this.checkFetchers, FETCH_DELAY);
|
|
@@ -192,11 +192,9 @@ export default class PresenceWorker {
|
|
|
192
192
|
|
|
193
193
|
if (expiration) {
|
|
194
194
|
// Renew subscription if they're about to expire
|
|
195
|
-
if (this.watchers[id] &&
|
|
196
|
-
now > expiration - PREMATURE_EXPIRATION_SUBSCRIPTION_TIME) {
|
|
195
|
+
if (this.watchers[id] && now > expiration - PREMATURE_EXPIRATION_SUBSCRIPTION_TIME) {
|
|
197
196
|
renewIds.push(id);
|
|
198
|
-
}
|
|
199
|
-
else if (now > expiration) {
|
|
197
|
+
} else if (now > expiration) {
|
|
200
198
|
delete this.subscribers[id];
|
|
201
199
|
}
|
|
202
200
|
}
|
|
@@ -228,7 +226,7 @@ export default class PresenceWorker {
|
|
|
228
226
|
if (trash.length) {
|
|
229
227
|
this.webex.internal.presence.emitEvent(PRESENCE_UPDATE, {
|
|
230
228
|
type: ENVELOPE_TYPE.DELETE,
|
|
231
|
-
payload: trash
|
|
229
|
+
payload: trash,
|
|
232
230
|
});
|
|
233
231
|
}
|
|
234
232
|
}
|
|
@@ -245,32 +243,26 @@ export default class PresenceWorker {
|
|
|
245
243
|
const campers = this.checkCampers();
|
|
246
244
|
const renewSubscriptions = this.checkSubscriptions();
|
|
247
245
|
|
|
248
|
-
const ids = [
|
|
249
|
-
...campers,
|
|
250
|
-
...renewSubscriptions
|
|
251
|
-
];
|
|
246
|
+
const ids = [...campers, ...renewSubscriptions];
|
|
252
247
|
|
|
253
248
|
if (ids.length) {
|
|
254
|
-
this.webex.internal.presence.subscribe(ids)
|
|
255
|
-
.
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
this.subscribers[response.subject] = now + DEFAULT_SUBSCRIPTION_TTL;
|
|
268
|
-
}
|
|
269
|
-
});
|
|
249
|
+
this.webex.internal.presence.subscribe(ids).then((body) => {
|
|
250
|
+
const now = new Date().getTime();
|
|
251
|
+
|
|
252
|
+
body.responses.forEach((response) => {
|
|
253
|
+
if (response.responseCode === 200) {
|
|
254
|
+
const ttl = response.subscriptionTtl * 1000;
|
|
255
|
+
|
|
256
|
+
this.subscribers[response.subject] = now + ttl;
|
|
257
|
+
this.presences[response.status.subject] = now;
|
|
258
|
+
} else {
|
|
259
|
+
// If it errored for any reason, set the ttl so we clean it out eventually
|
|
260
|
+
this.subscribers[response.subject] = now + DEFAULT_SUBSCRIPTION_TTL;
|
|
261
|
+
}
|
|
270
262
|
});
|
|
263
|
+
});
|
|
271
264
|
}
|
|
272
265
|
|
|
273
266
|
this.cleanPresences();
|
|
274
267
|
}
|
|
275
268
|
}
|
|
276
|
-
|
package/src/presence.js
CHANGED
|
@@ -21,7 +21,7 @@ const Presence = WebexPlugin.extend({
|
|
|
21
21
|
namespace: 'Presence',
|
|
22
22
|
|
|
23
23
|
children: {
|
|
24
|
-
batcher: PresenceBatcher
|
|
24
|
+
batcher: PresenceBatcher,
|
|
25
25
|
},
|
|
26
26
|
|
|
27
27
|
session: {
|
|
@@ -29,8 +29,8 @@ const Presence = WebexPlugin.extend({
|
|
|
29
29
|
default() {
|
|
30
30
|
return new PresenceWorker();
|
|
31
31
|
},
|
|
32
|
-
type: 'any'
|
|
33
|
-
}
|
|
32
|
+
type: 'any',
|
|
33
|
+
},
|
|
34
34
|
},
|
|
35
35
|
|
|
36
36
|
/**
|
|
@@ -62,7 +62,8 @@ const Presence = WebexPlugin.extend({
|
|
|
62
62
|
* @returns {Promise<boolean>} resolves with true, if successful
|
|
63
63
|
*/
|
|
64
64
|
enable() {
|
|
65
|
-
return this.webex.internal.feature
|
|
65
|
+
return this.webex.internal.feature
|
|
66
|
+
.setFeature(USER, USER_PRESENCE_ENABLED, true)
|
|
66
67
|
.then((response) => response.value);
|
|
67
68
|
},
|
|
68
69
|
|
|
@@ -71,7 +72,8 @@ const Presence = WebexPlugin.extend({
|
|
|
71
72
|
* @returns {Promise<boolean>} resolves with false, if successful
|
|
72
73
|
*/
|
|
73
74
|
disable() {
|
|
74
|
-
return this.webex.internal.feature
|
|
75
|
+
return this.webex.internal.feature
|
|
76
|
+
.setFeature(USER, USER_PRESENCE_ENABLED, false)
|
|
75
77
|
.then((response) => response.value);
|
|
76
78
|
},
|
|
77
79
|
|
|
@@ -113,17 +115,18 @@ const Presence = WebexPlugin.extend({
|
|
|
113
115
|
return Promise.reject(new Error('A person id is required'));
|
|
114
116
|
}
|
|
115
117
|
|
|
116
|
-
return this.webex
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
118
|
+
return this.webex
|
|
119
|
+
.request({
|
|
120
|
+
method: 'GET',
|
|
121
|
+
service: 'apheleia',
|
|
122
|
+
resource: `compositions?userId=${personId}`,
|
|
123
|
+
})
|
|
121
124
|
.then((response) => response.body);
|
|
122
125
|
},
|
|
123
126
|
|
|
124
127
|
/**
|
|
125
|
-
|
|
126
|
-
|
|
128
|
+
* @typedef {Object} PresenceStatusesObject
|
|
129
|
+
* @property {Array.<PresenceStatusObject>} statusList
|
|
127
130
|
*/
|
|
128
131
|
/**
|
|
129
132
|
* Gets the current presence statuses of an array of people ids
|
|
@@ -135,9 +138,9 @@ const Presence = WebexPlugin.extend({
|
|
|
135
138
|
return Promise.reject(new Error('An array of person ids is required'));
|
|
136
139
|
}
|
|
137
140
|
|
|
138
|
-
return Promise.all(personIds.map((id) =>
|
|
139
|
-
|
|
140
|
-
|
|
141
|
+
return Promise.all(personIds.map((id) => this.batcher.request(id))).then((presences) => ({
|
|
142
|
+
statusList: presences,
|
|
143
|
+
}));
|
|
141
144
|
},
|
|
142
145
|
|
|
143
146
|
/**
|
|
@@ -157,8 +160,7 @@ const Presence = WebexPlugin.extend({
|
|
|
157
160
|
}
|
|
158
161
|
if (Array.isArray(personIds)) {
|
|
159
162
|
subjects = personIds;
|
|
160
|
-
}
|
|
161
|
-
else {
|
|
163
|
+
} else {
|
|
162
164
|
subjects = [personIds];
|
|
163
165
|
}
|
|
164
166
|
// Limit batches to 50 ids per request
|
|
@@ -166,19 +168,22 @@ const Presence = WebexPlugin.extend({
|
|
|
166
168
|
batches.push(subjects.slice(i, i + batchLimit));
|
|
167
169
|
}
|
|
168
170
|
|
|
169
|
-
return Promise.all(
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
171
|
+
return Promise.all(
|
|
172
|
+
batches.map((ids) =>
|
|
173
|
+
this.webex
|
|
174
|
+
.request({
|
|
175
|
+
method: 'POST',
|
|
176
|
+
api: 'apheleia',
|
|
177
|
+
resource: 'subscriptions',
|
|
178
|
+
body: {
|
|
179
|
+
subjects: ids,
|
|
180
|
+
subscriptionTtl,
|
|
181
|
+
includeStatus: true,
|
|
182
|
+
},
|
|
183
|
+
})
|
|
184
|
+
.then((response) => response.body.responses)
|
|
185
|
+
)
|
|
186
|
+
).then((idBatches) => ({responses: [].concat(...idBatches)}));
|
|
182
187
|
},
|
|
183
188
|
|
|
184
189
|
/**
|
|
@@ -194,8 +199,7 @@ const Presence = WebexPlugin.extend({
|
|
|
194
199
|
}
|
|
195
200
|
if (Array.isArray(personIds)) {
|
|
196
201
|
subjects = personIds;
|
|
197
|
-
}
|
|
198
|
-
else {
|
|
202
|
+
} else {
|
|
199
203
|
subjects = [personIds];
|
|
200
204
|
}
|
|
201
205
|
|
|
@@ -206,8 +210,8 @@ const Presence = WebexPlugin.extend({
|
|
|
206
210
|
body: {
|
|
207
211
|
subjects,
|
|
208
212
|
subscriptionTtl: 0,
|
|
209
|
-
includeStatus: true
|
|
210
|
-
}
|
|
213
|
+
includeStatus: true,
|
|
214
|
+
},
|
|
211
215
|
});
|
|
212
216
|
},
|
|
213
217
|
|
|
@@ -222,16 +226,17 @@ const Presence = WebexPlugin.extend({
|
|
|
222
226
|
return Promise.reject(new Error('A status is required'));
|
|
223
227
|
}
|
|
224
228
|
|
|
225
|
-
return this.webex
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
229
|
+
return this.webex
|
|
230
|
+
.request({
|
|
231
|
+
method: 'POST',
|
|
232
|
+
api: 'apheleia',
|
|
233
|
+
resource: 'events',
|
|
234
|
+
body: {
|
|
235
|
+
subject: this.webex.internal.device.userId,
|
|
236
|
+
eventType: status,
|
|
237
|
+
ttl,
|
|
238
|
+
},
|
|
239
|
+
})
|
|
235
240
|
.then((response) => response.body);
|
|
236
241
|
},
|
|
237
242
|
|
|
@@ -251,7 +256,7 @@ const Presence = WebexPlugin.extend({
|
|
|
251
256
|
*/
|
|
252
257
|
dequeue(id) {
|
|
253
258
|
return this.worker.dequeue(id);
|
|
254
|
-
}
|
|
259
|
+
},
|
|
255
260
|
});
|
|
256
261
|
|
|
257
262
|
export default Presence;
|
|
@@ -16,77 +16,85 @@ describe('plugin-presence', function () {
|
|
|
16
16
|
describe('Presence', () => {
|
|
17
17
|
let mccoy, spock;
|
|
18
18
|
|
|
19
|
-
beforeEach('create users', () =>
|
|
20
|
-
.then((users) => {
|
|
19
|
+
beforeEach('create users', () =>
|
|
20
|
+
testUsers.create({count: 2}).then((users) => {
|
|
21
21
|
[spock, mccoy] = users;
|
|
22
22
|
spock.webex = new WebexCore({
|
|
23
23
|
credentials: {
|
|
24
|
-
authorization: users[0].token
|
|
25
|
-
}
|
|
24
|
+
authorization: users[0].token,
|
|
25
|
+
},
|
|
26
26
|
});
|
|
27
27
|
mccoy.webex = new WebexCore({
|
|
28
28
|
credentials: {
|
|
29
|
-
authorization: users[1].token
|
|
30
|
-
}
|
|
29
|
+
authorization: users[1].token,
|
|
30
|
+
},
|
|
31
31
|
});
|
|
32
|
-
})
|
|
32
|
+
})
|
|
33
|
+
);
|
|
33
34
|
|
|
34
|
-
beforeEach('register with wdm', () =>
|
|
35
|
-
spock.webex.internal.device.register(),
|
|
36
|
-
|
|
37
|
-
]));
|
|
35
|
+
beforeEach('register with wdm', () =>
|
|
36
|
+
Promise.all([spock.webex.internal.device.register(), mccoy.webex.internal.device.register()])
|
|
37
|
+
);
|
|
38
38
|
|
|
39
39
|
beforeEach('register spock with mercury', () => spock.webex.internal.mercury.connect());
|
|
40
40
|
|
|
41
41
|
afterEach('deregister spock with mercury', () => spock.webex.internal.mercury.disconnect());
|
|
42
42
|
|
|
43
43
|
describe('#enable()', () => {
|
|
44
|
-
it('enables presence', () =>
|
|
45
|
-
.
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
44
|
+
it('enables presence', () =>
|
|
45
|
+
spock.webex.internal.presence
|
|
46
|
+
.enable()
|
|
47
|
+
.then((isEnabled) => {
|
|
48
|
+
assert.equal(isEnabled, true);
|
|
49
|
+
})
|
|
50
|
+
.then(() => spock.webex.internal.presence.isEnabled())
|
|
51
|
+
.then((isEnabled) => {
|
|
52
|
+
assert.equal(isEnabled, true);
|
|
53
|
+
}));
|
|
52
54
|
});
|
|
53
55
|
|
|
54
56
|
describe('#disable()', () => {
|
|
55
|
-
it('disables presence', () =>
|
|
56
|
-
.
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
57
|
+
it('disables presence', () =>
|
|
58
|
+
spock.webex.internal.presence
|
|
59
|
+
.disable()
|
|
60
|
+
.then((isEnabled) => {
|
|
61
|
+
assert.equal(isEnabled, false);
|
|
62
|
+
})
|
|
63
|
+
.then(() => spock.webex.internal.presence.isEnabled())
|
|
64
|
+
.then((isEnabled) => {
|
|
65
|
+
assert.equal(isEnabled, false);
|
|
66
|
+
}));
|
|
63
67
|
});
|
|
64
68
|
|
|
65
69
|
describe('#isEnabled()', () => {
|
|
66
|
-
it('returns true when presence is enabled', () =>
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
70
|
+
it('returns true when presence is enabled', () =>
|
|
71
|
+
spock.webex.internal.presence
|
|
72
|
+
.enable()
|
|
73
|
+
.then(() => spock.webex.internal.presence.isEnabled())
|
|
74
|
+
.then((isEnabled) => {
|
|
75
|
+
assert.equal(isEnabled, true);
|
|
76
|
+
}));
|
|
71
77
|
|
|
72
|
-
it('returns false when presence is disabled', () =>
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
78
|
+
it('returns false when presence is disabled', () =>
|
|
79
|
+
spock.webex.internal.presence
|
|
80
|
+
.disable()
|
|
81
|
+
.then(() => spock.webex.internal.presence.isEnabled())
|
|
82
|
+
.then((isEnabled) => {
|
|
83
|
+
assert.equal(isEnabled, false);
|
|
84
|
+
}));
|
|
77
85
|
});
|
|
78
86
|
|
|
79
87
|
describe('#get()', () => {
|
|
80
|
-
it(
|
|
81
|
-
.then((presenceResponse) => {
|
|
88
|
+
it("gets a person's status by id", () =>
|
|
89
|
+
spock.webex.internal.presence.get(mccoy.id).then((presenceResponse) => {
|
|
82
90
|
assert.property(presenceResponse, 'subject');
|
|
83
91
|
assert.equal(presenceResponse.subject, mccoy.id);
|
|
84
92
|
}));
|
|
85
93
|
});
|
|
86
94
|
|
|
87
95
|
describe('#list()', () => {
|
|
88
|
-
it('returns an object with the status of all requested people', () =>
|
|
89
|
-
.then((presenceResponse) => {
|
|
96
|
+
it('returns an object with the status of all requested people', () =>
|
|
97
|
+
spock.webex.internal.presence.list([mccoy.id, spock.id]).then((presenceResponse) => {
|
|
90
98
|
assert.equal(presenceResponse.statusList.length, 2);
|
|
91
99
|
assert.property(presenceResponse.statusList[0], 'subject');
|
|
92
100
|
assert.equal(presenceResponse.statusList[0].subject, mccoy.id);
|
|
@@ -97,16 +105,18 @@ describe('plugin-presence', function () {
|
|
|
97
105
|
describe('batching of presence requests', () => {
|
|
98
106
|
let batchTestUsers;
|
|
99
107
|
|
|
100
|
-
beforeEach('create more users', () =>
|
|
101
|
-
.then((users) => {
|
|
108
|
+
beforeEach('create more users', () =>
|
|
109
|
+
testUsers.create({count: 6}).then((users) => {
|
|
102
110
|
batchTestUsers = users;
|
|
103
|
-
})
|
|
111
|
+
})
|
|
112
|
+
);
|
|
104
113
|
|
|
105
114
|
it('executes network requests for max limit', () => {
|
|
106
115
|
spock.webex.internal.presence.config.batcherMaxCalls = 2;
|
|
107
116
|
sinon.spy(spock.webex.internal.presence.batcher, 'submitHttpRequest');
|
|
108
117
|
|
|
109
|
-
return spock.webex.internal.presence
|
|
118
|
+
return spock.webex.internal.presence
|
|
119
|
+
.list(batchTestUsers.map((user) => user.id))
|
|
110
120
|
.then((presenceResponse) => {
|
|
111
121
|
assert.equal(presenceResponse.statusList.length, 6);
|
|
112
122
|
assert.calledThrice(spock.webex.internal.presence.batcher.submitHttpRequest);
|
|
@@ -117,61 +127,87 @@ describe('plugin-presence', function () {
|
|
|
117
127
|
});
|
|
118
128
|
|
|
119
129
|
describe('#subscribe', () => {
|
|
120
|
-
afterEach(
|
|
130
|
+
afterEach(
|
|
131
|
+
() =>
|
|
132
|
+
spock && spock.webex && spock.webex.internal.presence.unsubscribe([mccoy.id, spock.id])
|
|
133
|
+
);
|
|
121
134
|
|
|
122
|
-
it('subscribes to a person id and returns subscription status', () =>
|
|
123
|
-
.then((presenceResponse) => {
|
|
135
|
+
it('subscribes to a person id and returns subscription status', () =>
|
|
136
|
+
spock.webex.internal.presence.subscribe(mccoy.id).then((presenceResponse) => {
|
|
124
137
|
assert.property(presenceResponse, 'responses');
|
|
125
138
|
assert.equal(presenceResponse.responses.length, 1);
|
|
126
139
|
assert.equal(presenceResponse.responses[0].subject, mccoy.id);
|
|
127
140
|
}));
|
|
128
141
|
|
|
129
142
|
it('subscribes and returns subscription status of a list of people ids', () =>
|
|
130
|
-
spock.webex.internal.presence.subscribe([mccoy.id, spock.id])
|
|
131
|
-
.
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}));
|
|
143
|
+
spock.webex.internal.presence.subscribe([mccoy.id, spock.id]).then((presenceResponse) => {
|
|
144
|
+
assert.property(presenceResponse, 'responses');
|
|
145
|
+
assert.equal(presenceResponse.responses.length, 2);
|
|
146
|
+
assert.equal(presenceResponse.responses[0].subject, mccoy.id);
|
|
147
|
+
assert.equal(presenceResponse.responses[1].subject, spock.id);
|
|
148
|
+
}));
|
|
137
149
|
|
|
138
150
|
// Note: The presence service no longer accepts setting status to "inactive".
|
|
139
151
|
// Inactivity is now determined by a "last active time" of greater than 10 minutes.
|
|
140
|
-
it(
|
|
141
|
-
spock.webex.internal.presence
|
|
152
|
+
it("should receive a mercury event for a subscribed person's change", () =>
|
|
153
|
+
spock.webex.internal.presence
|
|
154
|
+
.subscribe(mccoy.id)
|
|
142
155
|
// 'active' status
|
|
143
|
-
.then(() =>
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
156
|
+
.then(() =>
|
|
157
|
+
Promise.all([
|
|
158
|
+
expectEvent(
|
|
159
|
+
10000,
|
|
160
|
+
'event:apheleia.subscription_update',
|
|
161
|
+
spock.webex.internal.mercury,
|
|
162
|
+
'spock should get the presence active event'
|
|
163
|
+
),
|
|
164
|
+
mccoy.webex.internal.presence.setStatus('active', 1500),
|
|
165
|
+
])
|
|
166
|
+
)
|
|
167
|
+
.then(([event]) =>
|
|
168
|
+
assert.equal(
|
|
169
|
+
event.data.status,
|
|
170
|
+
'active',
|
|
171
|
+
'mccoy presence event status should be active'
|
|
172
|
+
)
|
|
173
|
+
)
|
|
148
174
|
// 'dnd' status
|
|
149
|
-
.then(() =>
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
175
|
+
.then(() =>
|
|
176
|
+
Promise.all([
|
|
177
|
+
expectEvent(
|
|
178
|
+
10000,
|
|
179
|
+
'event:apheleia.subscription_update',
|
|
180
|
+
spock.webex.internal.mercury,
|
|
181
|
+
'spock should get the presence dnd event'
|
|
182
|
+
),
|
|
183
|
+
mccoy.webex.internal.presence.setStatus('dnd', 1500),
|
|
184
|
+
])
|
|
185
|
+
)
|
|
186
|
+
.then(([event]) =>
|
|
187
|
+
assert.equal(event.data.status, 'dnd', 'mccoy presence event status should be dnd')
|
|
188
|
+
));
|
|
154
189
|
});
|
|
155
190
|
|
|
156
191
|
describe('#unsubscribe', () => {
|
|
157
192
|
it('unsubscribes to presence updates of a single person id', () =>
|
|
158
|
-
spock.webex.internal.presence
|
|
193
|
+
spock.webex.internal.presence
|
|
194
|
+
.unsubscribe(mccoy.id)
|
|
159
195
|
.then((res) => assert.statusCode(res, 200)));
|
|
160
196
|
|
|
161
197
|
it('unsubscribes to presence updates of a list of people ids', () =>
|
|
162
|
-
spock.webex.internal.presence
|
|
198
|
+
spock.webex.internal.presence
|
|
199
|
+
.unsubscribe([mccoy.id, spock.id])
|
|
163
200
|
.then((res) => assert.statusCode(res, 200)));
|
|
164
201
|
});
|
|
165
202
|
|
|
166
203
|
describe('#setStatus', () => {
|
|
167
204
|
it('sets the presence status of the current user', () =>
|
|
168
|
-
spock.webex.internal.presence.setStatus('dnd', 1500)
|
|
169
|
-
.
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}));
|
|
205
|
+
spock.webex.internal.presence.setStatus('dnd', 1500).then((statusResponse) => {
|
|
206
|
+
assert.property(statusResponse, 'subject');
|
|
207
|
+
assert.property(statusResponse, 'status');
|
|
208
|
+
assert.equal(statusResponse.subject, spock.id);
|
|
209
|
+
assert.equal(statusResponse.status, 'dnd');
|
|
210
|
+
}));
|
|
175
211
|
});
|
|
176
212
|
});
|
|
177
213
|
});
|
|
@@ -18,22 +18,18 @@ describe('presence-worker', () => {
|
|
|
18
18
|
webex = new MockWebex({
|
|
19
19
|
children: {
|
|
20
20
|
mercury: Mercury,
|
|
21
|
-
presence: Presence
|
|
22
|
-
}
|
|
21
|
+
presence: Presence,
|
|
22
|
+
},
|
|
23
23
|
});
|
|
24
24
|
worker = new PresenceWorker();
|
|
25
25
|
worker.webex = webex;
|
|
26
26
|
});
|
|
27
27
|
|
|
28
28
|
describe('#initialize()', () => {
|
|
29
|
-
it('requires webex', () =>
|
|
30
|
-
worker.initialize,
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
it('requires webex internal', () => assert.throws(
|
|
34
|
-
() => worker.initialize({}),
|
|
35
|
-
/Must initialize Presence Worker with webex!/
|
|
36
|
-
));
|
|
29
|
+
it('requires webex', () =>
|
|
30
|
+
assert.throws(worker.initialize, /Must initialize Presence Worker with webex!/));
|
|
31
|
+
it('requires webex internal', () =>
|
|
32
|
+
assert.throws(() => worker.initialize({}), /Must initialize Presence Worker with webex!/));
|
|
37
33
|
});
|
|
38
34
|
|
|
39
35
|
describe('#enqueue()', () => {
|
|
@@ -119,12 +115,11 @@ describe('presence-worker', () => {
|
|
|
119
115
|
const boarding = {
|
|
120
116
|
pam: true,
|
|
121
117
|
jim: true,
|
|
122
|
-
dwight: true
|
|
118
|
+
dwight: true,
|
|
123
119
|
};
|
|
124
120
|
|
|
125
121
|
it('moves fetchers to flights', () => {
|
|
126
|
-
webex.internal.presence.list = sinon.stub()
|
|
127
|
-
.returns(Promise.resolve({statusList: []}));
|
|
122
|
+
webex.internal.presence.list = sinon.stub().returns(Promise.resolve({statusList: []}));
|
|
128
123
|
|
|
129
124
|
worker.fetchers = boarding;
|
|
130
125
|
|
|
@@ -134,13 +129,10 @@ describe('presence-worker', () => {
|
|
|
134
129
|
});
|
|
135
130
|
|
|
136
131
|
it('calls presence.list', async () => {
|
|
137
|
-
const response = [
|
|
138
|
-
{subject: 'pam'},
|
|
139
|
-
{subject: 'jim'},
|
|
140
|
-
{subject: 'dwight'}
|
|
141
|
-
];
|
|
132
|
+
const response = [{subject: 'pam'}, {subject: 'jim'}, {subject: 'dwight'}];
|
|
142
133
|
|
|
143
|
-
webex.internal.presence.list = sinon
|
|
134
|
+
webex.internal.presence.list = sinon
|
|
135
|
+
.stub()
|
|
144
136
|
.returns(Promise.resolve({statusList: response}));
|
|
145
137
|
webex.internal.presence.emitEvent = sinon.stub();
|
|
146
138
|
|
|
@@ -151,9 +143,10 @@ describe('presence-worker', () => {
|
|
|
151
143
|
assert.calledWith(webex.internal.presence.list, Object.keys(boarding));
|
|
152
144
|
assert.isEmpty(worker.flights);
|
|
153
145
|
assert.deepEqual(Object.keys(worker.presences), Object.keys(boarding));
|
|
154
|
-
assert.calledWith(webex.internal.presence.emitEvent,
|
|
155
|
-
'
|
|
156
|
-
|
|
146
|
+
assert.calledWith(webex.internal.presence.emitEvent, 'updated', {
|
|
147
|
+
type: 'presence',
|
|
148
|
+
payload: {statusList: response},
|
|
149
|
+
});
|
|
157
150
|
});
|
|
158
151
|
});
|
|
159
152
|
|
|
@@ -163,7 +156,7 @@ describe('presence-worker', () => {
|
|
|
163
156
|
const scouts = {
|
|
164
157
|
pam: now - 60001, // move them back a little over a minute
|
|
165
158
|
jim: now - 60001,
|
|
166
|
-
dwight: now
|
|
159
|
+
dwight: now,
|
|
167
160
|
};
|
|
168
161
|
|
|
169
162
|
worker.campers = scouts;
|
|
@@ -180,11 +173,11 @@ describe('presence-worker', () => {
|
|
|
180
173
|
const subbies = {
|
|
181
174
|
pam: now,
|
|
182
175
|
jim: now + 61000, // move forward a little over a minute
|
|
183
|
-
dwight: now
|
|
176
|
+
dwight: now,
|
|
184
177
|
};
|
|
185
178
|
const watching = {
|
|
186
179
|
pam: 1,
|
|
187
|
-
jim: 1
|
|
180
|
+
jim: 1,
|
|
188
181
|
};
|
|
189
182
|
|
|
190
183
|
worker.watchers = watching;
|
|
@@ -200,7 +193,7 @@ describe('presence-worker', () => {
|
|
|
200
193
|
const subbies = {
|
|
201
194
|
pam: now + 600000, // move forward 10 minutes
|
|
202
195
|
jim: now - 20000, // move back 20 seconds
|
|
203
|
-
dwight: now - 60000 // move back 1 minute
|
|
196
|
+
dwight: now - 60000, // move back 1 minute
|
|
204
197
|
};
|
|
205
198
|
|
|
206
199
|
worker.subscribers = subbies;
|
|
@@ -218,7 +211,7 @@ describe('presence-worker', () => {
|
|
|
218
211
|
const presences = {
|
|
219
212
|
pam: now - 300000, // 5 minutes ago
|
|
220
213
|
jim: now - 600001, // little over 10 minutes ago
|
|
221
|
-
dwight: now - 1200000 // 20 minutes ago
|
|
214
|
+
dwight: now - 1200000, // 20 minutes ago
|
|
222
215
|
};
|
|
223
216
|
|
|
224
217
|
webex.internal.presence.emitEvent = sinon.stub();
|
|
@@ -226,30 +219,33 @@ describe('presence-worker', () => {
|
|
|
226
219
|
|
|
227
220
|
worker.cleanPresences();
|
|
228
221
|
|
|
229
|
-
assert.calledWith(webex.internal.presence.emitEvent,
|
|
230
|
-
'
|
|
231
|
-
|
|
222
|
+
assert.calledWith(webex.internal.presence.emitEvent, 'updated', {
|
|
223
|
+
type: 'delete',
|
|
224
|
+
payload: ['jim', 'dwight'],
|
|
225
|
+
});
|
|
232
226
|
});
|
|
233
227
|
});
|
|
234
228
|
|
|
235
229
|
describe('#groundskeeper()', () => {
|
|
236
230
|
it('renews subscriptions', async () => {
|
|
237
|
-
webex.internal.presence.subscribe = sinon.stub()
|
|
238
|
-
|
|
231
|
+
webex.internal.presence.subscribe = sinon.stub().returns(
|
|
232
|
+
Promise.resolve({
|
|
239
233
|
responses: [
|
|
240
234
|
{
|
|
241
235
|
responseCode: 200,
|
|
242
236
|
subscriptionTtl: 600,
|
|
243
237
|
subject: 'pam',
|
|
244
238
|
status: {
|
|
245
|
-
subject: 'pam'
|
|
246
|
-
}
|
|
239
|
+
subject: 'pam',
|
|
240
|
+
},
|
|
247
241
|
},
|
|
248
242
|
{
|
|
249
243
|
responseCode: 500,
|
|
250
|
-
subject: 'jim'
|
|
251
|
-
}
|
|
252
|
-
|
|
244
|
+
subject: 'jim',
|
|
245
|
+
},
|
|
246
|
+
],
|
|
247
|
+
})
|
|
248
|
+
);
|
|
253
249
|
worker.checkCampers = sinon.stub().returns(['pam']);
|
|
254
250
|
worker.checkSubscriptions = sinon.stub().returns(['jim']);
|
|
255
251
|
worker.cleanPresences = sinon.stub();
|
|
@@ -14,23 +14,30 @@ describe('plugin-presence', () => {
|
|
|
14
14
|
beforeEach(() => {
|
|
15
15
|
webex = new MockWebex({
|
|
16
16
|
children: {
|
|
17
|
-
presence: Presence
|
|
18
|
-
}
|
|
17
|
+
presence: Presence,
|
|
18
|
+
},
|
|
19
19
|
});
|
|
20
20
|
});
|
|
21
21
|
|
|
22
22
|
describe('#get()', () => {
|
|
23
|
-
it('requires a person id parameter', () =>
|
|
23
|
+
it('requires a person id parameter', () =>
|
|
24
|
+
assert.isRejected(webex.internal.presence.get(), /A person id is required/));
|
|
24
25
|
});
|
|
25
26
|
|
|
26
27
|
describe('#list()', () => {
|
|
27
|
-
it('requires a parameter', () =>
|
|
28
|
+
it('requires a parameter', () =>
|
|
29
|
+
assert.isRejected(webex.internal.presence.list(), /An array of person ids is required/));
|
|
28
30
|
|
|
29
|
-
it('requires a person array parameter', () =>
|
|
31
|
+
it('requires a person array parameter', () =>
|
|
32
|
+
assert.isRejected(
|
|
33
|
+
webex.internal.presence.list('abc'),
|
|
34
|
+
/An array of person ids is required/
|
|
35
|
+
));
|
|
30
36
|
});
|
|
31
37
|
|
|
32
38
|
describe('#subscribe()', () => {
|
|
33
|
-
it('requires a person parameter', () =>
|
|
39
|
+
it('requires a person parameter', () =>
|
|
40
|
+
assert.isRejected(webex.internal.presence.subscribe(), /A person id is required/));
|
|
34
41
|
it('subscription request called twice with batch of 100 ids', () => {
|
|
35
42
|
const ids = [...Array(100).keys()];
|
|
36
43
|
|
|
@@ -38,7 +45,7 @@ describe('plugin-presence', () => {
|
|
|
38
45
|
return Promise.resolve({
|
|
39
46
|
statusCode: 204,
|
|
40
47
|
body: [],
|
|
41
|
-
options
|
|
48
|
+
options,
|
|
42
49
|
});
|
|
43
50
|
};
|
|
44
51
|
sinon.spy(webex, 'request');
|
|
@@ -49,11 +56,13 @@ describe('plugin-presence', () => {
|
|
|
49
56
|
});
|
|
50
57
|
|
|
51
58
|
describe('#unsubscribe()', () => {
|
|
52
|
-
it('requires a person parameter', () =>
|
|
59
|
+
it('requires a person parameter', () =>
|
|
60
|
+
assert.isRejected(webex.internal.presence.unsubscribe(), /A person id is required/));
|
|
53
61
|
});
|
|
54
62
|
|
|
55
63
|
describe('#setStatus()', () => {
|
|
56
|
-
it('requires a status', () =>
|
|
64
|
+
it('requires a status', () =>
|
|
65
|
+
assert.isRejected(webex.internal.presence.setStatus(), /A status is required/));
|
|
57
66
|
});
|
|
58
67
|
});
|
|
59
68
|
});
|