@rc-ex/ws 1.2.0 → 1.2.2
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 +49 -22
- package/lib/exceptions/ClosedException.js +1 -1
- package/lib/exceptions/ClosedException.js.map +1 -1
- package/lib/exceptions/ClosedException.ts +7 -0
- package/lib/exceptions/ConnectionException.d.ts +1 -1
- package/lib/exceptions/ConnectionException.js.map +1 -1
- package/lib/exceptions/ConnectionException.ts +17 -0
- package/lib/exceptions/TimeoutException.js +1 -1
- package/lib/exceptions/TimeoutException.js.map +1 -1
- package/lib/exceptions/TimeoutException.ts +7 -0
- package/lib/index.d.ts +8 -8
- package/lib/index.js +23 -23
- package/lib/index.js.map +1 -1
- package/lib/index.ts +418 -0
- package/lib/rest.d.ts +2 -2
- package/lib/rest.js +5 -6
- package/lib/rest.js.map +1 -1
- package/lib/rest.ts +71 -0
- package/lib/subscription.d.ts +4 -4
- package/lib/subscription.js +11 -9
- package/lib/subscription.js.map +1 -1
- package/lib/subscription.ts +131 -0
- package/lib/types.d.ts +5 -5
- package/lib/types.js.map +1 -1
- package/lib/types.ts +85 -0
- package/lib/utils.d.ts +2 -2
- package/lib/utils.js +16 -16
- package/lib/utils.js.map +1 -1
- package/lib/utils.ts +82 -0
- package/package.json +6 -6
- package/src/exceptions/ClosedException.d.ts +4 -0
- package/src/exceptions/ClosedException.js +9 -0
- package/src/exceptions/ClosedException.js.map +1 -0
- package/src/exceptions/ClosedException.ts +1 -1
- package/src/exceptions/ConnectionException.d.ts +7 -0
- package/src/exceptions/ConnectionException.js +16 -0
- package/src/exceptions/ConnectionException.js.map +1 -0
- package/src/exceptions/ConnectionException.ts +2 -2
- package/src/exceptions/TimeoutException.d.ts +4 -0
- package/src/exceptions/TimeoutException.js +9 -0
- package/src/exceptions/TimeoutException.js.map +1 -0
- package/src/exceptions/TimeoutException.ts +1 -1
- package/src/index.d.ts +44 -0
- package/src/index.js +329 -0
- package/src/index.js.map +1 -0
- package/src/index.ts +81 -51
- package/src/rest.d.ts +3 -0
- package/src/rest.js +55 -0
- package/src/rest.js.map +1 -0
- package/src/rest.ts +22 -12
- package/src/subscription.d.ts +20 -0
- package/src/subscription.js +91 -0
- package/src/subscription.js.map +1 -0
- package/src/subscription.ts +36 -18
- package/src/types.d.ts +61 -0
- package/src/types.js +3 -0
- package/src/types.js.map +1 -0
- package/src/types.ts +14 -5
- package/src/utils.d.ts +8 -0
- package/src/utils.js +72 -0
- package/src/utils.js.map +1 -0
- package/src/utils.ts +26 -23
- package/tsconfig.json +0 -3
package/src/rest.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.request = request;
|
|
7
|
+
const RestException_1 = __importDefault(require("@rc-ex/core/src/RestException"));
|
|
8
|
+
const hyperid_1 = __importDefault(require("hyperid"));
|
|
9
|
+
const http_status_codes_1 = require("http-status-codes");
|
|
10
|
+
const utils_1 = __importDefault(require("./utils"));
|
|
11
|
+
const version = "0.16";
|
|
12
|
+
const uuid = (0, hyperid_1.default)();
|
|
13
|
+
async function request(method, endpoint, content, queryParams, config) {
|
|
14
|
+
var _a;
|
|
15
|
+
const newConfig = {
|
|
16
|
+
method,
|
|
17
|
+
baseURL: (_a = this.wsToken) === null || _a === void 0 ? void 0 : _a.uri,
|
|
18
|
+
url: endpoint,
|
|
19
|
+
data: content,
|
|
20
|
+
params: queryParams,
|
|
21
|
+
...config,
|
|
22
|
+
};
|
|
23
|
+
newConfig.headers = {
|
|
24
|
+
...newConfig.headers,
|
|
25
|
+
"X-User-Agent": `${this.rc.rest.appName}/${this.rc.rest.appVersion} ringcentral-extensible/ws/${version}`,
|
|
26
|
+
};
|
|
27
|
+
const messageId = uuid();
|
|
28
|
+
const requestBody = [
|
|
29
|
+
{
|
|
30
|
+
type: "ClientRequest",
|
|
31
|
+
messageId,
|
|
32
|
+
method: newConfig.method,
|
|
33
|
+
path: newConfig.url,
|
|
34
|
+
headers: newConfig.headers,
|
|
35
|
+
query: newConfig.params,
|
|
36
|
+
},
|
|
37
|
+
];
|
|
38
|
+
if (newConfig.data) {
|
|
39
|
+
requestBody.push(newConfig.data);
|
|
40
|
+
}
|
|
41
|
+
await this.ws.send(JSON.stringify(requestBody));
|
|
42
|
+
const [meta, body] = await utils_1.default.waitForWebSocketMessage(this.ws, (_meta) => _meta.messageId === messageId);
|
|
43
|
+
const response = {
|
|
44
|
+
data: body,
|
|
45
|
+
status: meta.status,
|
|
46
|
+
statusText: (0, http_status_codes_1.getReasonPhrase)(meta.status),
|
|
47
|
+
headers: meta.headers,
|
|
48
|
+
config: newConfig,
|
|
49
|
+
};
|
|
50
|
+
if (meta.type === "ClientRequest" && meta.status >= 200 && meta.status < 300) {
|
|
51
|
+
return response;
|
|
52
|
+
}
|
|
53
|
+
throw new RestException_1.default(response);
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=rest.js.map
|
package/src/rest.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rest.js","sourceRoot":"","sources":["rest.ts"],"names":[],"mappings":";;;;;AAgBA,0BAsDC;AAjED,kFAA0D;AAC1D,sDAA8B;AAC9B,yDAAoD;AAEpD,oDAA4B;AAG5B,MAAM,OAAO,GAAG,MAAM,CAAC;AAEvB,MAAM,IAAI,GAAG,IAAA,iBAAO,GAAE,CAAC;AAEhB,KAAK,UAAU,OAAO,CAE3B,MAAkB,EAClB,QAAgB,EAChB,OAAY,EACZ,WAAgB,EAChB,MAA0B;;IAE1B,MAAM,SAAS,GAAsB;QACnC,MAAM;QACN,OAAO,EAAE,MAAA,IAAI,CAAC,OAAO,0CAAE,GAAG;QAC1B,GAAG,EAAE,QAAQ;QACb,IAAI,EAAE,OAAO;QACb,MAAM,EAAE,WAAW;QACnB,GAAG,MAAM;KACV,CAAC;IACF,SAAS,CAAC,OAAO,GAAG;QAClB,GAAG,SAAS,CAAC,OAAO;QACpB,cAAc,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC,IAAK,CAAC,OAAO,IACtC,IAAI,CAAC,EAAE,CAAC,IAAK,CAAC,UAChB,8BAA8B,OAAO,EAAE;KACjC,CAAC;IACT,MAAM,SAAS,GAAG,IAAI,EAAE,CAAC;IACzB,MAAM,WAAW,GAAG;QAClB;YACE,IAAI,EAAE,eAAe;YACrB,SAAS;YACT,MAAM,EAAE,SAAS,CAAC,MAAM;YACxB,IAAI,EAAE,SAAS,CAAC,GAAG;YACnB,OAAO,EAAE,SAAS,CAAC,OAAO;YAC1B,KAAK,EAAE,SAAS,CAAC,MAAM;SACxB;KACF,CAAC;IACF,IAAI,SAAS,CAAC,IAAI,EAAE,CAAC;QACnB,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;IACD,MAAM,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC;IAChD,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,MAAM,eAAK,CAAC,uBAAuB,CACtD,IAAI,CAAC,EAAE,EACP,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,KAAK,SAAS,CACzC,CAAC;IACF,MAAM,QAAQ,GAAiB;QAC7B,IAAI,EAAE,IAAS;QACf,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,UAAU,EAAE,IAAA,mCAAe,EAAC,IAAI,CAAC,MAAM,CAAC;QACxC,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,MAAM,EAAE,SAAgB;KACzB,CAAC;IACF,IACE,IAAI,CAAC,IAAI,KAAK,eAAe,IAAI,IAAI,CAAC,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,MAAM,GAAG,GAAG,EACxE,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,MAAM,IAAI,uBAAa,CAAC,QAAQ,CAAC,CAAC;AACpC,CAAC"}
|
package/src/rest.ts
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import type {
|
|
2
|
+
RestMethod,
|
|
3
|
+
RestRequestConfig,
|
|
4
|
+
RestResponse,
|
|
5
|
+
} from "@rc-ex/core/src/types";
|
|
6
|
+
import RestException from "@rc-ex/core/src/RestException";
|
|
7
|
+
import hyperid from "hyperid";
|
|
8
|
+
import { getReasonPhrase } from "http-status-codes";
|
|
5
9
|
|
|
6
|
-
import Utils from
|
|
7
|
-
import type { WebSocketExtensionInterface } from
|
|
10
|
+
import Utils from "./utils";
|
|
11
|
+
import type { WebSocketExtensionInterface } from "./types";
|
|
8
12
|
|
|
9
|
-
const version =
|
|
13
|
+
const version = "0.16";
|
|
10
14
|
|
|
11
15
|
const uuid = hyperid();
|
|
12
16
|
|
|
13
|
-
// eslint-disable-next-line max-params
|
|
14
17
|
export async function request<T>(
|
|
15
18
|
this: WebSocketExtensionInterface,
|
|
16
19
|
method: RestMethod,
|
|
@@ -29,12 +32,14 @@ export async function request<T>(
|
|
|
29
32
|
};
|
|
30
33
|
newConfig.headers = {
|
|
31
34
|
...newConfig.headers,
|
|
32
|
-
|
|
35
|
+
"X-User-Agent": `${this.rc.rest!.appName}/${
|
|
36
|
+
this.rc.rest!.appVersion
|
|
37
|
+
} ringcentral-extensible/ws/${version}`,
|
|
33
38
|
} as any;
|
|
34
39
|
const messageId = uuid();
|
|
35
40
|
const requestBody = [
|
|
36
41
|
{
|
|
37
|
-
type:
|
|
42
|
+
type: "ClientRequest",
|
|
38
43
|
messageId,
|
|
39
44
|
method: newConfig.method,
|
|
40
45
|
path: newConfig.url,
|
|
@@ -46,7 +51,10 @@ export async function request<T>(
|
|
|
46
51
|
requestBody.push(newConfig.data);
|
|
47
52
|
}
|
|
48
53
|
await this.ws.send(JSON.stringify(requestBody));
|
|
49
|
-
const [meta, body] = await Utils.waitForWebSocketMessage(
|
|
54
|
+
const [meta, body] = await Utils.waitForWebSocketMessage(
|
|
55
|
+
this.ws,
|
|
56
|
+
(_meta) => _meta.messageId === messageId,
|
|
57
|
+
);
|
|
50
58
|
const response: RestResponse = {
|
|
51
59
|
data: body as T,
|
|
52
60
|
status: meta.status,
|
|
@@ -54,7 +62,9 @@ export async function request<T>(
|
|
|
54
62
|
headers: meta.headers,
|
|
55
63
|
config: newConfig as any,
|
|
56
64
|
};
|
|
57
|
-
if (
|
|
65
|
+
if (
|
|
66
|
+
meta.type === "ClientRequest" && meta.status >= 200 && meta.status < 300
|
|
67
|
+
) {
|
|
58
68
|
return response;
|
|
59
69
|
}
|
|
60
70
|
throw new RestException(response);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type CreateSubscriptionRequest from "@rc-ex/core/src/definitions/CreateSubscriptionRequest";
|
|
2
|
+
import type SubscriptionInfo from "@rc-ex/core/src/definitions/SubscriptionInfo";
|
|
3
|
+
import type { MessageEvent } from "ws";
|
|
4
|
+
import type { WebSocketExtensionInterface } from "./types";
|
|
5
|
+
declare class Subscription {
|
|
6
|
+
subscriptionInfo?: SubscriptionInfo;
|
|
7
|
+
wse: WebSocketExtensionInterface;
|
|
8
|
+
eventFilters: string[];
|
|
9
|
+
eventListener: (event: MessageEvent) => void;
|
|
10
|
+
timeout?: NodeJS.Timeout;
|
|
11
|
+
enabled: boolean;
|
|
12
|
+
constructor(wse: WebSocketExtensionInterface, eventFilters: string[], callback: (event: {}) => void);
|
|
13
|
+
setupWsEventListener(): void;
|
|
14
|
+
get requestBody(): CreateSubscriptionRequest;
|
|
15
|
+
subscribe(): Promise<void>;
|
|
16
|
+
refresh(): Promise<void>;
|
|
17
|
+
revoke(): Promise<void>;
|
|
18
|
+
remove(): void;
|
|
19
|
+
}
|
|
20
|
+
export default Subscription;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const utils_1 = __importDefault(require("./utils"));
|
|
7
|
+
class Subscription {
|
|
8
|
+
constructor(wse, eventFilters, callback) {
|
|
9
|
+
this.enabled = true;
|
|
10
|
+
this.wse = wse;
|
|
11
|
+
this.eventFilters = eventFilters;
|
|
12
|
+
this.eventListener = (mEvent) => {
|
|
13
|
+
const event = mEvent;
|
|
14
|
+
const [meta, body] = utils_1.default
|
|
15
|
+
.splitWsgData(event.data);
|
|
16
|
+
if (this.enabled && meta.type === "ServerNotification" &&
|
|
17
|
+
body.subscriptionId === this.subscriptionInfo.id) {
|
|
18
|
+
callback(body);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
this.setupWsEventListener();
|
|
22
|
+
}
|
|
23
|
+
setupWsEventListener() {
|
|
24
|
+
this.wse.ws.addEventListener("message", this.eventListener);
|
|
25
|
+
}
|
|
26
|
+
get requestBody() {
|
|
27
|
+
return {
|
|
28
|
+
deliveryMode: { transportType: "WebSocket" }, // because WebSocket is not in spec
|
|
29
|
+
eventFilters: this.eventFilters,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
async subscribe() {
|
|
33
|
+
this.subscriptionInfo = (await this.wse.request("POST", "/restapi/v1.0/subscription", this.requestBody)).data;
|
|
34
|
+
}
|
|
35
|
+
async refresh() {
|
|
36
|
+
if (!this.subscriptionInfo) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
this.subscriptionInfo = (await this.wse.request("PUT", `/restapi/v1.0/subscription/${this.subscriptionInfo.id}`, this.requestBody)).data;
|
|
41
|
+
}
|
|
42
|
+
catch (e) {
|
|
43
|
+
const re = e;
|
|
44
|
+
if (re.response && re.response.status === 404) {
|
|
45
|
+
// subscription expired
|
|
46
|
+
await this.subscribe();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
async revoke() {
|
|
51
|
+
if (!this.subscriptionInfo) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
await this.wse.request("DELETE", `/restapi/v1.0/subscription/${this.subscriptionInfo.id}`);
|
|
56
|
+
}
|
|
57
|
+
catch (e) {
|
|
58
|
+
const re = e;
|
|
59
|
+
if (re.response && re.response.status === 404) {
|
|
60
|
+
// ignore
|
|
61
|
+
if (this.wse.options.debugMode) {
|
|
62
|
+
console.debug(`Subscription ${this.subscriptionInfo.id} doesn't exist on server side`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
else if (re.response && re.response.status === 401) {
|
|
66
|
+
// ignore
|
|
67
|
+
if (this.wse.options.debugMode) {
|
|
68
|
+
console.debug("Token invalid when trying to revoke subscription");
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
throw e;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
this.remove();
|
|
76
|
+
}
|
|
77
|
+
remove() {
|
|
78
|
+
if (this.timeout) {
|
|
79
|
+
global.clearTimeout(this.timeout);
|
|
80
|
+
this.timeout = undefined;
|
|
81
|
+
}
|
|
82
|
+
this.enabled = false;
|
|
83
|
+
this.subscriptionInfo = undefined;
|
|
84
|
+
if (this.wse.ws) {
|
|
85
|
+
this.wse.ws.removeEventListener("message", this.eventListener);
|
|
86
|
+
}
|
|
87
|
+
this.wse.subscription = undefined;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
exports.default = Subscription;
|
|
91
|
+
//# sourceMappingURL=subscription.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscription.js","sourceRoot":"","sources":["subscription.ts"],"names":[],"mappings":"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"}
|
package/src/subscription.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
import type
|
|
3
|
-
import type
|
|
4
|
-
import type {
|
|
5
|
-
import type { MessageEvent } from 'ws';
|
|
1
|
+
import type CreateSubscriptionRequest from "@rc-ex/core/src/definitions/CreateSubscriptionRequest";
|
|
2
|
+
import type SubscriptionInfo from "@rc-ex/core/src/definitions/SubscriptionInfo";
|
|
3
|
+
import type { RestResponse } from "@rc-ex/core/src/types";
|
|
4
|
+
import type { MessageEvent } from "ws";
|
|
6
5
|
|
|
7
|
-
import type { WsgEvent, WsgMeta
|
|
8
|
-
import Utils from
|
|
6
|
+
import type { WebSocketExtensionInterface, WsgEvent, WsgMeta } from "./types";
|
|
7
|
+
import Utils from "./utils";
|
|
9
8
|
|
|
10
9
|
class Subscription {
|
|
11
10
|
public subscriptionInfo?: SubscriptionInfo;
|
|
@@ -20,13 +19,21 @@ class Subscription {
|
|
|
20
19
|
|
|
21
20
|
public enabled = true;
|
|
22
21
|
|
|
23
|
-
public constructor(
|
|
22
|
+
public constructor(
|
|
23
|
+
wse: WebSocketExtensionInterface,
|
|
24
|
+
eventFilters: string[],
|
|
25
|
+
callback: (event: {}) => void,
|
|
26
|
+
) {
|
|
24
27
|
this.wse = wse;
|
|
25
28
|
this.eventFilters = eventFilters;
|
|
26
29
|
this.eventListener = (mEvent: MessageEvent) => {
|
|
27
30
|
const event = mEvent as WsgEvent;
|
|
28
|
-
const [meta, body]: [WsgMeta, { subscriptionId: string }] = Utils
|
|
29
|
-
|
|
31
|
+
const [meta, body]: [WsgMeta, { subscriptionId: string }] = Utils
|
|
32
|
+
.splitWsgData(event.data);
|
|
33
|
+
if (
|
|
34
|
+
this.enabled && meta.type === "ServerNotification" &&
|
|
35
|
+
body.subscriptionId === this.subscriptionInfo!.id
|
|
36
|
+
) {
|
|
30
37
|
callback(body);
|
|
31
38
|
}
|
|
32
39
|
};
|
|
@@ -34,19 +41,23 @@ class Subscription {
|
|
|
34
41
|
}
|
|
35
42
|
|
|
36
43
|
public setupWsEventListener() {
|
|
37
|
-
this.wse.ws.addEventListener(
|
|
44
|
+
this.wse.ws.addEventListener("message", this.eventListener);
|
|
38
45
|
}
|
|
39
46
|
|
|
40
47
|
public get requestBody(): CreateSubscriptionRequest {
|
|
41
48
|
return {
|
|
42
|
-
deliveryMode: { transportType:
|
|
49
|
+
deliveryMode: { transportType: "WebSocket" as any }, // because WebSocket is not in spec
|
|
43
50
|
eventFilters: this.eventFilters,
|
|
44
51
|
};
|
|
45
52
|
}
|
|
46
53
|
|
|
47
54
|
public async subscribe() {
|
|
48
55
|
this.subscriptionInfo = (
|
|
49
|
-
await this.wse.request<SubscriptionInfo>(
|
|
56
|
+
await this.wse.request<SubscriptionInfo>(
|
|
57
|
+
"POST",
|
|
58
|
+
"/restapi/v1.0/subscription",
|
|
59
|
+
this.requestBody,
|
|
60
|
+
)
|
|
50
61
|
).data;
|
|
51
62
|
}
|
|
52
63
|
|
|
@@ -57,7 +68,7 @@ class Subscription {
|
|
|
57
68
|
try {
|
|
58
69
|
this.subscriptionInfo = (
|
|
59
70
|
await this.wse.request<SubscriptionInfo>(
|
|
60
|
-
|
|
71
|
+
"PUT",
|
|
61
72
|
`/restapi/v1.0/subscription/${this.subscriptionInfo!.id}`,
|
|
62
73
|
this.requestBody,
|
|
63
74
|
)
|
|
@@ -76,18 +87,25 @@ class Subscription {
|
|
|
76
87
|
return;
|
|
77
88
|
}
|
|
78
89
|
try {
|
|
79
|
-
await this.wse.request<SubscriptionInfo>(
|
|
90
|
+
await this.wse.request<SubscriptionInfo>(
|
|
91
|
+
"DELETE",
|
|
92
|
+
`/restapi/v1.0/subscription/${this.subscriptionInfo!.id}`,
|
|
93
|
+
);
|
|
80
94
|
} catch (e) {
|
|
81
95
|
const re = e as { response: RestResponse };
|
|
82
96
|
if (re.response && re.response.status === 404) {
|
|
83
97
|
// ignore
|
|
84
98
|
if (this.wse.options.debugMode) {
|
|
85
|
-
console.debug(
|
|
99
|
+
console.debug(
|
|
100
|
+
`Subscription ${
|
|
101
|
+
this.subscriptionInfo!.id
|
|
102
|
+
} doesn't exist on server side`,
|
|
103
|
+
);
|
|
86
104
|
}
|
|
87
105
|
} else if (re.response && re.response.status === 401) {
|
|
88
106
|
// ignore
|
|
89
107
|
if (this.wse.options.debugMode) {
|
|
90
|
-
console.debug(
|
|
108
|
+
console.debug("Token invalid when trying to revoke subscription");
|
|
91
109
|
}
|
|
92
110
|
} else {
|
|
93
111
|
throw e;
|
|
@@ -104,7 +122,7 @@ class Subscription {
|
|
|
104
122
|
this.enabled = false;
|
|
105
123
|
this.subscriptionInfo = undefined;
|
|
106
124
|
if (this.wse.ws) {
|
|
107
|
-
this.wse.ws.removeEventListener(
|
|
125
|
+
this.wse.ws.removeEventListener("message", this.eventListener);
|
|
108
126
|
}
|
|
109
127
|
this.wse.subscription = undefined;
|
|
110
128
|
}
|
package/src/types.d.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type RingCentral from "@rc-ex/core";
|
|
2
|
+
import type { RestMethod, RestRequestConfig, RestResponse } from "@rc-ex/core/src/types";
|
|
3
|
+
import type WS from "isomorphic-ws";
|
|
4
|
+
export interface WsToken {
|
|
5
|
+
uri: string;
|
|
6
|
+
ws_access_token: string;
|
|
7
|
+
expires_in: number;
|
|
8
|
+
}
|
|
9
|
+
export type CheckInterval = (retriesAttempted: number) => number;
|
|
10
|
+
export interface WebSocketOptions {
|
|
11
|
+
restOverWebSocket?: boolean;
|
|
12
|
+
debugMode?: boolean;
|
|
13
|
+
autoRecover?: {
|
|
14
|
+
enabled: boolean;
|
|
15
|
+
checkInterval?: CheckInterval;
|
|
16
|
+
pingServerInterval?: number;
|
|
17
|
+
};
|
|
18
|
+
wscToken?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface WsgEvent {
|
|
21
|
+
data: string;
|
|
22
|
+
}
|
|
23
|
+
export interface Wsc {
|
|
24
|
+
token: string;
|
|
25
|
+
sequence: number;
|
|
26
|
+
}
|
|
27
|
+
export interface WsgMeta {
|
|
28
|
+
type: "ClientRequest" | "ServerNotification" | "Error" | "ConnectionDetails" | "Heartbeat";
|
|
29
|
+
messageId: string;
|
|
30
|
+
status: number;
|
|
31
|
+
headers: {
|
|
32
|
+
[key: string]: string;
|
|
33
|
+
};
|
|
34
|
+
wsc?: Wsc;
|
|
35
|
+
}
|
|
36
|
+
export interface WsgError {
|
|
37
|
+
errorCode: string;
|
|
38
|
+
message: string;
|
|
39
|
+
}
|
|
40
|
+
export interface ConnectionDetails {
|
|
41
|
+
creationTime: string;
|
|
42
|
+
maxConnectionsPerSession: number;
|
|
43
|
+
recoveryBufferSize: number;
|
|
44
|
+
recoveryTimeout: number;
|
|
45
|
+
idleTimeout: number;
|
|
46
|
+
absoluteTimeout: number;
|
|
47
|
+
maxActiveRequests: number;
|
|
48
|
+
recoveryState?: "Successful" | "Failed";
|
|
49
|
+
recoveryErrorCode?: string;
|
|
50
|
+
}
|
|
51
|
+
export interface WebSocketExtensionInterface {
|
|
52
|
+
options: WebSocketOptions;
|
|
53
|
+
subscription?: SubscriptionInterface;
|
|
54
|
+
ws: WS;
|
|
55
|
+
wsToken?: WsToken;
|
|
56
|
+
rc: RingCentral;
|
|
57
|
+
request: <T>(method: RestMethod, endpoint: string, content?: {}, queryParams?: {}, config?: RestRequestConfig) => Promise<RestResponse<T>>;
|
|
58
|
+
}
|
|
59
|
+
export interface SubscriptionInterface {
|
|
60
|
+
eventFilters: string[];
|
|
61
|
+
}
|
package/src/types.js
ADDED
package/src/types.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":""}
|
package/src/types.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import type RingCentral from
|
|
2
|
-
import type {
|
|
3
|
-
|
|
1
|
+
import type RingCentral from "@rc-ex/core";
|
|
2
|
+
import type {
|
|
3
|
+
RestMethod,
|
|
4
|
+
RestRequestConfig,
|
|
5
|
+
RestResponse,
|
|
6
|
+
} from "@rc-ex/core/src/types";
|
|
7
|
+
import type WS from "isomorphic-ws";
|
|
4
8
|
|
|
5
9
|
export interface WsToken {
|
|
6
10
|
uri: string;
|
|
@@ -30,7 +34,12 @@ export interface Wsc {
|
|
|
30
34
|
}
|
|
31
35
|
|
|
32
36
|
export interface WsgMeta {
|
|
33
|
-
type:
|
|
37
|
+
type:
|
|
38
|
+
| "ClientRequest"
|
|
39
|
+
| "ServerNotification"
|
|
40
|
+
| "Error"
|
|
41
|
+
| "ConnectionDetails"
|
|
42
|
+
| "Heartbeat";
|
|
34
43
|
messageId: string;
|
|
35
44
|
status: number;
|
|
36
45
|
headers: {
|
|
@@ -52,7 +61,7 @@ export interface ConnectionDetails {
|
|
|
52
61
|
idleTimeout: number;
|
|
53
62
|
absoluteTimeout: number;
|
|
54
63
|
maxActiveRequests: number;
|
|
55
|
-
recoveryState?:
|
|
64
|
+
recoveryState?: "Successful" | "Failed";
|
|
56
65
|
recoveryErrorCode?: string;
|
|
57
66
|
}
|
|
58
67
|
|
package/src/utils.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type WS from "isomorphic-ws";
|
|
2
|
+
import type { WsgEvent, WsgMeta } from "./types";
|
|
3
|
+
declare class Utils {
|
|
4
|
+
static splitWsgData(wsgData: string): [WsgMeta, any];
|
|
5
|
+
static debugWebSocket(_ws: WS): void;
|
|
6
|
+
static waitForWebSocketMessage(ws: WS, matchCondition: (meta: WsgMeta) => boolean, timeout?: number): Promise<[WsgMeta, any, WsgEvent]>;
|
|
7
|
+
}
|
|
8
|
+
export default Utils;
|
package/src/utils.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const ClosedException_1 = __importDefault(require("./exceptions/ClosedException"));
|
|
7
|
+
const TimeoutException_1 = __importDefault(require("./exceptions/TimeoutException"));
|
|
8
|
+
class Utils {
|
|
9
|
+
static splitWsgData(wsgData) {
|
|
10
|
+
if (wsgData.includes(",--Boundary")) {
|
|
11
|
+
const index = wsgData.indexOf(",--Boundary");
|
|
12
|
+
return [
|
|
13
|
+
JSON.parse(wsgData.substring(1, index)),
|
|
14
|
+
wsgData.substring(index + 1, wsgData.length - 1),
|
|
15
|
+
];
|
|
16
|
+
}
|
|
17
|
+
return JSON.parse(wsgData);
|
|
18
|
+
}
|
|
19
|
+
static debugWebSocket(_ws) {
|
|
20
|
+
const ws = _ws;
|
|
21
|
+
const send = ws.send.bind(ws);
|
|
22
|
+
ws.send = async (str) => {
|
|
23
|
+
await send(str);
|
|
24
|
+
console.debug(`*** WebSocket outgoing message: ***
|
|
25
|
+
${JSON.stringify(JSON.parse(str), null, 2)}
|
|
26
|
+
******`);
|
|
27
|
+
};
|
|
28
|
+
ws.addEventListener("message", (mEvent) => {
|
|
29
|
+
const event = mEvent;
|
|
30
|
+
console.debug(`*** WebSocket incoming message: ***
|
|
31
|
+
${JSON.stringify(JSON.parse(event.data), null, 2)}
|
|
32
|
+
******`);
|
|
33
|
+
});
|
|
34
|
+
ws.addEventListener("open", (event) => {
|
|
35
|
+
console.debug("WebSocket open event:", event);
|
|
36
|
+
});
|
|
37
|
+
ws.addEventListener("error", (event) => {
|
|
38
|
+
console.debug("WebSocket error event:", event);
|
|
39
|
+
});
|
|
40
|
+
ws.addEventListener("close", (event) => {
|
|
41
|
+
console.debug("WebSocket close event:", event);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
static waitForWebSocketMessage(ws, matchCondition, timeout = 60000) {
|
|
45
|
+
return new Promise((resolve, reject) => {
|
|
46
|
+
const checkHandle = setInterval(() => {
|
|
47
|
+
if (ws.readyState === ws.CLOSED) {
|
|
48
|
+
clearInterval(checkHandle);
|
|
49
|
+
reject(new ClosedException_1.default());
|
|
50
|
+
}
|
|
51
|
+
}, 1000);
|
|
52
|
+
const timeoutHandle = setTimeout(() => {
|
|
53
|
+
ws.removeEventListener("message", handler);
|
|
54
|
+
clearInterval(checkHandle);
|
|
55
|
+
reject(new TimeoutException_1.default());
|
|
56
|
+
}, timeout);
|
|
57
|
+
const handler = (mEvent) => {
|
|
58
|
+
const event = mEvent;
|
|
59
|
+
const [meta, body] = Utils.splitWsgData(event.data);
|
|
60
|
+
if (matchCondition(meta)) {
|
|
61
|
+
ws.removeEventListener("message", handler);
|
|
62
|
+
clearInterval(checkHandle);
|
|
63
|
+
clearTimeout(timeoutHandle);
|
|
64
|
+
resolve([meta, body, event]);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
ws.addEventListener("message", handler);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
exports.default = Utils;
|
|
72
|
+
//# sourceMappingURL=utils.js.map
|
package/src/utils.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["utils.ts"],"names":[],"mappings":"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"}
|
package/src/utils.ts
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
import type
|
|
3
|
-
import type WS from 'isomorphic-ws';
|
|
1
|
+
import type { MessageEvent } from "isomorphic-ws";
|
|
2
|
+
import type WS from "isomorphic-ws";
|
|
4
3
|
|
|
5
|
-
import type {
|
|
6
|
-
import ClosedException from
|
|
7
|
-
import TimeoutException from
|
|
4
|
+
import type { WsgEvent, WsgMeta } from "./types";
|
|
5
|
+
import ClosedException from "./exceptions/ClosedException";
|
|
6
|
+
import TimeoutException from "./exceptions/TimeoutException";
|
|
8
7
|
|
|
9
8
|
class Utils {
|
|
10
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
11
9
|
public static splitWsgData(wsgData: string): [WsgMeta, any] {
|
|
12
|
-
if (wsgData.includes(
|
|
13
|
-
const index = wsgData.indexOf(
|
|
14
|
-
return [
|
|
10
|
+
if (wsgData.includes(",--Boundary")) {
|
|
11
|
+
const index = wsgData.indexOf(",--Boundary");
|
|
12
|
+
return [
|
|
13
|
+
JSON.parse(wsgData.substring(1, index)),
|
|
14
|
+
wsgData.substring(index + 1, wsgData.length - 1),
|
|
15
|
+
];
|
|
15
16
|
}
|
|
16
17
|
return JSON.parse(wsgData);
|
|
17
18
|
}
|
|
@@ -27,7 +28,7 @@ ${JSON.stringify(JSON.parse(str), null, 2)}
|
|
|
27
28
|
******`,
|
|
28
29
|
);
|
|
29
30
|
};
|
|
30
|
-
ws.addEventListener(
|
|
31
|
+
ws.addEventListener("message", (mEvent: MessageEvent) => {
|
|
31
32
|
const event = mEvent as WsgEvent;
|
|
32
33
|
console.debug(
|
|
33
34
|
`*** WebSocket incoming message: ***
|
|
@@ -35,19 +36,22 @@ ${JSON.stringify(JSON.parse(event.data), null, 2)}
|
|
|
35
36
|
******`,
|
|
36
37
|
);
|
|
37
38
|
});
|
|
38
|
-
ws.addEventListener(
|
|
39
|
-
console.debug(
|
|
39
|
+
ws.addEventListener("open", (event) => {
|
|
40
|
+
console.debug("WebSocket open event:", event);
|
|
40
41
|
});
|
|
41
|
-
ws.addEventListener(
|
|
42
|
-
console.debug(
|
|
42
|
+
ws.addEventListener("error", (event) => {
|
|
43
|
+
console.debug("WebSocket error event:", event);
|
|
43
44
|
});
|
|
44
|
-
ws.addEventListener(
|
|
45
|
-
console.debug(
|
|
45
|
+
ws.addEventListener("close", (event) => {
|
|
46
|
+
console.debug("WebSocket close event:", event);
|
|
46
47
|
});
|
|
47
48
|
}
|
|
48
49
|
|
|
49
|
-
public static waitForWebSocketMessage(
|
|
50
|
-
|
|
50
|
+
public static waitForWebSocketMessage(
|
|
51
|
+
ws: WS,
|
|
52
|
+
matchCondition: (meta: WsgMeta) => boolean,
|
|
53
|
+
timeout = 60000,
|
|
54
|
+
) {
|
|
51
55
|
return new Promise<[WsgMeta, any, WsgEvent]>((resolve, reject) => {
|
|
52
56
|
const checkHandle = setInterval(() => {
|
|
53
57
|
if (ws.readyState === ws.CLOSED) {
|
|
@@ -56,8 +60,7 @@ ${JSON.stringify(JSON.parse(event.data), null, 2)}
|
|
|
56
60
|
}
|
|
57
61
|
}, 1000);
|
|
58
62
|
const timeoutHandle = setTimeout(() => {
|
|
59
|
-
|
|
60
|
-
ws.removeEventListener('message', handler);
|
|
63
|
+
ws.removeEventListener("message", handler);
|
|
61
64
|
clearInterval(checkHandle);
|
|
62
65
|
reject(new TimeoutException());
|
|
63
66
|
}, timeout);
|
|
@@ -65,13 +68,13 @@ ${JSON.stringify(JSON.parse(event.data), null, 2)}
|
|
|
65
68
|
const event = mEvent as WsgEvent;
|
|
66
69
|
const [meta, body] = Utils.splitWsgData(event.data);
|
|
67
70
|
if (matchCondition(meta)) {
|
|
68
|
-
ws.removeEventListener(
|
|
71
|
+
ws.removeEventListener("message", handler);
|
|
69
72
|
clearInterval(checkHandle);
|
|
70
73
|
clearTimeout(timeoutHandle);
|
|
71
74
|
resolve([meta, body, event]);
|
|
72
75
|
}
|
|
73
76
|
};
|
|
74
|
-
ws.addEventListener(
|
|
77
|
+
ws.addEventListener("message", handler);
|
|
75
78
|
});
|
|
76
79
|
}
|
|
77
80
|
}
|