Skip to content

Commit 8712d7a

Browse files
committed
feat(internal-plugin-usersub): add usersub plugin to allow the publishing of cross-client-state
1 parent 0af7097 commit 8712d7a

14 files changed

+441
-1
lines changed

jest.config.js

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ const packages = [
2626
'@webex/internal-plugin-support',
2727
'@webex/internal-plugin-team',
2828
'@webex/internal-plugin-user',
29+
'@webex/internal-plugin-usersub',
2930
'@webex/internal-plugin-voicea',
3031
'@webex/internal-plugin-wdm',
3132
'@webex/jsdoctrinetest',

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
},
2828
"scripts": {
2929
"@all": "yarn @workspaces run",
30-
"@legacy": "yarn @workspaces --from \"{@webex/common,@webex/common-evented,@webex/common-timers,@webex/helper-html,@webex/helper-image,@webex/http-core,@webex/internal-plugin-avatar,@webex/internal-plugin-board,@webex/internal-plugin-calendar,@webex/internal-plugin-conversation,@webex/internal-plugin-device,@webex/internal-plugin-dss,@webex/internal-plugin-ediscovery,@webex/internal-plugin-encryption,@webex/internal-plugin-feature,@webex/internal-plugin-flag,@webex/internal-plugin-llm,@webex/internal-plugin-locus,@webex/internal-plugin-lyra,@webex/internal-plugin-mercury,@webex/internal-plugin-metrics,@webex/internal-plugin-presence,@webex/internal-plugin-scheduler,@webex/internal-plugin-search,@webex/internal-plugin-support,@webex/internal-plugin-team,@webex/internal-plugin-user,@webex/internal-plugin-voicea,@webex/internal-plugin-wdm,@webex/jsdoctrinetest,@webex/media-helpers,@webex/plugin-attachment-actions,@webex/plugin-authorization,@webex/plugin-authorization-browser,@webex/plugin-authorization-browser-first-party,@webex/plugin-authorization-node,@webex/plugin-device-manager,@webex/plugin-logger,@webex/plugin-meetings,@webex/plugin-memberships,@webex/plugin-messages,@webex/plugin-people,@webex/plugin-presence,@webex/plugin-rooms,@webex/plugin-team-memberships,@webex/plugin-teams,@webex/plugin-webhooks,@webex/recipe-private-web-client,@webex/storage-adapter-local-forage,@webex/storage-adapter-local-storage,@webex/storage-adapter-session-storage,@webex/storage-adapter-spec,@webex/test-helper-appid,@webex/test-helper-automation,@webex/test-helper-chai,@webex/test-helper-file,@webex/test-helper-make-local-url,@webex/test-helper-mocha,@webex/test-helper-mock-web-socket,@webex/test-helper-mock-webex,@webex/test-helper-refresh-callback,@webex/test-helper-retry,@webex/test-helper-server,@webex/test-helper-test-users,@webex/test-users,@webex/webex-core,@webex/webex-server,@webex/webrtc,@webex/xunit-with-logs,webex}\" run",
30+
"@legacy": "yarn @workspaces --from \"{@webex/common,@webex/common-evented,@webex/common-timers,@webex/helper-html,@webex/helper-image,@webex/http-core,@webex/internal-plugin-avatar,@webex/internal-plugin-board,@webex/internal-plugin-calendar,@webex/internal-plugin-conversation,@webex/internal-plugin-device,@webex/internal-plugin-dss,@webex/internal-plugin-ediscovery,@webex/internal-plugin-encryption,@webex/internal-plugin-feature,@webex/internal-plugin-flag,@webex/internal-plugin-llm,@webex/internal-plugin-locus,@webex/internal-plugin-lyra,@webex/internal-plugin-mercury,@webex/internal-plugin-metrics,@webex/internal-plugin-presence,@webex/internal-plugin-scheduler,@webex/internal-plugin-search,@webex/internal-plugin-support,@webex/internal-plugin-team,@webex/internal-plugin-user,@webex/internal-plugin-usersub,@webex/internal-plugin-voicea,@webex/internal-plugin-wdm,@webex/jsdoctrinetest,@webex/media-helpers,@webex/plugin-attachment-actions,@webex/plugin-authorization,@webex/plugin-authorization-browser,@webex/plugin-authorization-browser-first-party,@webex/plugin-authorization-node,@webex/plugin-device-manager,@webex/plugin-logger,@webex/plugin-meetings,@webex/plugin-memberships,@webex/plugin-messages,@webex/plugin-people,@webex/plugin-presence,@webex/plugin-rooms,@webex/plugin-team-memberships,@webex/plugin-teams,@webex/plugin-webhooks,@webex/recipe-private-web-client,@webex/storage-adapter-local-forage,@webex/storage-adapter-local-storage,@webex/storage-adapter-session-storage,@webex/storage-adapter-spec,@webex/test-helper-appid,@webex/test-helper-automation,@webex/test-helper-chai,@webex/test-helper-file,@webex/test-helper-make-local-url,@webex/test-helper-mocha,@webex/test-helper-mock-web-socket,@webex/test-helper-mock-webex,@webex/test-helper-refresh-callback,@webex/test-helper-retry,@webex/test-helper-server,@webex/test-helper-test-users,@webex/test-users,@webex/webex-core,@webex/webex-server,@webex/webrtc,@webex/xunit-with-logs,webex}\" run",
3131
"@legacy-tools": "yarn @workspaces --topological-dev --from \"{@webex/babel-config-legacy,@webex/env-config-legacy,@webex/eslint-config-legacy,@webex/jest-config-legacy,@webex/legacy-tools}\" run",
3232
"@tools": "yarn @workspaces --topological-dev --from \"{@webex/cli-tools,@webex/package-tools}\" run",
3333
"@workspaces": "yarn workspaces foreach --parallel --verbose",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
const config = {
2+
root: true,
3+
extends: ['@webex/eslint-config-legacy'],
4+
};
5+
6+
module.exports = config;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# @webex/internal-plugin-usersub
2+
3+
[![standard-readme compliant](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme)
4+
5+
> Plugin for the UserSub services
6+
7+
This is an internal Cisco Webex plugin. As such, it does not strictly adhere to semantic versioning. Use at your own risk. If you're not working on one of our first party clients, please look at our [developer api](https://developer.webex.com/) and stick to our public plugins.
8+
9+
- [Install](#install)
10+
- [Usage](#usage)
11+
- [Contribute](#contribute)
12+
- [Maintainers](#maintainers)
13+
- [License](#license)
14+
15+
## Install
16+
17+
```bash
18+
npm install --save @webex/internal-plugin-usersub
19+
```
20+
21+
## Usage
22+
23+
```js
24+
import '@webex/internal-plugin-usersub';
25+
26+
import WebexCore from '@webex/webex-core';
27+
28+
const webex = new WebexCore();
29+
webex.internal.usersub.WHATEVER;
30+
```
31+
32+
## Maintainers
33+
34+
This package is maintained by [Cisco Webex for Developers](https://developer.webex.com/).
35+
36+
## Contribute
37+
38+
Pull requests welcome. Please see [CONTRIBUTING.md](https://github.com/webex/webex-js-sdk/blob/master/CONTRIBUTING.md) for more details.
39+
40+
## License
41+
42+
© 2016-2020 Cisco and/or its affiliates. All Rights Reserved.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
const babelConfigLegacy = require('@webex/babel-config-legacy');
2+
3+
module.exports = babelConfigLegacy;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
const config = require('@webex/jest-config-legacy');
2+
3+
module.exports = config;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
{
2+
"name": "@webex/internal-plugin-usersub",
3+
"description": "",
4+
"license": "MIT",
5+
"main": "dist/index.js",
6+
"devMain": "src/index.js",
7+
"repository": {
8+
"type": "git",
9+
"url": "https://github.com/webex/webex-js-sdk.git",
10+
"directory": "packages/@webex/internal-plugin-usersub"
11+
},
12+
"engines": {
13+
"node": ">=16"
14+
},
15+
"browserify": {
16+
"transform": [
17+
"babelify",
18+
"envify"
19+
]
20+
},
21+
"devDependencies": {
22+
"@babel/core": "^7.17.10",
23+
"@webex/babel-config-legacy": "workspace:*",
24+
"@webex/eslint-config-legacy": "workspace:*",
25+
"@webex/jest-config-legacy": "workspace:*",
26+
"@webex/legacy-tools": "workspace:*",
27+
"@webex/test-helper-chai": "workspace:*",
28+
"@webex/test-helper-mocha": "workspace:*",
29+
"@webex/test-helper-mock-webex": "workspace:*",
30+
"@webex/test-helper-test-users": "workspace:*",
31+
"eslint": "^8.24.0",
32+
"prettier": "^2.7.1",
33+
"sinon": "^9.2.4"
34+
},
35+
"dependencies": {
36+
"@webex/common": "workspace:*",
37+
"@webex/common-timers": "workspace:*",
38+
"@webex/internal-plugin-device": "workspace:*",
39+
"@webex/test-helper-chai": "workspace:*",
40+
"@webex/test-helper-mock-webex": "workspace:*",
41+
"@webex/test-helper-test-users": "workspace:*",
42+
"@webex/webex-core": "workspace:*",
43+
"lodash": "^4.17.21",
44+
"uuid": "^3.3.2"
45+
},
46+
"scripts": {
47+
"build": "yarn build:src",
48+
"build:src": "webex-legacy-tools build -dest \"./dist\" -src \"./src\" -js -ts -maps",
49+
"deploy:npm": "yarn npm publish",
50+
"test": "yarn test:style && yarn test:unit && yarn test:integration && yarn test:browser",
51+
"test:browser:broken": "webex-legacy-tools test --integration --runner karma",
52+
"test:style": "eslint ./src/**/*.*",
53+
"test:unit": "webex-legacy-tools test --unit --runner jest"
54+
}
55+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = {browser: true};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/*!
2+
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3+
*/
4+
5+
export default {
6+
userSub: {},
7+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export const EXPIRATION_OFFSET = 60 * 1000; // 1 minute in ms
2+
export const USERSUB_SERVICE_NAME = 'usersub';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/*!
2+
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3+
*/
4+
5+
import {registerInternalPlugin} from '@webex/webex-core';
6+
7+
import Usersub from './usersub';
8+
import config from './config';
9+
10+
registerInternalPlugin('usersub', Usersub, {config});
11+
12+
export {default} from './usersub';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
/*!
2+
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3+
*/
4+
5+
import '@webex/internal-plugin-device';
6+
7+
import {WebexPlugin} from '@webex/webex-core';
8+
import {safeSetTimeout} from '@webex/common-timers';
9+
import {EXPIRATION_OFFSET, USERSUB_SERVICE_NAME} from './constants';
10+
11+
/**
12+
* @class
13+
* @extends WebexPlugin
14+
*/
15+
const Usersub = WebexPlugin.extend({
16+
namespace: 'Usersub',
17+
18+
session: {
19+
crossClientState: {
20+
type: 'object',
21+
/**
22+
* Returns a new Map instance as the default value for crossClientState.
23+
* @returns {Map}
24+
*/
25+
default() {
26+
return new Map();
27+
},
28+
},
29+
30+
refreshTimer: {
31+
default: undefined,
32+
type: 'any',
33+
},
34+
},
35+
36+
/**
37+
* Sets the value for answer-calls-on-wxcc for the calling application.
38+
* @param {boolean} enable - The state will be enabled/disabled.
39+
* @param {string} appName - The app setting the state.
40+
* @param {number} ttl - Time To Live for the event in seconds.
41+
* @returns {Promise}
42+
*/
43+
updateAnswerCallsCrossClient(enable: boolean, appName: string, ttl: number) {
44+
if (!appName) {
45+
return Promise.reject(new Error('An appName is required'));
46+
}
47+
48+
const jsonData = {
49+
users: [this.webex.internal.device.userId],
50+
compositions: [
51+
{
52+
type: 'cross-client-state',
53+
ttl,
54+
composition: {
55+
devices: [
56+
{
57+
deviceId: this._extractIdFromUrl(this.webex.internal.device.url),
58+
appName,
59+
state: {
60+
'answer-calls-on-wxcc': enable,
61+
},
62+
},
63+
],
64+
},
65+
},
66+
],
67+
};
68+
69+
return this.webex
70+
.request({
71+
method: 'POST',
72+
service: USERSUB_SERVICE_NAME,
73+
resource: 'publish',
74+
body: jsonData,
75+
})
76+
.then((response) => {
77+
this.crossClientState.set(appName, enable);
78+
this._startRefreshTimer(appName, ttl);
79+
80+
return response.body;
81+
})
82+
.catch((error) => {
83+
this.logger.error(
84+
`userSub: updateAnswerCallsCrossClient failed with error: , ${error.message}`
85+
);
86+
87+
return Promise.reject(error);
88+
});
89+
},
90+
91+
/**
92+
* Starts the refresh timer for the cross-client state.
93+
* @private
94+
* @param {string} appName - The app setting the state.
95+
* @param {number} ttl - Time To Live for the event in seconds.
96+
* @returns {void}
97+
*/
98+
_startRefreshTimer(appName: string, ttl: number): void {
99+
this._stopRefreshTimer();
100+
const answerCallsState = this.crossClientState.get(appName);
101+
if (answerCallsState) {
102+
const refreshTime = ttl * 1000 - EXPIRATION_OFFSET;
103+
this.refreshTimer = safeSetTimeout(
104+
() => this.updateAnswerCallsCrossClient(answerCallsState, appName, ttl),
105+
refreshTime
106+
);
107+
}
108+
},
109+
110+
/**
111+
* Stops the refresh timer for the cross-client state.
112+
* @private
113+
* @returns {void}
114+
*/
115+
_stopRefreshTimer(): void {
116+
if (this.refreshTimer) {
117+
clearTimeout(this.refreshTimer);
118+
}
119+
},
120+
121+
/**
122+
* Extracts the device ID from a given URL.
123+
* @param {string} url - The URL to extract the device ID from.
124+
* @returns {string | null} The extracted device ID or null if not found.
125+
*/
126+
_extractIdFromUrl(url: string): string | null {
127+
if (url) {
128+
const regex = /\/devices\/(.+)/;
129+
const match = url.match(regex);
130+
131+
return match ? match[1] : null;
132+
}
133+
134+
return null;
135+
},
136+
});
137+
138+
export default Usersub;

0 commit comments

Comments
 (0)