rpcProtocol.ts ×73

Frontier kind: Code frontier

unlabeled · c_d0bfdcd69323

55 tests · 7903 LOC · 37 files · introduces 0 tests · 306 LOC · 2 files

Introduces — evidence that enters the hierarchy at this concept

Code
83 ranges306 lines · 2 files
Tests
0 tests

Contains — complete concept membership

All code (extent)
1199 ranges7903 lines · 37 files · Browse complete extent
All tests (intent)
55 testsBrowse complete intent

Neighbourhood graph

The orange circle is the focus. Violet and green circles are every ancestor and descendant, broader and narrower, at any distance; blue squares and pink diamonds are the introduced files and exact introduced tests of every visible concept, not only the focus's. Arrows point from broader to narrower concepts and bridge only concepts omitted from this view. Undirected links show source or test introduction. Concept and file size follows LOC; exact test nodes use test-count units.

Introduced files, introduced tests, and structurally relevant concept specialization

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 native relationship evidence on this page.

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the native relationship evidence on this page while the interactive map is unavailable.

Native relationship evidence

Every exact file and test below is linked only from the concept that introduces it.

Introduced tests

Every collected test enters the hierarchy at exactly one concept.

No tests are introduced at this concept. Its intent tests are introduced by other concepts.

Introduced code

Every collected source range enters the hierarchy at exactly one concept.

2 files ranked by introduced lines: 306 introduced LOC across 83 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

