@itwin/core-mobile 4.0.0-dev.7 → 4.0.0-dev.70
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/CHANGELOG.md +15 -1
- package/lib/cjs/MobileBackend.d.ts +7 -7
- package/lib/cjs/MobileBackend.js +28 -24
- package/lib/cjs/MobileBackend.js.map +1 -1
- package/lib/cjs/MobileFrontend.d.ts +5 -5
- package/lib/cjs/MobileFrontend.js +25 -21
- package/lib/cjs/MobileFrontend.js.map +1 -1
- package/lib/cjs/__DOC_ONLY__.d.ts +33 -33
- package/lib/cjs/__DOC_ONLY__.js +56 -52
- package/lib/cjs/__DOC_ONLY__.js.map +1 -1
- package/lib/cjs/backend/MobileAuthorizationBackend.d.ts +17 -17
- package/lib/cjs/backend/MobileAuthorizationBackend.js +46 -46
- package/lib/cjs/backend/MobileAuthorizationBackend.js.map +1 -1
- package/lib/cjs/backend/MobileFileHandler.d.ts +112 -112
- package/lib/cjs/backend/MobileFileHandler.js +263 -263
- package/lib/cjs/backend/MobileHost.d.ts +72 -72
- package/lib/cjs/backend/MobileHost.d.ts.map +1 -1
- package/lib/cjs/backend/MobileHost.js +155 -156
- package/lib/cjs/backend/MobileHost.js.map +1 -1
- package/lib/cjs/backend/MobileRpcServer.d.ts +19 -19
- package/lib/cjs/backend/MobileRpcServer.js +156 -156
- package/lib/cjs/backend/MobileRpcServer.js.map +1 -1
- package/lib/cjs/backend/Request.d.ts +149 -149
- package/lib/cjs/backend/Request.d.ts.map +1 -1
- package/lib/cjs/backend/Request.js +267 -267
- package/lib/cjs/common/MobileAppChannel.d.ts +4 -4
- package/lib/cjs/common/MobileAppChannel.js +11 -11
- package/lib/cjs/common/MobileAppProps.d.ts +35 -35
- package/lib/cjs/common/MobileAppProps.d.ts.map +1 -1
- package/lib/cjs/common/MobileAppProps.js +26 -26
- package/lib/cjs/common/MobileEventLoop.d.ts +11 -11
- package/lib/cjs/common/MobileEventLoop.js +30 -30
- package/lib/cjs/common/MobileEventLoop.js.map +1 -1
- package/lib/cjs/common/MobileIpc.d.ts +17 -17
- package/lib/cjs/common/MobileIpc.js +70 -70
- package/lib/cjs/common/MobilePush.d.ts +20 -20
- package/lib/cjs/common/MobilePush.js +53 -53
- package/lib/cjs/common/MobilePush.js.map +1 -1
- package/lib/cjs/common/MobileRpcManager.d.ts +40 -40
- package/lib/cjs/common/MobileRpcManager.js +110 -110
- package/lib/cjs/common/MobileRpcManager.js.map +1 -1
- package/lib/cjs/common/MobileRpcProtocol.d.ts +58 -58
- package/lib/cjs/common/MobileRpcProtocol.d.ts.map +1 -1
- package/lib/cjs/common/MobileRpcProtocol.js +277 -277
- package/lib/cjs/common/MobileRpcProtocol.js.map +1 -1
- package/lib/cjs/common/MobileRpcRequest.d.ts +20 -20
- package/lib/cjs/common/MobileRpcRequest.js +50 -50
- package/lib/cjs/frontend/MobileApp.d.ts +23 -23
- package/lib/cjs/frontend/MobileApp.d.ts.map +1 -1
- package/lib/cjs/frontend/MobileApp.js +79 -80
- package/lib/cjs/frontend/MobileApp.js.map +1 -1
- package/lib/cjs/frontend/MobileAuthorizationFrontend.d.ts +17 -17
- package/lib/cjs/frontend/MobileAuthorizationFrontend.d.ts.map +1 -1
- package/lib/cjs/frontend/MobileAuthorizationFrontend.js +54 -46
- package/lib/cjs/frontend/MobileAuthorizationFrontend.js.map +1 -1
- package/lib/cjs/test/ios/MobilePlatform.test.d.ts +1 -1
- package/lib/cjs/test/ios/MobilePlatform.test.js +84 -84
- package/package.json +18 -18
|
@@ -1,278 +1,278 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/*---------------------------------------------------------------------------------------------
|
|
3
|
-
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
|
|
4
|
-
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
5
|
-
*--------------------------------------------------------------------------------------------*/
|
|
6
|
-
/** @packageDocumentation
|
|
7
|
-
* @module RpcInterface
|
|
8
|
-
*/
|
|
9
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
-
exports.MobileRpcProtocol = void 0;
|
|
11
|
-
const core_bentley_1 = require("@itwin/core-bentley");
|
|
12
|
-
const core_common_1 = require("@itwin/core-common");
|
|
13
|
-
const MobileEventLoop_1 = require("./MobileEventLoop");
|
|
14
|
-
const MobileIpc_1 = require("./MobileIpc");
|
|
15
|
-
const MobilePush_1 = require("./MobilePush");
|
|
16
|
-
const MobileRpcManager_1 = require("./MobileRpcManager");
|
|
17
|
-
const MobileRpcRequest_1 = require("./MobileRpcRequest");
|
|
18
|
-
/** RPC interface protocol for an Mobile-based application.
|
|
19
|
-
* @internal
|
|
20
|
-
*/
|
|
21
|
-
class MobileRpcProtocol extends core_common_1.RpcProtocol {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
this.
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
initializeFrontend() {
|
|
61
|
-
if (typeof (WebSocket) === "undefined") {
|
|
62
|
-
throw new core_common_1.IModelError(core_bentley_1.BentleyStatus.ERROR, "MobileRpcProtocol on frontend require websocket to work");
|
|
63
|
-
}
|
|
64
|
-
if (!MobileRpcManager_1.MobileRpcConfiguration.args.port) {
|
|
65
|
-
throw new core_common_1.IModelError(core_bentley_1.BentleyStatus.ERROR, "MobileRpcProtocol require 'port' parameter");
|
|
66
|
-
}
|
|
67
|
-
this._port = MobileRpcManager_1.MobileRpcConfiguration.args.port;
|
|
68
|
-
this.connect(this._port, false);
|
|
69
|
-
window._imodeljs_rpc_reconnect = (port) => {
|
|
70
|
-
this.socket.close();
|
|
71
|
-
window.location.hash = window.location.hash.replace(`port=${this._port}`, `port=${port}`);
|
|
72
|
-
this._port = port;
|
|
73
|
-
this.connect(port, true);
|
|
74
|
-
};
|
|
75
|
-
const transport = new MobilePush_1.MobilePushTransport(this);
|
|
76
|
-
this._transport = transport;
|
|
77
|
-
core_common_1.RpcPushChannel.setup(transport);
|
|
78
|
-
}
|
|
79
|
-
connect(port, reset) {
|
|
80
|
-
const socket = new WebSocket(`ws://localhost:${port}`);
|
|
81
|
-
socket.binaryType = "arraybuffer";
|
|
82
|
-
this.connectMessageHandler(socket);
|
|
83
|
-
this.connectOpenHandler(socket, reset);
|
|
84
|
-
this.connectErrorHandler(socket);
|
|
85
|
-
this.socket = socket;
|
|
86
|
-
}
|
|
87
|
-
connectMessageHandler(socket) {
|
|
88
|
-
socket.addEventListener("message", async (event) => {
|
|
89
|
-
if (this.socket !== socket) {
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
this.handleMessageFromBackend(event.data);
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
connectOpenHandler(socket, reset) {
|
|
96
|
-
socket.addEventListener("open", (_event) => {
|
|
97
|
-
if (this.socket !== socket) {
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
if (reset) {
|
|
101
|
-
this.reset();
|
|
102
|
-
const requests = new Map(core_common_1.RpcRequest.activeRequests);
|
|
103
|
-
requests.forEach((req) => {
|
|
104
|
-
req.cancel();
|
|
105
|
-
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
106
|
-
req.submit();
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
this.scheduleSend();
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
connectErrorHandler(socket) {
|
|
113
|
-
socket.addEventListener("error", (_event) => {
|
|
114
|
-
if (this.socket !== socket) {
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
throw new core_common_1.IModelError(core_bentley_1.BentleyStatus.ERROR, "Socket error.");
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
reset() {
|
|
121
|
-
this.requests.clear();
|
|
122
|
-
this._capacity = Number.MAX_SAFE_INTEGER;
|
|
123
|
-
if (typeof (this._sendInterval) !== "undefined") {
|
|
124
|
-
window.clearInterval(this._sendInterval);
|
|
125
|
-
this._sendInterval = undefined;
|
|
126
|
-
}
|
|
127
|
-
this._partialRequest = undefined;
|
|
128
|
-
this._partialFulfillment = undefined;
|
|
129
|
-
this._partialData.length = 0;
|
|
130
|
-
}
|
|
131
|
-
scheduleSend() {
|
|
132
|
-
if (!this._pending.length) {
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
this.trySend();
|
|
136
|
-
if (this._pending.length && typeof (this._sendInterval) === "undefined") {
|
|
137
|
-
this._sendInterval = window.setInterval(this._sendIntervalHandler, 0);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
trySend() {
|
|
141
|
-
if (this.socket.readyState !== WebSocket.OPEN) {
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
while (this._capacity !== 0 && this._pending.length) {
|
|
145
|
-
--this._capacity;
|
|
146
|
-
const next = this._pending.shift();
|
|
147
|
-
for (const chunk of next) {
|
|
148
|
-
this.socket.send(chunk);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
if (!this._pending.length && typeof (this._sendInterval) !== "undefined") {
|
|
152
|
-
window.clearInterval(this._sendInterval);
|
|
153
|
-
this._sendInterval = undefined;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
handleMessageFromBackend(data) {
|
|
157
|
-
if (typeof (data) === "string") {
|
|
158
|
-
this.handleStringFromBackend(data);
|
|
159
|
-
}
|
|
160
|
-
else {
|
|
161
|
-
this.handleBinaryFromBackend(data);
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
handleStringFromBackend(data) {
|
|
165
|
-
if (this._partialFulfillment) {
|
|
166
|
-
throw new core_common_1.IModelError(core_bentley_1.BentleyStatus.ERROR, "Invalid state (already receiving response).");
|
|
167
|
-
}
|
|
168
|
-
const response = JSON.parse(data);
|
|
169
|
-
this._partialFulfillment = response;
|
|
170
|
-
if (!response.result.data.length) {
|
|
171
|
-
this.notifyResponse();
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
handleBinaryFromBackend(data) {
|
|
175
|
-
const fulfillment = this._partialFulfillment;
|
|
176
|
-
if (!fulfillment) {
|
|
177
|
-
throw new core_common_1.IModelError(core_bentley_1.BentleyStatus.ERROR, "Invalid state (no response received).");
|
|
178
|
-
}
|
|
179
|
-
this._partialData.push(new Uint8Array(data));
|
|
180
|
-
if (this._partialData.length === fulfillment.result.data.length) {
|
|
181
|
-
this.notifyResponse();
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
notifyResponse() {
|
|
185
|
-
const response = this._partialFulfillment;
|
|
186
|
-
if (!response) {
|
|
187
|
-
throw new core_common_1.IModelError(core_bentley_1.BentleyStatus.ERROR, "Invalid state (no response exists).");
|
|
188
|
-
}
|
|
189
|
-
++this._capacity;
|
|
190
|
-
this.consumePartialData(response.result);
|
|
191
|
-
this._partialFulfillment = undefined;
|
|
192
|
-
if (this._transport && this._transport.consume(response)) {
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
|
-
if (this._ipc.consumeResponse(response)) {
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
const request = this.requests.get(response.id);
|
|
199
|
-
this.requests.delete(response.id);
|
|
200
|
-
request.notifyResponse(response);
|
|
201
|
-
}
|
|
202
|
-
consumePartialData(value) {
|
|
203
|
-
for (let i = 0, l = value.data.length; i !== l; ++i) {
|
|
204
|
-
value.data[i] = this._partialData[i];
|
|
205
|
-
}
|
|
206
|
-
this._partialData.length = 0;
|
|
207
|
-
}
|
|
208
|
-
initializeBackend() {
|
|
209
|
-
const mobilegateway = MobileRpcProtocol.obtainInterop();
|
|
210
|
-
if (mobilegateway === undefined || mobilegateway == null) {
|
|
211
|
-
throw new core_common_1.IModelError(core_bentley_1.BentleyStatus.ERROR, "MobileRpcProtocol on backend require native bridge to be setup");
|
|
212
|
-
}
|
|
213
|
-
mobilegateway.handler = (payload, connectionId) => this.handleMessageFromFrontend(payload, connectionId);
|
|
214
|
-
core_common_1.RpcPushConnection.for = (channel, client) => new MobilePush_1.MobilePushConnection(channel, client, this);
|
|
215
|
-
core_common_1.RpcPushChannel.enabled = true;
|
|
216
|
-
}
|
|
217
|
-
handleMessageFromFrontend(data, connectionId) {
|
|
218
|
-
if (typeof (data) === "string") {
|
|
219
|
-
this.handleStringFromFrontend(data, connectionId);
|
|
220
|
-
}
|
|
221
|
-
else {
|
|
222
|
-
this.handleBinaryFromFrontend(data, connectionId);
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
handleStringFromFrontend(data, connection) {
|
|
226
|
-
if (this._partialRequest) {
|
|
227
|
-
throw new core_common_1.IModelError(core_bentley_1.BentleyStatus.ERROR, "Invalid state (already receiving request).");
|
|
228
|
-
}
|
|
229
|
-
const request = JSON.parse(data);
|
|
230
|
-
this._partialRequest = request;
|
|
231
|
-
if (!request.parameters.data.length) {
|
|
232
|
-
this.notifyRequest(connection); // eslint-disable-line @typescript-eslint/no-floating-promises
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
handleBinaryFromFrontend(data, connection) {
|
|
236
|
-
const request = this._partialRequest;
|
|
237
|
-
if (!request) {
|
|
238
|
-
throw new core_common_1.IModelError(core_bentley_1.BentleyStatus.ERROR, "Invalid state (no request received).");
|
|
239
|
-
}
|
|
240
|
-
this._partialData.push(new Uint8Array(data));
|
|
241
|
-
if (this._partialData.length === request.parameters.data.length) {
|
|
242
|
-
this.notifyRequest(connection); // eslint-disable-line @typescript-eslint/no-floating-promises
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
async notifyRequest(connection) {
|
|
246
|
-
const request = this._partialRequest;
|
|
247
|
-
if (!request) {
|
|
248
|
-
throw new core_common_1.IModelError(core_bentley_1.BentleyStatus.ERROR, "Invalid state (no request exists).");
|
|
249
|
-
}
|
|
250
|
-
this.consumePartialData(request.parameters);
|
|
251
|
-
this._partialRequest = undefined;
|
|
252
|
-
if (this._ipc.consumeRequest(request)) {
|
|
253
|
-
return;
|
|
254
|
-
}
|
|
255
|
-
MobileEventLoop_1.MobileEventLoop.addTask();
|
|
256
|
-
const fulfillment = await this.fulfill(request);
|
|
257
|
-
MobileEventLoop_1.MobileEventLoop.removeTask();
|
|
258
|
-
const response = MobileRpcProtocol.encodeResponse(fulfillment);
|
|
259
|
-
this.sendToFrontend(response, connection);
|
|
260
|
-
}
|
|
261
|
-
sendToBackend(message) {
|
|
262
|
-
this._pending.push(message);
|
|
263
|
-
this.scheduleSend();
|
|
264
|
-
}
|
|
265
|
-
sendToFrontend(message, connection) {
|
|
266
|
-
const mobilegateway = MobileRpcProtocol.obtainInterop();
|
|
267
|
-
for (const chunk of message) {
|
|
268
|
-
if (typeof (chunk) === "string") {
|
|
269
|
-
mobilegateway.sendString(chunk, connection || mobilegateway.connectionId);
|
|
270
|
-
}
|
|
271
|
-
else {
|
|
272
|
-
mobilegateway.sendBinary(chunk, connection || mobilegateway.connectionId);
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
exports.MobileRpcProtocol = MobileRpcProtocol;
|
|
1
|
+
"use strict";
|
|
2
|
+
/*---------------------------------------------------------------------------------------------
|
|
3
|
+
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
|
|
4
|
+
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
5
|
+
*--------------------------------------------------------------------------------------------*/
|
|
6
|
+
/** @packageDocumentation
|
|
7
|
+
* @module RpcInterface
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.MobileRpcProtocol = void 0;
|
|
11
|
+
const core_bentley_1 = require("@itwin/core-bentley");
|
|
12
|
+
const core_common_1 = require("@itwin/core-common");
|
|
13
|
+
const MobileEventLoop_1 = require("./MobileEventLoop");
|
|
14
|
+
const MobileIpc_1 = require("./MobileIpc");
|
|
15
|
+
const MobilePush_1 = require("./MobilePush");
|
|
16
|
+
const MobileRpcManager_1 = require("./MobileRpcManager");
|
|
17
|
+
const MobileRpcRequest_1 = require("./MobileRpcRequest");
|
|
18
|
+
/** RPC interface protocol for an Mobile-based application.
|
|
19
|
+
* @internal
|
|
20
|
+
*/
|
|
21
|
+
class MobileRpcProtocol extends core_common_1.RpcProtocol {
|
|
22
|
+
static obtainInterop() { throw new core_common_1.IModelError(core_bentley_1.BentleyStatus.ERROR, "Not implemented."); }
|
|
23
|
+
static async encodeRequest(request) {
|
|
24
|
+
const serialized = await request.protocol.serialize(request);
|
|
25
|
+
const data = serialized.parameters.data;
|
|
26
|
+
serialized.parameters.data = data.map((v) => v.byteLength);
|
|
27
|
+
return [JSON.stringify(serialized), ...data];
|
|
28
|
+
}
|
|
29
|
+
static encodeResponse(fulfillment) {
|
|
30
|
+
const data = fulfillment.result.data;
|
|
31
|
+
fulfillment.result.data = data.map((v) => v.byteLength);
|
|
32
|
+
const raw = fulfillment.rawResult;
|
|
33
|
+
fulfillment.rawResult = undefined;
|
|
34
|
+
const encoded = [JSON.stringify(fulfillment), ...data];
|
|
35
|
+
fulfillment.rawResult = raw;
|
|
36
|
+
return encoded;
|
|
37
|
+
}
|
|
38
|
+
constructor(configuration, endPoint) {
|
|
39
|
+
super(configuration);
|
|
40
|
+
this.socket = undefined;
|
|
41
|
+
this.requests = new Map();
|
|
42
|
+
this._pending = [];
|
|
43
|
+
this._capacity = Number.MAX_SAFE_INTEGER;
|
|
44
|
+
this._sendInterval = undefined;
|
|
45
|
+
this._sendIntervalHandler = () => this.trySend();
|
|
46
|
+
this.requestType = MobileRpcRequest_1.MobileRpcRequest;
|
|
47
|
+
this._partialRequest = undefined;
|
|
48
|
+
this._partialFulfillment = undefined;
|
|
49
|
+
this._partialData = [];
|
|
50
|
+
this._port = 0;
|
|
51
|
+
if (endPoint === core_common_1.RpcEndpoint.Frontend) {
|
|
52
|
+
this.initializeFrontend();
|
|
53
|
+
}
|
|
54
|
+
else if (endPoint === core_common_1.RpcEndpoint.Backend) {
|
|
55
|
+
this.initializeBackend();
|
|
56
|
+
}
|
|
57
|
+
this._ipc = new MobileIpc_1.MobileIpcTransport(this);
|
|
58
|
+
core_common_1.IpcWebSocket.transport = this._ipc;
|
|
59
|
+
}
|
|
60
|
+
initializeFrontend() {
|
|
61
|
+
if (typeof (WebSocket) === "undefined") {
|
|
62
|
+
throw new core_common_1.IModelError(core_bentley_1.BentleyStatus.ERROR, "MobileRpcProtocol on frontend require websocket to work");
|
|
63
|
+
}
|
|
64
|
+
if (!MobileRpcManager_1.MobileRpcConfiguration.args.port) {
|
|
65
|
+
throw new core_common_1.IModelError(core_bentley_1.BentleyStatus.ERROR, "MobileRpcProtocol require 'port' parameter");
|
|
66
|
+
}
|
|
67
|
+
this._port = MobileRpcManager_1.MobileRpcConfiguration.args.port;
|
|
68
|
+
this.connect(this._port, false);
|
|
69
|
+
window._imodeljs_rpc_reconnect = (port) => {
|
|
70
|
+
this.socket.close();
|
|
71
|
+
window.location.hash = window.location.hash.replace(`port=${this._port}`, `port=${port}`);
|
|
72
|
+
this._port = port;
|
|
73
|
+
this.connect(port, true);
|
|
74
|
+
};
|
|
75
|
+
const transport = new MobilePush_1.MobilePushTransport(this);
|
|
76
|
+
this._transport = transport;
|
|
77
|
+
core_common_1.RpcPushChannel.setup(transport);
|
|
78
|
+
}
|
|
79
|
+
connect(port, reset) {
|
|
80
|
+
const socket = new WebSocket(`ws://localhost:${port}`);
|
|
81
|
+
socket.binaryType = "arraybuffer";
|
|
82
|
+
this.connectMessageHandler(socket);
|
|
83
|
+
this.connectOpenHandler(socket, reset);
|
|
84
|
+
this.connectErrorHandler(socket);
|
|
85
|
+
this.socket = socket;
|
|
86
|
+
}
|
|
87
|
+
connectMessageHandler(socket) {
|
|
88
|
+
socket.addEventListener("message", async (event) => {
|
|
89
|
+
if (this.socket !== socket) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
this.handleMessageFromBackend(event.data);
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
connectOpenHandler(socket, reset) {
|
|
96
|
+
socket.addEventListener("open", (_event) => {
|
|
97
|
+
if (this.socket !== socket) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (reset) {
|
|
101
|
+
this.reset();
|
|
102
|
+
const requests = new Map(core_common_1.RpcRequest.activeRequests);
|
|
103
|
+
requests.forEach((req) => {
|
|
104
|
+
req.cancel();
|
|
105
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
106
|
+
req.submit();
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
this.scheduleSend();
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
connectErrorHandler(socket) {
|
|
113
|
+
socket.addEventListener("error", (_event) => {
|
|
114
|
+
if (this.socket !== socket) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
throw new core_common_1.IModelError(core_bentley_1.BentleyStatus.ERROR, "Socket error.");
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
reset() {
|
|
121
|
+
this.requests.clear();
|
|
122
|
+
this._capacity = Number.MAX_SAFE_INTEGER;
|
|
123
|
+
if (typeof (this._sendInterval) !== "undefined") {
|
|
124
|
+
window.clearInterval(this._sendInterval);
|
|
125
|
+
this._sendInterval = undefined;
|
|
126
|
+
}
|
|
127
|
+
this._partialRequest = undefined;
|
|
128
|
+
this._partialFulfillment = undefined;
|
|
129
|
+
this._partialData.length = 0;
|
|
130
|
+
}
|
|
131
|
+
scheduleSend() {
|
|
132
|
+
if (!this._pending.length) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
this.trySend();
|
|
136
|
+
if (this._pending.length && typeof (this._sendInterval) === "undefined") {
|
|
137
|
+
this._sendInterval = window.setInterval(this._sendIntervalHandler, 0);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
trySend() {
|
|
141
|
+
if (this.socket.readyState !== WebSocket.OPEN) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
while (this._capacity !== 0 && this._pending.length) {
|
|
145
|
+
--this._capacity;
|
|
146
|
+
const next = this._pending.shift();
|
|
147
|
+
for (const chunk of next) {
|
|
148
|
+
this.socket.send(chunk);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (!this._pending.length && typeof (this._sendInterval) !== "undefined") {
|
|
152
|
+
window.clearInterval(this._sendInterval);
|
|
153
|
+
this._sendInterval = undefined;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
handleMessageFromBackend(data) {
|
|
157
|
+
if (typeof (data) === "string") {
|
|
158
|
+
this.handleStringFromBackend(data);
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
this.handleBinaryFromBackend(data);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
handleStringFromBackend(data) {
|
|
165
|
+
if (this._partialFulfillment) {
|
|
166
|
+
throw new core_common_1.IModelError(core_bentley_1.BentleyStatus.ERROR, "Invalid state (already receiving response).");
|
|
167
|
+
}
|
|
168
|
+
const response = JSON.parse(data);
|
|
169
|
+
this._partialFulfillment = response;
|
|
170
|
+
if (!response.result.data.length) {
|
|
171
|
+
this.notifyResponse();
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
handleBinaryFromBackend(data) {
|
|
175
|
+
const fulfillment = this._partialFulfillment;
|
|
176
|
+
if (!fulfillment) {
|
|
177
|
+
throw new core_common_1.IModelError(core_bentley_1.BentleyStatus.ERROR, "Invalid state (no response received).");
|
|
178
|
+
}
|
|
179
|
+
this._partialData.push(new Uint8Array(data));
|
|
180
|
+
if (this._partialData.length === fulfillment.result.data.length) {
|
|
181
|
+
this.notifyResponse();
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
notifyResponse() {
|
|
185
|
+
const response = this._partialFulfillment;
|
|
186
|
+
if (!response) {
|
|
187
|
+
throw new core_common_1.IModelError(core_bentley_1.BentleyStatus.ERROR, "Invalid state (no response exists).");
|
|
188
|
+
}
|
|
189
|
+
++this._capacity;
|
|
190
|
+
this.consumePartialData(response.result);
|
|
191
|
+
this._partialFulfillment = undefined;
|
|
192
|
+
if (this._transport && this._transport.consume(response)) {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
if (this._ipc.consumeResponse(response)) {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const request = this.requests.get(response.id);
|
|
199
|
+
this.requests.delete(response.id);
|
|
200
|
+
request.notifyResponse(response);
|
|
201
|
+
}
|
|
202
|
+
consumePartialData(value) {
|
|
203
|
+
for (let i = 0, l = value.data.length; i !== l; ++i) {
|
|
204
|
+
value.data[i] = this._partialData[i];
|
|
205
|
+
}
|
|
206
|
+
this._partialData.length = 0;
|
|
207
|
+
}
|
|
208
|
+
initializeBackend() {
|
|
209
|
+
const mobilegateway = MobileRpcProtocol.obtainInterop();
|
|
210
|
+
if (mobilegateway === undefined || mobilegateway == null) {
|
|
211
|
+
throw new core_common_1.IModelError(core_bentley_1.BentleyStatus.ERROR, "MobileRpcProtocol on backend require native bridge to be setup");
|
|
212
|
+
}
|
|
213
|
+
mobilegateway.handler = (payload, connectionId) => this.handleMessageFromFrontend(payload, connectionId);
|
|
214
|
+
core_common_1.RpcPushConnection.for = (channel, client) => new MobilePush_1.MobilePushConnection(channel, client, this);
|
|
215
|
+
core_common_1.RpcPushChannel.enabled = true;
|
|
216
|
+
}
|
|
217
|
+
handleMessageFromFrontend(data, connectionId) {
|
|
218
|
+
if (typeof (data) === "string") {
|
|
219
|
+
this.handleStringFromFrontend(data, connectionId);
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
this.handleBinaryFromFrontend(data, connectionId);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
handleStringFromFrontend(data, connection) {
|
|
226
|
+
if (this._partialRequest) {
|
|
227
|
+
throw new core_common_1.IModelError(core_bentley_1.BentleyStatus.ERROR, "Invalid state (already receiving request).");
|
|
228
|
+
}
|
|
229
|
+
const request = JSON.parse(data);
|
|
230
|
+
this._partialRequest = request;
|
|
231
|
+
if (!request.parameters.data.length) {
|
|
232
|
+
this.notifyRequest(connection); // eslint-disable-line @typescript-eslint/no-floating-promises
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
handleBinaryFromFrontend(data, connection) {
|
|
236
|
+
const request = this._partialRequest;
|
|
237
|
+
if (!request) {
|
|
238
|
+
throw new core_common_1.IModelError(core_bentley_1.BentleyStatus.ERROR, "Invalid state (no request received).");
|
|
239
|
+
}
|
|
240
|
+
this._partialData.push(new Uint8Array(data));
|
|
241
|
+
if (this._partialData.length === request.parameters.data.length) {
|
|
242
|
+
this.notifyRequest(connection); // eslint-disable-line @typescript-eslint/no-floating-promises
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
async notifyRequest(connection) {
|
|
246
|
+
const request = this._partialRequest;
|
|
247
|
+
if (!request) {
|
|
248
|
+
throw new core_common_1.IModelError(core_bentley_1.BentleyStatus.ERROR, "Invalid state (no request exists).");
|
|
249
|
+
}
|
|
250
|
+
this.consumePartialData(request.parameters);
|
|
251
|
+
this._partialRequest = undefined;
|
|
252
|
+
if (this._ipc.consumeRequest(request)) {
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
MobileEventLoop_1.MobileEventLoop.addTask();
|
|
256
|
+
const fulfillment = await this.fulfill(request);
|
|
257
|
+
MobileEventLoop_1.MobileEventLoop.removeTask();
|
|
258
|
+
const response = MobileRpcProtocol.encodeResponse(fulfillment);
|
|
259
|
+
this.sendToFrontend(response, connection);
|
|
260
|
+
}
|
|
261
|
+
sendToBackend(message) {
|
|
262
|
+
this._pending.push(message);
|
|
263
|
+
this.scheduleSend();
|
|
264
|
+
}
|
|
265
|
+
sendToFrontend(message, connection) {
|
|
266
|
+
const mobilegateway = MobileRpcProtocol.obtainInterop();
|
|
267
|
+
for (const chunk of message) {
|
|
268
|
+
if (typeof (chunk) === "string") {
|
|
269
|
+
mobilegateway.sendString(chunk, connection || mobilegateway.connectionId);
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
mobilegateway.sendBinary(chunk, connection || mobilegateway.connectionId);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
exports.MobileRpcProtocol = MobileRpcProtocol;
|
|
278
278
|
//# sourceMappingURL=MobileRpcProtocol.js.map
|