ipc.ts ×60

Frontier kind: Code frontier

unlabeled · c_e036180d5bbd

113 tests · 7947 LOC · 37 files · introduces 0 tests · 452 LOC · 1 file

Introduces — evidence that enters the hierarchy at this concept

Code
60 ranges452 lines · 1 files
Tests
0 tests

Contains — complete concept membership

All code (extent)
1130 ranges7947 lines · 37 files · Browse complete extent
All tests (intent)
113 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.

1 file ranked by introduced lines: 452 introduced LOC across 60 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

src/vs/base/parts/ipc/common/ipc.ts 452 introduced LOC · 60 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- ipc.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 { getRandomElement } from '../../../common/arrays.js';
7 > import { CancelablePromise, createCancelablePromise, timeout } from '../../../common/async.js';
8 > import { VSBuffer } from '../../../common/buffer.js';
9 > import { CancellationToken, CancellationTokenSource } from '../../../common/cancellation.js';
10 > import { memoize } from '../../../common/decorators.js';
11 > import { CancellationError, ErrorNoTelemetry } from '../../../common/errors.js';
12 > import { Emitter, Event, EventMultiplexer, Relay } from '../../../common/event.js';
13 > import { createSingleCallFunction } from '../../../common/functional.js';
14 > import { DisposableStore, dispose, IDisposable, toDisposable } from '../../../common/lifecycle.js';
15 > import { revive } from '../../../common/marshalling.js';
16 > import * as strings from '../../../common/strings.js';
17 > import { isFunction, isUndefinedOrNull } from '../../../common/types.js';
18 >
19 > /**
20 > * An `IChannel` is an abstraction over a collection of commands.
21 > * You can `call` several commands on a channel, each taking at
22 > * most one single argument. A `call` always returns a promise
23 > * with at most one single return value.
24 > */
25 > export interface IChannel {
26 > call<T>(command: string, arg?: any, cancellationToken?: CancellationToken): Promise<T>;
27 > listen<T>(event: string, arg?: any): Event<T>;
28 > }
29 >
30 > /**
31 > * An `IServerChannel` is the counter part to `IChannel`,
32 > * on the server-side. You should implement this interface
33 > * if you'd like to handle remote promises or events.
34 > */
35 > export interface IServerChannel<TContext = string> {
36 > call<T>(ctx: TContext, command: string, arg?: any, cancellationToken?: CancellationToken): Promise<T>;
37 > listen<T>(ctx: TContext, event: string, arg?: any): Event<T>;
38 > }
39 >
40 > const enum RequestType {
41 > Promise = 100,
42 > PromiseCancel = 101,
43 > EventListen = 102,
44 > EventDispose = 103
45 > }
46 >
47 function requestTypeToStr(type: RequestType): string {
48 switch (type) {
57 }
58 }
59 > ipc.ts
60 > type IRawPromiseRequest = { type: RequestType.Promise; id: number; channelName: string; name: string; arg: any };
61 > type IRawPromiseCancelRequest = { type: RequestType.PromiseCancel; id: number };
62 > type IRawEventListenRequest = { type: RequestType.EventListen; id: number; channelName: string; name: string; arg: any };
63 > type IRawEventDisposeRequest = { type: RequestType.EventDispose; id: number };
64 > type IRawRequest = IRawPromiseRequest | IRawPromiseCancelRequest | IRawEventListenRequest | IRawEventDisposeRequest;
65 >
66 > const enum ResponseType {
67 > Initialize = 200,
68 > PromiseSuccess = 201,
69 > PromiseError = 202,
70 > PromiseErrorObj = 203,
71 > EventFire = 204
72 > }
73 >
74 function responseTypeToStr(type: ResponseType): string {
75 switch (type) {
85 }
86 }
87 > ipc.ts
88 > type IRawInitializeResponse = { type: ResponseType.Initialize };
89 > type IRawPromiseSuccessResponse = { type: ResponseType.PromiseSuccess; id: number; data: any };
90 > type IRawPromiseErrorResponse = { type: ResponseType.PromiseError; id: number; data: { message: string; name: string; stack: string[] | undefined } };
91 > type IRawPromiseErrorObjResponse = { type: ResponseType.PromiseErrorObj; id: number; data: any };
92 > type IRawEventFireResponse = { type: ResponseType.EventFire; id: number; data: any };
93 > type IRawResponse = IRawInitializeResponse | IRawPromiseSuccessResponse | IRawPromiseErrorResponse | IRawPromiseErrorObjResponse | IRawEventFireResponse;
94 >
95 > interface IHandler {
96 > (response: IRawResponse): void;
97 > }
98 >
99 > export interface IMessagePassingProtocol {
100 > send(buffer: VSBuffer): void;
101 > readonly onMessage: Event<VSBuffer>;
102 > /**
103 > * Wait for the write buffer (if applicable) to become empty.
104 > */
105 > drain?(): Promise<void>;
106 > }
107 >
108 > enum State {
109 > Uninitialized,
110 > Idle
111 > }
112 >
113 > /**
114 > * An `IChannelServer` hosts a collection of channels. You are
115 > * able to register channels onto it, provided a channel name.
116 > */
117 > export interface IChannelServer<TContext = string> {
118 > registerChannel(channelName: string, channel: IServerChannel<TContext>): void;
119 > }
120 >
121 > /**
122 > * An `IChannelClient` has access to a collection of channels. You
123 > * are able to get those channels, given their channel name.
124 > */
125 > export interface IChannelClient {
126 > getChannel<T extends IChannel>(channelName: string): T;
127 > }
128 >
129 > export interface Client<TContext> {
130 > readonly ctx: TContext;
131 > }
132 >
133 > export interface IConnectionHub<TContext> {
134 > readonly connections: Connection<TContext>[];
135 > readonly onDidAddConnection: Event<Connection<TContext>>;
136 > readonly onDidRemoveConnection: Event<Connection<TContext>>;
137 > }
138 >
139 > /**
140 > * An `IClientRouter` is responsible for routing calls to specific
141 > * channels, in scenarios in which there are multiple possible
142 > * channels (each from a separate client) to pick from.
143 > */
144 > export interface IClientRouter<TContext = string> {
145 > routeCall(hub: IConnectionHub<TContext>, command: string, arg?: any, cancellationToken?: CancellationToken): Promise<Client<TContext>>;
146 > routeEvent(hub: IConnectionHub<TContext>, event: string, arg?: any): Promise<Client<TContext>>;
147 > }
148 >
149 > /**
150 > * Similar to the `IChannelClient`, you can get channels from this
151 > * collection of channels. The difference being that in the
152 > * `IRoutingChannelClient`, there are multiple clients providing
153 > * the same channel. You'll need to pass in an `IClientRouter` in
154 > * order to pick the right one.
155 > */
156 > export interface IRoutingChannelClient<TContext = string> {
157 > getChannel<T extends IChannel>(channelName: string, router?: IClientRouter<TContext>): T;
158 > }
159 >
160 > interface IReader {
161 > read(bytes: number): VSBuffer;
162 > }
163 >
164 > interface IWriter {
165 > write(buffer: VSBuffer): void;
166 > }
167 >
168 >
169 > /**
170 > * @see https://en.wikipedia.org/wiki/Variable-length_quantity
171 > */
172 function readIntVQL(reader: IReader) {
173 let value = 0;
180 }
181 }
182 > ipc.ts
183 > const vqlZero = createOneByteBuffer(0);
184 >
185 > /**
186 > * @see https://en.wikipedia.org/wiki/Variable-length_quantity
187 > */
188 function writeInt32VQL(writer: IWriter, value: number) {
189 if (value === 0) {
208 writer.write(scratch);
209 }
210 > ipc.ts
211 > export class BufferReader implements IReader {
212 >
213 > private pos = 0;
214 >
215 > constructor(private buffer: VSBuffer) { }
216 >
217 > read(bytes: number): VSBuffer {
218 const result = this.buffer.slice(this.pos, this.pos + bytes);
219 this.pos += result.byteLength;
220 return result;
221 }
222 > } ipc.ts
223 >
224 > export class BufferWriter implements IWriter, IDisposable {
225
226 private buffers: VSBuffer[] = [];
227 > ipc.ts
228 > get buffer(): VSBuffer {
229 return VSBuffer.concat(this.buffers);
230 }
231 > ipc.ts
232 > write(buffer: VSBuffer): void {
233 this.buffers.push(buffer);
234 }
235 > ipc.ts
236 > dispose(): void {
237 // Release the buffers so a thrown serialization error's stack can't pin them.
238 this.buffers.length = 0;
239 }
240 > } ipc.ts
241 >
242 > enum DataType {
243 > Undefined = 0,
244 > String = 1,
245 > Buffer = 2,
246 > VSBuffer = 3,
247 > Array = 4,
248 > Object = 5,
249 > Int = 6
250 > }
251 >
252 > function createOneByteBuffer(value: number): VSBuffer {
253 > const result = VSBuffer.alloc(1);
254 > result.writeUInt8(value, 0);
255 > return result;
256 > }
257 >
258 > const BufferPresets = {
259 > Undefined: createOneByteBuffer(DataType.Undefined),
260 > String: createOneByteBuffer(DataType.String),
261 > Buffer: createOneByteBuffer(DataType.Buffer),
262 > VSBuffer: createOneByteBuffer(DataType.VSBuffer),
263 > Array: createOneByteBuffer(DataType.Array),
264 > Object: createOneByteBuffer(DataType.Object),
265 > Uint: createOneByteBuffer(DataType.Int),
266 > };
267 >
268 > export function serialize(writer: IWriter, data: any): void {
269 if (typeof data === 'undefined') {
270 writer.write(BufferPresets.Undefined);
301 }
302 }
303 > ipc.ts
304 > export function deserialize(reader: IReader): any {
305 const type = reader.read(1).readUInt8(0);
306
324 }
325 }
326 > ipc.ts
327 > interface PendingRequest {
328 > request: IRawPromiseRequest | IRawEventListenRequest;
329 > timeoutTimer: Timeout;
330 > }
331 >
332 > export class ChannelServer<TContext = string> implements IChannelServer<TContext>, IDisposable {
333 >
334 > private channels = new Map<string, IServerChannel<TContext>>();
335 > private activeRequests = new Map<number, IDisposable>();
336 > private protocolListener: IDisposable | null;
337 >
338 > // Requests might come in for channels which are not yet registered.
339 > // They will timeout after `timeoutDelay`.
340 > private pendingRequests = new Map<string, PendingRequest[]>();
341 >
342 > constructor(private protocol: IMessagePassingProtocol, private ctx: TContext, private logger: IIPCLogger | null = null, private timeoutDelay = 1000) {
343 this.protocolListener = this.protocol.onMessage(msg => this.onRawMessage(msg));
344 this.sendResponse({ type: ResponseType.Initialize });
345 }
346 > ipc.ts
347 > registerChannel(channelName: string, channel: IServerChannel<TContext>): void {
348 this.channels.set(channelName, channel);
349
351 setTimeout(() => this.flushPendingRequests(channelName), 0);
352 }
353 > ipc.ts
354 > private sendResponse(response: IRawResponse): void {
355 switch (response.type) {
356 case ResponseType.Initialize: {
370 }
371 }
372 > ipc.ts
373 > private send(header: unknown, body: any = undefined): number {
374 const writer = new BufferWriter();
375 try {
381 }
382 }
383 > ipc.ts
384 > private sendBuffer(message: VSBuffer): number {
385 try {
386 this.protocol.send(message);
391 }
392 }
393 > ipc.ts
394 > private onRawMessage(message: VSBuffer): void {
395 const reader = new BufferReader(message);
396 const header = deserialize(reader);
413 }
414 }
415 > ipc.ts
416 > private onPromise(request: IRawPromiseRequest): void {
417 const channel = this.channels.get(request.channelName);
418
455 this.activeRequests.set(request.id, disposable);
456 }
457 > ipc.ts
458 > private onEventListen(request: IRawEventListenRequest): void {
459 const channel = this.channels.get(request.channelName);
460
470 this.activeRequests.set(request.id, disposable);
471 }
472 > ipc.ts
473 > private disposeActiveRequest(request: IRawRequest): void {
474 const disposable = this.activeRequests.get(request.id);
475
479 }
480 }
481 > ipc.ts
482 > private collectPendingRequest(request: IRawPromiseRequest | IRawEventListenRequest): void {
483 let pendingRequests = this.pendingRequests.get(request.channelName);
484
502 pendingRequests.push({ request, timeoutTimer: timer });
503 }
504 > ipc.ts
505 > private flushPendingRequests(channelName: string): void {
506 const requests = this.pendingRequests.get(channelName);
507
519 }
520 }
521 > ipc.ts
522 > public dispose(): void {
523 if (this.protocolListener) {
524 this.protocolListener.dispose();
528 this.activeRequests.clear();
529 }
530 > } ipc.ts
531 >
532 > export const enum RequestInitiator {
533 > LocalSide = 0,
534 > OtherSide = 1
535 > }
536 >
537 > export interface IIPCLogger {
538 > logIncoming(msgLength: number, requestId: number, initiator: RequestInitiator, str: string, data?: any): void;
539 > logOutgoing(msgLength: number, requestId: number, initiator: RequestInitiator, str: string, data?: any): void;
540 > }
541 >
542 > export class ChannelClient implements IChannelClient, IDisposable {
543 >
544 > private isDisposed = false;
545 > private state: State = State.Uninitialized;
546 > private activeRequests = new Set<IDisposable>();
547 > private handlers = new Map<number, IHandler>();
548 > private lastRequestId = 0;
549 > private protocolListener: IDisposable | null;
550 > private logger: IIPCLogger | null;
551 >
552 > private readonly _onDidInitialize = new Emitter<void>();
553 > readonly onDidInitialize = this._onDidInitialize.event;
554 >
555 > constructor(private protocol: IMessagePassingProtocol, logger: IIPCLogger | null = null) {
556 this.protocolListener = this.protocol.onMessage(msg => this.onBuffer(msg));
557 this.logger = logger;
558 }
559 > ipc.ts
560 > getChannel<T extends IChannel>(channelName: string): T {
561 const that = this;
562
577 } as T;
578 }
579 > ipc.ts
580 > private requestPromise(channelName: string, name: string, arg?: any, cancellationToken = CancellationToken.None): Promise<unknown> {
581 const id = this.lastRequestId++;
582 const type = RequestType.Promise;
671 });
672 }
673 > ipc.ts
674 > private requestEvent(channelName: string, name: string, arg?: any): Event<any> {
675 const id = this.lastRequestId++;
676 const type = RequestType.EventListen;
711 return emitter.event;
712 }
713 > ipc.ts
714 > private sendRequest(request: IRawRequest): void {
715 switch (request.type) {
716 case RequestType.Promise:
729 }
730 }
731 > ipc.ts
732 > private send(header: unknown, body: any = undefined): number {
733 const writer = new BufferWriter();
734 try {
740 }
741 }
742 > ipc.ts
743 > private sendBuffer(message: VSBuffer): number {
744 try {
745 this.protocol.send(message);
750 }
751 }
752 > ipc.ts
753 > private onBuffer(message: VSBuffer): void {
754 const reader = new BufferReader(message);
755 const header = deserialize(reader);
770 }
771 }
772 > ipc.ts
773 > private onResponse(response: IRawResponse): void {
774 if (response.type === ResponseType.Initialize) {
775 this.state = State.Idle;
782 handler?.(response);
783 }
784 > ipc.ts
785 > @memoize
786 > get onDidInitializePromise(): Promise<void> {
787 return Event.toPromise(this.onDidInitialize);
788 }
789 > ipc.ts
790 > private whenInitialized(): Promise<void> {
791 if (this.state === State.Idle) {
792 return Promise.resolve();
795 }
796 }
797 > ipc.ts
798 > dispose(): void {
799 this.isDisposed = true;
800 if (this.protocolListener) {
806 this._onDidInitialize.dispose();
807 }
808 > } ipc.ts
809 >
810 > export interface ClientConnectionEvent {
811 > protocol: IMessagePassingProtocol;
812 > readonly onDidClientDisconnect: Event<void>;
813 > }
814 >
815 > interface Connection<TContext> extends Client<TContext> {
816 > readonly channelServer: ChannelServer<TContext>;
817 > readonly channelClient: ChannelClient;
818 > }
819 >
820 > /**
821 > * An `IPCServer` is both a channel server and a routing channel
822 > * client.
823 > *
824 > * As the owner of a protocol, you should extend both this
825 > * and the `IPCClient` classes to get IPC implementations
826 > * for your protocol.
827 > */
828 > export class IPCServer<TContext = string> implements IChannelServer<TContext>, IRoutingChannelClient<TContext>, IConnectionHub<TContext>, IDisposable {
829 >
830 > private channels = new Map<string, IServerChannel<TContext>>();
831 > private _connections = new Set<Connection<TContext>>();
832 >
833 > private readonly _onDidAddConnection = new Emitter<Connection<TContext>>();
834 > readonly onDidAddConnection: Event<Connection<TContext>> = this._onDidAddConnection.event;
835 >
836 > private readonly _onDidRemoveConnection = new Emitter<Connection<TContext>>();
837 > readonly onDidRemoveConnection: Event<Connection<TContext>> = this._onDidRemoveConnection.event;
838 >
839 > private readonly disposables = new DisposableStore();
840 >
841 > get connections(): Connection<TContext>[] {
842 > const result: Connection<TContext>[] = [];
843 > this._connections.forEach(ctx => result.push(ctx));
844 > return result;
845 > }
846 >
847 > constructor(onDidClientConnect: Event<ClientConnectionEvent>, ipcLogger?: IIPCLogger | null, timeoutDelay?: number) {
848 this.disposables.add(onDidClientConnect(({ protocol, onDidClientDisconnect }) => {
849 const onFirstMessage = Event.once(protocol.onMessage);
878 }));
879 }
880 > ipc.ts
881 > /**
882 > * Get a channel from a remote client. When passed a router,
883 > * one can specify which client it wants to call and listen to/from.
884 > * Otherwise, when calling without a router, a random client will
885 > * be selected and when listening without a router, every client
886 > * will be listened to.
887 > */
888 > getChannel<T extends IChannel>(channelName: string, router: IClientRouter<TContext>): T;
889 > getChannel<T extends IChannel>(channelName: string, clientFilter: (client: Client<TContext>) => boolean): T;
890 > getChannel<T extends IChannel>(channelName: string, routerOrClientFilter: IClientRouter<TContext> | ((client: Client<TContext>) => boolean)): T {
891 const that = this;
892
928 } as T;
929 }
930 > ipc.ts
931 > private getMulticastEvent<T extends IChannel>(channelName: string, clientFilter: (client: Client<TContext>) => boolean, eventName: string, arg: any): Event<T> {
932 const that = this;
933 let disposables: DisposableStore | undefined;
982 return emitter.event;
983 }
984 > ipc.ts
985 > registerChannel(channelName: string, channel: IServerChannel<TContext>): void {
986 this.channels.set(channelName, channel);
987
990 }
991 }
992 > ipc.ts
993 > dispose(): void {
994 this.disposables.dispose();
995
1004 this._onDidRemoveConnection.dispose();
1005 }
1006 > } ipc.ts
1007 >
1008 > /**
1009 > * An `IPCClient` is both a channel client and a channel server.
1010 > *
1011 > * As the owner of a protocol, you should extend both this
1012 > * and the `IPCServer` classes to get IPC implementations
1013 > * for your protocol.
1014 > */
1015 > export class IPCClient<TContext = string> implements IChannelClient, IChannelServer<TContext>, IDisposable {
1016 >
1017 > private channelClient: ChannelClient;
1018 > private channelServer: ChannelServer<TContext>;
1019 >
1020 > constructor(protocol: IMessagePassingProtocol, ctx: TContext, ipcLogger: IIPCLogger | null = null) {
1021 const writer = new BufferWriter();
1022 try {
1030 this.channelServer = new ChannelServer(protocol, ctx, ipcLogger);
1031 }
1032 > ipc.ts
1033 > getChannel<T extends IChannel>(channelName: string): T {
1034 return this.channelClient.getChannel(channelName);
1035 }
1036 > ipc.ts
1037 > registerChannel(channelName: string, channel: IServerChannel<TContext>): void {
1038 this.channelServer.registerChannel(channelName, channel);
1039 }
1040 > ipc.ts
1041 > dispose(): void {
1042 this.channelClient.dispose();
1043 this.channelServer.dispose();
1044 }
1045 > } ipc.ts
1046 >
1047 > export function getDelayedChannel<T extends IChannel>(promise: Promise<T>): T {
1048 // eslint-disable-next-line local/code-no-dangerous-type-assertions
1049 return {
1059 } as T;
1060 }
1061 > ipc.ts
1062 > export function getNextTickChannel<T extends IChannel>(channel: T): T {
1063 let didTick = false;
1064
1089 } as T;
1090 }
1091 > ipc.ts
1092 > export class StaticRouter<TContext = string> implements IClientRouter<TContext> {
1093 >
1094 > constructor(private fn: (ctx: TContext) => boolean | Promise<boolean>) { }
1095 >
1096 > routeCall(hub: IConnectionHub<TContext>): Promise<Client<TContext>> {
1097 return this.route(hub);
1098 }
1099 > ipc.ts
1100 > routeEvent(hub: IConnectionHub<TContext>): Promise<Client<TContext>> {
1101 return this.route(hub);
1102 }
1103 > ipc.ts
1104 > private async route(hub: IConnectionHub<TContext>): Promise<Client<TContext>> {
1105 for (const connection of hub.connections) {
1106 if (await Promise.resolve(this.fn(connection.ctx))) {
1112 return await this.route(hub);
1113 }
1114 > } ipc.ts
1115 >
1116 > /**
1117 > * Use ProxyChannels to automatically wrapping and unwrapping
1118 > * services to/from IPC channels, instead of manually wrapping
1119 > * each service method and event.
1120 > *
1121 > * Restrictions:
1122 > * - If marshalling is enabled, only `URI` and `RegExp` is converted
1123 > * automatically for you
1124 > * - Events must follow the naming convention `onUpperCase`
1125 > * - `CancellationToken` is currently not supported
1126 > * - If a context is provided, you can use `AddFirstParameterToFunctions`
1127 > * utility to signal this in the receiving side type
1128 > */
1129 > export namespace ProxyChannel {
1130 >
1131 > export interface IProxyOptions {
1132 >
1133 > /**
1134 > * Disables automatic marshalling of `URI`.
1135 > * If marshalling is disabled, `UriComponents`
1136 > * must be used instead.
1137 > */
1138 > disableMarshalling?: boolean;
1139 > }
1140 >
1141 > export interface ICreateServiceChannelOptions extends IProxyOptions { }
1142 >
1143 > export function fromService<TContext>(service: unknown, disposables: DisposableStore, options?: ICreateServiceChannelOptions): IServerChannel<TContext> {
1144 const handler = service as { [key: string]: unknown };
1145 const disableMarshalling = options?.disableMarshalling;
1203 };
1204 }
1205 > ipc.ts
1206 > export interface ICreateProxyServiceOptions extends IProxyOptions {
1207 >
1208 > /**
1209 > * If provided, will add the value of `context`
1210 > * to each method call to the target.
1211 > */
1212 > context?: unknown;
1213 >
1214 > /**
1215 > * If provided, will not proxy any of the properties
1216 > * that are part of the Map but rather return that value.
1217 > */
1218 > properties?: Map<string, unknown>;
1219 > }
1220 >
1221 > export function toService<T extends object>(channel: IChannel, options?: ICreateProxyServiceOptions): T {
1222 const disableMarshalling = options?.disableMarshalling;
1223
1269 }) as T;
1270 }
1271 > ipc.ts
1272 > function propertyIsEvent(name: string): boolean {
1273 // Assume a property is an event if it has a form of "onSomething"
1274 return name[0] === 'o' && name[1] === 'n' && strings.isUpperAsciiLetter(name.charCodeAt(2));
1275 }
1276 > ipc.ts
1277 > function propertyIsDynamicEvent(name: string): boolean {
1278 // Assume a property is a dynamic event (a method that returns an event) if it has a form of "onDynamicSomething"
1279 return /^onDynamic/.test(name) && strings.isUpperAsciiLetter(name.charCodeAt(9));
1280 }
1281 > } ipc.ts
1282 >
1283 > const colorTables = [
1284 > ['#2977B1', '#FC802D', '#34A13A', '#D3282F', '#9366BA'],
1285 > ['#8B564C', '#E177C0', '#7F7F7F', '#BBBE3D', '#2EBECD']
1286 > ];
1287 >
1288 function prettyWithoutArrays(data: unknown): any {
1289 if (Array.isArray(data)) {
1298 return data;
1299 }
1300 > ipc.ts
1301 function pretty(data: unknown): any {
1302 if (Array.isArray(data)) {
1305 return prettyWithoutArrays(data);
1306 }
1307 > ipc.ts
1308 function logWithColors(direction: string, totalLength: number, msgLength: number, req: number, initiator: RequestInitiator, str: string, data: any): void {
1309 data = pretty(data);
1320 console.log.apply(console, args as [string, ...string[]]);
1321 }
1322 > ipc.ts
1323 > export class IPCLogger implements IIPCLogger {
1324 > private _totalIncoming = 0;
1325 > private _totalOutgoing = 0;
1326 >
1327 > constructor(
1328 private readonly _outgoingPrefix: string,
1329 private readonly _incomingPrefix: string,
1330 ) { }
1331 > ipc.ts
1332 > public logOutgoing(msgLength: number, requestId: number, initiator: RequestInitiator, str: string, data?: any): void {
1333 this._totalOutgoing += msgLength;
1334 logWithColors(this._outgoingPrefix, this._totalOutgoing, msgLength, requestId, initiator, str, data);
1335 }
1336 > ipc.ts
1337 > public logIncoming(msgLength: number, requestId: number, initiator: RequestInitiator, str: string, data?: any): void {
1338 this._totalIncoming += msgLength;
1339 logWithColors(this._incomingPrefix, this._totalIncoming, msgLength, requestId, initiator, str, data);
1340 }
1341 > } ipc.ts