@theia/plugin-ext 1.33.0-next.5 → 1.33.0-next.8
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/lib/common/index.js +2 -0
- package/lib/common/index.js.map +1 -1
- package/lib/common/plugin-api-rpc.d.ts +5 -3
- package/lib/common/plugin-api-rpc.d.ts.map +1 -1
- package/lib/common/plugin-api-rpc.js +0 -2
- package/lib/common/plugin-api-rpc.js.map +1 -1
- package/lib/common/plugin-protocol.d.ts +4 -4
- package/lib/common/plugin-protocol.d.ts.map +1 -1
- package/lib/common/proxy-handler.d.ts +66 -0
- package/lib/common/proxy-handler.d.ts.map +1 -0
- package/lib/common/proxy-handler.js +98 -0
- package/lib/common/proxy-handler.js.map +1 -0
- package/lib/common/rpc-protocol.d.ts +25 -51
- package/lib/common/rpc-protocol.d.ts.map +1 -1
- package/lib/common/rpc-protocol.js +126 -323
- package/lib/common/rpc-protocol.js.map +1 -1
- package/lib/hosted/browser/hosted-plugin-watcher.d.ts +1 -1
- package/lib/hosted/browser/hosted-plugin-watcher.d.ts.map +1 -1
- package/lib/hosted/browser/hosted-plugin-watcher.js.map +1 -1
- package/lib/hosted/browser/hosted-plugin.d.ts.map +1 -1
- package/lib/hosted/browser/hosted-plugin.js +13 -8
- package/lib/hosted/browser/hosted-plugin.js.map +1 -1
- package/lib/hosted/browser/plugin-worker.d.ts.map +1 -1
- package/lib/hosted/browser/plugin-worker.js +14 -9
- package/lib/hosted/browser/plugin-worker.js.map +1 -1
- package/lib/hosted/browser/worker/worker-main.d.ts +1 -1
- package/lib/hosted/browser/worker/worker-main.d.ts.map +1 -1
- package/lib/hosted/browser/worker/worker-main.js +23 -22
- package/lib/hosted/browser/worker/worker-main.js.map +1 -1
- package/lib/hosted/node/hosted-plugin-process.d.ts +5 -4
- package/lib/hosted/node/hosted-plugin-process.d.ts.map +1 -1
- package/lib/hosted/node/hosted-plugin-process.js +20 -13
- package/lib/hosted/node/hosted-plugin-process.js.map +1 -1
- package/lib/hosted/node/hosted-plugin-protocol.d.ts +22 -0
- package/lib/hosted/node/hosted-plugin-protocol.d.ts.map +1 -0
- package/lib/hosted/node/hosted-plugin-protocol.js +37 -0
- package/lib/hosted/node/hosted-plugin-protocol.js.map +1 -0
- package/lib/hosted/node/hosted-plugin.d.ts +1 -1
- package/lib/hosted/node/hosted-plugin.d.ts.map +1 -1
- package/lib/hosted/node/hosted-plugin.js.map +1 -1
- package/lib/hosted/node/plugin-host.d.ts +1 -1
- package/lib/hosted/node/plugin-host.d.ts.map +1 -1
- package/lib/hosted/node/plugin-host.js +10 -21
- package/lib/hosted/node/plugin-host.js.map +1 -1
- package/lib/hosted/node/plugin-service.d.ts +1 -1
- package/lib/hosted/node/plugin-service.d.ts.map +1 -1
- package/lib/hosted/node/plugin-service.js.map +1 -1
- package/lib/main/browser/main-context.d.ts.map +1 -1
- package/lib/main/browser/main-context.js +0 -3
- package/lib/main/browser/main-context.js.map +1 -1
- package/lib/main/browser/tasks-main.d.ts.map +1 -1
- package/lib/main/browser/tasks-main.js +13 -9
- package/lib/main/browser/tasks-main.js.map +1 -1
- package/lib/plugin/type-converters.d.ts.map +1 -1
- package/lib/plugin/type-converters.js +6 -14
- package/lib/plugin/type-converters.js.map +1 -1
- package/lib/plugin/type-converters.spec.js +5 -4
- package/lib/plugin/type-converters.spec.js.map +1 -1
- package/lib/plugin/types-impl.d.ts +4 -8
- package/lib/plugin/types-impl.d.ts.map +1 -1
- package/lib/plugin/types-impl.js +8 -29
- package/lib/plugin/types-impl.js.map +1 -1
- package/package.json +25 -25
- package/src/common/index.ts +4 -0
- package/src/common/plugin-api-rpc.ts +5 -3
- package/src/common/plugin-protocol.ts +4 -4
- package/src/common/proxy-handler.ts +126 -0
- package/src/common/rpc-protocol.ts +128 -401
- package/src/hosted/browser/hosted-plugin-watcher.ts +4 -3
- package/src/hosted/browser/hosted-plugin.ts +17 -8
- package/src/hosted/browser/plugin-worker.ts +16 -10
- package/src/hosted/browser/worker/worker-main.ts +25 -26
- package/src/hosted/node/hosted-plugin-process.ts +25 -16
- package/src/hosted/node/hosted-plugin-protocol.ts +49 -0
- package/src/hosted/node/hosted-plugin.ts +1 -1
- package/src/hosted/node/plugin-host.ts +11 -22
- package/src/hosted/node/plugin-service.ts +1 -1
- package/src/main/browser/main-context.ts +0 -4
- package/src/main/browser/tasks-main.ts +13 -9
- package/src/plugin/type-converters.spec.ts +5 -4
- package/src/plugin/type-converters.ts +10 -12
- package/src/plugin/types-impl.ts +6 -26
|
@@ -22,14 +22,17 @@
|
|
|
22
22
|
|
|
23
23
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
24
24
|
|
|
25
|
+
import { Channel, Disposable, DisposableCollection, ReadBuffer, WriteBuffer } from '@theia/core';
|
|
25
26
|
import { Emitter, Event } from '@theia/core/lib/common/event';
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
27
|
+
import { ChannelMultiplexer, MessageProvider } from '@theia/core/lib/common/message-rpc/channel';
|
|
28
|
+
import { MsgPackMessageDecoder, MsgPackMessageEncoder } from '@theia/core/lib/common/message-rpc/rpc-message-encoder';
|
|
29
|
+
import { Uint8ArrayReadBuffer, Uint8ArrayWriteBuffer } from '@theia/core/lib/common/message-rpc/uint8-array-message-buffer';
|
|
30
|
+
import { ClientProxyHandler, RpcInvocationHandler } from './proxy-handler';
|
|
31
|
+
import { MsgPackExtensionManager } from '@theia/core/lib/common/message-rpc/msg-pack-extension-manager';
|
|
28
32
|
import { URI as VSCodeURI } from '@theia/core/shared/vscode-uri';
|
|
29
33
|
import URI from '@theia/core/lib/common/uri';
|
|
30
|
-
import { CancellationToken, CancellationTokenSource } from '@theia/core/shared/vscode-languageserver-protocol';
|
|
31
|
-
import { Range, Position } from '../plugin/types-impl';
|
|
32
34
|
import { BinaryBuffer } from '@theia/core/lib/common/buffer';
|
|
35
|
+
import { Range, Position } from '../plugin/types-impl';
|
|
33
36
|
|
|
34
37
|
export interface MessageConnection {
|
|
35
38
|
send(msg: string): void;
|
|
@@ -76,49 +79,29 @@ export namespace ConnectionClosedError {
|
|
|
76
79
|
}
|
|
77
80
|
|
|
78
81
|
export class RPCProtocolImpl implements RPCProtocol {
|
|
79
|
-
|
|
80
|
-
private readonly locals = new Map<string, any>();
|
|
82
|
+
private readonly locals = new Map<string, RpcInvocationHandler>();
|
|
81
83
|
private readonly proxies = new Map<string, any>();
|
|
82
|
-
private
|
|
83
|
-
private readonly
|
|
84
|
-
private readonly
|
|
85
|
-
private readonly multiplexer: RPCMultiplexer;
|
|
86
|
-
|
|
87
|
-
private replacer: (key: string | undefined, value: any) => any;
|
|
88
|
-
private reviver: (key: string | undefined, value: any) => any;
|
|
84
|
+
private readonly multiplexer: ChannelMultiplexer;
|
|
85
|
+
private readonly encoder = new MsgPackMessageEncoder();
|
|
86
|
+
private readonly decoder = new MsgPackMessageDecoder();
|
|
89
87
|
|
|
90
88
|
private readonly toDispose = new DisposableCollection(
|
|
91
89
|
Disposable.create(() => { /* mark as no disposed */ })
|
|
92
90
|
);
|
|
93
91
|
|
|
94
|
-
constructor(
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}) {
|
|
98
|
-
this.toDispose.push(
|
|
99
|
-
this.multiplexer = new RPCMultiplexer(connection)
|
|
100
|
-
);
|
|
101
|
-
this.multiplexer.onMessage(msg => this.receiveOneMessage(msg));
|
|
102
|
-
this.toDispose.push(Disposable.create(() => {
|
|
103
|
-
this.proxies.clear();
|
|
104
|
-
for (const reply of this.pendingRPCReplies.values()) {
|
|
105
|
-
reply.reject(ConnectionClosedError.create());
|
|
106
|
-
}
|
|
107
|
-
this.pendingRPCReplies.clear();
|
|
108
|
-
}));
|
|
109
|
-
|
|
110
|
-
this.reviver = transformations?.reviver || ObjectsTransferrer.reviver;
|
|
111
|
-
this.replacer = transformations?.replacer || ObjectsTransferrer.replacer;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
private get isDisposed(): boolean {
|
|
115
|
-
return this.toDispose.disposed;
|
|
92
|
+
constructor(channel: Channel) {
|
|
93
|
+
this.toDispose.push(this.multiplexer = new ChannelMultiplexer(new BatchingChannel(channel)));
|
|
94
|
+
this.toDispose.push(Disposable.create(() => this.proxies.clear()));
|
|
116
95
|
}
|
|
117
96
|
|
|
118
97
|
dispose(): void {
|
|
119
98
|
this.toDispose.dispose();
|
|
120
99
|
}
|
|
121
100
|
|
|
101
|
+
protected get isDisposed(): boolean {
|
|
102
|
+
return this.toDispose.disposed;
|
|
103
|
+
}
|
|
104
|
+
|
|
122
105
|
getProxy<T>(proxyId: ProxyIdentifier<T>): T {
|
|
123
106
|
if (this.isDisposed) {
|
|
124
107
|
throw ConnectionClosedError.create();
|
|
@@ -131,274 +114,125 @@ export class RPCProtocolImpl implements RPCProtocol {
|
|
|
131
114
|
return proxy;
|
|
132
115
|
}
|
|
133
116
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
throw ConnectionClosedError.create();
|
|
137
|
-
}
|
|
138
|
-
this.locals.set(identifier.id, instance);
|
|
139
|
-
if (Disposable.is(instance)) {
|
|
140
|
-
this.toDispose.push(instance);
|
|
141
|
-
}
|
|
142
|
-
this.toDispose.push(Disposable.create(() => this.locals.delete(identifier.id)));
|
|
143
|
-
return instance;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
private createProxy<T>(proxyId: string): T {
|
|
147
|
-
const handler = {
|
|
148
|
-
get: (target: any, name: string) => {
|
|
149
|
-
if (!target[name] && name.charCodeAt(0) === 36 /* CharCode.DollarSign */) {
|
|
150
|
-
target[name] = (...myArgs: any[]) =>
|
|
151
|
-
this.remoteCall(proxyId, name, myArgs);
|
|
152
|
-
}
|
|
153
|
-
return target[name];
|
|
154
|
-
}
|
|
155
|
-
};
|
|
117
|
+
protected createProxy<T>(proxyId: string): T {
|
|
118
|
+
const handler = new ClientProxyHandler({ id: proxyId, encoder: this.encoder, decoder: this.decoder, channelProvider: () => this.multiplexer.open(proxyId) });
|
|
156
119
|
return new Proxy(Object.create(null), handler);
|
|
157
120
|
}
|
|
158
121
|
|
|
159
|
-
|
|
122
|
+
set<T, R extends T>(identifier: ProxyIdentifier<T>, instance: R): R {
|
|
160
123
|
if (this.isDisposed) {
|
|
161
|
-
|
|
162
|
-
}
|
|
163
|
-
const cancellationToken: CancellationToken | undefined = args.length && CancellationToken.is(args[args.length - 1]) ? args.pop() : undefined;
|
|
164
|
-
if (cancellationToken && cancellationToken.isCancellationRequested) {
|
|
165
|
-
return Promise.reject(canceled());
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const callId = String(++this.lastMessageId);
|
|
169
|
-
const result = new Deferred();
|
|
170
|
-
|
|
171
|
-
if (cancellationToken) {
|
|
172
|
-
args.push('add.cancellation.token');
|
|
173
|
-
cancellationToken.onCancellationRequested(() =>
|
|
174
|
-
this.multiplexer.send(this.cancel(callId))
|
|
175
|
-
);
|
|
124
|
+
throw ConnectionClosedError.create();
|
|
176
125
|
}
|
|
126
|
+
const invocationHandler = this.locals.get(identifier.id);
|
|
127
|
+
if (!invocationHandler) {
|
|
128
|
+
const handler = new RpcInvocationHandler({ id: identifier.id, target: instance, encoder: this.encoder, decoder: this.decoder });
|
|
177
129
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
const msg = <RPCMessage>JSON.parse(rawmsg, this.reviver);
|
|
189
|
-
|
|
190
|
-
switch (msg.type) {
|
|
191
|
-
case MessageType.Request:
|
|
192
|
-
this.receiveRequest(msg);
|
|
193
|
-
break;
|
|
194
|
-
case MessageType.Reply:
|
|
195
|
-
this.receiveReply(msg);
|
|
196
|
-
break;
|
|
197
|
-
case MessageType.ReplyErr:
|
|
198
|
-
this.receiveReplyErr(msg);
|
|
199
|
-
break;
|
|
200
|
-
case MessageType.Cancel:
|
|
201
|
-
this.receiveCancel(msg);
|
|
202
|
-
break;
|
|
130
|
+
const channel = this.multiplexer.getOpenChannel(identifier.id);
|
|
131
|
+
if (channel) {
|
|
132
|
+
handler.listen(channel);
|
|
133
|
+
} else {
|
|
134
|
+
const channelOpenListener = this.multiplexer.onDidOpenChannel(event => {
|
|
135
|
+
if (event.id === identifier.id) {
|
|
136
|
+
handler.listen(event.channel);
|
|
137
|
+
channelOpenListener.dispose();
|
|
138
|
+
}
|
|
139
|
+
});
|
|
203
140
|
}
|
|
204
|
-
} catch (e) {
|
|
205
|
-
// exception does not show problematic content: log it!
|
|
206
|
-
console.log('failed to parse message: ' + rawmsg);
|
|
207
|
-
throw e;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
private receiveCancel(msg: CancelMessage): void {
|
|
213
|
-
const cancellationTokenSource = this.cancellationTokenSources.get(msg.id);
|
|
214
|
-
if (cancellationTokenSource) {
|
|
215
|
-
cancellationTokenSource.cancel();
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
private receiveRequest(msg: RequestMessage): void {
|
|
220
|
-
const callId = msg.id;
|
|
221
|
-
const proxyId = msg.proxyId;
|
|
222
|
-
// convert `null` to `undefined`, since we don't use `null` in internal plugin APIs
|
|
223
|
-
const args = msg.args.map(arg => arg === null ? undefined : arg); // eslint-disable-line no-null/no-null
|
|
224
|
-
|
|
225
|
-
const addToken = args.length && args[args.length - 1] === 'add.cancellation.token' ? args.pop() : false;
|
|
226
|
-
if (addToken) {
|
|
227
|
-
const tokenSource = new CancellationTokenSource();
|
|
228
|
-
this.cancellationTokenSources.set(callId, tokenSource);
|
|
229
|
-
args.push(tokenSource.token);
|
|
230
|
-
}
|
|
231
|
-
const invocation = this.invokeHandler(proxyId, msg.method, args);
|
|
232
|
-
|
|
233
|
-
invocation.then(result => {
|
|
234
|
-
this.cancellationTokenSources.delete(callId);
|
|
235
|
-
this.multiplexer.send(this.replyOK(callId, result));
|
|
236
|
-
}, error => {
|
|
237
|
-
this.cancellationTokenSources.delete(callId);
|
|
238
|
-
this.multiplexer.send(this.replyErr(callId, error));
|
|
239
|
-
});
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
private receiveReply(msg: ReplyMessage): void {
|
|
243
|
-
const callId = msg.id;
|
|
244
|
-
const pendingReply = this.pendingRPCReplies.get(callId);
|
|
245
|
-
if (!pendingReply) {
|
|
246
|
-
return;
|
|
247
|
-
}
|
|
248
|
-
this.pendingRPCReplies.delete(callId);
|
|
249
|
-
pendingReply.resolve(msg.res);
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
private receiveReplyErr(msg: ReplyErrMessage): void {
|
|
253
|
-
const callId = msg.id;
|
|
254
|
-
const pendingReply = this.pendingRPCReplies.get(callId);
|
|
255
|
-
if (!pendingReply) {
|
|
256
|
-
return;
|
|
257
|
-
}
|
|
258
|
-
this.pendingRPCReplies.delete(callId);
|
|
259
|
-
|
|
260
|
-
let err: Error | undefined = undefined;
|
|
261
|
-
if (msg.err && msg.err.$isError) {
|
|
262
|
-
err = new Error();
|
|
263
|
-
err.name = msg.err.name;
|
|
264
|
-
err.message = msg.err.message;
|
|
265
|
-
err.stack = msg.err.stack;
|
|
266
|
-
}
|
|
267
|
-
pendingReply.reject(err);
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
private invokeHandler(proxyId: string, methodName: string, args: any[]): Promise<any> {
|
|
271
|
-
try {
|
|
272
|
-
return Promise.resolve(this.doInvokeHandler(proxyId, methodName, args));
|
|
273
|
-
} catch (err) {
|
|
274
|
-
return Promise.reject(err);
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
private doInvokeHandler(proxyId: string, methodName: string, args: any[]): any {
|
|
279
|
-
const actor = this.locals.get(proxyId);
|
|
280
|
-
if (!actor) {
|
|
281
|
-
throw new Error('Unknown actor ' + proxyId);
|
|
282
|
-
}
|
|
283
|
-
const method = actor[methodName];
|
|
284
|
-
if (typeof method !== 'function') {
|
|
285
|
-
throw new Error('Unknown method ' + methodName + ' on actor ' + proxyId);
|
|
286
|
-
}
|
|
287
|
-
return method.apply(actor, args);
|
|
288
|
-
}
|
|
289
141
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
return `{"type":${MessageType.Request},"id":"${req}","proxyId":"${rpcId}","method":"${method}","args":${JSON.stringify(args, this.replacer)}}`;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
private replyOK(req: string, res: any): string {
|
|
299
|
-
if (typeof res === 'undefined') {
|
|
300
|
-
return `{"type":${MessageType.Reply},"id":"${req}"}`;
|
|
301
|
-
}
|
|
302
|
-
return `{"type":${MessageType.Reply},"id":"${req}","res":${safeStringify(res, this.replacer)}}`;
|
|
303
|
-
}
|
|
142
|
+
this.locals.set(identifier.id, handler);
|
|
143
|
+
if (Disposable.is(instance)) {
|
|
144
|
+
this.toDispose.push(instance);
|
|
145
|
+
}
|
|
146
|
+
this.toDispose.push(Disposable.create(() => this.locals.delete(identifier.id)));
|
|
304
147
|
|
|
305
|
-
private replyErr(req: string, err: any): string {
|
|
306
|
-
err = typeof err === 'string' ? new Error(err) : err;
|
|
307
|
-
if (err instanceof Error) {
|
|
308
|
-
return `{"type":${MessageType.ReplyErr},"id":"${req}","err":${safeStringify(transformErrorForSerialization(err))}}`;
|
|
309
148
|
}
|
|
310
|
-
return
|
|
149
|
+
return instance;
|
|
311
150
|
}
|
|
312
151
|
}
|
|
313
152
|
|
|
314
|
-
function canceled(): Error {
|
|
315
|
-
const error = new Error('Canceled');
|
|
316
|
-
error.name = error.message;
|
|
317
|
-
return error;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
153
|
/**
|
|
321
|
-
*
|
|
154
|
+
* Wraps and underlying channel to send/receive multiple messages in one go:
|
|
322
155
|
* - multiple messages to be sent from one stack get sent in bulk at `process.nextTick`.
|
|
323
156
|
* - each incoming message is handled in a separate `process.nextTick`.
|
|
324
157
|
*/
|
|
325
|
-
class
|
|
326
|
-
|
|
327
|
-
private readonly connection: MessageConnection;
|
|
328
|
-
private readonly sendAccumulatedBound: () => void;
|
|
329
|
-
|
|
330
|
-
private messagesToSend: string[];
|
|
158
|
+
export class BatchingChannel implements Channel {
|
|
159
|
+
protected messagesToSend: Uint8Array[] = [];
|
|
331
160
|
|
|
332
|
-
|
|
333
|
-
|
|
161
|
+
constructor(protected underlyingChannel: Channel) {
|
|
162
|
+
underlyingChannel.onMessage(msg => this.handleMessages(msg()));
|
|
163
|
+
}
|
|
334
164
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
165
|
+
protected onMessageEmitter: Emitter<MessageProvider> = new Emitter();
|
|
166
|
+
get onMessage(): Event<MessageProvider> {
|
|
167
|
+
return this.onMessageEmitter.event;
|
|
168
|
+
};
|
|
338
169
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
const messages = JSON.parse(msg);
|
|
342
|
-
for (const message of messages) {
|
|
343
|
-
this.messageEmitter.fire(message);
|
|
344
|
-
}
|
|
345
|
-
}));
|
|
346
|
-
this.toDispose.push(this.messageEmitter);
|
|
170
|
+
readonly onClose = this.underlyingChannel.onClose;
|
|
171
|
+
readonly onError = this.underlyingChannel.onError;
|
|
347
172
|
|
|
173
|
+
close(): void {
|
|
174
|
+
this.underlyingChannel.close();
|
|
175
|
+
this.onMessageEmitter.dispose();
|
|
348
176
|
this.messagesToSend = [];
|
|
349
177
|
}
|
|
350
178
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
get onMessage(): Event<string> {
|
|
356
|
-
return this.messageEmitter.event;
|
|
179
|
+
getWriteBuffer(): WriteBuffer {
|
|
180
|
+
const writer = new Uint8ArrayWriteBuffer();
|
|
181
|
+
writer.onCommit(buffer => this.commitSingleMessage(buffer));
|
|
182
|
+
return writer;
|
|
357
183
|
}
|
|
358
184
|
|
|
359
|
-
|
|
360
|
-
const tmp = this.messagesToSend;
|
|
361
|
-
this.messagesToSend = [];
|
|
362
|
-
this.connection.send(JSON.stringify(tmp));
|
|
363
|
-
}
|
|
185
|
+
protected commitSingleMessage(msg: Uint8Array): void {
|
|
364
186
|
|
|
365
|
-
public send(msg: string): void {
|
|
366
|
-
if (this.toDispose.disposed) {
|
|
367
|
-
throw ConnectionClosedError.create();
|
|
368
|
-
}
|
|
369
187
|
if (this.messagesToSend.length === 0) {
|
|
370
188
|
if (typeof setImmediate !== 'undefined') {
|
|
371
|
-
setImmediate(this.
|
|
189
|
+
setImmediate(() => this.sendAccumulated());
|
|
372
190
|
} else {
|
|
373
|
-
setTimeout(this.
|
|
191
|
+
setTimeout(() => this.sendAccumulated(), 0);
|
|
374
192
|
}
|
|
375
193
|
}
|
|
376
194
|
this.messagesToSend.push(msg);
|
|
377
195
|
}
|
|
196
|
+
|
|
197
|
+
protected sendAccumulated(): void {
|
|
198
|
+
const cachedMessages = this.messagesToSend;
|
|
199
|
+
this.messagesToSend = [];
|
|
200
|
+
const writer = this.underlyingChannel.getWriteBuffer();
|
|
201
|
+
|
|
202
|
+
if (cachedMessages.length > 0) {
|
|
203
|
+
writer.writeLength(cachedMessages.length);
|
|
204
|
+
cachedMessages.forEach(msg => {
|
|
205
|
+
writer.writeBytes(msg);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
}
|
|
209
|
+
writer.commit();
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
protected handleMessages(buffer: ReadBuffer): void {
|
|
213
|
+
// Read in the list of messages and dispatch each message individually
|
|
214
|
+
const length = buffer.readLength();
|
|
215
|
+
if (length > 0) {
|
|
216
|
+
for (let index = 0; index < length; index++) {
|
|
217
|
+
const message = buffer.readBytes();
|
|
218
|
+
this.onMessageEmitter.fire(() => new Uint8ArrayReadBuffer(message));
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
378
222
|
}
|
|
379
223
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
393
|
-
export function replacer(key: string | undefined, value: any): any {
|
|
394
|
-
if (value instanceof URI) {
|
|
395
|
-
return {
|
|
396
|
-
$type: SerializedObjectType.THEIA_URI,
|
|
397
|
-
data: value.toString()
|
|
398
|
-
} as SerializedObject;
|
|
399
|
-
} else if (value instanceof Range) {
|
|
400
|
-
const range = value as Range;
|
|
401
|
-
const serializedValue = {
|
|
224
|
+
export function registerMsgPackExtensions(): void {
|
|
225
|
+
MsgPackExtensionManager.getInstance().registerExtensions(
|
|
226
|
+
{
|
|
227
|
+
class: URI,
|
|
228
|
+
tag: 2,
|
|
229
|
+
serialize: (instance: URI) => instance.toString(),
|
|
230
|
+
deserialize: data => new URI(data)
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
class: Range,
|
|
234
|
+
tag: 3,
|
|
235
|
+
serialize: (range: Range) => ({
|
|
402
236
|
start: {
|
|
403
237
|
line: range.start.line,
|
|
404
238
|
character: range.start.character
|
|
@@ -407,140 +241,33 @@ export namespace ObjectsTransferrer {
|
|
|
407
241
|
line: range.end.line,
|
|
408
242
|
character: range.end.character
|
|
409
243
|
}
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
data
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
if (isSerializedObject(value)) {
|
|
437
|
-
switch (value.$type) {
|
|
438
|
-
case SerializedObjectType.THEIA_URI:
|
|
439
|
-
return new URI(value.data);
|
|
440
|
-
case SerializedObjectType.VSCODE_URI:
|
|
441
|
-
return VSCodeURI.parse(value.data);
|
|
442
|
-
case SerializedObjectType.THEIA_RANGE:
|
|
443
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
444
|
-
const obj: any = JSON.parse(value.data);
|
|
445
|
-
const start = new Position(obj.start.line, obj.start.character);
|
|
446
|
-
const end = new Position(obj.end.line, obj.end.character);
|
|
447
|
-
return new Range(start, end);
|
|
448
|
-
case SerializedObjectType.TEXT_BUFFER:
|
|
449
|
-
const data: { bytes: number[] } = JSON.parse(value.data);
|
|
450
|
-
return BinaryBuffer.wrap(Uint8Array.from(data.bytes));
|
|
244
|
+
}),
|
|
245
|
+
deserialize: data => {
|
|
246
|
+
const start = new Position(data.start.line, data.start.character);
|
|
247
|
+
const end = new Position(data.end.line, data.end.character);
|
|
248
|
+
return new Range(start, end);
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
class: VSCodeURI,
|
|
253
|
+
tag: 4,
|
|
254
|
+
// eslint-disable-next-line arrow-body-style
|
|
255
|
+
serialize: (instance: URI) => {
|
|
256
|
+
return instance.toString();
|
|
257
|
+
},
|
|
258
|
+
deserialize: data => VSCodeURI.parse(data)
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
class: BinaryBuffer,
|
|
262
|
+
tag: 5,
|
|
263
|
+
// eslint-disable-next-line arrow-body-style
|
|
264
|
+
serialize: (instance: BinaryBuffer) => {
|
|
265
|
+
return instance.buffer;
|
|
266
|
+
},
|
|
267
|
+
// eslint-disable-next-line arrow-body-style
|
|
268
|
+
deserialize: buffer => {
|
|
269
|
+
return BinaryBuffer.wrap(buffer);
|
|
451
270
|
}
|
|
452
271
|
}
|
|
453
|
-
|
|
454
|
-
return value;
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
interface SerializedObject {
|
|
460
|
-
$type: SerializedObjectType;
|
|
461
|
-
data: string;
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
enum SerializedObjectType {
|
|
465
|
-
THEIA_URI,
|
|
466
|
-
VSCODE_URI,
|
|
467
|
-
THEIA_RANGE,
|
|
468
|
-
TEXT_BUFFER
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
function isSerializedObject(obj: unknown): obj is SerializedObject {
|
|
472
|
-
const serializedObject = obj as SerializedObject;
|
|
473
|
-
return !!obj && typeof obj === 'object' && serializedObject.$type !== undefined && serializedObject.data !== undefined;
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
export const enum MessageType {
|
|
477
|
-
Request = 1,
|
|
478
|
-
Reply = 2,
|
|
479
|
-
ReplyErr = 3,
|
|
480
|
-
Cancel = 4,
|
|
481
|
-
Terminate = 5,
|
|
482
|
-
Terminated = 6
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
class CancelMessage {
|
|
486
|
-
type: MessageType.Cancel;
|
|
487
|
-
id: string;
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
class RequestMessage {
|
|
491
|
-
type: MessageType.Request;
|
|
492
|
-
id: string;
|
|
493
|
-
proxyId: string;
|
|
494
|
-
method: string;
|
|
495
|
-
args: any[];
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
class ReplyMessage {
|
|
499
|
-
type: MessageType.Reply;
|
|
500
|
-
id: string;
|
|
501
|
-
res: any;
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
class ReplyErrMessage {
|
|
505
|
-
type: MessageType.ReplyErr;
|
|
506
|
-
id: string;
|
|
507
|
-
err: SerializedError;
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
type RPCMessage = RequestMessage | ReplyMessage | ReplyErrMessage | CancelMessage;
|
|
511
|
-
|
|
512
|
-
export interface SerializedError {
|
|
513
|
-
readonly $isError: true;
|
|
514
|
-
readonly name: string;
|
|
515
|
-
readonly message: string;
|
|
516
|
-
readonly stack: string;
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
export function transformErrorForSerialization(error: Error): SerializedError {
|
|
520
|
-
if (error instanceof Error) {
|
|
521
|
-
const { name, message } = error;
|
|
522
|
-
const stack: string = (<any>error).stacktrace || error.stack;
|
|
523
|
-
return {
|
|
524
|
-
$isError: true,
|
|
525
|
-
name,
|
|
526
|
-
message,
|
|
527
|
-
stack
|
|
528
|
-
};
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
// return as is
|
|
532
|
-
return error;
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
interface JSONStringifyReplacer {
|
|
536
|
-
(key: string, value: any): any;
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
function safeStringify(obj: any, replacer?: JSONStringifyReplacer): string {
|
|
540
|
-
try {
|
|
541
|
-
return JSON.stringify(obj, replacer);
|
|
542
|
-
} catch (err) {
|
|
543
|
-
console.error('error stringifying response: ', err);
|
|
544
|
-
return 'null';
|
|
545
|
-
}
|
|
272
|
+
);
|
|
546
273
|
}
|
|
@@ -21,7 +21,8 @@ import { LogPart } from '../../common/types';
|
|
|
21
21
|
|
|
22
22
|
@injectable()
|
|
23
23
|
export class HostedPluginWatcher {
|
|
24
|
-
private onPostMessage = new Emitter<{ pluginHostId: string, message:
|
|
24
|
+
private onPostMessage = new Emitter<{ pluginHostId: string, message: Uint8Array }>();
|
|
25
|
+
|
|
25
26
|
private onLogMessage = new Emitter<LogPart>();
|
|
26
27
|
|
|
27
28
|
private readonly onDidDeployEmitter = new Emitter<void>();
|
|
@@ -31,7 +32,7 @@ export class HostedPluginWatcher {
|
|
|
31
32
|
const messageEmitter = this.onPostMessage;
|
|
32
33
|
const logEmitter = this.onLogMessage;
|
|
33
34
|
return {
|
|
34
|
-
postMessage(pluginHostId, message:
|
|
35
|
+
postMessage(pluginHostId, message: Uint8Array): Promise<void> {
|
|
35
36
|
messageEmitter.fire({ pluginHostId, message });
|
|
36
37
|
return Promise.resolve();
|
|
37
38
|
},
|
|
@@ -43,7 +44,7 @@ export class HostedPluginWatcher {
|
|
|
43
44
|
};
|
|
44
45
|
}
|
|
45
46
|
|
|
46
|
-
get onPostMessageEvent(): Event<{ pluginHostId: string, message:
|
|
47
|
+
get onPostMessageEvent(): Event<{ pluginHostId: string, message: Uint8Array }> {
|
|
47
48
|
return this.onPostMessage.event;
|
|
48
49
|
}
|
|
49
50
|
|
|
@@ -66,6 +66,8 @@ import { StandaloneServices } from '@theia/monaco-editor-core/esm/vs/editor/stan
|
|
|
66
66
|
import { ILanguageService } from '@theia/monaco-editor-core/esm/vs/editor/common/languages/language';
|
|
67
67
|
import { LanguageService } from '@theia/monaco-editor-core/esm/vs/editor/common/services/languageService';
|
|
68
68
|
import { Measurement, Stopwatch } from '@theia/core/lib/common';
|
|
69
|
+
import { Uint8ArrayReadBuffer, Uint8ArrayWriteBuffer } from '@theia/core/lib/common/message-rpc/uint8-array-message-buffer';
|
|
70
|
+
import { BasicChannel } from '@theia/core/lib/common/message-rpc/channel';
|
|
69
71
|
|
|
70
72
|
export type PluginHost = 'frontend' | string;
|
|
71
73
|
export type DebugActivationEvent = 'onDebugResolve' | 'onDebugInitialConfigurations' | 'onDebugAdapterProtocolTracker' | 'onDebugDynamicConfigurations';
|
|
@@ -534,18 +536,25 @@ export class HostedPluginSupport {
|
|
|
534
536
|
}
|
|
535
537
|
|
|
536
538
|
protected createServerRpc(pluginHostId: string): RPCProtocol {
|
|
537
|
-
|
|
539
|
+
|
|
540
|
+
const channel = new BasicChannel(() => {
|
|
541
|
+
const writer = new Uint8ArrayWriteBuffer();
|
|
542
|
+
writer.onCommit(buffer => {
|
|
543
|
+
this.server.onMessage(pluginHostId, buffer);
|
|
544
|
+
});
|
|
545
|
+
return writer;
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
// Create RPC protocol before adding the listener to the watcher to receive the watcher's cached messages after the rpc protocol was created.
|
|
549
|
+
const rpc = new RPCProtocolImpl(channel);
|
|
550
|
+
|
|
538
551
|
this.watcher.onPostMessageEvent(received => {
|
|
539
552
|
if (pluginHostId === received.pluginHostId) {
|
|
540
|
-
|
|
541
|
-
}
|
|
542
|
-
});
|
|
543
|
-
return new RPCProtocolImpl({
|
|
544
|
-
onMessage: emitter.event,
|
|
545
|
-
send: message => {
|
|
546
|
-
this.server.onMessage(pluginHostId, message);
|
|
553
|
+
channel.onMessageEmitter.fire(() => new Uint8ArrayReadBuffer(received.message));
|
|
547
554
|
}
|
|
548
555
|
});
|
|
556
|
+
|
|
557
|
+
return rpc;
|
|
549
558
|
}
|
|
550
559
|
|
|
551
560
|
protected async updateStoragePath(): Promise<void> {
|