Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/api/test/common/testRPCProtocol.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
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 { isThenable } from '../../../../base/common/async.js';
7
import { CharCode } from '../../../../base/common/charCode.js';
8
import { IExtHostRpcService } from '../../common/extHostRpcService.js';
9
import { IExtHostContext } from '../../../services/extensions/common/extHostCustomers.js';
10
import { ExtensionHostKind } from '../../../services/extensions/common/extensionHostKind.js';
11
import { Proxied, ProxyIdentifier, SerializableObjectWithBuffers } from '../../../services/extensions/common/proxyIdentifier.js';
12
import { parseJsonAndRestoreBufferRefs, stringifyJsonWithBufferRefs } from '../../../services/extensions/common/rpcProtocol.js';
13
14
export function SingleProxyRPCProtocol(thing: any): IExtHostContext & IExtHostRpcService {
15
return {
16
_serviceBrand: undefined,
17
remoteAuthority: null!,
18
getProxy<T>(): T {
19
return thing;
20
},
21
set<T, R extends T>(identifier: ProxyIdentifier<T>, value: R): R {
22
return value;
23
},
24
dispose: undefined!,
25
assertRegistered: undefined!,
26
drain: undefined!,
27
extensionHostKind: ExtensionHostKind.LocalProcess
28
};
29
}
30
31
/** Makes a fake {@link SingleProxyRPCProtocol} on which any method can be called */
32
export function AnyCallRPCProtocol<T>(useCalls?: { [K in keyof T]: T[K] }) {
33
return SingleProxyRPCProtocol(new Proxy({}, {
34
get(_target, prop: string) {
35
if (useCalls && prop in useCalls) {
36
return (useCalls as any)[prop];
37
}
38
return () => Promise.resolve(undefined);
39
}
40
}));
41
}
42
43
export class TestRPCProtocol implements IExtHostContext, IExtHostRpcService {
44
45
public _serviceBrand: undefined;
46
public remoteAuthority = null!;
47
public extensionHostKind = ExtensionHostKind.LocalProcess;
48
49
private _callCountValue: number = 0;
50
private _idle?: Promise<any>;
51
private _completeIdle?: Function;
52
53
private readonly _locals: { [id: string]: any };
54
private readonly _proxies: { [id: string]: any };
55
56
constructor() {
57
this._locals = Object.create(null);
58
this._proxies = Object.create(null);
59
}
60
61
drain(): Promise<void> {
62
return Promise.resolve();
63
}
64
65
private get _callCount(): number {
66
return this._callCountValue;
67
}
68
69
private set _callCount(value: number) {
70
this._callCountValue = value;
71
if (this._callCountValue === 0) {
72
this._completeIdle?.();
73
this._idle = undefined;
74
}
75
}
76
77
sync(): Promise<any> {
78
return new Promise<any>((c) => {
79
setTimeout(c, 0);
80
}).then(() => {
81
if (this._callCount === 0) {
82
return undefined;
83
}
84
if (!this._idle) {
85
this._idle = new Promise<any>((c, e) => {
86
this._completeIdle = c;
87
});
88
}
89
return this._idle;
90
});
91
}
92
93
public getProxy<T>(identifier: ProxyIdentifier<T>): Proxied<T> {
94
if (!this._proxies[identifier.sid]) {
95
this._proxies[identifier.sid] = this._createProxy(identifier.sid);
96
}
97
return this._proxies[identifier.sid];
98
}
99
100
private _createProxy<T>(proxyId: string): T {
101
const handler = {
102
get: (target: any, name: PropertyKey) => {
103
if (typeof name === 'string' && !target[name] && name.charCodeAt(0) === CharCode.DollarSign) {
104
target[name] = (...myArgs: any[]) => {
105
return this._remoteCall(proxyId, name, myArgs);
106
};
107
}
108
109
return target[name];
110
}
111
};
112
return new Proxy(Object.create(null), handler);
113
}
114
115
public set<T, R extends T>(identifier: ProxyIdentifier<T>, value: R): R {
116
this._locals[identifier.sid] = value;
117
return value;
118
}
119
120
protected _remoteCall(proxyId: string, path: string, args: any[]): Promise<any> {
121
this._callCount++;
122
123
return new Promise<any>((c) => {
124
setTimeout(c, 0);
125
}).then(() => {
126
const instance = this._locals[proxyId];
127
// pretend the args went over the wire... (invoke .toJSON on objects...)
128
const wireArgs = simulateWireTransfer(args);
129
let p: Promise<any>;
130
try {
131
const result = (<Function>instance[path]).apply(instance, wireArgs);
132
p = isThenable(result) ? result : Promise.resolve(result);
133
} catch (err) {
134
p = Promise.reject(err);
135
}
136
137
return p.then(result => {
138
this._callCount--;
139
// pretend the result went over the wire... (invoke .toJSON on objects...)
140
const wireResult = simulateWireTransfer(result);
141
return wireResult;
142
}, err => {
143
this._callCount--;
144
return Promise.reject(err);
145
});
146
});
147
}
148
149
public dispose() { }
150
151
public assertRegistered(identifiers: ProxyIdentifier<any>[]): void {
152
throw new Error('Not implemented!');
153
}
154
}
155
156
function simulateWireTransfer<T>(obj: T): T {
157
if (!obj) {
158
return obj;
159
}
160
161
if (Array.isArray(obj)) {
162
return obj.map(simulateWireTransfer) as any;
163
}
164
165
if (obj instanceof SerializableObjectWithBuffers) {
166
const { jsonString, referencedBuffers } = stringifyJsonWithBufferRefs(obj);
167
return parseJsonAndRestoreBufferRefs(jsonString, referencedBuffers, null);
168
} else {
169
return JSON.parse(JSON.stringify(obj));
170
}
171
}
172
173