Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/base/parts/ipc/node/ipc.mp.ts
4780 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 { MessagePortMain, isUtilityProcess, MessageEvent } from '../../sandbox/node/electronTypes.js';
7
import { VSBuffer } from '../../../common/buffer.js';
8
import { ClientConnectionEvent, IMessagePassingProtocol, IPCServer } from '../common/ipc.js';
9
import { Emitter, Event } from '../../../common/event.js';
10
import { assertType } from '../../../common/types.js';
11
12
/**
13
* The MessagePort `Protocol` leverages MessagePortMain style IPC communication
14
* for the implementation of the `IMessagePassingProtocol`.
15
*/
16
class Protocol implements IMessagePassingProtocol {
17
18
readonly onMessage;
19
20
constructor(private port: MessagePortMain) {
21
this.onMessage = Event.fromNodeEventEmitter<VSBuffer>(this.port, 'message', (e: MessageEvent) => {
22
if (e.data) {
23
return VSBuffer.wrap(e.data as Uint8Array);
24
}
25
return VSBuffer.alloc(0);
26
});
27
// we must call start() to ensure messages are flowing
28
port.start();
29
}
30
31
send(message: VSBuffer): void {
32
this.port.postMessage(message.buffer);
33
}
34
35
disconnect(): void {
36
this.port.close();
37
}
38
}
39
40
export interface IClientConnectionFilter {
41
42
/**
43
* Allows to filter incoming messages to the
44
* server to handle them differently.
45
*
46
* @param e the message event to handle
47
* @returns `true` if the event was handled
48
* and should not be processed by the server.
49
*/
50
handledClientConnection(e: MessageEvent): boolean;
51
}
52
53
/**
54
* An implementation of a `IPCServer` on top of MessagePort style IPC communication.
55
* The clients register themselves via Electron Utility Process IPC transfer.
56
*/
57
export class Server extends IPCServer {
58
59
private static getOnDidClientConnect(filter?: IClientConnectionFilter): Event<ClientConnectionEvent> {
60
assertType(isUtilityProcess(process), 'Electron Utility Process');
61
62
const onCreateMessageChannel = new Emitter<MessagePortMain>();
63
64
process.parentPort.on('message', (e: MessageEvent) => {
65
if (filter?.handledClientConnection(e)) {
66
return;
67
}
68
69
const port = e.ports.at(0);
70
if (port) {
71
onCreateMessageChannel.fire(port);
72
}
73
});
74
75
return Event.map(onCreateMessageChannel.event, port => {
76
const protocol = new Protocol(port);
77
78
const result: ClientConnectionEvent = {
79
protocol,
80
// Not part of the standard spec, but in Electron we get a `close` event
81
// when the other side closes. We can use this to detect disconnects
82
// (https://github.com/electron/electron/blob/11-x-y/docs/api/message-port-main.md#event-close)
83
onDidClientDisconnect: Event.fromNodeEventEmitter(port, 'close')
84
};
85
86
return result;
87
});
88
}
89
90
constructor(filter?: IClientConnectionFilter) {
91
super(Server.getOnDidClientConnect(filter));
92
}
93
}
94
95
interface INodeMessagePortFragment {
96
on(event: 'message', listener: (messageEvent: MessageEvent) => void): this;
97
removeListener(event: 'message', listener: (messageEvent: MessageEvent) => void): this;
98
}
99
100
export function once(port: INodeMessagePortFragment, message: unknown, callback: () => void): void {
101
const listener = (e: MessageEvent) => {
102
if (e.data === message) {
103
port.removeListener('message', listener);
104
callback();
105
}
106
};
107
108
port.on('message', listener);
109
}
110
111