@theia/core 1.26.0 → 1.27.0-next.10
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 +6 -7
- package/lib/browser/messaging/ws-connection-provider.d.ts +5 -4
- package/lib/browser/messaging/ws-connection-provider.d.ts.map +1 -1
- package/lib/browser/messaging/ws-connection-provider.js +30 -23
- package/lib/browser/messaging/ws-connection-provider.js.map +1 -1
- package/lib/browser/progress-status-bar-item.d.ts +1 -1
- package/lib/browser/progress-status-bar-item.d.ts.map +1 -1
- package/lib/browser/tree/tree-compression/compressed-tree-widget.js +2 -2
- package/lib/browser/tree/tree-compression/compressed-tree-widget.js.map +1 -1
- package/lib/browser/widgets/select-component.d.ts +4 -1
- package/lib/browser/widgets/select-component.d.ts.map +1 -1
- package/lib/browser/widgets/select-component.js +30 -16
- package/lib/browser/widgets/select-component.js.map +1 -1
- package/lib/common/cancellation.d.ts +1 -0
- package/lib/common/cancellation.d.ts.map +1 -1
- package/lib/common/cancellation.js +8 -0
- package/lib/common/cancellation.js.map +1 -1
- package/lib/common/index.d.ts +2 -0
- package/lib/common/index.d.ts.map +1 -1
- package/lib/common/index.js +2 -0
- package/lib/common/index.js.map +1 -1
- package/lib/common/message-rpc/channel.d.ts +106 -0
- package/lib/common/message-rpc/channel.d.ts.map +1 -0
- package/lib/common/message-rpc/channel.js +195 -0
- package/lib/common/message-rpc/channel.js.map +1 -0
- package/lib/common/message-rpc/channel.spec.d.ts +9 -0
- package/lib/common/message-rpc/channel.spec.d.ts.map +1 -0
- package/lib/common/message-rpc/channel.spec.js +80 -0
- package/lib/common/message-rpc/channel.spec.js.map +1 -0
- package/lib/common/message-rpc/index.d.ts +4 -0
- package/lib/common/message-rpc/index.d.ts.map +1 -0
- package/lib/{node/messaging/logger.js → common/message-rpc/index.js} +6 -19
- package/lib/common/message-rpc/index.js.map +1 -0
- package/lib/common/message-rpc/message-buffer.d.ts +50 -0
- package/lib/common/message-rpc/message-buffer.d.ts.map +1 -0
- package/lib/common/message-rpc/message-buffer.js +56 -0
- package/lib/common/message-rpc/message-buffer.js.map +1 -0
- package/lib/common/message-rpc/rpc-message-encoder.d.ts +159 -0
- package/lib/common/message-rpc/rpc-message-encoder.d.ts.map +1 -0
- package/lib/common/message-rpc/rpc-message-encoder.js +362 -0
- package/lib/common/message-rpc/rpc-message-encoder.js.map +1 -0
- package/lib/common/message-rpc/rpc-message-encoder.spec.d.ts +2 -0
- package/lib/common/message-rpc/rpc-message-encoder.spec.d.ts.map +1 -0
- package/lib/common/message-rpc/rpc-message-encoder.spec.js +37 -0
- package/lib/common/message-rpc/rpc-message-encoder.spec.js.map +1 -0
- package/lib/common/message-rpc/rpc-protocol.d.ts +61 -0
- package/lib/common/message-rpc/rpc-protocol.d.ts.map +1 -0
- package/lib/common/message-rpc/rpc-protocol.js +183 -0
- package/lib/common/message-rpc/rpc-protocol.js.map +1 -0
- package/lib/common/message-rpc/uint8-array-message-buffer.d.ts +52 -0
- package/lib/common/message-rpc/uint8-array-message-buffer.d.ts.map +1 -0
- package/lib/common/message-rpc/uint8-array-message-buffer.js +169 -0
- package/lib/common/message-rpc/uint8-array-message-buffer.js.map +1 -0
- package/lib/common/message-rpc/uint8-array-message-buffer.spec.d.ts +2 -0
- package/lib/common/message-rpc/uint8-array-message-buffer.spec.d.ts.map +1 -0
- package/lib/common/message-rpc/uint8-array-message-buffer.spec.js +39 -0
- package/lib/common/message-rpc/uint8-array-message-buffer.spec.js.map +1 -0
- package/lib/common/messaging/abstract-connection-provider.d.ts +9 -8
- package/lib/common/messaging/abstract-connection-provider.d.ts.map +1 -1
- package/lib/common/messaging/abstract-connection-provider.js +20 -35
- package/lib/common/messaging/abstract-connection-provider.js.map +1 -1
- package/lib/common/messaging/connection-error-handler.d.ts +1 -2
- package/lib/common/messaging/connection-error-handler.d.ts.map +1 -1
- package/lib/common/messaging/connection-error-handler.js +1 -1
- package/lib/common/messaging/connection-error-handler.js.map +1 -1
- package/lib/common/messaging/handler.d.ts +2 -2
- package/lib/common/messaging/handler.d.ts.map +1 -1
- package/lib/common/messaging/proxy-factory.d.ts +13 -7
- package/lib/common/messaging/proxy-factory.d.ts.map +1 -1
- package/lib/common/messaging/proxy-factory.js +18 -13
- package/lib/common/messaging/proxy-factory.js.map +1 -1
- package/lib/common/messaging/proxy-factory.spec.js +4 -15
- package/lib/common/messaging/proxy-factory.spec.js.map +1 -1
- package/lib/common/messaging/web-socket-channel.d.ts +54 -48
- package/lib/common/messaging/web-socket-channel.d.ts.map +1 -1
- package/lib/common/messaging/web-socket-channel.js +41 -105
- package/lib/common/messaging/web-socket-channel.js.map +1 -1
- package/lib/electron-browser/messaging/electron-ipc-connection-provider.d.ts +2 -2
- package/lib/electron-browser/messaging/electron-ipc-connection-provider.d.ts.map +1 -1
- package/lib/electron-browser/messaging/electron-ipc-connection-provider.js +18 -7
- package/lib/electron-browser/messaging/electron-ipc-connection-provider.js.map +1 -1
- package/lib/electron-browser/messaging/electron-ws-connection-provider.d.ts +2 -2
- package/lib/electron-browser/messaging/electron-ws-connection-provider.d.ts.map +1 -1
- package/lib/electron-browser/messaging/electron-ws-connection-provider.js +5 -7
- package/lib/electron-browser/messaging/electron-ws-connection-provider.js.map +1 -1
- package/lib/electron-main/messaging/electron-messaging-contribution.d.ts +37 -9
- package/lib/electron-main/messaging/electron-messaging-contribution.d.ts.map +1 -1
- package/lib/electron-main/messaging/electron-messaging-contribution.js +83 -68
- package/lib/electron-main/messaging/electron-messaging-contribution.js.map +1 -1
- package/lib/electron-main/messaging/electron-messaging-service.d.ts +2 -8
- package/lib/electron-main/messaging/electron-messaging-service.d.ts.map +1 -1
- package/lib/electron-main/messaging/electron-messaging-service.js.map +1 -1
- package/lib/electron-main/theia-electron-window.d.ts.map +1 -1
- package/lib/electron-main/theia-electron-window.js +11 -8
- package/lib/electron-main/theia-electron-window.js.map +1 -1
- package/lib/node/messaging/binary-message-pipe.d.ts +45 -0
- package/lib/node/messaging/binary-message-pipe.d.ts.map +1 -0
- package/lib/node/messaging/binary-message-pipe.js +152 -0
- package/lib/node/messaging/binary-message-pipe.js.map +1 -0
- package/lib/node/messaging/ipc-bootstrap.js +2 -11
- package/lib/node/messaging/ipc-bootstrap.js.map +1 -1
- package/lib/node/messaging/ipc-channel.d.ts +26 -0
- package/lib/node/messaging/ipc-channel.d.ts.map +1 -0
- package/lib/node/messaging/ipc-channel.js +86 -0
- package/lib/node/messaging/ipc-channel.js.map +1 -0
- package/lib/node/messaging/ipc-connection-provider.d.ts +3 -5
- package/lib/node/messaging/ipc-connection-provider.d.ts.map +1 -1
- package/lib/node/messaging/ipc-connection-provider.js +14 -31
- package/lib/node/messaging/ipc-connection-provider.js.map +1 -1
- package/lib/node/messaging/ipc-protocol.d.ts +2 -2
- package/lib/node/messaging/ipc-protocol.d.ts.map +1 -1
- package/lib/node/messaging/messaging-contribution.d.ts +6 -9
- package/lib/node/messaging/messaging-contribution.d.ts.map +1 -1
- package/lib/node/messaging/messaging-contribution.js +23 -68
- package/lib/node/messaging/messaging-contribution.js.map +1 -1
- package/lib/node/messaging/messaging-service.d.ts +4 -23
- package/lib/node/messaging/messaging-service.d.ts.map +1 -1
- package/lib/node/messaging/messaging-service.js +1 -15
- package/lib/node/messaging/messaging-service.js.map +1 -1
- package/lib/node/messaging/test/test-web-socket-channel.d.ts +4 -2
- package/lib/node/messaging/test/test-web-socket-channel.d.ts.map +1 -1
- package/lib/node/messaging/test/test-web-socket-channel.js +25 -12
- package/lib/node/messaging/test/test-web-socket-channel.js.map +1 -1
- package/package.json +5 -8
- package/src/browser/messaging/ws-connection-provider.ts +34 -25
- package/src/browser/progress-status-bar-item.ts +1 -1
- package/src/browser/style/menus.css +1 -0
- package/src/browser/tree/tree-compression/compressed-tree-widget.tsx +2 -2
- package/src/browser/widgets/select-component.tsx +37 -17
- package/src/common/cancellation.ts +8 -0
- package/src/common/index.ts +2 -0
- package/src/common/message-rpc/channel.spec.ts +88 -0
- package/src/common/message-rpc/channel.ts +260 -0
- package/src/{node/messaging/logger.ts → common/message-rpc/index.ts} +4 -23
- package/src/common/message-rpc/message-buffer.ts +99 -0
- package/src/common/message-rpc/rpc-message-encoder.spec.ts +42 -0
- package/src/common/message-rpc/rpc-message-encoder.ts +497 -0
- package/src/common/message-rpc/rpc-protocol.ts +217 -0
- package/src/common/message-rpc/uint8-array-message-buffer.spec.ts +41 -0
- package/src/common/message-rpc/uint8-array-message-buffer.ts +206 -0
- package/src/common/messaging/abstract-connection-provider.ts +28 -37
- package/src/common/messaging/connection-error-handler.ts +1 -2
- package/src/common/messaging/handler.ts +2 -2
- package/src/common/messaging/proxy-factory.spec.ts +4 -17
- package/src/common/messaging/proxy-factory.ts +27 -16
- package/src/common/messaging/web-socket-channel.ts +79 -135
- package/src/electron-browser/messaging/electron-ipc-connection-provider.ts +21 -7
- package/src/electron-browser/messaging/electron-ws-connection-provider.ts +5 -8
- package/src/electron-main/messaging/electron-messaging-contribution.ts +87 -65
- package/src/electron-main/messaging/electron-messaging-service.ts +2 -8
- package/src/electron-main/theia-electron-window.ts +12 -9
- package/src/node/messaging/binary-message-pipe.ts +168 -0
- package/src/node/messaging/ipc-bootstrap.ts +3 -11
- package/src/node/messaging/ipc-channel.ts +97 -0
- package/src/node/messaging/ipc-connection-provider.ts +18 -35
- package/src/node/messaging/ipc-protocol.ts +2 -2
- package/src/node/messaging/messaging-contribution.ts +29 -74
- package/src/node/messaging/messaging-service.ts +4 -31
- package/src/node/messaging/test/test-web-socket-channel.ts +26 -17
- package/lib/node/messaging/logger.d.ts +0 -8
- package/lib/node/messaging/logger.d.ts.map +0 -1
- package/lib/node/messaging/logger.js.map +0 -1
- package/shared/vscode-ws-jsonrpc/index.d.ts +0 -1
- package/shared/vscode-ws-jsonrpc/index.js +0 -1
|
@@ -0,0 +1,497 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2022 Red Hat, Inc. and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
17
|
+
|
|
18
|
+
import { ReadBuffer, WriteBuffer } from './message-buffer';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* This code lets you encode rpc protocol messages (request/reply/notification/error/cancel)
|
|
22
|
+
* into a channel write buffer and decode the same messages from a read buffer.
|
|
23
|
+
* Custom encoders/decoders can be registered to specially handling certain types of values
|
|
24
|
+
* to be encoded. Clients are responsible for ensuring that the set of tags for encoders
|
|
25
|
+
* is distinct and the same at both ends of a channel.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
export type RpcMessage = RequestMessage | ReplyMessage | ReplyErrMessage | CancelMessage | NotificationMessage;
|
|
29
|
+
|
|
30
|
+
export const enum RpcMessageType {
|
|
31
|
+
Request = 1,
|
|
32
|
+
Notification = 2,
|
|
33
|
+
Reply = 3,
|
|
34
|
+
ReplyErr = 4,
|
|
35
|
+
Cancel = 5,
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface CancelMessage {
|
|
39
|
+
type: RpcMessageType.Cancel;
|
|
40
|
+
id: number;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface RequestMessage {
|
|
44
|
+
type: RpcMessageType.Request;
|
|
45
|
+
id: number;
|
|
46
|
+
method: string;
|
|
47
|
+
args: any[];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface NotificationMessage {
|
|
51
|
+
type: RpcMessageType.Notification;
|
|
52
|
+
id: number;
|
|
53
|
+
method: string;
|
|
54
|
+
args: any[];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface ReplyMessage {
|
|
58
|
+
type: RpcMessageType.Reply;
|
|
59
|
+
id: number;
|
|
60
|
+
res: any;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface ReplyErrMessage {
|
|
64
|
+
type: RpcMessageType.ReplyErr;
|
|
65
|
+
id: number;
|
|
66
|
+
err: any;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface SerializedError {
|
|
70
|
+
readonly $isError: true;
|
|
71
|
+
readonly name: string;
|
|
72
|
+
readonly message: string;
|
|
73
|
+
readonly stack: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* A special error that can be returned in case a request
|
|
78
|
+
* has failed. Provides additional information i.e. an error code
|
|
79
|
+
* and additional error data.
|
|
80
|
+
*/
|
|
81
|
+
export class ResponseError extends Error {
|
|
82
|
+
constructor(readonly code: number, message: string, readonly data: any) {
|
|
83
|
+
super(message);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* The tag values for the default {@link ValueEncoder}s & {@link ValueDecoder}s
|
|
89
|
+
*/
|
|
90
|
+
|
|
91
|
+
export enum ObjectType {
|
|
92
|
+
JSON = 0,
|
|
93
|
+
ByteArray = 1,
|
|
94
|
+
ObjectArray = 2,
|
|
95
|
+
Undefined = 3,
|
|
96
|
+
Object = 4,
|
|
97
|
+
String = 5,
|
|
98
|
+
Boolean = 6,
|
|
99
|
+
Number = 7,
|
|
100
|
+
// eslint-disable-next-line @typescript-eslint/no-shadow
|
|
101
|
+
ResponseError = 8,
|
|
102
|
+
Error = 9
|
|
103
|
+
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* A value encoder writes javascript values to a write buffer. Encoders will be asked
|
|
108
|
+
* in turn (ordered by their tag value, descending) whether they can encode a given value
|
|
109
|
+
* This means encoders with higher tag values have priority. Since the default encoders
|
|
110
|
+
* have tag values from 1-7, they can be easily overridden.
|
|
111
|
+
*/
|
|
112
|
+
export interface ValueEncoder {
|
|
113
|
+
/**
|
|
114
|
+
* Returns true if this encoder wants to encode this value.
|
|
115
|
+
* @param value the value to be encoded
|
|
116
|
+
*/
|
|
117
|
+
is(value: any): boolean;
|
|
118
|
+
/**
|
|
119
|
+
* Write the given value to the buffer. Will only be called if {@link is(value)} returns true.
|
|
120
|
+
* @param buf The buffer to write to
|
|
121
|
+
* @param value The value to be written
|
|
122
|
+
* @param recursiveEncode A function that will use the encoders registered on the {@link MessageEncoder}
|
|
123
|
+
* to write a value to the underlying buffer. This is used mostly to write structures like an array
|
|
124
|
+
* without having to know how to encode the values in the array
|
|
125
|
+
*/
|
|
126
|
+
write(buf: WriteBuffer, value: any, recursiveEncode?: (buf: WriteBuffer, value: any) => void): void;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Reads javascript values from a read buffer
|
|
131
|
+
*/
|
|
132
|
+
export interface ValueDecoder {
|
|
133
|
+
/**
|
|
134
|
+
* Reads a value from a read buffer. This method will be called for the decoder that is
|
|
135
|
+
* registered for the tag associated with the value encoder that encoded this value.
|
|
136
|
+
* @param buf The read buffer to read from
|
|
137
|
+
* @param recursiveDecode A function that will use the decoders registered on the {@link RpcMessageDecoder}
|
|
138
|
+
* to read values from the underlying read buffer. This is used mostly to decode structures like an array
|
|
139
|
+
* without having to know how to decode the values in the array.
|
|
140
|
+
*/
|
|
141
|
+
read(buf: ReadBuffer, recursiveDecode: (buf: ReadBuffer) => unknown): unknown;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* A `RpcMessageDecoder` parses a a binary message received via {@link ReadBuffer} into a {@link RpcMessage}
|
|
146
|
+
*/
|
|
147
|
+
export class RpcMessageDecoder {
|
|
148
|
+
|
|
149
|
+
protected decoders: Map<number, ValueDecoder> = new Map();
|
|
150
|
+
|
|
151
|
+
constructor() {
|
|
152
|
+
this.registerDecoder(ObjectType.JSON, {
|
|
153
|
+
read: buf => {
|
|
154
|
+
const json = buf.readString();
|
|
155
|
+
return JSON.parse(json);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
this.registerDecoder(ObjectType.Error, {
|
|
159
|
+
read: buf => {
|
|
160
|
+
const serializedError: SerializedError = JSON.parse(buf.readString());
|
|
161
|
+
const error = new Error(serializedError.message);
|
|
162
|
+
Object.assign(error, serializedError);
|
|
163
|
+
return error;
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
this.registerDecoder(ObjectType.ResponseError, {
|
|
168
|
+
read: buf => {
|
|
169
|
+
const error = JSON.parse(buf.readString());
|
|
170
|
+
return new ResponseError(error.code, error.message, error.data);
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
this.registerDecoder(ObjectType.ByteArray, {
|
|
174
|
+
read: buf => buf.readBytes()
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
this.registerDecoder(ObjectType.ObjectArray, {
|
|
178
|
+
read: buf => this.readArray(buf)
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
this.registerDecoder(ObjectType.Undefined, {
|
|
182
|
+
read: () => undefined
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
this.registerDecoder(ObjectType.Object, {
|
|
186
|
+
read: (buf, recursiveRead) => {
|
|
187
|
+
const propertyCount = buf.readLength();
|
|
188
|
+
const result = Object.create({});
|
|
189
|
+
for (let i = 0; i < propertyCount; i++) {
|
|
190
|
+
const key = buf.readString();
|
|
191
|
+
const value = recursiveRead(buf);
|
|
192
|
+
result[key] = value;
|
|
193
|
+
}
|
|
194
|
+
return result;
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
this.registerDecoder(ObjectType.String, {
|
|
199
|
+
read: (buf, recursiveRead) => buf.readString()
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
this.registerDecoder(ObjectType.Boolean, {
|
|
203
|
+
read: buf => buf.readUint8() === 1
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
this.registerDecoder(ObjectType.Number, {
|
|
207
|
+
read: buf => buf.readNumber()
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Registers a new {@link ValueDecoder} for the given tag.
|
|
214
|
+
* After the successful registration the {@link tagIntType} is recomputed
|
|
215
|
+
* by retrieving the highest tag value and calculating the required Uint size to store it.
|
|
216
|
+
* @param tag the tag for which the decoder should be registered.
|
|
217
|
+
* @param decoder the decoder that should be registered.
|
|
218
|
+
*/
|
|
219
|
+
registerDecoder(tag: number, decoder: ValueDecoder): void {
|
|
220
|
+
if (this.decoders.has(tag)) {
|
|
221
|
+
throw new Error(`Decoder already registered: ${tag}`);
|
|
222
|
+
}
|
|
223
|
+
this.decoders.set(tag, decoder);
|
|
224
|
+
}
|
|
225
|
+
parse(buf: ReadBuffer): RpcMessage {
|
|
226
|
+
try {
|
|
227
|
+
const msgType = buf.readUint8();
|
|
228
|
+
|
|
229
|
+
switch (msgType) {
|
|
230
|
+
case RpcMessageType.Request:
|
|
231
|
+
return this.parseRequest(buf);
|
|
232
|
+
case RpcMessageType.Notification:
|
|
233
|
+
return this.parseNotification(buf);
|
|
234
|
+
case RpcMessageType.Reply:
|
|
235
|
+
return this.parseReply(buf);
|
|
236
|
+
case RpcMessageType.ReplyErr:
|
|
237
|
+
return this.parseReplyErr(buf);
|
|
238
|
+
case RpcMessageType.Cancel:
|
|
239
|
+
return this.parseCancel(buf);
|
|
240
|
+
}
|
|
241
|
+
throw new Error(`Unknown message type: ${msgType}`);
|
|
242
|
+
} catch (e) {
|
|
243
|
+
// exception does not show problematic content: log it!
|
|
244
|
+
console.log('failed to parse message: ' + buf);
|
|
245
|
+
throw e;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
protected parseCancel(msg: ReadBuffer): CancelMessage {
|
|
250
|
+
const callId = msg.readUint32();
|
|
251
|
+
return {
|
|
252
|
+
type: RpcMessageType.Cancel,
|
|
253
|
+
id: callId
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
protected parseRequest(msg: ReadBuffer): RequestMessage {
|
|
258
|
+
const callId = msg.readUint32();
|
|
259
|
+
const method = msg.readString();
|
|
260
|
+
let args = this.readArray(msg);
|
|
261
|
+
// convert `null` to `undefined`, since we don't use `null` in internal plugin APIs
|
|
262
|
+
args = args.map(arg => arg === null ? undefined : arg); // eslint-disable-line no-null/no-null
|
|
263
|
+
|
|
264
|
+
return {
|
|
265
|
+
type: RpcMessageType.Request,
|
|
266
|
+
id: callId,
|
|
267
|
+
method: method,
|
|
268
|
+
args: args
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
protected parseNotification(msg: ReadBuffer): NotificationMessage {
|
|
273
|
+
const callId = msg.readUint32();
|
|
274
|
+
const method = msg.readString();
|
|
275
|
+
let args = this.readArray(msg);
|
|
276
|
+
// convert `null` to `undefined`, since we don't use `null` in internal plugin APIs
|
|
277
|
+
args = args.map(arg => arg === null ? undefined : arg); // eslint-disable-line no-null/no-null
|
|
278
|
+
|
|
279
|
+
return {
|
|
280
|
+
type: RpcMessageType.Notification,
|
|
281
|
+
id: callId,
|
|
282
|
+
method: method,
|
|
283
|
+
args: args
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
parseReply(msg: ReadBuffer): ReplyMessage {
|
|
288
|
+
const callId = msg.readUint32();
|
|
289
|
+
const value = this.readTypedValue(msg);
|
|
290
|
+
return {
|
|
291
|
+
type: RpcMessageType.Reply,
|
|
292
|
+
id: callId,
|
|
293
|
+
res: value
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
parseReplyErr(msg: ReadBuffer): ReplyErrMessage {
|
|
298
|
+
const callId = msg.readUint32();
|
|
299
|
+
|
|
300
|
+
const err = this.readTypedValue(msg);
|
|
301
|
+
|
|
302
|
+
return {
|
|
303
|
+
type: RpcMessageType.ReplyErr,
|
|
304
|
+
id: callId,
|
|
305
|
+
err
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
readArray(buf: ReadBuffer): any[] {
|
|
310
|
+
const length = buf.readLength();
|
|
311
|
+
const result = new Array(length);
|
|
312
|
+
for (let i = 0; i < length; i++) {
|
|
313
|
+
result[i] = this.readTypedValue(buf);
|
|
314
|
+
}
|
|
315
|
+
return result;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
readTypedValue(buf: ReadBuffer): any {
|
|
319
|
+
const type = buf.readUint8();
|
|
320
|
+
const decoder = this.decoders.get(type);
|
|
321
|
+
if (!decoder) {
|
|
322
|
+
throw new Error(`No decoder for tag ${type}`);
|
|
323
|
+
}
|
|
324
|
+
return decoder.read(buf, innerBuffer => this.readTypedValue(innerBuffer));
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* A `RpcMessageEncoder` writes {@link RpcMessage} objects to a {@link WriteBuffer}. Note that it is
|
|
330
|
+
* up to clients to commit the message. This allows for multiple messages being
|
|
331
|
+
* encoded before sending.
|
|
332
|
+
*/
|
|
333
|
+
export class RpcMessageEncoder {
|
|
334
|
+
|
|
335
|
+
protected readonly encoders: [number, ValueEncoder][] = [];
|
|
336
|
+
protected readonly registeredTags: Set<number> = new Set();
|
|
337
|
+
|
|
338
|
+
constructor() {
|
|
339
|
+
this.registerEncoders();
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
protected registerEncoders(): void {
|
|
343
|
+
// encoders will be consulted in reverse order of registration, so the JSON fallback needs to be last
|
|
344
|
+
this.registerEncoder(ObjectType.JSON, {
|
|
345
|
+
is: () => true,
|
|
346
|
+
write: (buf, value) => {
|
|
347
|
+
buf.writeString(JSON.stringify(value));
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
this.registerEncoder(ObjectType.Object, {
|
|
352
|
+
is: value => typeof value === 'object',
|
|
353
|
+
write: (buf, object, recursiveEncode) => {
|
|
354
|
+
const properties = Object.keys(object);
|
|
355
|
+
const relevant = [];
|
|
356
|
+
for (const property of properties) {
|
|
357
|
+
const value = object[property];
|
|
358
|
+
if (typeof value !== 'function') {
|
|
359
|
+
relevant.push([property, value]);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
buf.writeLength(relevant.length);
|
|
364
|
+
for (const [property, value] of relevant) {
|
|
365
|
+
buf.writeString(property);
|
|
366
|
+
recursiveEncode?.(buf, value);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
this.registerEncoder(ObjectType.Error, {
|
|
372
|
+
is: value => value instanceof Error,
|
|
373
|
+
write: (buf, error: Error) => {
|
|
374
|
+
const { name, message } = error;
|
|
375
|
+
const stack: string = (<any>error).stacktrace || error.stack;
|
|
376
|
+
const serializedError = {
|
|
377
|
+
$isError: true,
|
|
378
|
+
name,
|
|
379
|
+
message,
|
|
380
|
+
stack
|
|
381
|
+
};
|
|
382
|
+
buf.writeString(JSON.stringify(serializedError));
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
this.registerEncoder(ObjectType.ResponseError, {
|
|
387
|
+
is: value => value instanceof ResponseError,
|
|
388
|
+
write: (buf, value) => buf.writeString(JSON.stringify(value))
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
this.registerEncoder(ObjectType.Undefined, {
|
|
392
|
+
// eslint-disable-next-line no-null/no-null
|
|
393
|
+
is: value => value == null,
|
|
394
|
+
write: () => { }
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
this.registerEncoder(ObjectType.ObjectArray, {
|
|
398
|
+
is: value => Array.isArray(value),
|
|
399
|
+
write: (buf, value) => {
|
|
400
|
+
this.writeArray(buf, value);
|
|
401
|
+
}
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
this.registerEncoder(ObjectType.ByteArray, {
|
|
405
|
+
is: value => value instanceof Uint8Array,
|
|
406
|
+
write: (buf, value) => {
|
|
407
|
+
buf.writeBytes(value);
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
this.registerEncoder(ObjectType.String, {
|
|
412
|
+
is: value => typeof value === 'string',
|
|
413
|
+
write: (buf, value) => {
|
|
414
|
+
buf.writeString(value);
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
this.registerEncoder(ObjectType.Boolean, {
|
|
419
|
+
is: value => typeof value === 'boolean',
|
|
420
|
+
write: (buf, value) => {
|
|
421
|
+
buf.writeUint8(value === true ? 1 : 0);
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
this.registerEncoder(ObjectType.Number, {
|
|
426
|
+
is: value => typeof value === 'number',
|
|
427
|
+
write: (buf, value) => {
|
|
428
|
+
buf.writeNumber(value);
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Registers a new {@link ValueEncoder} for the given tag.
|
|
435
|
+
* After the successful registration the {@link tagIntType} is recomputed
|
|
436
|
+
* by retrieving the highest tag value and calculating the required Uint size to store it.
|
|
437
|
+
* @param tag the tag for which the encoder should be registered.
|
|
438
|
+
* @param decoder the encoder that should be registered.
|
|
439
|
+
*/
|
|
440
|
+
registerEncoder<T>(tag: number, encoder: ValueEncoder): void {
|
|
441
|
+
if (this.registeredTags.has(tag)) {
|
|
442
|
+
throw new Error(`Tag already registered: ${tag}`);
|
|
443
|
+
}
|
|
444
|
+
this.registeredTags.add(tag);
|
|
445
|
+
this.encoders.push([tag, encoder]);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
cancel(buf: WriteBuffer, requestId: number): void {
|
|
449
|
+
buf.writeUint8(RpcMessageType.Cancel);
|
|
450
|
+
buf.writeUint32(requestId);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
notification(buf: WriteBuffer, requestId: number, method: string, args: any[]): void {
|
|
454
|
+
buf.writeUint8(RpcMessageType.Notification);
|
|
455
|
+
buf.writeUint32(requestId);
|
|
456
|
+
buf.writeString(method);
|
|
457
|
+
this.writeArray(buf, args);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
request(buf: WriteBuffer, requestId: number, method: string, args: any[]): void {
|
|
461
|
+
buf.writeUint8(RpcMessageType.Request);
|
|
462
|
+
buf.writeUint32(requestId);
|
|
463
|
+
buf.writeString(method);
|
|
464
|
+
this.writeArray(buf, args);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
replyOK(buf: WriteBuffer, requestId: number, res: any): void {
|
|
468
|
+
buf.writeUint8(RpcMessageType.Reply);
|
|
469
|
+
buf.writeUint32(requestId);
|
|
470
|
+
this.writeTypedValue(buf, res);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
replyErr(buf: WriteBuffer, requestId: number, err: any): void {
|
|
474
|
+
buf.writeUint8(RpcMessageType.ReplyErr);
|
|
475
|
+
buf.writeUint32(requestId);
|
|
476
|
+
this.writeTypedValue(buf, err);
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
writeTypedValue(buf: WriteBuffer, value: any): void {
|
|
480
|
+
for (let i: number = this.encoders.length - 1; i >= 0; i--) {
|
|
481
|
+
if (this.encoders[i][1].is(value)) {
|
|
482
|
+
buf.writeUint8(this.encoders[i][0]);
|
|
483
|
+
this.encoders[i][1].write(buf, value, (innerBuffer, innerValue) => {
|
|
484
|
+
this.writeTypedValue(innerBuffer, innerValue);
|
|
485
|
+
});
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
writeArray(buf: WriteBuffer, value: any[]): void {
|
|
492
|
+
buf.writeLength(value.length);
|
|
493
|
+
for (let i = 0; i < value.length; i++) {
|
|
494
|
+
this.writeTypedValue(buf, value[i]);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
}
|