src/vs/workbench/services/extensions/common/rpcProtocol.ts

968 LOC · 889 covered · 79 uncovered · 262 ranges · 110 concepts · 35 introducers · 55 tests

File neighbourhood

The centred file is linked to every concept that introduces one of its ranges, every test that runs code from the file, and the gray connector concepts standing between those tests and the file's own introducer concepts. Undirected links join concepts to every file where they introduce source and concepts to the tests they introduce; arrows show specialization between the displayed concepts and bridge only concepts omitted from this view. Concept colors match the source ranges below; connector concepts have no source color and are shown in gray.

Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the file

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the related-file, concept, and source links on this page.

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the related-file, concept, and source links on this page while the interactive map is unavailable.

1 > /*--------------------------------------------------------------------------------------------- rpcProtocol.ts ×73
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import { RunOnceScheduler } from '../../../../base/common/async.js';
7 > import { VSBuffer } from '../../../../base/common/buffer.js';
8 > import { CancellationToken, CancellationTokenSource } from '../../../../base/common/cancellation.js';
9 > import { CharCode } from '../../../../base/common/charCode.js';
10 > import * as errors from '../../../../base/common/errors.js';
11 > import { Emitter, Event } from '../../../../base/common/event.js';
12 > import { Disposable, DisposableStore, IDisposable } from '../../../../base/common/lifecycle.js';
13 > import { MarshalledObject } from '../../../../base/common/marshalling.js';
14 > import { MarshalledId } from '../../../../base/common/marshallingIds.js';
15 > import { IURITransformer, transformIncomingURIs } from '../../../../base/common/uriIpc.js';
16 > import { IMessagePassingProtocol } from '../../../../base/parts/ipc/common/ipc.js';
17 > import { CanceledLazyPromise, LazyPromise } from './lazyPromise.js';
18 > import { getStringIdentifierForProxy, IRPCProtocol, Proxied, ProxyIdentifier, SerializableObjectWithBuffers } from './proxyIdentifier.js';
19 >
20 > export interface JSONStringifyReplacer {
21 > (key: string, value: any): any;
22 > }
23 >
24 > function safeStringify(obj: any, replacer: JSONStringifyReplacer | null): string { rpcProtocol.ts ×2
25 > try {
26 > return JSON.stringify(obj, <(key: string, value: any) => any>replacer);
27 > } catch (err) {
28 > return 'null'; rpcProtocol.ts ×1
29 > }
32 > const refSymbolName = '$$ref$$';
33 > const undefinedRef = { [refSymbolName]: -1 } as const;
34 >
35 > class StringifiedJsonWithBufferRefs {
36 > constructor(
37 public readonly jsonString: string,
38 public readonly referencedBuffers: readonly VSBuffer[],
39 ) { }
41 >
42 > export function stringifyJsonWithBufferRefs<T>(obj: T, replacer: JSONStringifyReplacer | null = null, useSafeStringify = false): StringifiedJsonWithBufferRefs {
43 > const foundBuffers: VSBuffer[] = []; rpcProtocol.ts ×15
44 > const serialized = (useSafeStringify ? safeStringify : JSON.stringify)(obj, (key, value) => {
45 > if (typeof value === 'undefined') {
46 return undefinedRef; // JSON.stringify normally converts 'undefined' to 'null'
47 > } else if (typeof value === 'object') { rpcProtocol.ts ×15
48 > if (value instanceof VSBuffer) {
49 > const bufferIndex = foundBuffers.push(value) - 1;
50 > return { [refSymbolName]: bufferIndex };
51 > }
52 > if (replacer) {
53 return replacer(key, value);
54 }
56 > return value;
57 > });
58 > return {
59 > jsonString: serialized,
60 > referencedBuffers: foundBuffers
61 > };
62 > }
64 > export function parseJsonAndRestoreBufferRefs(jsonString: string, buffers: readonly VSBuffer[], uriTransformer: IURITransformer | null): any {
65 > return JSON.parse(jsonString, (_key, value) => { rpcProtocol.ts ×15
66 > if (value) {
67 > const ref = value[refSymbolName];
68 > if (typeof ref === 'number') {
69 > return buffers[ref];
70 > }
71 >
72 > if (uriTransformer && (<MarshalledObject>value).$mid === MarshalledId.Uri) {
73 return uriTransformer.transformIncoming(value);
74 }
76 > return value;
77 > });
78 > }
80 >
81 > function stringify(obj: any, replacer: JSONStringifyReplacer | null): string { rpcProtocol.ts ×1
82 > return JSON.stringify(obj, <(key: string, value: any) => any>replacer);
83 > }
85 > function createURIReplacer(transformer: IURITransformer | null): JSONStringifyReplacer | null { rpcProtocol.ts ×13
86 > if (!transformer) {
87 > return null;
88 > }
89 return (key: string, value: any): any => {
90 if (value && value.$mid === MarshalledId.Uri) {
91 return transformer.transformOutgoing(value);
92 }
93 return value;
94 };
95 }
97 > export const enum RequestInitiator {
98 > LocalSide = 0,
99 > OtherSide = 1
100 > }
101 >
102 > export const enum ResponsiveState {
103 > Responsive = 0,
104 > Unresponsive = 1
105 > }
106 >
107 > export interface IRPCProtocolLogger {
108 > logIncoming(msgLength: number, req: number, initiator: RequestInitiator, str: string, data?: any): void;
109 > logOutgoing(msgLength: number, req: number, initiator: RequestInitiator, str: string, data?: any): void;
110 > }
111 >
112 > const noop = () => { };
113 >
114 > const _RPCProtocolSymbol = Symbol.for('rpcProtocol');
115 > const _RPCProxySymbol = Symbol.for('rpcProxy');
116 >
117 > export class RPCProtocol extends Disposable implements IRPCProtocol {
118 >
119 > [_RPCProtocolSymbol] = true;
120 >
121 > private static readonly UNRESPONSIVE_TIME = 3 * 1000; // 3s
122 >
123 > private readonly _onDidChangeResponsiveState: Emitter<ResponsiveState> = this._register(new Emitter<ResponsiveState>());
124 > public readonly onDidChangeResponsiveState: Event<ResponsiveState> = this._onDidChangeResponsiveState.event;
125 >
126 > private readonly _protocol: IMessagePassingProtocol;
127 > private readonly _logger: IRPCProtocolLogger | null;
128 > private readonly _uriTransformer: IURITransformer | null;
129 > private readonly _uriReplacer: JSONStringifyReplacer | null;
130 > private _isDisposed: boolean;
131 > private readonly _locals: any[];
132 > private readonly _proxies: any[];
133 > private _lastMessageId: number;
134 > private readonly _cancelInvokedHandlers: { [req: string]: () => void };
135 > private readonly _pendingRPCReplies: { [msgId: string]: PendingRPCReply };
136 > private _responsiveState: ResponsiveState;
137 > private _unacknowledgedCount: number;
138 > private _unresponsiveTime: number;
139 > private _asyncCheckUresponsive: RunOnceScheduler;
140 >
141 > constructor(protocol: IMessagePassingProtocol, logger: IRPCProtocolLogger | null = null, transformer: IURITransformer | null = null) {
142 > super(); rpcProtocol.ts ×13
143 > this._protocol = protocol;
144 > this._logger = logger;
145 > this._uriTransformer = transformer;
146 > this._uriReplacer = createURIReplacer(this._uriTransformer);
147 > this._isDisposed = false;
148 > this._locals = [];
149 > this._proxies = [];
150 > for (let i = 0, len = ProxyIdentifier.count; i < len; i++) {
151 this._locals[i] = null;
152 this._proxies[i] = null;
153 }
154 > this._lastMessageId = 0; rpcProtocol.ts ×13
155 > this._cancelInvokedHandlers = Object.create(null);
156 > this._pendingRPCReplies = {};
157 > this._responsiveState = ResponsiveState.Responsive;
158 > this._unacknowledgedCount = 0;
159 > this._unresponsiveTime = 0;
160 > this._asyncCheckUresponsive = this._register(new RunOnceScheduler(() => this._checkUnresponsive(), 1000));
161 > this._register(this._protocol.onMessage((msg) => this._receiveOneMessage(msg)));
162 > }
164 > public override dispose(): void {
165 > this._isDisposed = true; rpcProtocol.ts ×13
166 >
167 > // Release all outstanding promises with a canceled error
168 > Object.keys(this._pendingRPCReplies).forEach((msgId) => {
169 const pending = this._pendingRPCReplies[msgId];
170 delete this._pendingRPCReplies[msgId];
171 pending.resolveErr(errors.canceled());
173 >
174 > super.dispose();
175 > }
177 > public drain(): Promise<void> {
178 if (typeof this._protocol.drain === 'function') {
179 return this._protocol.drain();
180 }
181 return Promise.resolve();
182 }
184 > private _onWillSendRequest(req: number): void {
185 > if (this._unacknowledgedCount === 0) { rpcProtocol.ts ×47
186 > // Since this is the first request we are sending in a while,
187 > // mark this moment as the start for the countdown to unresponsive time
188 > this._unresponsiveTime = Date.now() + RPCProtocol.UNRESPONSIVE_TIME;
189 > }
190 > this._unacknowledgedCount++;
191 > if (!this._asyncCheckUresponsive.isScheduled()) {
192 > this._asyncCheckUresponsive.schedule();
193 > }
194 > }
196 > private _onDidReceiveAcknowledge(req: number): void {
197 > // The next possible unresponsive time is now + delta. rpcProtocol.ts ×47
198 > this._unresponsiveTime = Date.now() + RPCProtocol.UNRESPONSIVE_TIME;
199 > this._unacknowledgedCount--;
200 > if (this._unacknowledgedCount === 0) {
201 > // No more need to check for unresponsive
202 > this._asyncCheckUresponsive.cancel();
203 > }
204 > // The ext host is responsive!
205 > this._setResponsiveState(ResponsiveState.Responsive);
206 > }
208 > private _checkUnresponsive(): void {
209 if (this._unacknowledgedCount === 0) {
210 // Not waiting for anything => cannot say if it is responsive or not
211 return;
212 }
213
214 if (Date.now() > this._unresponsiveTime) {
215 // Unresponsive!!
216 this._setResponsiveState(ResponsiveState.Unresponsive);
217 } else {
218 // Not (yet) unresponsive, be sure to check again soon
219 this._asyncCheckUresponsive.schedule();
220 }
221 }
223 > private _setResponsiveState(newResponsiveState: ResponsiveState): void {
224 > if (this._responsiveState === newResponsiveState) { rpcProtocol.ts ×47
225 > // no change
226 > return;
227 > }
228 this._responsiveState = newResponsiveState;
229 this._onDidChangeResponsiveState.fire(this._responsiveState);
232 > public get responsiveState(): ResponsiveState {
233 return this._responsiveState;
234 }
236 > public transformIncomingURIs<T>(obj: T): T {
237 if (!this._uriTransformer) {
238 return obj;
239 }
240 return transformIncomingURIs(obj, this._uriTransformer);
241 }
243 > public getProxy<T>(identifier: ProxyIdentifier<T>): Proxied<T> {
244 > const { nid: rpcId, sid } = identifier; rpcProtocol.ts ×13
245 > if (!this._proxies[rpcId]) {
246 > this._proxies[rpcId] = this._createProxy(rpcId, sid);
247 > }
248 > return this._proxies[rpcId];
249 > }
251 > private _createProxy<T>(rpcId: number, debugName: string): T {
252 > const handler = { rpcProtocol.ts ×13
253 > get: (target: any, name: PropertyKey) => {
254 > if (typeof name === 'string' && !target[name] && name.charCodeAt(0) === CharCode.DollarSign) {
255 > target[name] = (...myArgs: any[]) => {
256 > return this._remoteCall(rpcId, name, myArgs);
257 > };
258 > }
259 > if (name === _RPCProxySymbol) {
260 return debugName;
261 }
262 > return target[name]; rpcProtocol.ts ×13
263 > }
264 > };
265 > return new Proxy(Object.create(null), handler);
266 > }
268 > public set<T, R extends T>(identifier: ProxyIdentifier<T>, value: R): R {
269 > this._locals[identifier.nid] = value; rpcProtocol.ts ×13
270 > return value;
271 > }
273 > public assertRegistered(identifiers: ProxyIdentifier<any>[]): void {
274 for (let i = 0, len = identifiers.length; i < len; i++) {
275 const identifier = identifiers[i];
276 if (!this._locals[identifier.nid]) {
277 throw new Error(`Missing proxy instance ${identifier.sid}`);
278 }
279 }
280 }
282 > private _receiveOneMessage(rawmsg: VSBuffer): void {
283 > if (this._isDisposed) { rpcProtocol.ts ×47
284 return;
285 }
287 > const msgLength = rawmsg.byteLength;
288 > const buff = MessageBuffer.read(rawmsg, 0);
289 > const messageType = <MessageType>buff.readUInt8();
290 > const req = buff.readUInt32();
291 >
292 > switch (messageType) {
293 > case MessageType.RequestJSONArgs:
294 > case MessageType.RequestJSONArgsWithCancellation: {
295 > let { rpcId, method, args } = MessageIO.deserializeRequestJSONArgs(buff); rpcProtocol.ts ×5
296 > if (this._uriTransformer) {
297 args = transformIncomingURIs(args, this._uriTransformer);
298 }
299 > this._receiveRequest(msgLength, req, rpcId, method, args, (messageType === MessageType.RequestJSONArgsWithCancellation)); rpcProtocol.ts ×5
300 > break;
301 > }
302 > case MessageType.RequestMixedArgs: rpcProtocol.ts ×47
303 > case MessageType.RequestMixedArgsWithCancellation: {
304 > let { rpcId, method, args } = MessageIO.deserializeRequestMixedArgs(buff); rpcProtocol.ts ×26
305 > if (this._uriTransformer) {
306 args = transformIncomingURIs(args, this._uriTransformer);
307 }
308 > this._receiveRequest(msgLength, req, rpcId, method, args, (messageType === MessageType.RequestMixedArgsWithCancellation)); rpcProtocol.ts ×26
309 > break;
310 > }
311 > case MessageType.Acknowledged: { rpcProtocol.ts ×47
312 > this._logger?.logIncoming(msgLength, req, RequestInitiator.LocalSide, `ack`);
313 > this._onDidReceiveAcknowledge(req);
314 > break;
315 > }
316 > case MessageType.Cancel: {
317 > this._receiveCancel(msgLength, req); rpcProtocol.ts ×4
318 > break;
319 > }
320 > case MessageType.ReplyOKEmpty: { rpcProtocol.ts ×47
321 > this._receiveReply(msgLength, req, undefined); rpcProtocol.ts ×3
322 > break;
323 > }
324 > case MessageType.ReplyOKJSON: { rpcProtocol.ts ×47
325 > let value = MessageIO.deserializeReplyOKJSON(buff); rpcProtocol.ts ×5
326 > if (this._uriTransformer) {
327 value = transformIncomingURIs(value, this._uriTransformer);
328 }
329 > this._receiveReply(msgLength, req, value); rpcProtocol.ts ×5
330 > break;
331 > }
332 > case MessageType.ReplyOKJSONWithBuffers: { rpcProtocol.ts ×47
333 > const value = MessageIO.deserializeReplyOKJSONWithBuffers(buff, this._uriTransformer); rpcProtocol.ts ×15
334 > this._receiveReply(msgLength, req, value);
335 > break;
336 > }
337 > case MessageType.ReplyOKVSBuffer: { rpcProtocol.ts ×47
338 > const value = MessageIO.deserializeReplyOKVSBuffer(buff); rpcProtocol.ts ×4
339 > this._receiveReply(msgLength, req, value);
340 > break;
341 > }
342 > case MessageType.ReplyErrError: { rpcProtocol.ts ×47
343 > let err = MessageIO.deserializeReplyErrError(buff); rpcProtocol.ts ×8
344 > if (this._uriTransformer) {
345 err = transformIncomingURIs(err, this._uriTransformer);
346 }
347 > this._receiveReplyErr(msgLength, req, err); rpcProtocol.ts ×8
348 > break;
349 > }
350 > case MessageType.ReplyErrEmpty: { rpcProtocol.ts ×47
351 > this._receiveReplyErr(msgLength, req, undefined); rpcProtocol.ts ×3
352 > break;
353 > }
354 > default: rpcProtocol.ts ×47
355 console.error(`received unexpected message`);
356 console.error(rawmsg);
358 > }
360 > private _receiveRequest(msgLength: number, req: number, rpcId: number, method: string, args: any[], usesCancellationToken: boolean): void {
361 > this._logger?.logIncoming(msgLength, req, RequestInitiator.OtherSide, `receiveRequest ${getStringIdentifierForProxy(rpcId)}.${method}(`, args); rpcProtocol.ts ×47
362 > const callId = String(req);
363 >
364 > let promise: Promise<any>;
365 > let cancel: () => void;
366 > if (usesCancellationToken) {
367 > const cancellationTokenSource = new CancellationTokenSource(); rpcProtocol.ts ×3
368 > args.push(cancellationTokenSource.token);
369 > promise = this._invokeHandler(rpcId, method, args);
370 > cancel = () => cancellationTokenSource.cancel();
371 > } else { rpcProtocol.ts ×47
372 > // cannot be cancelled rpcProtocol.ts ×1
373 > promise = this._invokeHandler(rpcId, method, args);
374 > cancel = noop;
375 > }
377 > this._cancelInvokedHandlers[callId] = cancel;
378 >
379 > // Acknowledge the request
380 > const msg = MessageIO.serializeAcknowledged(req);
381 > this._logger?.logOutgoing(msg.byteLength, req, RequestInitiator.OtherSide, `ack`);
382 > this._protocol.send(msg);
383 >
384 > promise.then((r) => {
385 > delete this._cancelInvokedHandlers[callId]; rpcProtocol.ts ×7
386 > const msg = MessageIO.serializeReplyOK(req, r, this._uriReplacer);
387 > this._logger?.logOutgoing(msg.byteLength, req, RequestInitiator.OtherSide, `reply:`, r);
388 > this._protocol.send(msg);
389 > }, (err) => { rpcProtocol.ts ×47
390 > delete this._cancelInvokedHandlers[callId]; rpcProtocol.ts ×7
391 > const msg = MessageIO.serializeReplyErr(req, err);
392 > this._logger?.logOutgoing(msg.byteLength, req, RequestInitiator.OtherSide, `replyErr:`, err);
393 > this._protocol.send(msg);
395 > }
397 > private _receiveCancel(msgLength: number, req: number): void {
398 > this._logger?.logIncoming(msgLength, req, RequestInitiator.OtherSide, `receiveCancel`); rpcProtocol.ts ×4
399 > const callId = String(req);
400 > this._cancelInvokedHandlers[callId]?.();
401 > }
403 > private _receiveReply(msgLength: number, req: number, value: any): void {
404 > this._logger?.logIncoming(msgLength, req, RequestInitiator.LocalSide, `receiveReply:`, value); rpcProtocol.ts ×7
405 > const callId = String(req);
406 > if (!this._pendingRPCReplies.hasOwnProperty(callId)) {
407 return;
408 }
410 > const pendingReply = this._pendingRPCReplies[callId];
411 > delete this._pendingRPCReplies[callId];
412 >
413 > pendingReply.resolveOk(value);
414 > }
416 > private _receiveReplyErr(msgLength: number, req: number, value: any): void {
417 > this._logger?.logIncoming(msgLength, req, RequestInitiator.LocalSide, `receiveReplyErr:`, value); rpcProtocol.ts ×7
418 >
419 > const callId = String(req);
420 > if (!this._pendingRPCReplies.hasOwnProperty(callId)) {
421 return;
422 }
424 > const pendingReply = this._pendingRPCReplies[callId];
425 > delete this._pendingRPCReplies[callId];
426 >
427 > let err: any = undefined;
428 > if (value) {
429 > if (value.$isError) { rpcProtocol.ts ×8
430 > err = new Error(); rpcProtocol.ts ×1
431 > err.name = value.name;
432 > err.message = value.message;
433 > err.stack = value.stack;
434 > } else { rpcProtocol.ts ×8
435 > err = value; errors.ts ×1
436 > }
438 > pendingReply.resolveErr(err); rpcProtocol.ts ×7
439 > }
441 > private _invokeHandler(rpcId: number, methodName: string, args: any[]): Promise<any> {
442 > try { rpcProtocol.ts ×47
443 > return Promise.resolve(this._doInvokeHandler(rpcId, methodName, args));
444 > } catch (err) {
445 > return Promise.reject(err); rpcProtocol.ts ×8
446 > }
449 > private _doInvokeHandler(rpcId: number, methodName: string, args: any[]): any {
450 > const actor = this._locals[rpcId]; rpcProtocol.ts ×47
451 > if (!actor) {
452 throw new Error('Unknown actor ' + getStringIdentifierForProxy(rpcId));
453 }
454 > const method = actor[methodName]; rpcProtocol.ts ×47
455 > if (typeof method !== 'function') {
456 throw new Error('Unknown method ' + methodName + ' on actor ' + getStringIdentifierForProxy(rpcId));
457 }
458 > return method.apply(actor, args); rpcProtocol.ts ×47
459 > }
461 > private _remoteCall(rpcId: number, methodName: string, args: any[]): Promise<any> {
462 > if (this._isDisposed) { rpcProtocol.ts ×13
463 return new CanceledLazyPromise();
464 }
465 > let cancellationToken: CancellationToken | null = null; rpcProtocol.ts ×13
466 > if (args.length > 0 && CancellationToken.isCancellationToken(args[args.length - 1])) {
467 > cancellationToken = args.pop(); rpcProtocol.ts ×1
468 > }
470 > if (cancellationToken && cancellationToken.isCancellationRequested) {
471 > // No need to do anything... rpcProtocol.ts ×1
472 > return Promise.reject<any>(errors.canceled());
473 > }
475 > const serializedRequestArguments = MessageIO.serializeRequestArguments(args, this._uriReplacer);
476 >
477 > const req = ++this._lastMessageId;
478 > const callId = String(req);
479 > const result = new LazyPromise();
480 >
481 > const disposable = new DisposableStore();
482 > if (cancellationToken) {
483 > disposable.add(cancellationToken.onCancellationRequested(() => { rpcProtocol.ts ×3
484 > const msg = MessageIO.serializeCancel(req); rpcProtocol.ts ×4
485 > this._logger?.logOutgoing(msg.byteLength, req, RequestInitiator.LocalSide, `cancel`);
486 > this._protocol.send(msg);
487 > })); rpcProtocol.ts ×3
488 > }
490 > this._pendingRPCReplies[callId] = new PendingRPCReply(result, disposable);
491 > this._onWillSendRequest(req);
492 > const msg = MessageIO.serializeRequest(req, rpcId, methodName, serializedRequestArguments, !!cancellationToken);
493 > this._logger?.logOutgoing(msg.byteLength, req, RequestInitiator.LocalSide, `request: ${getStringIdentifierForProxy(rpcId)}.${methodName}(`, args); rpcProtocol.ts ×13
494 > this._protocol.send(msg);
495 > return result;
496 > }
498 >
499 > class PendingRPCReply {
500 > constructor(
501 > private readonly _promise: LazyPromise, rpcProtocol.ts ×47
502 > private readonly _disposable: IDisposable
503 > ) { }
505 > public resolveOk(value: any): void {
506 > this._promise.resolveOk(value); rpcProtocol.ts ×7
507 > this._disposable.dispose();
508 > }
510 > public resolveErr(err: any): void {
511 > this._promise.resolveErr(err); rpcProtocol.ts ×7
512 > this._disposable.dispose();
513 > }
515 >
516 > class MessageBuffer {
517 >
518 > public static alloc(type: MessageType, req: number, messageSize: number): MessageBuffer {
519 > const result = new MessageBuffer(VSBuffer.alloc(messageSize + 1 /* type */ + 4 /* req */), 0); rpcProtocol.ts ×47
520 > result.writeUInt8(type);
521 > result.writeUInt32(req);
522 > return result;
523 > }
525 > public static read(buff: VSBuffer, offset: number): MessageBuffer {
526 > return new MessageBuffer(buff, offset); rpcProtocol.ts ×47
527 > }
529 > private _buff: VSBuffer;
530 > private _offset: number;
531 >
532 > public get buffer(): VSBuffer {
533 > return this._buff; rpcProtocol.ts ×47
534 > }
536 > private constructor(buff: VSBuffer, offset: number) {
537 > this._buff = buff; rpcProtocol.ts ×47
538 > this._offset = offset;
539 > }
541 > public static sizeUInt8(): number {
542 > return 1; rpcProtocol.ts ×47
543 > }
545 > public static readonly sizeUInt32 = 4;
546 >
547 > public writeUInt8(n: number): void {
548 > this._buff.writeUInt8(n, this._offset); this._offset += 1; rpcProtocol.ts ×47
549 > }
551 > public readUInt8(): number {
552 > const n = this._buff.readUInt8(this._offset); this._offset += 1; rpcProtocol.ts ×47
553 > return n;
554 > }
556 > public writeUInt32(n: number): void {
557 > this._buff.writeUInt32BE(n, this._offset); this._offset += 4; rpcProtocol.ts ×47
558 > }
560 > public readUInt32(): number {
561 > const n = this._buff.readUInt32BE(this._offset); this._offset += 4; rpcProtocol.ts ×47
562 > return n;
563 > }
565 > public static sizeShortString(str: VSBuffer): number {
566 > return 1 /* string length */ + str.byteLength /* actual string */; rpcProtocol.ts ×47
567 > }
569 > public writeShortString(str: VSBuffer): void {
570 > this._buff.writeUInt8(str.byteLength, this._offset); this._offset += 1; rpcProtocol.ts ×47
571 > this._buff.set(str, this._offset); this._offset += str.byteLength;
572 > }
574 > public readShortString(): string {
575 > const strByteLength = this._buff.readUInt8(this._offset); this._offset += 1; rpcProtocol.ts ×47
576 > const strBuff = this._buff.slice(this._offset, this._offset + strByteLength);
577 > const str = strBuff.toString(); this._offset += strByteLength;
578 > return str;
579 > }
581 > public static sizeLongString(str: VSBuffer): number {
582 > return 4 /* string length */ + str.byteLength /* actual string */; rpcProtocol.ts ×47
583 > }
585 > public writeLongString(str: VSBuffer): void {
586 > this._buff.writeUInt32BE(str.byteLength, this._offset); this._offset += 4; rpcProtocol.ts ×47
587 > this._buff.set(str, this._offset); this._offset += str.byteLength;
588 > }
590 > public readLongString(): string {
591 > const strByteLength = this._buff.readUInt32BE(this._offset); this._offset += 4; rpcProtocol.ts ×47
592 > const strBuff = this._buff.slice(this._offset, this._offset + strByteLength);
593 > const str = strBuff.toString(); this._offset += strByteLength;
594 > return str;
595 > }
597 > public writeBuffer(buff: VSBuffer): void {
598 > this._buff.writeUInt32BE(buff.byteLength, this._offset); this._offset += 4; rpcProtocol.ts ×15
599 > this._buff.set(buff, this._offset); this._offset += buff.byteLength;
600 > }
602 > public static sizeVSBuffer(buff: VSBuffer): number {
603 > return 4 /* buffer length */ + buff.byteLength /* actual buffer */; rpcProtocol.ts ×2
604 > }
606 > public writeVSBuffer(buff: VSBuffer): void {
607 > this._buff.writeUInt32BE(buff.byteLength, this._offset); this._offset += 4; rpcProtocol.ts ×1
608 > this._buff.set(buff, this._offset); this._offset += buff.byteLength;
609 > }
611 > public readVSBuffer(): VSBuffer {
612 > const buffLength = this._buff.readUInt32BE(this._offset); this._offset += 4; rpcProtocol.ts ×2
613 > const buff = this._buff.slice(this._offset, this._offset + buffLength); this._offset += buffLength;
614 > return buff;
615 > }
617 > public static sizeMixedArray(arr: readonly MixedArg[]): number {
618 > let size = 0; rpcProtocol.ts ×26
619 > size += 1; // arr length
620 > for (let i = 0, len = arr.length; i < len; i++) {
621 > const el = arr[i];
622 > size += 1; // arg type
623 > switch (el.type) {
624 > case ArgType.String:
625 > size += this.sizeLongString(el.value); rpcProtocol.ts ×5
626 > break;
627 > case ArgType.VSBuffer: rpcProtocol.ts ×26
628 > size += this.sizeVSBuffer(el.value); rpcProtocol.ts ×5
629 > break;
630 > case ArgType.SerializedObjectWithBuffers: rpcProtocol.ts ×26
631 > size += this.sizeUInt32; // buffer count rpcProtocol.ts ×15
632 > size += this.sizeLongString(el.value);
633 > for (let i = 0; i < el.buffers.length; ++i) {
634 > size += this.sizeVSBuffer(el.buffers[i]);
635 > }
636 > break;
637 > case ArgType.Undefined: rpcProtocol.ts ×26
638 > // empty... rpcProtocol.ts ×4
639 > break;
641 > }
642 > return size;
643 > }
645 > public writeMixedArray(arr: readonly MixedArg[]): void {
646 > this._buff.writeUInt8(arr.length, this._offset); this._offset += 1; rpcProtocol.ts ×26
647 > for (let i = 0, len = arr.length; i < len; i++) {
648 > const el = arr[i];
649 > switch (el.type) {
650 > case ArgType.String:
651 > this.writeUInt8(ArgType.String); rpcProtocol.ts ×5
652 > this.writeLongString(el.value);
653 > break;
654 > case ArgType.VSBuffer: rpcProtocol.ts ×26
655 > this.writeUInt8(ArgType.VSBuffer); rpcProtocol.ts ×5
656 > this.writeVSBuffer(el.value);
657 > break;
658 > case ArgType.SerializedObjectWithBuffers: rpcProtocol.ts ×26
659 > this.writeUInt8(ArgType.SerializedObjectWithBuffers); rpcProtocol.ts ×15
660 > this.writeUInt32(el.buffers.length);
661 > this.writeLongString(el.value);
662 > for (let i = 0; i < el.buffers.length; ++i) {
663 > this.writeBuffer(el.buffers[i]);
664 > }
665 > break;
666 > case ArgType.Undefined: rpcProtocol.ts ×26
667 > this.writeUInt8(ArgType.Undefined); rpcProtocol.ts ×4
668 > break;
670 > }
671 > }
673 > public readMixedArray(): Array<string | VSBuffer | SerializableObjectWithBuffers<any> | undefined> {
674 > const arrLen = this._buff.readUInt8(this._offset); this._offset += 1; rpcProtocol.ts ×26
675 > const arr: Array<string | VSBuffer | SerializableObjectWithBuffers<any> | undefined> = new Array(arrLen);
676 > for (let i = 0; i < arrLen; i++) {
677 > const argType = <ArgType>this.readUInt8();
678 > switch (argType) {
679 > case ArgType.String:
680 > arr[i] = this.readLongString(); rpcProtocol.ts ×5
681 > break;
682 > case ArgType.VSBuffer: rpcProtocol.ts ×26
683 > arr[i] = this.readVSBuffer(); rpcProtocol.ts ×5
684 > break;
685 > case ArgType.SerializedObjectWithBuffers: { rpcProtocol.ts ×26
686 > const bufferCount = this.readUInt32(); rpcProtocol.ts ×15
687 > const jsonString = this.readLongString();
688 > const buffers: VSBuffer[] = [];
689 > for (let i = 0; i < bufferCount; ++i) {
690 > buffers.push(this.readVSBuffer());
691 > }
692 > arr[i] = new SerializableObjectWithBuffers(parseJsonAndRestoreBufferRefs(jsonString, buffers, null));
693 > break;
694 > }
695 > case ArgType.Undefined: rpcProtocol.ts ×26
696 > arr[i] = undefined; rpcProtocol.ts ×4
697 > break;
699 > }
700 > return arr;
701 > }
703 >
704 > const enum SerializedRequestArgumentType {
705 > Simple,
706 > Mixed,
707 > }
708 >
709 > type SerializedRequestArguments =
710 > | { readonly type: SerializedRequestArgumentType.Simple; args: string }
711 > | { readonly type: SerializedRequestArgumentType.Mixed; args: MixedArg[] };
712 >
713 >
714 > class MessageIO {
715 >
716 > private static _useMixedArgSerialization(arr: any[]): boolean {
717 > for (let i = 0, len = arr.length; i < len; i++) { rpcProtocol.ts ×6
718 > if (arr[i] instanceof VSBuffer) {
719 > return true; rpcProtocol.ts ×5
720 > }
721 > if (arr[i] instanceof SerializableObjectWithBuffers) { rpcProtocol.ts ×1
722 > return true; rpcProtocol.ts ×15
723 > }
724 > if (typeof arr[i] === 'undefined') { rpcProtocol.ts ×1
725 > return true; rpcProtocol.ts ×1
726 > }
728 > return false; rpcProtocol.ts ×2
731 > public static serializeRequestArguments(args: any[], replacer: JSONStringifyReplacer | null): SerializedRequestArguments {
732 > if (this._useMixedArgSerialization(args)) { rpcProtocol.ts ×6
733 > const massagedArgs: MixedArg[] = []; rpcProtocol.ts ×26
734 > for (let i = 0, len = args.length; i < len; i++) {
735 > const arg = args[i];
736 > if (arg instanceof VSBuffer) {
737 > massagedArgs[i] = { type: ArgType.VSBuffer, value: arg }; rpcProtocol.ts ×5
738 > } else if (typeof arg === 'undefined') { rpcProtocol.ts ×26
739 > massagedArgs[i] = { type: ArgType.Undefined }; rpcProtocol.ts ×4
740 > } else if (arg instanceof SerializableObjectWithBuffers) { rpcProtocol.ts ×26
741 > const { jsonString, referencedBuffers } = stringifyJsonWithBufferRefs(arg.value, replacer); rpcProtocol.ts ×15
742 > massagedArgs[i] = { type: ArgType.SerializedObjectWithBuffers, value: VSBuffer.fromString(jsonString), buffers: referencedBuffers };
743 > } else { rpcProtocol.ts ×26
744 > massagedArgs[i] = { type: ArgType.String, value: VSBuffer.fromString(stringify(arg, replacer)) }; rpcProtocol.ts ×5
745 > }
747 > return {
748 > type: SerializedRequestArgumentType.Mixed,
749 > args: massagedArgs,
750 > };
751 > }
752 > return { rpcProtocol.ts ×2
753 > type: SerializedRequestArgumentType.Simple,
754 > args: stringify(args, replacer)
755 > };
758 > public static serializeRequest(req: number, rpcId: number, method: string, serializedArgs: SerializedRequestArguments, usesCancellationToken: boolean): VSBuffer {
759 > switch (serializedArgs.type) { rpcProtocol.ts ×47
760 > case SerializedRequestArgumentType.Simple:
761 > return this._requestJSONArgs(req, rpcId, method, serializedArgs.args, usesCancellationToken); rpcProtocol.ts ×5
762 > case SerializedRequestArgumentType.Mixed: rpcProtocol.ts ×47
763 > return this._requestMixedArgs(req, rpcId, method, serializedArgs.args, usesCancellationToken); rpcProtocol.ts ×26
765 > }
767 > private static _requestJSONArgs(req: number, rpcId: number, method: string, args: string, usesCancellationToken: boolean): VSBuffer {
768 > const methodBuff = VSBuffer.fromString(method); rpcProtocol.ts ×5
769 > const argsBuff = VSBuffer.fromString(args);
770 >
771 > let len = 0;
772 > len += MessageBuffer.sizeUInt8();
773 > len += MessageBuffer.sizeShortString(methodBuff);
774 > len += MessageBuffer.sizeLongString(argsBuff);
775 >
776 > const result = MessageBuffer.alloc(usesCancellationToken ? MessageType.RequestJSONArgsWithCancellation : MessageType.RequestJSONArgs, req, len);
777 > result.writeUInt8(rpcId);
778 > result.writeShortString(methodBuff);
779 > result.writeLongString(argsBuff);
780 > return result.buffer;
781 > }
783 > public static deserializeRequestJSONArgs(buff: MessageBuffer): { rpcId: number; method: string; args: any[] } {
784 > const rpcId = buff.readUInt8(); rpcProtocol.ts ×5
785 > const method = buff.readShortString();
786 > const args = buff.readLongString();
787 > return {
788 > rpcId: rpcId,
789 > method: method,
790 > args: JSON.parse(args)
791 > };
792 > }
794 > private static _requestMixedArgs(req: number, rpcId: number, method: string, args: readonly MixedArg[], usesCancellationToken: boolean): VSBuffer {
795 > const methodBuff = VSBuffer.fromString(method); rpcProtocol.ts ×26
796 >
797 > let len = 0;
798 > len += MessageBuffer.sizeUInt8();
799 > len += MessageBuffer.sizeShortString(methodBuff);
800 > len += MessageBuffer.sizeMixedArray(args);
801 >
802 > const result = MessageBuffer.alloc(usesCancellationToken ? MessageType.RequestMixedArgsWithCancellation : MessageType.RequestMixedArgs, req, len);
803 > result.writeUInt8(rpcId);
804 > result.writeShortString(methodBuff);
805 > result.writeMixedArray(args);
806 > return result.buffer;
807 > }
809 > public static deserializeRequestMixedArgs(buff: MessageBuffer): { rpcId: number; method: string; args: any[] } {
810 > const rpcId = buff.readUInt8(); rpcProtocol.ts ×26
811 > const method = buff.readShortString();
812 > const rawargs = buff.readMixedArray();
813 > const args: any[] = new Array(rawargs.length);
814 > for (let i = 0, len = rawargs.length; i < len; i++) {
815 > const rawarg = rawargs[i];
816 > if (typeof rawarg === 'string') {
817 > args[i] = JSON.parse(rawarg); rpcProtocol.ts ×5
818 > } else { rpcProtocol.ts ×26
819 > args[i] = rawarg;
820 > }
821 > }
822 > return {
823 > rpcId: rpcId,
824 > method: method,
825 > args: args
826 > };
827 > }
829 > public static serializeAcknowledged(req: number): VSBuffer {
830 > return MessageBuffer.alloc(MessageType.Acknowledged, req, 0).buffer; rpcProtocol.ts ×47
831 > }
833 > public static serializeCancel(req: number): VSBuffer {
834 > return MessageBuffer.alloc(MessageType.Cancel, req, 0).buffer; rpcProtocol.ts ×4
835 > }
837 > public static serializeReplyOK(req: number, res: any, replacer: JSONStringifyReplacer | null): VSBuffer {
838 > if (typeof res === 'undefined') { rpcProtocol.ts ×7
839 > return this._serializeReplyOKEmpty(req); rpcProtocol.ts ×3
840 > } else if (res instanceof VSBuffer) { rpcProtocol.ts ×7
841 > return this._serializeReplyOKVSBuffer(req, res); rpcProtocol.ts ×4
842 > } else if (res instanceof SerializableObjectWithBuffers) { rpcProtocol.ts ×1
843 > const { jsonString, referencedBuffers } = stringifyJsonWithBufferRefs(res.value, replacer, true); rpcProtocol.ts ×15
844 > return this._serializeReplyOKJSONWithBuffers(req, jsonString, referencedBuffers);
845 > } else { rpcProtocol.ts ×1
846 > return this._serializeReplyOKJSON(req, safeStringify(res, replacer)); rpcProtocol.ts ×5
847 > }
850 > private static _serializeReplyOKEmpty(req: number): VSBuffer {
851 > return MessageBuffer.alloc(MessageType.ReplyOKEmpty, req, 0).buffer; rpcProtocol.ts ×3
852 > }
854 > private static _serializeReplyOKVSBuffer(req: number, res: VSBuffer): VSBuffer {
855 > let len = 0; rpcProtocol.ts ×4
856 > len += MessageBuffer.sizeVSBuffer(res);
857 >
858 > const result = MessageBuffer.alloc(MessageType.ReplyOKVSBuffer, req, len);
859 > result.writeVSBuffer(res);
860 > return result.buffer;
861 > }
863 > public static deserializeReplyOKVSBuffer(buff: MessageBuffer): VSBuffer {
864 > return buff.readVSBuffer(); rpcProtocol.ts ×4
865 > }
867 > private static _serializeReplyOKJSON(req: number, res: string): VSBuffer {
868 > const resBuff = VSBuffer.fromString(res); rpcProtocol.ts ×5
869 >
870 > let len = 0;
871 > len += MessageBuffer.sizeLongString(resBuff);
872 >
873 > const result = MessageBuffer.alloc(MessageType.ReplyOKJSON, req, len);
874 > result.writeLongString(resBuff);
875 > return result.buffer;
876 > }
878 > private static _serializeReplyOKJSONWithBuffers(req: number, res: string, buffers: readonly VSBuffer[]): VSBuffer {
879 > const resBuff = VSBuffer.fromString(res); rpcProtocol.ts ×15
880 >
881 > let len = 0;
882 > len += MessageBuffer.sizeUInt32; // buffer count
883 > len += MessageBuffer.sizeLongString(resBuff);
884 > for (const buffer of buffers) {
885 > len += MessageBuffer.sizeVSBuffer(buffer);
886 > }
887 >
888 > const result = MessageBuffer.alloc(MessageType.ReplyOKJSONWithBuffers, req, len);
889 > result.writeUInt32(buffers.length);
890 > result.writeLongString(resBuff);
891 > for (const buffer of buffers) {
892 > result.writeBuffer(buffer);
893 > }
894 >
895 > return result.buffer;
896 > }
898 > public static deserializeReplyOKJSON(buff: MessageBuffer): any {
899 > const res = buff.readLongString(); rpcProtocol.ts ×5
900 > return JSON.parse(res);
901 > }
903 > public static deserializeReplyOKJSONWithBuffers(buff: MessageBuffer, uriTransformer: IURITransformer | null): SerializableObjectWithBuffers<any> {
904 > const bufferCount = buff.readUInt32(); rpcProtocol.ts ×15
905 > const res = buff.readLongString();
906 >
907 > const buffers: VSBuffer[] = [];
908 > for (let i = 0; i < bufferCount; ++i) {
909 > buffers.push(buff.readVSBuffer());
910 > }
911 >
912 > return new SerializableObjectWithBuffers(parseJsonAndRestoreBufferRefs(res, buffers, uriTransformer));
913 > }
915 > public static serializeReplyErr(req: number, err: any): VSBuffer {
916 > const errStr: string | undefined = (err ? safeStringify(errors.transformErrorForSerialization(err), null) : undefined); rpcProtocol.ts ×7
917 > if (typeof errStr !== 'string') {
918 > return this._serializeReplyErrEmpty(req); rpcProtocol.ts ×3
919 > }
920 > const errBuff = VSBuffer.fromString(errStr); rpcProtocol.ts ×8
921 >
922 > let len = 0;
923 > len += MessageBuffer.sizeLongString(errBuff);
924 >
925 > const result = MessageBuffer.alloc(MessageType.ReplyErrError, req, len);
926 > result.writeLongString(errBuff);
927 > return result.buffer;
930 > public static deserializeReplyErrError(buff: MessageBuffer): Error {
931 > const err = buff.readLongString(); rpcProtocol.ts ×8
932 > return JSON.parse(err);
933 > }
935 > private static _serializeReplyErrEmpty(req: number): VSBuffer {
936 > return MessageBuffer.alloc(MessageType.ReplyErrEmpty, req, 0).buffer; rpcProtocol.ts ×3
937 > }
939 >
940 > const enum MessageType {
941 > RequestJSONArgs = 1,
942 > RequestJSONArgsWithCancellation = 2,
943 > RequestMixedArgs = 3,
944 > RequestMixedArgsWithCancellation = 4,
945 > Acknowledged = 5,
946 > Cancel = 6,
947 > ReplyOKEmpty = 7,
948 > ReplyOKVSBuffer = 8,
949 > ReplyOKJSON = 9,
950 > ReplyOKJSONWithBuffers = 10,
951 > ReplyErrError = 11,
952 > ReplyErrEmpty = 12,
953 > }
954 >
955 > const enum ArgType {
956 > String = 1,
957 > VSBuffer = 2,
958 > SerializedObjectWithBuffers = 3,
959 > Undefined = 4,
960 > }
961 >
962 >
963 > type MixedArg =
964 > | { readonly type: ArgType.String; readonly value: VSBuffer }
965 > | { readonly type: ArgType.VSBuffer; readonly value: VSBuffer }
966 > | { readonly type: ArgType.SerializedObjectWithBuffers; readonly value: VSBuffer; readonly buffers: readonly VSBuffer[] }
967 > | { readonly type: ArgType.Undefined }
968 > ;