src/vs/workbench/services/extensions/common/rpcProtocol.ts 267 introduced LOC · 73 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- rpcProtocol.ts
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 {
25 try {
29 }
30 }
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[] = [];
44 const serialized = (useSafeStringify ? safeStringify : JSON.stringify)(obj, (key, value) => {
61 };
62 }
64 > export function parseJsonAndRestoreBufferRefs(jsonString: string, buffers: readonly VSBuffer[], uriTransformer: IURITransformer | null): any {
65 return JSON.parse(jsonString, (_key, value) => {
66 if (value) {
77 });
78 }
80 >
81 function stringify(obj: any, replacer: JSONStringifyReplacer | null): string {
82 return JSON.stringify(obj, <(key: string, value: any) => any>replacer);
83 }
85 function createURIReplacer(transformer: IURITransformer | null): JSONStringifyReplacer | null {
86 if (!transformer) {
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();
143 this._protocol = protocol;
161 this._register(this._protocol.onMessage((msg) => this._receiveOneMessage(msg)));
162 }
164 > public override dispose(): void {
165 this._isDisposed = true;
166
174 super.dispose();
175 }
177 > public drain(): Promise<void> {
178 if (typeof this._protocol.drain === 'function') {
179 return this._protocol.drain();
181 return Promise.resolve();
182 }
184 > private _onWillSendRequest(req: number): void {
185 if (this._unacknowledgedCount === 0) {
186 // Since this is the first request we are sending in a while,
193 }
194 }
196 > private _onDidReceiveAcknowledge(req: number): void {
197 // The next possible unresponsive time is now + delta.
198 this._unresponsiveTime = Date.now() + RPCProtocol.UNRESPONSIVE_TIME;
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
220 }
221 }
223 > private _setResponsiveState(newResponsiveState: ResponsiveState): void {
224 if (this._responsiveState === newResponsiveState) {
225 // no change
229 this._onDidChangeResponsiveState.fire(this._responsiveState);
230 }
232 > public get responsiveState(): ResponsiveState {
233 return this._responsiveState;
234 }
236 > public transformIncomingURIs<T>(obj: T): T {
237 if (!this._uriTransformer) {
238 return obj;
240 return transformIncomingURIs(obj, this._uriTransformer);
241 }
243 > public getProxy<T>(identifier: ProxyIdentifier<T>): Proxied<T> {
244 const { nid: rpcId, sid } = identifier;
245 if (!this._proxies[rpcId]) {
248 return this._proxies[rpcId];
249 }
251 > private _createProxy<T>(rpcId: number, debugName: string): T {
252 const handler = {
253 get: (target: any, name: PropertyKey) => {
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;
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];
279 }
280 }
282 > private _receiveOneMessage(rawmsg: VSBuffer): void {
283 if (this._isDisposed) {
284 return;
357 }
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);
362 const callId = String(req);
394 });
395 }
397 > private _receiveCancel(msgLength: number, req: number): void {
398 this._logger?.logIncoming(msgLength, req, RequestInitiator.OtherSide, `receiveCancel`);
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);
405 const callId = String(req);
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);
418
438 pendingReply.resolveErr(err);
439 }
441 > private _invokeHandler(rpcId: number, methodName: string, args: any[]): Promise<any> {
442 try {
443 return Promise.resolve(this._doInvokeHandler(rpcId, methodName, args));
446 }
447 }
449 > private _doInvokeHandler(rpcId: number, methodName: string, args: any[]): any {
450 const actor = this._locals[rpcId];
451 if (!actor) {
458 return method.apply(actor, args);
459 }
461 > private _remoteCall(rpcId: number, methodName: string, args: any[]): Promise<any> {
462 if (this._isDisposed) {
463 return new CanceledLazyPromise();
495 return result;
496 }
497 > } rpcProtocol.ts
498 >
499 > class PendingRPCReply {
500 > constructor(
501 private readonly _promise: LazyPromise,
502 private readonly _disposable: IDisposable
503 ) { }
505 > public resolveOk(value: any): void {
506 this._promise.resolveOk(value);
507 this._disposable.dispose();
508 }
510 > public resolveErr(err: any): void {
511 this._promise.resolveErr(err);
512 this._disposable.dispose();
513 }
514 > } rpcProtocol.ts
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);
520 result.writeUInt8(type);
522 return result;
523 }
525 > public static read(buff: VSBuffer, offset: number): MessageBuffer {
526 return new MessageBuffer(buff, offset);
527 }
529 > private _buff: VSBuffer;
530 > private _offset: number;
531 >
532 > public get buffer(): VSBuffer {
533 return this._buff;
534 }
536 > private constructor(buff: VSBuffer, offset: number) {
537 this._buff = buff;
538 this._offset = offset;
539 }
541 > public static sizeUInt8(): number {
542 return 1;
543 }
545 > public static readonly sizeUInt32 = 4;
546 >
547 > public writeUInt8(n: number): void {
548 this._buff.writeUInt8(n, this._offset); this._offset += 1;
549 }
551 > public readUInt8(): number {
552 const n = this._buff.readUInt8(this._offset); this._offset += 1;
553 return n;
554 }
556 > public writeUInt32(n: number): void {
557 this._buff.writeUInt32BE(n, this._offset); this._offset += 4;
558 }
560 > public readUInt32(): number {
561 const n = this._buff.readUInt32BE(this._offset); this._offset += 4;
562 return n;
563 }
565 > public static sizeShortString(str: VSBuffer): number {
566 return 1 /* string length */ + str.byteLength /* actual string */;
567 }
569 > public writeShortString(str: VSBuffer): void {
570 this._buff.writeUInt8(str.byteLength, this._offset); this._offset += 1;
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;
576 const strBuff = this._buff.slice(this._offset, this._offset + strByteLength);
578 return str;
579 }
581 > public static sizeLongString(str: VSBuffer): number {
582 return 4 /* string length */ + str.byteLength /* actual string */;
583 }
585 > public writeLongString(str: VSBuffer): void {
586 this._buff.writeUInt32BE(str.byteLength, this._offset); this._offset += 4;
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;
592 const strBuff = this._buff.slice(this._offset, this._offset + strByteLength);
594 return str;
595 }
597 > public writeBuffer(buff: VSBuffer): void {
598 this._buff.writeUInt32BE(buff.byteLength, this._offset); this._offset += 4;
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 */;
604 }
606 > public writeVSBuffer(buff: VSBuffer): void {
607 this._buff.writeUInt32BE(buff.byteLength, this._offset); this._offset += 4;
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;
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;
619 size += 1; // arr length
642 return size;
643 }
645 > public writeMixedArray(arr: readonly MixedArg[]): void {
646 this._buff.writeUInt8(arr.length, this._offset); this._offset += 1;
647 for (let i = 0, len = arr.length; i < len; i++) {
670 }
671 }
673 > public readMixedArray(): Array<string | VSBuffer | SerializableObjectWithBuffers<any> | undefined> {
674 const arrLen = this._buff.readUInt8(this._offset); this._offset += 1;
675 const arr: Array<string | VSBuffer | SerializableObjectWithBuffers<any> | undefined> = new Array(arrLen);
700 return arr;
701 }
702 > } rpcProtocol.ts
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++) {
718 if (arr[i] instanceof VSBuffer) {
728 return false;
729 }
731 > public static serializeRequestArguments(args: any[], replacer: JSONStringifyReplacer | null): SerializedRequestArguments {
732 if (this._useMixedArgSerialization(args)) {
733 const massagedArgs: MixedArg[] = [];
755 };
756 }
758 > public static serializeRequest(req: number, rpcId: number, method: string, serializedArgs: SerializedRequestArguments, usesCancellationToken: boolean): VSBuffer {
759 switch (serializedArgs.type) {
760 case SerializedRequestArgumentType.Simple:
764 }
765 }
767 > private static _requestJSONArgs(req: number, rpcId: number, method: string, args: string, usesCancellationToken: boolean): VSBuffer {
768 const methodBuff = VSBuffer.fromString(method);
769 const argsBuff = VSBuffer.fromString(args);
780 return result.buffer;
781 }
783 > public static deserializeRequestJSONArgs(buff: MessageBuffer): { rpcId: number; method: string; args: any[] } {
784 const rpcId = buff.readUInt8();
785 const method = buff.readShortString();
791 };
792 }
794 > private static _requestMixedArgs(req: number, rpcId: number, method: string, args: readonly MixedArg[], usesCancellationToken: boolean): VSBuffer {
795 const methodBuff = VSBuffer.fromString(method);
796
806 return result.buffer;
807 }
809 > public static deserializeRequestMixedArgs(buff: MessageBuffer): { rpcId: number; method: string; args: any[] } {
810 const rpcId = buff.readUInt8();
811 const method = buff.readShortString();
826 };
827 }
829 > public static serializeAcknowledged(req: number): VSBuffer {
830 return MessageBuffer.alloc(MessageType.Acknowledged, req, 0).buffer;
831 }
833 > public static serializeCancel(req: number): VSBuffer {
834 return MessageBuffer.alloc(MessageType.Cancel, req, 0).buffer;
835 }
837 > public static serializeReplyOK(req: number, res: any, replacer: JSONStringifyReplacer | null): VSBuffer {
838 if (typeof res === 'undefined') {
839 return this._serializeReplyOKEmpty(req);
847 }
848 }
850 > private static _serializeReplyOKEmpty(req: number): VSBuffer {
851 return MessageBuffer.alloc(MessageType.ReplyOKEmpty, req, 0).buffer;
852 }
854 > private static _serializeReplyOKVSBuffer(req: number, res: VSBuffer): VSBuffer {
855 let len = 0;
856 len += MessageBuffer.sizeVSBuffer(res);
860 return result.buffer;
861 }
863 > public static deserializeReplyOKVSBuffer(buff: MessageBuffer): VSBuffer {
864 return buff.readVSBuffer();
865 }
867 > private static _serializeReplyOKJSON(req: number, res: string): VSBuffer {
868 const resBuff = VSBuffer.fromString(res);
869
875 return result.buffer;
876 }
878 > private static _serializeReplyOKJSONWithBuffers(req: number, res: string, buffers: readonly VSBuffer[]): VSBuffer {
879 const resBuff = VSBuffer.fromString(res);
880
895 return result.buffer;
896 }
898 > public static deserializeReplyOKJSON(buff: MessageBuffer): any {
899 const res = buff.readLongString();
900 return JSON.parse(res);
901 }
903 > public static deserializeReplyOKJSONWithBuffers(buff: MessageBuffer, uriTransformer: IURITransformer | null): SerializableObjectWithBuffers<any> {
904 const bufferCount = buff.readUInt32();
905 const res = buff.readLongString();
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);
917 if (typeof errStr !== 'string') {
927 return result.buffer;
928 }
930 > public static deserializeReplyErrError(buff: MessageBuffer): Error {
931 const err = buff.readLongString();
932 return JSON.parse(err);
933 }
935 > private static _serializeReplyErrEmpty(req: number): VSBuffer {
936 return MessageBuffer.alloc(MessageType.ReplyErrEmpty, req, 0).buffer;
937 }
938 > } rpcProtocol.ts
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 > ;
src/vs/workbench/services/extensions/common/lazyPromise.ts 39 introduced LOC · 10 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- lazyPromise.ts
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 { CancellationError, onUnexpectedError } from '../../../../base/common/errors.js';
7 >
8 > export class LazyPromise implements Promise<any> {
9 >
10 > private _actual: Promise<any> | null;
11 > private _actualOk: ((value?: any) => any) | null;
12 > private _actualErr: ((err?: any) => any) | null;
13 >
14 > private _hasValue: boolean;
15 > private _value: any;
16 >
17 > protected _hasErr: boolean;
18 > protected _err: any;
19 >
20 > constructor() {
21 this._actual = null;
22 this._actualOk = null;
27 this._err = null;
28 }
30 > get [Symbol.toStringTag](): string {
31 return this.toString();
32 }
34 > private _ensureActual(): Promise<any> {
35 if (!this._actual) {
36 this._actual = new Promise<any>((c, e) => {
49 return this._actual;
50 }
52 > public resolveOk(value: any): void {
53 if (this._hasValue || this._hasErr) {
54 return;
62 }
63 }
65 > public resolveErr(err: any): void {
66 if (this._hasValue || this._hasErr) {
67 return;
79 }
80 }
82 > public then(success: any, error: any): any {
83 return this._ensureActual().then(success, error);
84 }
86 > public catch(error: any): any {
87 return this._ensureActual().then(undefined, error);
88 }
90 > public finally(callback: () => void): any {
91 return this._ensureActual().finally(callback);
92 }
94 >
95 > export class CanceledLazyPromise extends LazyPromise {
96 > constructor() {
97 super();
98 this._hasErr = true;
99 this._err = new CancellationError();
100 }
101 > } lazyPromise.ts