@webex/webex-core 3.8.0-next.21 → 3.8.0-next.22
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/dist/index.js +6 -6
- package/dist/index.js.map +1 -1
- package/dist/lib/batcher.js +1 -1
- package/dist/lib/credentials/credentials.js +1 -1
- package/dist/lib/credentials/token.js +1 -1
- package/dist/lib/services/services.js +1 -1
- package/dist/lib/services-v2/constants.js.map +1 -1
- package/dist/lib/services-v2/index.js +5 -5
- package/dist/lib/services-v2/index.js.map +1 -1
- package/dist/lib/services-v2/service-catalog.js +26 -30
- package/dist/lib/services-v2/service-catalog.js.map +1 -1
- package/dist/lib/services-v2/service-detail.js +94 -0
- package/dist/lib/services-v2/service-detail.js.map +1 -0
- package/dist/lib/services-v2/service-fed-ramp.js.map +1 -1
- package/dist/lib/services-v2/services-v2.js +70 -48
- package/dist/lib/services-v2/services-v2.js.map +1 -1
- package/dist/lib/services-v2/types.js +7 -0
- package/dist/lib/services-v2/types.js.map +1 -0
- package/dist/plugins/logger.js +1 -1
- package/dist/webex-core.js +2 -2
- package/package.json +13 -13
- package/src/index.js +1 -1
- package/src/lib/services-v2/{index.js → index.ts} +1 -1
- package/src/lib/services-v2/{service-catalog.js → service-catalog.ts} +41 -47
- package/src/lib/services-v2/service-detail.ts +97 -0
- package/src/lib/services-v2/services-v2.js +41 -24
- package/src/lib/services-v2/types.ts +12 -0
- package/test/fixtures/host-catalog-v2.js +18 -16
- package/test/unit/spec/services-v2/service-detail.ts +147 -0
- package/test/unit/spec/services-v2/services-v2.js +12 -14
- package/dist/lib/services-v2/service-url.js +0 -119
- package/dist/lib/services-v2/service-url.js.map +0 -1
- package/src/lib/services-v2/service-url.js +0 -124
- /package/src/lib/services-v2/{constants.js → constants.ts} +0 -0
- /package/src/lib/services-v2/{service-fed-ramp.js → service-fed-ramp.ts} +0 -0
|
@@ -20,4 +20,4 @@ export {default as ServiceInterceptorV2} from './interceptors/service';
|
|
|
20
20
|
export {default as ServerErrorInterceptorV2} from './interceptors/server-error';
|
|
21
21
|
export {default as HostMapInterceptorV2} from './interceptors/hostmap';
|
|
22
22
|
export {default as ServiceCatalogV2} from './service-catalog';
|
|
23
|
-
export {default as
|
|
23
|
+
export {default as ServiceDetail} from './service-detail';
|
|
@@ -3,7 +3,8 @@ import Url from 'url';
|
|
|
3
3
|
import AmpState from 'ampersand-state';
|
|
4
4
|
|
|
5
5
|
import {union} from 'lodash';
|
|
6
|
-
import
|
|
6
|
+
import ServiceDetail from './service-detail';
|
|
7
|
+
import {IServiceDetail} from './types';
|
|
7
8
|
|
|
8
9
|
/* eslint-disable no-underscore-dangle */
|
|
9
10
|
/**
|
|
@@ -56,13 +57,13 @@ const ServiceCatalog = AmpState.extend({
|
|
|
56
57
|
|
|
57
58
|
/**
|
|
58
59
|
* @private
|
|
59
|
-
* Search the service url array to locate a `
|
|
60
|
+
* Search the service url array to locate a `ServiceDetail`
|
|
60
61
|
* class object based on its name.
|
|
61
62
|
* @param {string} name
|
|
62
63
|
* @param {string} [serviceGroup]
|
|
63
|
-
* @returns {
|
|
64
|
+
* @returns {IServiceDetail}
|
|
64
65
|
*/
|
|
65
|
-
_getUrl(name, serviceGroup) {
|
|
66
|
+
_getUrl(name: string, serviceGroup: string): IServiceDetail | undefined {
|
|
66
67
|
const serviceUrls =
|
|
67
68
|
typeof serviceGroup === 'string'
|
|
68
69
|
? this.serviceGroups[serviceGroup] || []
|
|
@@ -74,16 +75,16 @@ const ServiceCatalog = AmpState.extend({
|
|
|
74
75
|
...this.serviceGroups.discovery,
|
|
75
76
|
];
|
|
76
77
|
|
|
77
|
-
return serviceUrls.find((serviceUrl) => serviceUrl.
|
|
78
|
+
return serviceUrls.find((serviceUrl: IServiceDetail) => serviceUrl.serviceName === name);
|
|
78
79
|
},
|
|
79
80
|
|
|
80
81
|
/**
|
|
81
82
|
* @private
|
|
82
|
-
* Generate an array of `
|
|
83
|
+
* Generate an array of `ServiceDetail`s that is organized from highest auth
|
|
83
84
|
* level to lowest auth level.
|
|
84
|
-
* @returns {Array<
|
|
85
|
+
* @returns {Array<IServiceDetail>} - array of `ServiceDetail`s
|
|
85
86
|
*/
|
|
86
|
-
_listServiceUrls() {
|
|
87
|
+
_listServiceUrls(): Array<IServiceDetail> {
|
|
87
88
|
return [
|
|
88
89
|
...this.serviceGroups.override,
|
|
89
90
|
...this.serviceGroups.postauth,
|
|
@@ -95,39 +96,37 @@ const ServiceCatalog = AmpState.extend({
|
|
|
95
96
|
|
|
96
97
|
/**
|
|
97
98
|
* @private
|
|
98
|
-
* Safely load one or more `
|
|
99
|
+
* Safely load one or more `ServiceDetail`s into this `Services` instance.
|
|
99
100
|
* @param {string} serviceGroup
|
|
100
|
-
* @param {Array<
|
|
101
|
+
* @param {Array<IServiceDetail>} services
|
|
101
102
|
* @returns {Services}
|
|
102
103
|
*/
|
|
103
|
-
_loadServiceUrls(serviceGroup, services) {
|
|
104
|
+
_loadServiceUrls(serviceGroup: string, services: Array<IServiceDetail>): void {
|
|
104
105
|
// declare namespaces outside of loop
|
|
105
|
-
let existingService;
|
|
106
|
+
let existingService: IServiceDetail | undefined;
|
|
106
107
|
|
|
107
108
|
services.forEach((service) => {
|
|
108
|
-
existingService = this._getUrl(service.
|
|
109
|
+
existingService = this._getUrl(service.serviceName, serviceGroup);
|
|
109
110
|
|
|
110
111
|
if (!existingService) {
|
|
111
112
|
this.serviceGroups[serviceGroup].push(service);
|
|
112
113
|
}
|
|
113
114
|
});
|
|
114
|
-
|
|
115
|
-
return this;
|
|
116
115
|
},
|
|
117
116
|
|
|
118
117
|
/**
|
|
119
118
|
* @private
|
|
120
|
-
* Safely unload one or more `
|
|
119
|
+
* Safely unload one or more `ServiceDetail`s into this `Services` instance
|
|
121
120
|
* @param {string} serviceGroup
|
|
122
|
-
* @param {Array<
|
|
121
|
+
* @param {Array<IServiceDetail>} services
|
|
123
122
|
* @returns {Services}
|
|
124
123
|
*/
|
|
125
|
-
_unloadServiceUrls(serviceGroup, services) {
|
|
124
|
+
_unloadServiceUrls(serviceGroup: string, services: Array<IServiceDetail>): void {
|
|
126
125
|
// declare namespaces outside of loop
|
|
127
|
-
let existingService;
|
|
126
|
+
let existingService: IServiceDetail | undefined;
|
|
128
127
|
|
|
129
128
|
services.forEach((service) => {
|
|
130
|
-
existingService = this._getUrl(service.
|
|
129
|
+
existingService = this._getUrl(service.serviceName, serviceGroup);
|
|
131
130
|
|
|
132
131
|
if (existingService) {
|
|
133
132
|
this.serviceGroups[serviceGroup].splice(
|
|
@@ -136,8 +135,6 @@ const ServiceCatalog = AmpState.extend({
|
|
|
136
135
|
);
|
|
137
136
|
}
|
|
138
137
|
});
|
|
139
|
-
|
|
140
|
-
return this;
|
|
141
138
|
},
|
|
142
139
|
|
|
143
140
|
/**
|
|
@@ -145,7 +142,7 @@ const ServiceCatalog = AmpState.extend({
|
|
|
145
142
|
*
|
|
146
143
|
* @returns {void}
|
|
147
144
|
*/
|
|
148
|
-
clean() {
|
|
145
|
+
clean(): void {
|
|
149
146
|
this.serviceGroups.preauth.length = 0;
|
|
150
147
|
this.serviceGroups.signin.length = 0;
|
|
151
148
|
this.serviceGroups.postauth.length = 0;
|
|
@@ -160,7 +157,7 @@ const ServiceCatalog = AmpState.extend({
|
|
|
160
157
|
* @param {string} url - Must be parsable by `Url`
|
|
161
158
|
* @returns {string} - ClusterId of a given url
|
|
162
159
|
*/
|
|
163
|
-
findClusterId(url) {
|
|
160
|
+
findClusterId(url: string): string | undefined {
|
|
164
161
|
const incomingUrlObj = Url.parse(url);
|
|
165
162
|
let serviceUrlObj;
|
|
166
163
|
|
|
@@ -205,7 +202,7 @@ const ServiceCatalog = AmpState.extend({
|
|
|
205
202
|
* @returns {string} service.name
|
|
206
203
|
* @returns {string} service.url
|
|
207
204
|
*/
|
|
208
|
-
findServiceFromClusterId({clusterId, priorityHost = true, serviceGroup}
|
|
205
|
+
findServiceFromClusterId({clusterId, priorityHost = true, serviceGroup}) {
|
|
209
206
|
const serviceUrls =
|
|
210
207
|
typeof serviceGroup === 'string'
|
|
211
208
|
? this.serviceGroups[serviceGroup] || []
|
|
@@ -234,9 +231,9 @@ const ServiceCatalog = AmpState.extend({
|
|
|
234
231
|
/**
|
|
235
232
|
* Find a service based on the provided url.
|
|
236
233
|
* @param {string} url - Must be parsable by `Url`
|
|
237
|
-
* @returns {
|
|
234
|
+
* @returns {IServiceDetail} - ServiceDetail assocated with provided url
|
|
238
235
|
*/
|
|
239
|
-
findServiceUrlFromUrl(url) {
|
|
236
|
+
findServiceUrlFromUrl(url: string): IServiceDetail | undefined {
|
|
240
237
|
const serviceUrls = [
|
|
241
238
|
...this.serviceGroups.discovery,
|
|
242
239
|
...this.serviceGroups.preauth,
|
|
@@ -273,7 +270,7 @@ const ServiceCatalog = AmpState.extend({
|
|
|
273
270
|
* @param {string} url - The url to match the allowed domains against.
|
|
274
271
|
* @returns {string} - The matching allowed domain.
|
|
275
272
|
*/
|
|
276
|
-
findAllowedDomain(url) {
|
|
273
|
+
findAllowedDomain(url: string): string {
|
|
277
274
|
const urlObj = Url.parse(url);
|
|
278
275
|
|
|
279
276
|
if (!urlObj.host) {
|
|
@@ -290,7 +287,7 @@ const ServiceCatalog = AmpState.extend({
|
|
|
290
287
|
* @param {string} serviceGroup
|
|
291
288
|
* @returns {string}
|
|
292
289
|
*/
|
|
293
|
-
get(name, priorityHost, serviceGroup) {
|
|
290
|
+
get(name: string, priorityHost: boolean, serviceGroup: string): string | undefined {
|
|
294
291
|
const serviceUrl = this._getUrl(name, serviceGroup);
|
|
295
292
|
|
|
296
293
|
return serviceUrl ? serviceUrl.get(priorityHost) : undefined;
|
|
@@ -301,7 +298,7 @@ const ServiceCatalog = AmpState.extend({
|
|
|
301
298
|
*
|
|
302
299
|
* @returns {Array<string>} - the current allowed domains list.
|
|
303
300
|
*/
|
|
304
|
-
getAllowedDomains() {
|
|
301
|
+
getAllowedDomains(): Array<string> {
|
|
305
302
|
return [...this.allowedDomains];
|
|
306
303
|
},
|
|
307
304
|
|
|
@@ -338,17 +335,17 @@ const ServiceCatalog = AmpState.extend({
|
|
|
338
335
|
/**
|
|
339
336
|
* Mark a priority host service url as failed.
|
|
340
337
|
* This will mark the host associated with the
|
|
341
|
-
* `
|
|
338
|
+
* `ServiceDetail` to be removed from the its
|
|
342
339
|
* respective host array, and then return the next
|
|
343
|
-
* viable host from the `
|
|
344
|
-
* or the `
|
|
340
|
+
* viable host from the `ServiceDetail` host array,
|
|
341
|
+
* or the `ServiceDetail` default url if no other priority
|
|
345
342
|
* hosts are available, or if `noPriorityHosts` is set to
|
|
346
343
|
* `true`.
|
|
347
344
|
* @param {string} url
|
|
348
345
|
* @param {boolean} noPriorityHosts
|
|
349
346
|
* @returns {string}
|
|
350
347
|
*/
|
|
351
|
-
markFailedUrl(url, noPriorityHosts) {
|
|
348
|
+
markFailedUrl(url: string, noPriorityHosts = false): string | undefined {
|
|
352
349
|
const serviceUrl = this._getUrl(
|
|
353
350
|
Object.keys(this.list()).find((key) => this._getUrl(key).failHost(url))
|
|
354
351
|
);
|
|
@@ -366,7 +363,7 @@ const ServiceCatalog = AmpState.extend({
|
|
|
366
363
|
* @param {Array<string>} allowedDomains - allowed domains to be assigned.
|
|
367
364
|
* @returns {void}
|
|
368
365
|
*/
|
|
369
|
-
setAllowedDomains(allowedDomains) {
|
|
366
|
+
setAllowedDomains(allowedDomains: Array<string>): void {
|
|
370
367
|
this.allowedDomains = [...allowedDomains];
|
|
371
368
|
},
|
|
372
369
|
|
|
@@ -375,37 +372,36 @@ const ServiceCatalog = AmpState.extend({
|
|
|
375
372
|
* @param {Array<string>} newAllowedDomains - new allowed domains to add to existing set of allowed domains
|
|
376
373
|
* @returns {void}
|
|
377
374
|
*/
|
|
378
|
-
addAllowedDomains(newAllowedDomains) {
|
|
375
|
+
addAllowedDomains(newAllowedDomains: Array<string>): void {
|
|
379
376
|
this.allowedDomains = union(this.allowedDomains, newAllowedDomains);
|
|
380
377
|
},
|
|
381
378
|
|
|
382
379
|
/**
|
|
383
|
-
* Update the current list of `
|
|
380
|
+
* Update the current list of `ServiceDetail`s against a provided
|
|
384
381
|
* service hostmap.
|
|
385
382
|
* @emits ServiceCatalog#preauthorized
|
|
386
383
|
* @emits ServiceCatalog#postauthorized
|
|
387
384
|
* @param {string} serviceGroup
|
|
388
385
|
* @param {object} serviceHostmap
|
|
389
|
-
* @returns {
|
|
386
|
+
* @returns {void}
|
|
390
387
|
*/
|
|
391
|
-
updateServiceUrls(serviceGroup, serviceHostmap) {
|
|
388
|
+
updateServiceUrls(serviceGroup: string, serviceHostmap: Array<IServiceDetail>): void {
|
|
392
389
|
const currentServiceUrls = this.serviceGroups[serviceGroup];
|
|
393
390
|
|
|
394
391
|
const unusedUrls = currentServiceUrls.filter((serviceUrl) =>
|
|
395
|
-
serviceHostmap.every((item) => item.
|
|
392
|
+
serviceHostmap.every((item) => item.serviceName !== serviceUrl.serviceName)
|
|
396
393
|
);
|
|
397
394
|
|
|
398
395
|
this._unloadServiceUrls(serviceGroup, unusedUrls);
|
|
399
396
|
|
|
400
397
|
serviceHostmap.forEach((serviceObj) => {
|
|
401
|
-
const service = this._getUrl(serviceObj.
|
|
398
|
+
const service = this._getUrl(serviceObj.serviceName, serviceGroup);
|
|
402
399
|
|
|
403
400
|
if (service) {
|
|
404
|
-
service.
|
|
405
|
-
service.hosts = serviceObj.hosts || [];
|
|
401
|
+
service.serviceUrls = serviceObj.serviceUrls || [];
|
|
406
402
|
} else {
|
|
407
403
|
this._loadServiceUrls(serviceGroup, [
|
|
408
|
-
new
|
|
404
|
+
new ServiceDetail({
|
|
409
405
|
...serviceObj,
|
|
410
406
|
}),
|
|
411
407
|
]);
|
|
@@ -414,8 +410,6 @@ const ServiceCatalog = AmpState.extend({
|
|
|
414
410
|
|
|
415
411
|
this.status[serviceGroup].ready = true;
|
|
416
412
|
this.trigger(serviceGroup);
|
|
417
|
-
|
|
418
|
-
return this;
|
|
419
413
|
},
|
|
420
414
|
|
|
421
415
|
/**
|
|
@@ -426,7 +420,7 @@ const ServiceCatalog = AmpState.extend({
|
|
|
426
420
|
* @returns {Promise<void>}
|
|
427
421
|
*/
|
|
428
422
|
waitForCatalog(serviceGroup, timeout) {
|
|
429
|
-
return new Promise((resolve, reject) => {
|
|
423
|
+
return new Promise<void>((resolve, reject) => {
|
|
430
424
|
if (this.status[serviceGroup].ready) {
|
|
431
425
|
resolve();
|
|
432
426
|
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import AmpState from 'ampersand-state';
|
|
2
|
+
import {ServiceUrl} from './types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @class
|
|
6
|
+
*/
|
|
7
|
+
const ServiceDetail = AmpState.extend({
|
|
8
|
+
namespace: 'ServiceDetail',
|
|
9
|
+
|
|
10
|
+
props: {
|
|
11
|
+
serviceUrls: ['array', false, () => []],
|
|
12
|
+
serviceName: ['string', true, undefined],
|
|
13
|
+
id: ['string', true, undefined],
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Generate a host url based on the host
|
|
18
|
+
* uri provided.
|
|
19
|
+
* @param {ServiceUrl} serviceUrl
|
|
20
|
+
* @returns {string}
|
|
21
|
+
*/
|
|
22
|
+
_generateHostUrl(serviceUrl: ServiceUrl): string {
|
|
23
|
+
const url = new URL(serviceUrl.baseUrl);
|
|
24
|
+
|
|
25
|
+
// setting url.hostname will not apply during Url.format(), set host via
|
|
26
|
+
// a string literal instead.
|
|
27
|
+
url.host = `${serviceUrl.host}${url.port ? `:${url.port}` : ''}`;
|
|
28
|
+
|
|
29
|
+
return url.href;
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Get the current host url with the highest priority. This will only return a URL with a filtered host that has the
|
|
34
|
+
* `homeCluster` value set to `true`.
|
|
35
|
+
* @returns {string} - The priority host url.
|
|
36
|
+
*/
|
|
37
|
+
_getPriorityHostUrl(): string {
|
|
38
|
+
// format of catalog ensures that array is sorted by highest priority
|
|
39
|
+
let priorityServiceUrl = this._searchForValidPriorityHost();
|
|
40
|
+
|
|
41
|
+
if (!priorityServiceUrl) {
|
|
42
|
+
this.serviceUrls = this.serviceUrls.map((serviceUrl) => {
|
|
43
|
+
serviceUrl.failed = false;
|
|
44
|
+
|
|
45
|
+
return serviceUrl;
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
priorityServiceUrl = this._searchForValidPriorityHost();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return priorityServiceUrl ? this._generateHostUrl(priorityServiceUrl) : '';
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Searches for a valid service URL with a priority greater than 0 that has not failed.
|
|
56
|
+
* @returns {ServiceUrl | undefined} - The first valid service URL found, or undefined if none exist.
|
|
57
|
+
*/
|
|
58
|
+
_searchForValidPriorityHost(): ServiceUrl | undefined {
|
|
59
|
+
return this.serviceUrls.find((serviceUrl) => serviceUrl.priority > 0 && !serviceUrl.failed);
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Attempt to mark a host from this `ServiceDetail` as failed and return true
|
|
64
|
+
* if the provided url has a host that could be successfully marked as failed.
|
|
65
|
+
*
|
|
66
|
+
* @param {string} url
|
|
67
|
+
* @returns {boolean}
|
|
68
|
+
*/
|
|
69
|
+
failHost(url: string): boolean {
|
|
70
|
+
const failedUrl = new URL(url);
|
|
71
|
+
|
|
72
|
+
const foundHost = this.serviceUrls.find((serviceUrl) => serviceUrl.host === failedUrl.host);
|
|
73
|
+
|
|
74
|
+
if (foundHost) {
|
|
75
|
+
foundHost.failed = true;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return foundHost !== undefined;
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Generate a url using the host with the
|
|
83
|
+
* highest priority via host rendering.
|
|
84
|
+
*
|
|
85
|
+
* @returns {string} - The full service url.
|
|
86
|
+
*/
|
|
87
|
+
get(): string {
|
|
88
|
+
// return empty string to indicate that no service url is available
|
|
89
|
+
if (!this.serviceUrls || this.serviceUrls.length === 0) {
|
|
90
|
+
return '';
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return this._getPriorityHostUrl();
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
export default ServiceDetail;
|
|
@@ -189,7 +189,7 @@ const Services = WebexPlugin.extend({
|
|
|
189
189
|
forceRefresh,
|
|
190
190
|
})
|
|
191
191
|
.then((serviceHostMap) => {
|
|
192
|
-
catalog.
|
|
192
|
+
catalog.updateServiceGroups(serviceGroup, serviceHostMap);
|
|
193
193
|
this.updateCredentialsConfig();
|
|
194
194
|
catalog.status[serviceGroup].collecting = false;
|
|
195
195
|
})
|
|
@@ -455,7 +455,7 @@ const Services = WebexPlugin.extend({
|
|
|
455
455
|
|
|
456
456
|
const serviceHostMap = this._formatReceivedHostmap(hostMap);
|
|
457
457
|
|
|
458
|
-
return catalog.
|
|
458
|
+
return catalog.updateServiceGroups(serviceGroup, serviceHostMap);
|
|
459
459
|
},
|
|
460
460
|
|
|
461
461
|
/**
|
|
@@ -662,6 +662,28 @@ const Services = WebexPlugin.extend({
|
|
|
662
662
|
return uri;
|
|
663
663
|
},
|
|
664
664
|
|
|
665
|
+
/**
|
|
666
|
+
* Formats a host map entry for use in service catalog.
|
|
667
|
+
*
|
|
668
|
+
* @param {Object} entry - The host map entry to format.
|
|
669
|
+
* @param {string} entry.serviceName - i.e. conversation, identity, etc.
|
|
670
|
+
* @param {string} entry.id - The unique identifier for the service, usually clusterId.
|
|
671
|
+
* @param {Array<IServiceDetail>} entry.serviceUrls - The group to which the service belongs.
|
|
672
|
+
* @returns {Object} - The formatted host map entry.
|
|
673
|
+
*/
|
|
674
|
+
_formatHostMapEntry({id, serviceName, serviceUrls}) {
|
|
675
|
+
const formattedServiceUrls = serviceUrls.map((serviceUrl) => ({
|
|
676
|
+
host: new URL(serviceUrl.baseUrl).host,
|
|
677
|
+
...serviceUrl,
|
|
678
|
+
}));
|
|
679
|
+
|
|
680
|
+
return {
|
|
681
|
+
id,
|
|
682
|
+
serviceName,
|
|
683
|
+
serviceUrls: formattedServiceUrls,
|
|
684
|
+
};
|
|
685
|
+
},
|
|
686
|
+
|
|
665
687
|
/**
|
|
666
688
|
* @private
|
|
667
689
|
* Organize a received hostmap from a service
|
|
@@ -670,18 +692,7 @@ const Services = WebexPlugin.extend({
|
|
|
670
692
|
* @returns {object}
|
|
671
693
|
*/
|
|
672
694
|
_formatReceivedHostmap({services, activeServices}) {
|
|
673
|
-
const formattedHostmap = services.map((
|
|
674
|
-
const formattedServiceUrls = serviceUrls.map((serviceUrl) => ({
|
|
675
|
-
host: new URL(serviceUrl.baseUrl).host,
|
|
676
|
-
...serviceUrl,
|
|
677
|
-
}));
|
|
678
|
-
|
|
679
|
-
return {
|
|
680
|
-
id,
|
|
681
|
-
serviceName,
|
|
682
|
-
serviceUrls: formattedServiceUrls,
|
|
683
|
-
};
|
|
684
|
-
});
|
|
695
|
+
const formattedHostmap = services.map((service) => this._formatHostMapEntry(service));
|
|
685
696
|
this._updateActiveServices(activeServices);
|
|
686
697
|
this._updateServices(services);
|
|
687
698
|
|
|
@@ -850,24 +861,30 @@ const Services = WebexPlugin.extend({
|
|
|
850
861
|
// Check for discovery services.
|
|
851
862
|
if (services.discovery) {
|
|
852
863
|
// Format the discovery configuration into an injectable array.
|
|
853
|
-
const formattedDiscoveryServices = Object.keys(services.discovery).map((key) =>
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
864
|
+
const formattedDiscoveryServices = Object.keys(services.discovery).map((key) =>
|
|
865
|
+
this._formatHostMapEntry({
|
|
866
|
+
id: key,
|
|
867
|
+
serviceName: key,
|
|
868
|
+
serviceUrls: [{baseUrl: services.discovery[key], priority: 1}],
|
|
869
|
+
})
|
|
870
|
+
);
|
|
857
871
|
|
|
858
872
|
// Inject formatted discovery services into services catalog.
|
|
859
|
-
catalog.
|
|
873
|
+
catalog.updateServiceGroups('discovery', formattedDiscoveryServices);
|
|
860
874
|
}
|
|
861
875
|
|
|
862
876
|
if (services.override) {
|
|
863
877
|
// Format the override configuration into an injectable array.
|
|
864
|
-
const formattedOverrideServices = Object.keys(services.override).map((key) =>
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
878
|
+
const formattedOverrideServices = Object.keys(services.override).map((key) =>
|
|
879
|
+
this._formatHostMapEntry({
|
|
880
|
+
id: key,
|
|
881
|
+
serviceName: key,
|
|
882
|
+
serviceUrls: [{baseUrl: services.override[key], priority: 1}],
|
|
883
|
+
})
|
|
884
|
+
);
|
|
868
885
|
|
|
869
886
|
// Inject formatted override services into services catalog.
|
|
870
|
-
catalog.
|
|
887
|
+
catalog.updateServiceGroups('override', formattedOverrideServices);
|
|
871
888
|
}
|
|
872
889
|
|
|
873
890
|
// if not fedramp, append on the commercialAllowedDomains
|
|
@@ -120,23 +120,25 @@ export const serviceHostmapV2 = {
|
|
|
120
120
|
format: 'U2Cv2',
|
|
121
121
|
};
|
|
122
122
|
|
|
123
|
+
export const formattedServiceHostmapEntryConv = {
|
|
124
|
+
id: 'urn:TEAM:us-east-2_a:conversation',
|
|
125
|
+
serviceName: 'conversation',
|
|
126
|
+
serviceUrls: [
|
|
127
|
+
{
|
|
128
|
+
baseUrl: 'https://prod-achm-message.svc.webex.com/conversation/api/v1',
|
|
129
|
+
host: 'prod-achm-message.svc.webex.com',
|
|
130
|
+
priority: 1,
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
baseUrl: 'https://conv-a.wbx2.com/conversation/api/v1',
|
|
134
|
+
host: 'conv-a.wbx2.com',
|
|
135
|
+
priority: 2,
|
|
136
|
+
},
|
|
137
|
+
],
|
|
138
|
+
};
|
|
139
|
+
|
|
123
140
|
export const formattedServiceHostmapV2 = [
|
|
124
|
-
|
|
125
|
-
id: 'urn:TEAM:us-east-2_a:conversation',
|
|
126
|
-
serviceName: 'conversation',
|
|
127
|
-
serviceUrls: [
|
|
128
|
-
{
|
|
129
|
-
baseUrl: 'https://prod-achm-message.svc.webex.com/conversation/api/v1',
|
|
130
|
-
host: 'prod-achm-message.svc.webex.com',
|
|
131
|
-
priority: 1,
|
|
132
|
-
},
|
|
133
|
-
{
|
|
134
|
-
baseUrl: 'https://conv-a.wbx2.com/conversation/api/v1',
|
|
135
|
-
host: 'conv-a.wbx2.com',
|
|
136
|
-
priority: 2,
|
|
137
|
-
},
|
|
138
|
-
],
|
|
139
|
-
},
|
|
141
|
+
formattedServiceHostmapEntryConv,
|
|
140
142
|
{
|
|
141
143
|
id: 'urn:TEAM:me-central-1_d:conversation',
|
|
142
144
|
serviceName: 'conversation',
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import {assert} from '@webex/test-helper-chai';
|
|
6
|
+
import MockWebex from '@webex/test-helper-mock-webex';
|
|
7
|
+
import {ServicesV2, ServiceDetail} from '@webex/webex-core';
|
|
8
|
+
import {formattedServiceHostmapEntryConv} from '../../../fixtures/host-catalog-v2';
|
|
9
|
+
|
|
10
|
+
describe('webex-core', () => {
|
|
11
|
+
describe('ServiceDetail', () => {
|
|
12
|
+
let webex;
|
|
13
|
+
let serviceDetail;
|
|
14
|
+
let template;
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
webex = new MockWebex();
|
|
18
|
+
new ServicesV2(undefined, {parent: webex});
|
|
19
|
+
|
|
20
|
+
template = formattedServiceHostmapEntryConv;
|
|
21
|
+
|
|
22
|
+
serviceDetail = new ServiceDetail({...template});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
describe('#namespace', () => {
|
|
26
|
+
it('is accurate to plugin name', () => {
|
|
27
|
+
assert.equal(serviceDetail.namespace, 'ServiceDetail');
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe('#serviceName', () => {
|
|
32
|
+
it('is valid value', () => {
|
|
33
|
+
assert.typeOf(serviceDetail.serviceName, 'string');
|
|
34
|
+
assert.equal(serviceDetail.serviceName, 'conversation');
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
describe('#serviceUrls', () => {
|
|
39
|
+
it('is valid value', () => {
|
|
40
|
+
assert.typeOf(serviceDetail.serviceUrls, 'array');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('contains all appended hosts on construction', () => {
|
|
44
|
+
template.serviceUrls.forEach((serviceUrl) => {
|
|
45
|
+
assert.include([...serviceDetail.serviceUrls], serviceUrl);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
describe('#id', () => {
|
|
51
|
+
it('is valid value', () => {
|
|
52
|
+
assert.typeOf(serviceDetail.id, 'string');
|
|
53
|
+
assert.equal(serviceDetail.id, 'urn:TEAM:us-east-2_a:conversation');
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
describe('#_generateHostUrl()', () => {
|
|
58
|
+
it('returns a string', () => {
|
|
59
|
+
serviceDetail.serviceUrls.forEach((serviceUrl) => {
|
|
60
|
+
assert.typeOf(serviceDetail._generateHostUrl(serviceUrl), 'string');
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('replaces the host of a pass in url', () => {
|
|
65
|
+
serviceDetail.serviceUrls.forEach((serviceUrl) => {
|
|
66
|
+
assert.equal(
|
|
67
|
+
serviceDetail._generateHostUrl(serviceUrl),
|
|
68
|
+
`https://${serviceUrl.host}/conversation/api/v1`
|
|
69
|
+
);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe('#_getPriorityHostUrl()', () => {
|
|
75
|
+
it('validates that the retrieved high priority host matches the manually retrieved high priority host', () => {
|
|
76
|
+
assert.equal(
|
|
77
|
+
serviceDetail._getPriorityHostUrl(),
|
|
78
|
+
serviceDetail._generateHostUrl(template.serviceUrls[0])
|
|
79
|
+
);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('should pick most priority non failed host', () => {
|
|
83
|
+
serviceDetail.serviceUrls[0].failed = true;
|
|
84
|
+
|
|
85
|
+
assert.isTrue(serviceDetail.serviceUrls[0].failed);
|
|
86
|
+
|
|
87
|
+
const priorityHost = serviceDetail._getPriorityHostUrl();
|
|
88
|
+
assert.equal(priorityHost, serviceDetail.serviceUrls[1].baseUrl);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('should reset the hosts when all have failed', () => {
|
|
92
|
+
serviceDetail.serviceUrls.forEach((serviceUrl) => {
|
|
93
|
+
/* eslint-disable-next-line no-param-reassign */
|
|
94
|
+
serviceUrl.failed = true;
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
assert.isTrue(serviceDetail.serviceUrls.every((serviceUrl) => serviceUrl.failed));
|
|
98
|
+
|
|
99
|
+
const priorityHost = serviceDetail._getPriorityHostUrl();
|
|
100
|
+
|
|
101
|
+
assert.equal(priorityHost, serviceDetail.serviceUrls[0].baseUrl);
|
|
102
|
+
assert.isTrue(serviceDetail.serviceUrls.every((serviceUrl) => !serviceUrl.failed));
|
|
103
|
+
});
|
|
104
|
+
it('should return empty string if no available hosts', () => {
|
|
105
|
+
serviceDetail.serviceUrls = [{priority: -1}];
|
|
106
|
+
|
|
107
|
+
const priorityHost = serviceDetail.get();
|
|
108
|
+
|
|
109
|
+
assert.equal(priorityHost, '');
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
describe('#get', () => {
|
|
114
|
+
it('should return empty string if no hosts are available', () => {
|
|
115
|
+
serviceDetail.serviceUrls = [];
|
|
116
|
+
|
|
117
|
+
const priorityHost = serviceDetail.get();
|
|
118
|
+
|
|
119
|
+
assert.equal(priorityHost, '');
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
describe('#failHost()', () => {
|
|
124
|
+
it('marks a host as failed', () => {
|
|
125
|
+
serviceDetail.failHost(serviceDetail.serviceUrls[0].baseUrl);
|
|
126
|
+
|
|
127
|
+
const removedHost = serviceDetail.serviceUrls.find(
|
|
128
|
+
(currentHost) => currentHost.host === serviceDetail.serviceUrls[0].host
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
assert.isTrue(removedHost.failed);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('returns true if hostUrl was found', () => {
|
|
135
|
+
const removedHostResult = serviceDetail.failHost(serviceDetail.serviceUrls[0].baseUrl);
|
|
136
|
+
|
|
137
|
+
assert.isTrue(removedHostResult);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('returns false if hostUrl was not found', () => {
|
|
141
|
+
const removedHostResult = serviceDetail.failHost('https://someurl.com/api/vq');
|
|
142
|
+
|
|
143
|
+
assert.isFalse(removedHostResult);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
});
|